[Qt-interest] Painting question

Robert Hairgrove evorgriahr at hispeed.ch
Tue Aug 18 16:01:11 CEST 2009


Stephen Kelly wrote:
> Robert Hairgrove wrote:
> 
>> I would like to paint on a widget but only AFTER starting a drag
>> operation. The documentation says not to use QPainter except inside a
>> widget's paintEvent() function (there is a way on Linux, but not on
>> Windows).
>>
>> My scenario is this: in a class derived from QTableView, I display a
>> schedule of lessons with individual students' names displayed in a
>> timetable. I have successfully implemented the drag & drop functionality
>> which allows the user to change lessons by dragging the students around
>> in the timetable.
>>
>> What I would like to do is to display a little green dot or icon in the
>> available spaces to show the user the location of the available slots
>> depending on the student's free hours for the lesson which is being
>> dragged.
> 
> I'd say you when you start the drag, do model->setData(idx, Qt::green, 
> Qt::DecorationRole), then when you finish it, do model->setData(idx, 
> theDecorationThatWasThereBefore, Qt::DecorationRole).
> 
> Would that work?

Thanks for your input!

Well, I got it to work, but not exactly that way.

I changed the scenario now to show the icons when the left mouse button 
is pressed and hide them again when released, regardless of whether 
dragging is taking place. It is actually better that way because the 
user might not start a drag operation, but only wish to see what 
availabilities there are by clicking on the student's name. Besides, it 
makes sense to see the availabilities and only then decide in which 
direction to drag.

Now it works, but not as easily as I thought it would. What I discovered 
is that the view's mouseReleasedEvent() is apparently NOT called if 
there was a dragging operation going on, so I have to copy a lot of code 
from the mouseReleasedEvent() into the dropEvent() in order to make it 
work. I'll probably refactor it into a common function, but it would be 
nice if I could just call it in one single place.

It's a lot of code, so I'll give only a brief summary. What I am doing 
is this:

1. The Model and View classes are friends of each other, and each 
contains a pointer member to the other (communication is much simpler 
that way). My view derives from QTableView and the model from 
QAbstractTableModel.

2. In the view's mousePressedEvent, I first call the base class' 
implementation of that event handler. Next, I set a flag in the model: 
"needIcon" (bool) and set a pointer to the current Student object which 
has all of the availability information for that student. I then emit 
the dataChanged() signal for all slots in the view (upper left = 
QPoint(0,0), bottom right = QPoint(model.columnCount()-1, 
model.rowCount()-1). Since the availabilities can be anywhere, I need to 
update the enitre view.

3. In the model's data() function, if role == Qt::DecorationRole, I 
check the needIcon and student pointer members. If these are set, I 
return a valid icon; otherwise, I return a default constructed QIcon().

4. In the view's mouseReleasedEvent, after calling the base class' 
handler, I set the needIcon flag in the model to = 0 and the student 
pointer to NULL. Then I emit the dataChanged signal.

5. Also in the dropEvent() handler, I reset the flag and student pointer 
and emit dataChanged. Only if I do this in BOTH event handlers does it 
seem to work; otherwise, after dragging is finished, there are still 
green icons left showing in the old places.




More information about the Qt-interest-old mailing list