2017-02-12 14 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

私はそれをテストしました。ウィンドウが見えない場合、update()は効果がないので、効果はまだそこにあります(Windows 7、Aero有効)。現時点で私は回避策を使用しています:私はそれを隠す代わりに、画面のウィンドウを移動します。 (はい悪い...) – pulp

+0

それはQtのバグです。 –

+0

作成されたバグレポート:https://bugreports.qt.io/browse/QTBUG-58911 – pulp