背景:
要至少能快速生成、顯示50W+的圖元。由于圖元數(shù)目過多,以及繪制圖形復(fù)雜還有很多文字因此生成顯示效率非常之低。因此就希望采用其他方法進(jìn)行效率提升。
在圖元生成階段一直想是否可以使用QThread多線程進(jìn)行一部分圖元的生成,但由于所有的圖形顯示操作都應(yīng)該只由GUI主線程負(fù)責(zé),其他線程無法直接控制GUI的繪制等操作。所以希望能通過子線程進(jìn)行圖元生成,最后通過GUI主線程來繪制。但這里又碰到一個(gè)問題,Qt里面每個(gè)QObject類對象都屬于創(chuàng)建它的線程,除非手動(dòng)對它進(jìn)行moveToThread(QApplication->thread()),在進(jìn)行編碼過程中卻發(fā)現(xiàn)這樣得到的效果并沒有比直接使用主線程好,甚至表現(xiàn)更差了。需要上論壇問問為什么~~
【20150708】問答發(fā)起了幾天沒有一個(gè)人回復(fù),可能是自己表述不佳或者他們認(rèn)為這個(gè)問題有點(diǎn)傻。不過在自己的實(shí)驗(yàn)中發(fā)現(xiàn):
- 一次性把所有的items都直接add到Scene里面,其效率會(huì)遠(yuǎn)遠(yuǎn)低于分層思想來組織items的結(jié)構(gòu)。也就是說使用一個(gè)rootItem作為其他items的parentItem,然后把rootItem添加到scene里,其顯示交互效率好很多。
- Qt的圖形體系與QObject是有區(qū)分的。QGraphicsItem并不繼承于QObject,因此他們也沒有signal/slot的成本。
- Qt中QObject系列的類都是有線程歸屬的。而GUI操作都只能通過main thread來進(jìn)行。所以繪制圖形之類都只能是主線程。而如果是QGraphicsObject它繼承自QObject和QGraphicsItem,那么它在顯示時(shí)候就需要是屬于主線程。
- 可以通過次線程來構(gòu)建圖元(QGraphicsItem或者QGraphicsObject)但如果是Object那么需要手動(dòng)將它們moveToThread()到主線程
- 但經(jīng)過測試發(fā)現(xiàn),雖然可以通過次線程構(gòu)建,然后move到主線程,但在后續(xù)添加到scene的過程中卻花費(fèi)了更多時(shí)間,同時(shí)后續(xù)縮放等操作也有更明顯延遲。
[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<Chip *> mlstopItems;
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]