2014-11-21 45 views
1

我有一个应用程序,可以在屏幕上交互地移动从QWidget派生的对象。有时,当我将焦点切换到另一个应用程序时,它们会留下先前几何图形的人工痕迹,但直到此时才停留在屏幕上。QWidgets遗留以前绘画的工件

下面是我看的时候重新调整大小的窗口小部件交互文物的一些例子:

artifacts

我能够创建可自动复制一个类似的问题相当简单的测试案例(尽管只留下一行厚的文物)。在这个例子中,一个单一的垂直线神器一致的几何形状的每个水平“翻转”后留下的:

#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转移到Qt Creator时,我可以单步执行,但是这些工件会消失,这使得跟踪起来有点棘手,事实上,它是双缓冲使得它更难看到什么时候项呈现给暂存缓冲器,由于存在,因为它发生没有视觉反馈)

添加添加后:

update(); 

(并在下面的评论中提到),有显着的改进,但其他方面相同的代码,仍然产生了一个工件,在红色箭头指向的红色圆圈中显示:

enter image description here

+0

如果你尝试调用'更新()'后这一行:'setGeometry(geo);'? – vahancho 2014-11-21 10:09:01

+0

这绝对有帮助。谢谢。我仍然有一个小神器。我添加了上面剩下的神器的图片。 – user3761340 2014-11-21 22:13:52

+0

我找到了解决方案。解决方案是在更改子几何之后更新()parentWidget。 (这对我来说很有意义,因为孩子的几何是相对于parentWidget,而不是孩子本身。我现在认为这很可能不是一个bug,但是如果有一个很好的参考很容易更好地理解渲染内部可用或甚至几句智慧。) – user3761340 2014-11-21 23:55:31

回答

0

我发现似乎是一个解决方案。解决方法是更新()(如vhancho所示),但是更改对象的parentWidget后更改其几何。 (这对我来说很有意义,因为孩子的几何是相对于parentWidget而不是孩子本身的。在更新几何topLeft时,我也有类似的混乱情况,当然,这总是在坐标系中。drawRect中的父窗口部件,相反,将在对象插件,其中它被称为的坐标)

这里是校正测试用例:

#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); 
 

 
    parentWidget()->update(); //this line removes all artifacts from this test case 
 

 
} 
 

 

 

 
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(); 
 
}

0

这不仅仅是答案,而是评论的大小和其他限制,我认为这些信息可能对其他人有价值,所以我会在这里包括它。

我回头想这可能是一个错误。我现在刚刚使用文档中的QRubberBand示例模式,并且如果快速旋转橡皮筋的原点,则会看到相同类型的工件。下面是我从创建的文档的例子的全码:

#ifndef WIDGET_H 
#define WIDGET_H 
#include <QWidget> 
#include <QRubberBand> 
class Widget : public QWidget 
{ Q_OBJECT void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); public: Widget(QWidget *parent = 0); ~Widget(); private: QRubberBand rubberBand; QPoint origin; }; #endif // WIDGET_H #include <QMouseEvent> Widget::Widget(QWidget *parent) : QWidget(parent) , rubberBand(QRubberBand::Rectangle, this) { } Widget::~Widget() { } 
void Widget::mousePressEvent(QMouseEvent *event) 
{ 
origin = event->pos(); 
//if (!rubberBand) 
// rubberBand = new QRubberBand(QRubberBand::Rectangle, this); 
rubberBand.setGeometry(QRect(origin, QSize())); 
rubberBand.show(); 
} 
void Widget::mouseMoveEvent(QMouseEvent *event) 
{ 
rubberBand.setGeometry(QRect(origin, event->pos()).normalized()); 
} 
void Widget::mouseReleaseEvent(QMouseEvent *event) 
{ 
rubberBand.hide(); 
// determine selection, for example using QRect::intersects() 
// and QRect::contains(). 
} 
#include <QApplication> 
int main(int argc, char *argv[]) 
{ 
QApplication a(argc, argv); 
Widget w; 
w.show(); 
return a.exec(); 
} 

再次,这可以通过添加仅几何图形修改后更新()来解决,但由于这不是记录图案的一部分。例如,我预计它不被认为是必要的。这是适当的期望吗?

这里是解决神器问题的修改:

void Widget::mouseMoveEvent(QMouseEvent *event) 
{ 
rubberBand.setGeometry(QRect(origin, event->pos()).normalized()); 
update(); 
} 

这又提出如下错误:

https://bugreports.qt-project.org/browse/QTBUG-42827