0

I created a small test application with 2 widgets, one inside the other. I reimplemented the mouse move, press and release events for the inner widget in order to be able to move it inside its bigger parent with drag&drop.

However, when I move it a black trace appears from top and from left. This is how it looks:

enter image description here

Here is my code:

main.cpp:

#include <QApplication>

#include "widget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Widget w;
    w.show();

    return a.exec();
}

widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPaintEvent>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

protected:
    void paintEvent(QPaintEvent *e);
};

#endif // WIDGET_H

widget.cpp:

#include "widget.h"
#include "innerwidget.h"

#include <QPainter>

Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
    new InnerWidget(this);

    resize(400, 200);
}

Widget::~Widget()
{
}

void Widget::paintEvent(QPaintEvent* e)
{
    QPainter p(this);
    p.setBrush(Qt::lightGray);
    p.drawRect(e->rect());
}

innerwidget.h:

#ifndef INNERWIDGET_H
#define INNERWIDGET_H

#include <QWidget>
#include <QPaintEvent>

class InnerWidget : public QWidget
{
    Q_OBJECT
public:
    explicit InnerWidget(QWidget *parent = 0);
    ~InnerWidget();

protected:
    void mousePressEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);
    void mouseMoveEvent(QMouseEvent *e);
    void paintEvent(QPaintEvent *e);

private:
    bool m_leftButtonPressed;
    QPoint m_mousePosOnBar;
};

#endif // INNERWIDGET_H

innerwidget.cpp:

#include "innerwidget.h"

#include <QPainter>
#include <QPaintEvent>
#include <QStyleOption>

InnerWidget::InnerWidget(QWidget *parent) : QWidget(parent)
{
    setGeometry(10, 10, 100, 100);
    setStyleSheet("background-color: red");
}

InnerWidget::~InnerWidget()
{

}

void InnerWidget::mousePressEvent(QMouseEvent* e)
{
    if(e->button() == Qt::LeftButton)
    {
        m_mousePosOnBar = e->pos();
        m_leftButtonPressed = true;
    }

    e->accept();
}

void InnerWidget::mouseReleaseEvent(QMouseEvent* e)
{
    if(e->button() == Qt::LeftButton)
    {
        m_leftButtonPressed = false;
    }

    e->accept();
}

void InnerWidget::mouseMoveEvent(QMouseEvent* e)
{
    if(m_leftButtonPressed)
    {
        move(e->pos().x() - m_mousePosOnBar.x() + geometry().x(),
             e->pos().y() - m_mousePosOnBar.y() + geometry().y());
    }


    e->accept();
}

void InnerWidget::paintEvent(QPaintEvent* e)
{
    Q_UNUSED(e)

    QPainter p(this);

    QStyleOption opt;
    opt.init(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

EDIT: The trace disappears when I call Widget::repaint but then I would have to install an event filter on InnerWidget and repaint everytime it moves. I would want a cleaner solution without having to use event filters...

Can anyone tell me what is really happening?

Iuliu
  • 4,001
  • 19
  • 31
Jacob Krieg
  • 2,834
  • 15
  • 68
  • 140
  • The widget is not erasing its previously drawn position. Add a call to the widget's update( ) function in mouseMoveEvent: http://doc.qt.io/qt-5/qwidget.html#update – TheDarkKnight Apr 15 '15 at 12:17
  • @TheDarkKnight Thanks for the interest! That doesn't solve it because I'd have to update `Widget`, not `InnerWidget`. I could however install an event filter inside `Widget` for `InnerWidget` and call `update` or `repaint` there but I would want to solve it in a more cleaner/elegant way...do you have any other idea? :( – Jacob Krieg Apr 15 '15 at 12:19
  • "That doesn't solve it" - did you try it? I would expected that to have helped. As the docs state in Update( ) "Qt normally erases the widget's area before the paintEvent() call" – TheDarkKnight Apr 15 '15 at 12:24
  • 1
    Or instead of messing with event filters, you could just call `parentWidget()->update();`. – thuga Apr 15 '15 at 12:42
  • @thuga - yup, I'd agree with that ;O) – TheDarkKnight Apr 15 '15 at 12:52
  • 2
    `QGraphicsView` exists for such tasks. If you want to implement it's functionality on `QWidget`, I would strongly recommend you study it's sources. – Amartel Apr 15 '15 at 13:00

1 Answers1

0

Calling QWidget::update() in Widget::paintEvent solved the problem:

void Widget::paintEvent(QPaintEvent* e)
{
    QPainter p(this);
    p.setBrush(Qt::lightGray);
    p.drawRect(e->rect());

    update();
}
Jacob Krieg
  • 2,834
  • 15
  • 68
  • 140