在之前的一篇文章中,实现了QT场景视图的打印功能,主要通过render函数来实现,非常简单和方便。

在实际的项目需求中,除了打印整个场景外,还需要对单个图形进行打印操作,基于item的图形可以在paint函数中打在QPrinter作为绘图设备实现打印,基于Widget的图形则提供了更方便的render函数,都可以很好地实现。但是,如果图形存在父子嵌套关系,则需要在打印该图形时,连同其子图形以及孙子图形也要一起打印出来,为此,本文对此进行了研究,方便参考。

目的:实现QT场景视图中父子关系打印

具体要求: 打印某图形时,打印其为根的一颗图形树;  打印左上角不留空白区域

主要代码,仅供参考:

 MyItem.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 
#ifndef MYITEM_H
#define MYITEM_H

#include <QGraphicsItem>

class QPainter;
class MyItem : public QGraphicsItem
{
public:
    explicit MyItem(QGraphicsItem *parent = nullptr);
    MyItem(const QString &name, QGraphicsItem *parent = nullptr);

// custom item type
};
    // overriding bounding rect
    QRectF boundingRect() const override;
    // overriding type()
    int type() const override;
    // overrriding paint()
    void paint(QPainter *painter,
               const QStyleOptionGraphicsItem *option,
               QWidget *widget = nullptr) override;
    // recursive print items
    void printAll(QPainter *painter,    // painter
,      // x偏移
,      // y偏移
                  bool root = true);    // 是否是最顶层item

protected:
    // overriding mouse events
    virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);

private:
    // actual drawing
    void draw(QPainter *painter,    // painter
,      // x偏移
       // y偏移
             );

// find item from full parent/child tree
    void findInherit(MyItem *itemFind, bool &find);

private:
    QString     m_name;
    QColor      m_color;
    QPointF     m_scenePos;

};

#endif // MYITEM_H

 MyItem.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
 
#include "MyItem.h"
#include <QPainter>
#include <QGraphicsScene>
#include <QRandomGenerator>
#include <QPrinter>
#include <QPrintDialog>

MyItem::MyItem(QGraphicsItem *parent)
    : QGraphicsItem (parent)
    , m_name("")
{
    // radom color
));
    m_color.setGreen(QRandomGenerator::global()->bounded());
    m_color.setBlue(QRandomGenerator::global()->bounded());
    // item options
    setFlag(ItemIsMovable);
    setFlag(ItemIsSelectable);
}

MyItem::MyItem(const QString &name, QGraphicsItem *parent)
    : QGraphicsItem (parent)
    , m_name(name)
{
    // radom color
));
    m_color.setGreen(QRandomGenerator::global()->bounded());
    m_color.setBlue(QRandomGenerator::global()->bounded());
    // item options
    setFlag(ItemIsMovable);
    setFlag(ItemIsSelectable);
}

QRectF MyItem::boundingRect() const
{
    // outer most edges
);
}

int MyItem::type() const
{
    // Enable the use of qgraphicsitem_cast with this item.
    return Type;
}

void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    draw(painter);
}

void MyItem::printAll(QPainter *painter, int xOffset, int yOffset, bool root)
{
    if (root)
    {
        bool bFindH = false;
        bool bFindV = false;
        unsigned int xPos = scenePos().x();
        unsigned int yPos = scenePos().y();
        // 如果其child item不在其坐标的左上区域,则移除打印的左上角空白区域
, scene()->width(), scenePos().y());
        QRectF rectBlankV = QRectF(, scenePos().x(), scene()->height());
        // 水平区域
        QList<QGraphicsItem *> itemListH = scene()->items(rectBlankH);
        foreach (QGraphicsItem *item, itemListH)
        {
            if (item->type() == MyItem::Type)
            {
                MyItem *itemTmp = qgraphicsitem_cast<MyItem *>(item);
                if (itemTmp != nullptr)
                {
                    bool find = false;
                    findInherit(itemTmp, find);
                    if (find)
                    {
                        bFindH = true;
                        if (itemTmp->m_scenePos.y() < yPos)
                        {
                            yPos = itemTmp->m_scenePos.y() <  : itemTmp->m_scenePos.y();
                        }
                    }
                }
            }
        }
        if (bFindH)
        {
            painter->translate(-QPointF(, yPos));
        }
        else
        {
            painter->translate(-QPointF(, scenePos().y()));
        }

// 垂直区域
        QList<QGraphicsItem *> itemListV = scene()->items(rectBlankV);
        foreach (QGraphicsItem *item, itemListV)
        {
            if (item->type() == MyItem::Type)
            {
                MyItem *itemTmp = qgraphicsitem_cast<MyItem *>(item);
                if (itemTmp != nullptr)
                {
                    bool find = false;
                    findInherit(itemTmp, find);
                    if (find)
                    {
                        bFindV = true;
                        if (itemTmp->m_scenePos.x() < xPos)
                        {
                            xPos = itemTmp->m_scenePos.x() <  : itemTmp->m_scenePos.x();
                        }
                    }
                }
            }
        }
        if (bFindV)
        {
            painter->translate(-QPointF(xPos, ));
        }
        else
        {
            painter->translate(-QPointF(scenePos().x(), ));
        }
    }
    draw(painter, m_scenePos.x(), m_scenePos.y());

