QT场景视图父子关系图元打印研究

在之前的一篇文章中,实现了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( 0 0 100 100 );
}

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 . 0 0 . 0 , scene()->width(), scenePos().y());
        QRectF rectBlankV = QRectF(
0 . 0 0 . 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 . 0 0 . 0 800 . 0 800 . 0 );
m_view->setScene(m_scene);

// 绘制场景坐标系
QPen pen(Qt::black,  1 , Qt::DashLine);
m_scene->addLine(QLineF(-
400 . 0 0 . 0 400 0 . 0 ), pen);
m_scene->addLine(QLineF(
0 . 0 , - 400 0 . 0 400 . 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(
100 100 );
m_scene->addItem(child2);

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

转载于:https://www.cnblogs.com/MakeView660/p/11125112.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值