背景:
要至少能快速生成、显示50W+的图元。由于图元数目过多,以及绘制图形复杂还有很多文字因此生成显示效率非常之低。因此就希望采用其他方法进行效率提升。
在图元生成阶段一直想是否可以使用QThread多线程进行一部分图元的生成,但由于所有的图形显示操作都应该只由GUI主线程负责,其他线程无法直接控制GUI的绘制等操作。所以希望能通过子线程进行图元生成,最后通过GUI主线程来绘制。但这里又碰到一个问题,Qt里面每个QObject类对象都属于创建它的线程,除非手动对它进行moveToThread(QApplication->thread()),在进行编码过程中却发现这样得到的效果并没有比直接使用主线程好,甚至表现更差了。需要上论坛问问为什么~~
【20150708】问答发起了几天没有一个人回复,可能是自己表述不佳或者他们认为这个问题有点傻。不过在自己的实验中发现:
- 一次性把所有的items都直接add到Scene里面,其效率会远远低于分层思想来组织items的结构。也就是说使用一个rootItem作为其他items的parentItem,然后把rootItem添加到scene里,其显示交互效率好很多。
- Qt的图形体系与QObject是有区分的。QGraphicsItem并不继承于QObject,因此他们也没有signal/slot的成本。
- Qt中QObject系列的类都是有线程归属的。而GUI操作都只能通过main thread来进行。所以绘制图形之类都只能是主线程。而如果是QGraphicsObject它继承自QObject和QGraphicsItem,那么它在显示时候就需要是属于主线程。
- 可以通过次线程来构建图元(QGraphicsItem或者QGraphicsObject)但如果是Object那么需要手动将它们moveToThread()到主线程
- 但经过测试发现,虽然可以通过次线程构建,然后move到主线程,但在后续添加到scene的过程中却花费了更多时间,同时后续缩放等操作也有更明显延迟。
问答链接
[SIZE=2]Hi, Everyone.
I am using QGraphicsView system to show a layout in chip design system.(EDA tools like Virtuso、Thunder、ICC)
And the max amount of QGraphicsObject/QGraphicsItem can be 500,000+, or even more.
Thus i have problem making items easy and quick to be drawn or view in the scene.
I followed the Chips demo, and query the solutions from Google, also read lots of topics in QtCentre.
But still i did not find a viable solution, Also Text item impact enormous.
Out group use the tree structure to organize the objects, which use a root item as the top level item, and then level 2, level 3...
But the users always need to flat all the items. And Then i use QTransform()::m11() to control the shape the item is paint.
But with so many items inside even this methods does not work.
There are two difficult parts on this case:[/SIZE]
[SIZE=3][SIZE=2]1)how to reduce the loading time for creating QGraphicsItem.
2)how to make it smoother while zoom in/zoom out, with so many items.[/SIZE][/SIZE]
[SIZE=2]Codes below are the sample i tried to use QThread to save loading time. But it does not work, or the program works
bad than no sub thread is used to load the items. I am very curious why the program has no response when i used sub thread,
and the program runs smoother with no sub thread.
Thanks all.
[/SIZE]
[CODE]
// Used to as Root item
class CRoot: public QGraphicsObject
{
public:
CRoot(QGraphicsObject *opParent = NULL) : QGraphicsObject(opParent)
{}
QRectF boundingRect() { return QRectF(); }
...
};
// Leaf Item
class Chip : public QGraphicsObject
{
...
void paint(QPainter *opPainter, const QStyleOptionGraphicsItem *opOPtion, QWidget *opWidget)
{
Q_UNUSED(opOPtion);
Q_UNUSED(opWidget);
opPainter->save();
double d_value = mdWidth * transform().m11();
if (d_value >= 7)
{
opPainter->drawShape(moShape);
}
else
{
opPainter->drawPoint(0, 0);
}
opPainter->restore();
}
private:
QPainterPath moShape; // used to store the path of Chip
QGraphicsTextItem *mopLabel; // Label item of this cell.
};
class CLayout : public QGraphicsObject
{
Q_OBJECT
public:
CLayout(QGraphicsObject *opParent = NULL) : QGraphicsObject(opParent)
{
}
CRoot *mopGetRoot()
{
QReadLocker o_locker(&moLock);
return mopRoot;
}
signals:
void msigLoadDone();
public slots:
void mslotLoadItems()
{
QWriteLocker o_locker(&moLock);
mopRoot = new CRoot;
const int I_COUNT = 500000;
for (int i_cnt = 0; i_cnt < I_COUNT; ++i_cnt)
{
Chip *op_chip = new chip(CRoot);
op_chip->setPos(i_cnt / 10000, i_cnt / 10000);
mlstopItems.push_back(op_chip);
}
// move items from curThread to GUI thread.
moveToThread(QApplication::instance()->thread());
mopRoot->moveToThread(QApplication::instance()->thread());
foreach(Chip *op_item, mlstopItems)
{
op_item->moveToThread(QApplication::instance()->thread());
}
emit msigLoadDone();
}
private:
CRoot *mopRoot;
QList
QReadWriteLock moLock;
};
class CMainWindow: public QMainWindow
{
Q_OBJECT
public:
...
void mvInitScene()
{
mopScene = new QGraphicsScene();
}
signals:
void msigGoToLoad();
public slots:
void mslotSetRootItem()
{
std::call_once(meFlag, &CMainWindow::mvInitScene, this);
mopScene()->addItem(mopLayout->mopGetRoot());
}
void mslotBtnClicked()
{
mopThread = new QThread();
mopLayout = new Layout();
#ifdef USED_THREAD
connect(this, SIGNAL(msigGoToLoad()), mopLayout, SLOT(mslotLoadItems()));
connect(mopLayout, SIGNAL(msigLoadDone()), this, SLOT(mslotSetRootItem()));
connect(mopThread, SIGNAL(finished()), mopThread, SLOT(deleteLater()));
mopLayout->moveToThread(mopThread);
mopThread->start();
#else
mopLayout->mslotLOadItems();
mslotSetRootItem();
#endif
emit msigGoToLoad();
}
private:
QThread *mopThread;
CLayout *mopLayout;
QGraphicsScene *mopScene;
std::once_flag meFlag;
};
[/CODE]