QList<QGraphicsItem *> childList = childItems();
    foreach (QGraphicsItem *item, childList)
    {
        if (item->type() == MyItem::Type)
        {
            MyItem *myChilditem = qgraphicsitem_cast<MyItem *>(item);
            if (myChilditem != nullptr)
            {
                myChilditem->printAll(painter, m_scenePos.x(), m_scenePos.y(), false);
            }
        }
    }
}

void MyItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    QPrinter printer;
    QPrintDialog printDlg(&printer);
    if (printDlg.exec())
    {
        QPainter painter(&printer);
        QRectF rect = scene()->sceneRect();
        painter.translate(-rect.x(), -rect.y());
        printAll(&painter);
    }
}

void MyItem::draw(QPainter *painter, int xOffset, int yOffset)
{
    QRectF rect = boundingRect();
    qreal width = rect.width();
    qreal height = rect.height();
    rect.setX(xOffset);
    rect.setY(yOffset);
    rect.setWidth(width);
    rect.setHeight(height);
    painter->drawText(rect.x() + rect.width() / ,
                      rect.y() + rect.height() / ,
                      m_name);
    QPen pen(m_color, );
    painter->setPen(pen);
    painter->drawRect(rect);

m_scenePos = scenePos();
}

void MyItem::findInherit(MyItem *itemFind, bool &find)
{
    QList<QGraphicsItem *> childList = childItems();
    )
    {
        foreach (QGraphicsItem *item, childList)
        {
            if (item->type() == MyItem::type())
            {
                MyItem *itemChild = qgraphicsitem_cast<MyItem *>(item);
                if (itemChild != nullptr)
                {
                    if (itemChild == itemFind)
                    {
                        find = true;
                    }
                    itemChild->findInherit(itemFind, find);
                }
            }
        }
    }
}

测试代码:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
m_view = new QGraphicsView(this);
m_scene = new QGraphicsScene();
m_scene->setSceneRect();
m_view->setScene(m_scene);

// 绘制场景坐标系
, Qt::DashLine);
m_scene->addLine(QLineF(-), pen);
m_scene->addLine(QLineF(), pen);

// item-based
MyItem *item = new MyItem("parent");
m_scene->addItem(item);

MyItem *child1 = new MyItem("child1");
child1->setParentItem(item);
child1->setPos(-);
m_scene->addItem(child1);

MyItem *child2 = new MyItem("child2");
child2->setParentItem(item);
child2->setPos();
m_scene->addItem(child2);

MyItem *child21 = new MyItem("child21");
child21->setParentItem(child2);
child21->setPos();
m_scene->addItem(child21);

