2014-11-21 23 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