2017-02-12 6 views
0

Мне нужно показать прямоугольники в разных положениях в прозрачном окне Qt. Перед тем, как показывать окно, я устанавливаю новую позицию прямоугольника. Иногда старая позиция отображается в течение нескольких миллисекунд. (например, m_y_pos = 100 вместо m_y_pos = 400). Кажется, есть какое-то состояние гонки между показом окна и обновлением окна.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

Я не могу воспроизвести проблему здесь, но в целом вы должны сообщить лакокрасочную систему, которая должна быть обновлена ​​ваш виджет, вызвав 'обновления()', когда изменение параметров, которые изменяют внешний вид вашего виджета. (Например, в вашем случае непосредственно после установки 'm_y_pos' в' Tick() ') – E4z9

+0

Поведение воспроизводится только в Windows 7 с включенным Aero. – 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

спасибо за ваше решение. Я протестировал его: эффект все еще существует (возможно, Windows 7, Aero), потому что update() не действует, если окна не видны. на данный момент я использую обходное решение: я перемещаю окно экрана, а не скрываю его. (да плохо ...) – pulp

+0

Тогда это ошибка Qt. –

+0

Отчет об ошибке создан: https://bugreports.qt.io/browse/QTBUG-58911 – pulp

Смежные вопросы