PDA

View Full Version : Painting during dragging



inktomi
25th February 2011, 17:26
Hi,

Is it possible to cause a paintEvent during a drag operation? I'm calling repaint() from the dragMoveEvent() method but paintEvent() is not being called.

Thank you.

wysota
27th February 2011, 08:09
dragMoveEvent() will only be invoked if dragEnterEvent() accepted the drag in the first place.

inktomi
27th February 2011, 23:12
dragMoveEvent() will only be invoked if dragEnterEvent() accepted the drag in the first place.

I'm actually getting the dragMoveEvent() which I can confirm from the stream of qDebug) output. The problem is a call to repaint() within dragMoveEvent() has no effect whatsoever.

This happens to be a subclass of QTreeWidget and if I do myTreeWidgetItem->setExpanded() the paintEvent() gets triggered. Only explicit calls to update() and repaint() have no effect.

wysota
28th February 2011, 00:15
What is the effect you are trying to achieve? What is your exact code including the paint event?

inktomi
28th February 2011, 13:58
What is the effect you are trying to achieve? What is your exact code including the paint event?

I want to update the QTreeWidget with feedback to reflect the effect of the drag operation. I will post a small demo later on today.

inktomi
1st March 2011, 07:27
The code below essentially demonstrates the problem. The dragMoveEvent() is processed however no painting occurs.


#include "Tree.h"

#include <QDrag>
#include <QDragEnterEvent>
#include <QPainter>
#include <QDebug>

Tree::Tree(QWidget *parent) :
QTreeWidget(parent)
{
setDragEnabled(true);
setAcceptDrops(true);
}

void Tree::mousePressEvent(QMouseEvent *event)
{
QDrag *drag = new QDrag(this);
drag->setMimeData(new QMimeData());
drag->exec();
}

void Tree::dragEnterEvent(QDragEnterEvent *event)
{
event->accept();
}

void Tree::dragMoveEvent(QDragMoveEvent *)
{
qDebug() << "Drag move event";

repaint();
}

void Tree::paintEvent(QPaintEvent *event)
{
QTreeWidget::paintEvent(event);
QPainter painter(viewport());

painter.setPen(Qt::gray);
painter.drawEllipse(QPointF(qrand() % width(), qrand() % height()), 5, 5);
}

wysota
1st March 2011, 12:55
How do you know that no painting occurs? BTW. use update() instead of repaint(). And add a qDebug() statement in the paint event to see if it gets called. In my opinion it does get called only that you don't see the ellipse.

inktomi
1st March 2011, 15:11
How do you know that no painting occurs? BTW. use update() instead of repaint(). And add a qDebug() statement in the paint event to see if it gets called. In my opinion it does get called only that you don't see the ellipse.

I already tried doing the qDebug() in the paintEvent() and it's not getting called.

wysota
2nd March 2011, 00:03
To be honest nothing in your code gets called. I don't see a point in reimplementing events of the view if 99% of the view is occupied by other widgets (viewport, header, scroll bars).

inktomi
2nd March 2011, 07:22
To be honest nothing in your code gets called. I don't see a point in reimplementing events of the view if 99% of the view is occupied by other widgets (viewport, header, scroll bars).

This is not the actual code. It is just a demo that shows the problem.

What do you mean nothing gets called? The drag events are working fine, the problem seems to be that the paint event does not get called whilst dragging.

I've seen someone with the same problem on some other mailing list. I'm now starting to think this is a Qt bug.

wysota
2nd March 2011, 09:38
This is not the actual code. It is just a demo that shows the problem.
Well then it doesn't show the problem.


What do you mean nothing gets called? The drag events are working fine, the problem seems to be that the paint event does not get called whilst dragging.

This is a direct wrap of your code to make it compilable, run it and see if you get any output. If you want help, provide something meaningful.

#include <QDrag>
#include <QDragEnterEvent>
#include <QPainter>
#include <QDebug>
#include <QApplication>
#include <QTreeWidget>

class Tree : public QTreeWidget {
public:
Tree(QWidget *parent = 0);
protected:
void mousePressEvent(QMouseEvent*);
void dragEnterEvent(QDragEnterEvent*);
void dragMoveEvent(QDragMoveEvent*);
void paintEvent(QPaintEvent*);
};

Tree::Tree(QWidget *parent) :
QTreeWidget(parent)
{
setDragEnabled(true);
setAcceptDrops(true);
}

void Tree::mousePressEvent(QMouseEvent *event)
{
qDebug() << Q_FUNC_INFO;
QDrag *drag = new QDrag(this);
drag->setMimeData(new QMimeData());
drag->exec();
}

void Tree::dragEnterEvent(QDragEnterEvent *event)
{
qDebug() << Q_FUNC_INFO;
event->accept();
}

