【发布时间】:2014-11-21 09:34:54
【问题描述】:
我有一个应用程序可以交互式地在屏幕上移动从 QWidget 派生的对象。有时,当我将焦点切换到另一个应用程序时,它们会留下先前几何图形的伪影,但会一直留在屏幕上。
以下是我在交互式调整小部件大小时看到的一些工件示例:
我能够创建一个相当简单的测试用例,自动复制类似的问题(尽管只留下一行粗的工件)。在此示例中,几何图形的每次水平“翻转”后始终会留下一条垂直线伪影:
#include <QApplication>
#include <QDialog>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>
#include <QWidget>
class TestWidget : public QWidget
{
Q_OBJECT
public:
explicit TestWidget(QWidget *parent = 0);
private:
void paintEvent(QPaintEvent *e);
QRect thisRect();
void timerEvent(QTimerEvent *t);
};
TestWidget::TestWidget(QWidget *parent) :
QWidget(parent)
{
setGeometry(100,100, 100,100);
startTimer(5);
}
QRect TestWidget::thisRect()
{
return QRect(QPoint(),geometry().size());
}
void TestWidget::timerEvent(QTimerEvent *t)
{
QRect geo = geometry();
static bool growUp = false;
static bool flipUp = false;
static bool flipOver = false;
static bool growOver = false;
static int delta = 1;
static int delta2 = 1;
static int tick = 0;
static int enDelta = 1;
tick++;
if(flipUp)
geo.adjust(0,enDelta * delta,0,0);
else
geo.adjust(0,0,0,enDelta * delta);
if(tick%3==0)
enDelta = 0;
else
enDelta = 1;
if(geo.height()>100)
{
if(growUp)
delta = 1;
else
delta = -1;
growUp = !growUp;
}
if(geo.height() == 0)
flipUp = !flipUp;
if(flipOver)
geo.adjust(delta2 ,0, 0,0);
else
geo.adjust(0,0,delta2 ,0);
if(geo.width()>100)
{
if(growOver)
delta2 = 1;
else
delta2 = -1;
growOver = !growOver;
}
if(geo.height() == 0)
flipOver = !flipOver;
setGeometry(geo);
}
void TestWidget::paintEvent(QPaintEvent *e)
{
QBrush b(QColor(55,200,55,190));
QPainter p(this);
p.setBrush(b);
//p.drawRect(QRect(QPoint,this->geometry().size()));
//p.drawRect(QRect(QPoint,geometry().size()));
if(thisRect().width() != 0 && thisRect().height() != 0)
{
p.drawRect(thisRect());
qDebug() << "painted rect is " << thisRect();
qDebug() << "painted geo is " << geometry();
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//MainWindow w;
//w.show();
QDialog d;
d.show();
int i;
TestWidget *tw;
for(i=0; i<1; i++) //2000; i++)
{
tw = new TestWidget(&d);
tw->show();
}
return a.exec();
}
我是否缺少某种同步,或者这是一个错误? (我开始研究事件队列和后备存储算法,但是一旦我将焦点从测试应用程序转移到 Qt Creator 以便我可以单步执行,工件就消失了。这使得跟踪有点棘手。另外,由于它是双缓冲的,因此很难准确查看项目何时渲染到暂存缓冲区,因为它发生时没有视觉反馈。)
添加后添加:
update();
(正如下面的评论中提到的),有显着的改进,但其他方面相同的代码仍然产生了一个工件,这里显示在红色箭头所指的红色圆圈中:
【问题讨论】:
-
如果您尝试在此行之后调用
update()怎么办:setGeometry(geo);? -
这绝对有帮助。谢谢你。我还有一个小神器。我在上面添加了剩余神器的图片。
-
我找到了解决方案。解决方案是在更改子对象的几何形状后更新() parentWidget。 (这对我来说很有意义,因为孩子的几何形状是相对于 parentWidget,而不是孩子本身。我现在认为这很可能不是一个错误,但如果有一个很好的参考,我也想更好地理解渲染内部可用,甚至是几句智慧的话。)