問題描述
工作數小時后,我可以在 QListView
上繪制小部件.但是,繪制是通過QPixmap
完成的.小部件出現,我可以看到一個進度條.然而,它有點像素化"(由于使用了QPixmap
).是否可以直接作為普通小部件進行繪制?這是我的問題.
After hours of work, I'm able to paint a widget on QListView
. However, the painting is done through a QPixmap
. The widget appears, and I can see a progress bar. However, it's a little "pixelated" (due to using QPixmap
). Is it possible to paint directly as a normal widget? That's my question.
以下是我所做的:
void FileQueueItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QPaintDevice* original_pdev_ptr = painter->device();
FileQueueListItem* itemWidget = reinterpret_cast<FileQueueListItem*>(index.data(Qt::UserRole).value<void*>());
itemWidget->setGeometry(option.rect);
painter->end();
QPixmap pixmap(itemWidget->size());
if (option.state & QStyle::State_Selected)
pixmap.fill(option.palette.highlight().color());
else
pixmap.fill(option.palette.background().color());
itemWidget->render(&pixmap,QPoint(),QRegion(),QWidget::RenderFlag::DrawChildren);
painter->begin(original_pdev_ptr);
painter->drawPixmap(option.rect, pixmap);
}
我從此處學習了如何使用提示進行操作.在那里,繪畫是直接在 QListView
上完成的,這正是我想要實現的.以下嘗試不起作用,我做錯了什么:
I learned how to do what I did with the hints from here. There, the painting is done directly on QListView
, which is what I'm looking to achieve. What am I doing wrong for the following attempt not to work:
void FileQueueItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
std::cout<<"Painting..."<<std::endl;
QPaintDevice* original_pdev_ptr = painter->device();
FileQueueListItem* itemWidget = reinterpret_cast<FileQueueListItem*>(index.data(Qt::UserRole).value<void*>());
itemWidget->setGeometry(option.rect);
painter->end();
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
else
painter->fillRect(option.rect, option.palette.background());
itemWidget->render(painter->device(),
QPoint(option.rect.x(), option.rect.y()),
QRegion(0, 0, option.rect.width(), option.rect.height()),
QWidget::RenderFlag::DrawChildren);
painter->begin(original_pdev_ptr);
}
列表只是空著,什么也沒有發生.雖然可以看到選擇,但小部件不顯示.
The list just remains empty, and nothing happens. Though the selection can be seen, but the widget doesn't show up.
推薦答案
讓我們把一些事情說清楚:
Let's make a few things clear:
您不應該創建小部件并將它們放入模型中.這有一個很好的理由.Qt 事件循環中涉及小部件,這意味著擁有過多小部件會顯著降低您的程序速度.
You're not supposed to create widgets and put them in a model. There's a very good reason for this. Widgets are involved in the Qt event loop, which means that having too many widgets will significantly slow down your program.
小部件不僅僅是一堆控件(這似乎是您看待它們的方式).它們參與事件循環,這就是為什么您不應該擁有屬于數據模型一部分的小部件.
Widgets are not simply a bunch of controls (which seems to be how you see them). They take part in the event loop, which is why you should not have a widget that's a part of a data model.
如果您使用的是多線程程序并且我們的模型與視圖分離,那么內存管理將成為一場噩夢.Qt 永遠不會容忍嘗試從其他線程構造或刪除任何小部件(這是有道理的,因為從事件循環中分離線程通常不是線程安全的).
If you're using a multithreaded program and you have our model separated from the view, memory management will become a nightmare. Qt will never tolerate trying to construct or delete any widgets from other threads (which makes sense, since detaching threads from the event loop is not generally thread-safe).
根據這些信息,做您想做的事情的正確方法是什么?遺憾的是,唯一正確的方法是自己繪制控件.如果您的小部件很簡單,那很容易做到.如果您的小部件很復雜,您將需要大量數學運算來計算每個小部件的位置.
Given this information, what's the right way to do what you're trying to do? Sadly the only correct way is to draw the controls yourself. If your widget is simple, that's easy to do. If your widget is complicated, you're gonna need lots of math to calculate the positions of every widget.
在 Qt Torrent 示例中,您將看看進度條是如何繪制的.繪制控件所需要做的就是計算位置,并使用rect
成員變量作為控件的包含矩形,然后繪制它們(當然,在設置它們的值之后).paint()
函數中有一個 option.rect
參數,它是整個項目的矩形.您所要做的就是使用一些數學方法來計算每個小部件在此矩形內的位置.
In the Qt Torrent Example, you'll see how a progress bar is drawn. All you have to do to draw your controls, is calculate the position, and use the rect
member variable as the containing rectangle of the controls, and then draw them (of course, after setting their values). The function paint()
has an option.rect
parameter in it, which is the rectangle of the whole item. All you have to do, is use some math to calculate the positions inside this rect for every widget.
PS:永遠不要對位置使用絕對值.你永遠不會做對,尤其是對于不同的 DPI.
PS: NEVER USE ABSOLUTE VALUES FOR THE POSITIONS. You will never get it right, especially for different DPIs.
這將在沒有小部件的情況下繪制控件,并且即使對于數千個元素也能保證您所需的速度.
That will draw the controls without widgets, and will guarantee the speed you need even for thousands of elements.
這篇關于使用 QStyledItemDelegate::paint() 直接在 QListView 上繪制小部件的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!