void Tree::dragMoveEvent(QDragMoveEvent *)
{
qDebug() << Q_FUNC_INFO;

repaint();
}

void Tree::paintEvent(QPaintEvent *event)
{
qDebug() << Q_FUNC_INFO;
QTreeWidget::paintEvent(event);
QPainter painter(viewport());

painter.setPen(Qt::gray);
painter.drawEllipse(QPointF(qrand() % width(), qrand() % height()), 5, 5);
}


int main(int argc, char **argv){
QApplication app(argc, argv);
QTreeWidget w;
w.show();
return app.exec();
}

And it's not a bug in Qt, it's a bug in your thinking, if I understand the problem correctly. But before I share what I know, I want to see the situation clearly because the code you posted doesn't describe it.

inktomi
2nd March 2011, 10:51
It seems there are some misunderstandings. I modified your code snippet to add a few items to the tree widget. Also your snippet creates an instance of QTreeWidget rather than Tree.


#include <QDrag>
#include <QDragEnterEvent>
#include <QPainter>
#include <QDebug>
#include <QApplication>
#include <QTreeWidget>

class Tree : public QTreeWidget {
public:
Tree(QWidget *parent = 0);
protected:
void mousePressEvent(QMouseEvent*);
void dragEnterEvent(QDragEnterEvent*);
void dragMoveEvent(QDragMoveEvent*);
void paintEvent(QPaintEvent*);
};

Tree::Tree(QWidget *parent) :
QTreeWidget(parent)
{
setDragEnabled(true);
setAcceptDrops(true);
}

void Tree::mousePressEvent(QMouseEvent *event)
{
qDebug() << Q_FUNC_INFO;
QDrag *drag = new QDrag(this);
drag->setMimeData(new QMimeData());
drag->exec();
}

void Tree::dragEnterEvent(QDragEnterEvent *event)
{
qDebug() << Q_FUNC_INFO;
event->accept();
}

void Tree::dragMoveEvent(QDragMoveEvent *)
{
qDebug() << Q_FUNC_INFO;

repaint();
}

void Tree::paintEvent(QPaintEvent *event)
{
qDebug() << Q_FUNC_INFO;
QTreeWidget::paintEvent(event);
QPainter painter(viewport());

painter.setPen(Qt::gray);
painter.drawEllipse(QPointF(qrand() % width(), qrand() % height()), 5, 5);
}


int main(int argc, char **argv){
QApplication app(argc, argv);
Tree w;

QTreeWidgetItem *item1 = new QTreeWidgetItem(&w);
item1->setText(0, "Item 1");
QTreeWidgetItem *item2 = new QTreeWidgetItem(&w);
item2->setText(0, "Item 2");
QTreeWidgetItem *item3 = new QTreeWidgetItem(&w);
item3->setText(0, "Item 3");
QTreeWidgetItem *item4 = new QTreeWidgetItem(&w);
item4->setText(0, "Item 4");
w.addTopLevelItem(item1);
w.addTopLevelItem(item2);
w.addTopLevelItem(item3);
w.addTopLevelItem(item4);

w.show();
return app.exec();
}

wysota
2nd March 2011, 11:37
Ah, my bad with the Tree vs QTreeWidget thing. But then I'm right about the cause, the paint event does get triggered.

Add this code to your test app:

class App : public QApplication {
public:
App(int argc, char **argv) : QApplication(argc, argv){}
protected:
bool eventFilter(QObject *o, QEvent *e){
QString v = QEvent::staticMetaObject.enumerator(0).valueToKey( e->type());
qDebug() << o->objectName() << v;
return QApplication::eventFilter(o,e);
}

};

int main(int argc, char **argv){
App app(argc, argv);
Tree w;
w.setObjectName("Tree");
w.viewport()->setObjectName("Tree's viewport");
w.installEventFilter(&app);
w.viewport()->installEventFilter(&app);
//...

Among the results you'll find this:
"Tree's viewport" "DragMove"
virtual void Tree::dragMoveEvent(QDragMoveEvent*)
"Tree" "UpdateRequest"
"Tree" "Paint"
so in fact you see that the paint event for the tree does get called after every drag move event. The thing is it doesn't end up in calling paintEvent(). Why? Because paintEvent() is called when the view's viewport is updated and not the view itself (just like with DragMove and every other event handler for abstract scroll areas). And that's exactly what you want - if you call:

viewport()->update();
you'll get the result you expect.

inktomi
2nd March 2011, 11:52
so in fact you see that the paint event for the tree does get called after every drag move event. The thing is it doesn't end up in calling paintEvent(). Why? Because paintEvent() is called when the view's viewport is updated and not the view itself (just like with DragMove and every other event handler for abstract scroll areas).

Ah, that makes sense. And that also explains QPainter painter(viewport()) rather than QPainter painter(this).

Thanks wysota!