2017-02-12 10 views
0

투명한 Qt 윈도우에서 다른 위치에 직사각형을 표시해야합니다. 창을 표시하기 전에 새 사각형 위치를 설정합니다. 때로는 몇 밀리 초 동안 이전 위치가 표시됩니다. (예 : m_y_pos = 400 대신 m_y_pos = 100). 창을 표시하고 창을 업데이트하는 사이에는 경쟁 조건이있는 것 같습니다.QWidget/QPainter show() + paintEvent() -> 이전 위치에 사각형 표시

누군가가 제안을 알고 있기를 바랍니다.

감사 펄프

예제 코드 :

#include <QApplication> 
#include <QtWidgets/QMainWindow> 
#include <QPaintEvent> 
#include <QTimer> 
#include <QDebug> 
#include <QPainter> 

class QtGuiApplication : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    int m_x_pos; 
    int m_y_pos; 
    QTimer* m_timer; 

    QtGuiApplication(QWidget *parent = Q_NULLPTR) : QMainWindow(parent), m_x_pos(100), m_y_pos(100) 
    { 
    setGeometry(100, 100, 1000, 1000); 

    //Make Window transparent 
    setAttribute(Qt::WA_NoSystemBackground, true); 
    setAttribute(Qt::WA_TranslucentBackground); 
    setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowTransparentForInput | Qt::WindowDoesNotAcceptFocus); 

    m_timer = new QTimer(this); 
    m_timer->setInterval(500); 
    m_timer->start(); 
    connect(m_timer, &QTimer::timeout, this, &QtGuiApplication::Tick); 
    } 

    private slots: 

    //toggle visibility of the window to show the effect 
    void Tick() 
    { 
    if (isVisible()) 
    { 
     hide(); 
    } 
    else 
    { 
     //Set new position before showing the window 
     m_y_pos = m_y_pos == 100 ? 400 : 100; 
     show(); 
    } 
    } 

    //Paint rectangles at different positions 
    void paintEvent(QPaintEvent* event) 
    { 
    QPainter painter(this); 

    painter.setBrush(Qt::red); 
    painter.setPen(Qt::black); 

    for (int i = 0; i < event->rect().width(); i += 50) 
    { 
     painter.drawRect(m_x_pos + i, m_y_pos, 30, 30); 
    } 
    } 

}; 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    QtGuiApplication w; 
    w.show(); 
    return a.exec(); 
} 
+0

내가 여기 당신의 문제를 재현 할 수는 없지만 일반적으로는'업데이 트를 호출하여 위젯을 업데이트해야하는 페인트 시스템을 알려야한다()'때마다 위젯의 모양을 변경할 매개 변수를 변경할 수 있습니다. (즉, Tick()에'm_y_pos'를 설정 한 직후에 귀하의 경우) – E4z9

+0

Aero가 활성화 된 Windows 7에서만 동작이 재현 가능합니다. 귀하의 솔루션에 대해 – pulp

답변

0

당신은 위치를 변경 한 후 update()에 대한 호출이 부족하다. 일반적으로 이것은 setPos 방법으로 분해되어야합니다.

이렇게하면 hide()show()이 더 이상 필요하지 않습니다. 각 setPos 호출은 필요에 따라 위젯을 업데이트합니다.

귀하의 요구를 충족시키는 가장 기본적인 클래스에서 파생되어야합니다 : QWidget. 결국 QMainWindow의 기능을 사용하지 않고 있습니다.

// https://github.com/KubaO/stackoverflown/tree/master/questions/rect-paint-42194052 
#include <QtWidgets> 

class Window : public QWidget 
{ 
    QPointF m_pos{100, 100}; 
    void paintEvent(QPaintEvent* event) override 
    { 
     QPainter painter(this); 
     painter.setBrush(Qt::red); 
     painter.setPen(Qt::black); 
     for (int i = 0; i < event->rect().width(); i += 50) 
     painter.drawRect(QRectF(m_pos.x() + i, m_pos.y(), 30, 30)); 
    } 
public: 
    Window(QWidget *parent = nullptr) : QWidget(parent) 
    { 
     setAttribute(Qt::WA_NoSystemBackground, true); 
     setAttribute(Qt::WA_TranslucentBackground); 
     setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint 
        | Qt::WindowTransparentForInput | Qt::WindowDoesNotAcceptFocus); 
    } 
    void setPos(const QPointF & pos) { 
     m_pos = pos; 
     update(); 
    } 
}; 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    Window w; 
    QTimer timer; 
    QObject::connect(&timer, &QTimer::timeout, [&w]{ 
     static bool toggle{}; 
     if (!w.isVisible()) { 
     toggle = !toggle; 
     if (toggle) 
      w.setPos({200, 200}); 
     else 
      w.setPos({100, 100}); 
     }; 
     w.setVisible(!w.isVisible()); 
    }); 
    timer.start(500); 
    w.resize(1000, 500); 
    return app.exec(); 
} 
+0

주셔서 감사합니다. 나는 그것을 테스트했다. 창 (window)이 보이지 않으면 update()가 효과가 없기 때문에 결과는 여전히 존재한다 (Windows 7, Aero enabled). 지금은 해결 방법을 사용하고 있습니다. 화면의 창을 숨기는 대신 이동합니다. (예 ... 나쁜 ...) – pulp

+0

그럼 Qt 버그입니다. –

+0

생성 된 버그 보고서 : https://bugreports.qt.io/browse/QTBUG-58911 – pulp