QT场景视图父子关系图元打印研究的更多相关文章

  1. Qt Examples - Boxes (在Qt场景视图中结合OpenGL渲染)

    QT自带例程Boxes使用QT Graphics View框架实现了2D图形和3D图形的混合渲染,综合性比较强,整合知识较多,值得学习. 可以使用鼠标通过以下方式控制演示中的元素: 按住鼠标左键的同时 ...

  2. iOS 父子关系

    1.面向对象特征,类的继承 成员变量(实例变量) 子类继承父类所有功能,只能直接(访问)调用父类中的.h中的protect和public成员变量(实例变量)及方法, .h中的私有的成员变量,子类不能直 ...

  3. Qt 对象间的父子关系

    C++中只要有一个new就必须要有一个delete与之对应 但是Qt中的对象之间有特殊的关系 Qt 对象间的父子关系 每一个对象都保存有它所有子对象的指针 每一个对象都有一个指向其父对象的指针 par ...

  4. Qt图形视图体系结构

    导读:本文主要翻译自QT 5.9.3GraphicsView官方文档 一.GraphicsView框架简介 QT4.2开始引入了Graphics View框架用来取代QT3中的Canvas模块,并作出 ...

  5. QT 图形视图框架

    https://blog.csdn.net/qq769651718/article/details/79357936 使用QPushButton.QLabel.QCheckBox等构成GUI的控件或自 ...

  6. 7.QT-Qt对象间的父子关系

    Qt对象之间可以存在父子关系 继承于QObject类或者其子类的对象,都称为Qt对象 当指定Qt对象的父对象时 需要通过setParent()成员函数来设置对象间的父子关系 子对象将会把自己的指针地址 ...

  7. 个人永久性免费-Excel催化剂功能第68波-父子结构表转换之父子关系BOM表拆分篇

    Excel中制造业行业中,有一个非常刚需的需求是对BOM(成品物料清单)的拆解,一般系统导出的BOM表,是经过压缩处理的,由父子表结构的方式存储数据.对某些有能力使用SAP等专业ERP软件的工厂来说, ...

  8. MFC窗口的父子关系和层级关系

    一直对窗口之间的关系有些混乱,遇到需要指定父窗口的函数时常常要考虑很久,究竟父窗口是哪个窗口,遂上网查资料,略有所悟,简记如下: 对话框中的所有控件(比如Button等)都是其子窗口.        ...

  9. oracle处理节点之间的父子关系

    通常当与树的结构之间的关系处理,这是一个很复杂的事情,我们可以通过程序代码去逐层遍历父或子节点,这样做的缺点是很明显,效率不高,操作复杂性是比较大的.而当我们使用Oracle当数据库,我们可以有一个简 ...

随机推荐

  1. tar命令-解压和压缩文件

    tar命令 可以用来压缩打包单文件.多个文件.单个目录.多个目录. Linux打包命令_tar tar命令可以用来压缩打包单文件.多个文件.单个目录.多个目录. 常用格式: 单个文件压缩打包 tar ...

  2. WebSocket协议-基础篇

    本篇文章主要讲述以下几点: WebSocket协议出现的背景 WebSocket与HTTP WebSocket API WebSocket协议出现的背景 我们在上网过程中经常用到的是HTTP和HTTP ...

  3. NOIP201110观光公交

    题目描述 Description 风景迷人的小城Y市,拥有n个美丽的景点.由于慕名而来的游客越来越多,Y市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第0分钟出现在1号景点,随后 ...

  4. zzulioj - 2600: 有多少天?

    题目链接:http://acm.zzuli.edu.cn/problem.php?id=2600 题目描述 小D同学对日期类的问题很是有兴趣,已知1900-01-01是星期一,那么小D想知道给定两个年 ...

  5. android 自定义gridview(导航)

    最近又重新做回安卓,做了个小项目.下绝心使用android studio,通过这一回实战,终于用上了.综合了前人的经验,搞了个自己满意的导航界面,用的是gridview. 代码: package co ...

  6. Unity Shader 2D水流效果

    水流的模拟主要运用了顶点变换和纹理动画的结合: 顶点变换中,利用正弦函数模拟河流的大致形态,例如波长,振幅等. 纹理动画中,将纹理坐标朝某一方向持续滚动以形成流动的效果. 脚本如下: Shader & ...

  7. 我自己整理的 Linux 常用命令

    1.查看文件安装路径: 由于软件安装的地方不止一个地方,所有先说查看文件安装的所有路径(地址). 这里以 xsp 为例.比如说我安装了xsp,但是不知道文件都安装在哪些地方.放在哪些文件夹里,可以用下 ...

  8. 喜大普奔,又拍云全新产品 WebSocket 上线啦

    作为一款现象级 MMORPG,魔兽世界迎来了自己的 9.0 版本.巧的是,又拍云最近也更新发布了一款产品--WebSocket.你可能会说,两者有个 mao 关系,不着急.我们先来聊聊魔兽世界~ 熟悉 ...

  9. redux的本质是一套行为解释系统

    redux的本质是一套行为解释系统. 首先构建解释系统: 然后使用解释系统对行为进行解释,进而完成对store和状态的维护.

  10. Why React Is Favored by Front-End Specialists

    In this section, we will discuss some of the features that make React a superior choice for front-en ...