首页 > 技术文章 > QT场景视图父子关系图元打印研究

MakeView660 2019-07-03 10:57 原文

在之前的一篇文章中,实现了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
    enum {Type = UserType + 1};
    
// 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
                  int xOffset = 0,      // x偏移
                  int yOffset = 0,      // y偏移
                  bool root = true);    // 是否是最顶层item

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

private:
    
// actual drawing
    void draw(QPainter *painter,    // painter
              int xOffset = 0,      // x偏移
              int yOffset = 0       // 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.setRed(QRandomGenerator::global()->bounded(255));
    m_color.setGreen(QRandomGenerator::global()->bounded(
255));
    m_color.setBlue(QRandomGenerator::global()->bounded(
255));
    
// item options
    setFlag(ItemIsMovable);
    setFlag(ItemIsSelectable);
}

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

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

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不在其坐标的左上区域,则移除打印的左上角空白区域
        QRectF rectBlankH = QRectF(0.00.0, scene()->width(), scenePos().y());
        QRectF rectBlankV = QRectF(
0.00.0, 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() < 
0 ? 0 : itemTmp->m_scenePos.y();
                        }
                    }
                }
            }
        }
        
if (bFindH)
        {
            painter->translate(-QPointF(
0.0, yPos));
        }
        
else
        {
            painter->translate(-QPointF(
0.0, 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() < 
0 ? 0 : itemTmp->m_scenePos.x();
                        }
                    }
                }
            }
        }
        
if (bFindV)
        {
            painter->translate(-QPointF(xPos, 
0.0));
        }
        
else
        {
            painter->translate(-QPointF(scenePos().x(), 
0.0));
        }
    }
    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() / 
2,
                      rect.y() + rect.height() / 
2,
                      m_name);
    QPen pen(m_color, 
2);
    painter->setPen(pen);
    painter->drawRect(rect);

    m_scenePos = scenePos();
}

void MyItem::findInherit(MyItem *itemFind, bool &find)
{
    QList<QGraphicsItem *> childList = childItems();
    
if (childList.size() > 0)
    {
        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(
0.00.0800.0800.0);
m_view->setScene(m_scene);

// 绘制场景坐标系
QPen pen(Qt::black, 1, Qt::DashLine);
m_scene->addLine(QLineF(-
400.00.04000.0), pen);
m_scene->addLine(QLineF(
0.0, -4000.0400.0), pen);

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

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

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

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

推荐阅读