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); |
希望大家能把自己的所学和他人一起分享,不要去鄙视别人索取时的贪婪,因为最应该被鄙视的是不肯分享时的吝啬。