PDA

View Full Version : Problem with QListWidget



Elwe
15th June 2009, 14:26
Hello everybody!

I've a problem since a while now with QListWidget. I'll try to explain it.

I've a QListWidget containing a widget. I've done this with the setItemWidget() method. But when I move an item of the list (by drag'n'drop or by button), his widget disappear. I don't know why. Let me illustrate it:

http://free0.hiboox.com/images/2509/475af68fd3bfc1b18c7d63acccd53a15.png (http://www.hiboox.fr/go/images/informatique/capture-dragndrop1,475af68fd3bfc1b18c7d63acccd53a15.png.ht ml)http://free0.hiboox.com/images/2509/4fab78fc8c9de3c4f99d40893d213745.png (http://www.hiboox.fr/go/images/informatique/capture-dragndrop2,4fab78fc8c9de3c4f99d40893d213745.png.ht ml)





Someody have an idea?

Here's a little bit of code:


QListWidgetItem *item = new QListWidgetItem;

QWidget *w = new QWidget;
QLabel *labelGroup = new QLabel("Label");
QLabel *labelTime = new QLabel("14:00");
QListWidget *listWidgetGroup = new QListWidget;
listWidgetGroup->addItem("Groupe");
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(labelGroup);
vLayout->addWidget(labelTime);
vLayout->addWidget(listWidgetGroup);

w->setLayout(vLayout);
w->adjustSize();

item->setSizeHint(w->size());
ui.listWidget->addItem(item);
ui.listWidget->setItemWidget(item, w);


I think i'm not using the right widget, but I don't know wich to use...

Thank you in advance for your precious help!

Elwe

PS: I'm working with Qt 4.5.1 and WindowsXP (but I've the same problem on Linux).

Lykurg
15th June 2009, 14:53
But when I move an item of the list (by drag'n'drop or by button), his widget disappear. I don't know why.

Please post that code of the button and drag'n'drop. There must be the error.

Elwe
15th June 2009, 15:55
Here's the button's code:


void DragNDrop::upSlot(void) {
int row = ui.listWidget->currentRow();

if(!(0 == row)) {
QListWidgetItem *item = ui.listWidget->takeItem(row);

row--;

ui.listWidget->insertItem(row, item);
ui.listWidget->setCurrentItem(item);
ui.listWidget->selectionModel()->select(ui.listWidget->currentIndex(), QItemSelectionModel::Select);
}
}



void DragNDrop::downSlot(void) {
int row = ui.listWidget->currentRow();

if(!(ui.listWidget->count() - 1 == row)) {
QListWidgetItem *item = ui.listWidget->takeItem(row);

row++;

ui.listWidget->insertItem(row, item);
ui.listWidget->setCurrentItem(item);
ui.listWidget->selectionModel()->select(ui.listWidget->currentIndex(), QItemSelectionModel::Select);
}
}

For the drag'n'drop, I've set it by the QtDesigner (activating acceptDrop, dragEnable and dragMode to InternalMove).

Lykurg
15th June 2009, 16:18
ui.listWidget->insertItem(row, item);

This will delete the original one! You have to swap the values! Like (not optimized):

Take item a in a
Take item b in b
insert a in the row of b
insert b in the row of a

if you call

ui.listWidget->setCurrentItem(item);
then

ui.listWidget->selectionModel()->select(ui.listWidget->currentIndex(), QItemSelectionModel::Select);
is not necessary.

Elwe
15th June 2009, 16:33
This:

ui.listWidget->insertItem(row, item);
Doesn't delete the original one (look at the picture, the item in second position is in third after moving up the third item).

However, I've try your suggestion. But the problem is still there. The items widgets aren't repaint. They just disappear.

Lykurg
15th June 2009, 17:06
Ok,ok, sorry, after further investigations I see clearer: The widget one is setting for the item is not stored inside them. So moving an item via your button or per drag and drop "destroys" the relation between the item and the widget. This could be a bug or intended by Qt. Don't know.

But If you have the same arrangement of widget for each row you really should reconsider using a QListView with a custom delegate, where you can draw the content yourself. That isn't so hard. Only the list inside could be tricky.

May be also a QScrollArea with a simple box layout could be a solution for you. Then you have to code the movement of the elements (inside the box layout) on yourowne.

Elwe
15th June 2009, 17:12
Ok I see. In this case, I've another question;

The labels and QListWidgets insides the widgets are dynamic. I mean they depend on values in a database and they could change with some events. Is the custom delegate and a QListView a good choice?

Lykurg
15th June 2009, 17:20
The labels and QListWidgets insides the widgets are dynamic. I mean they depend on values in a database and they could change with some events. Is the custom delegate and a QListView a good choice?
Definitely yes.
...but if you want to use "QListWidgets" inside "QListWidgets" then the QScrollArea could be easier to realize. Because I don't know spontaneous how to imitate a list view with a QPainter...

Elwe
15th June 2009, 17:22
Thanks a lot for your responses! I'll try this and if I have something good, I'll post here the solution.

Thank you.

Elwe
16th June 2009, 08:48
I've forgot something. I've to insert or remove items. So I'm not sure that a view is the best choice. What do you think?

Elwe
17th June 2009, 21:04
So, finally I've do my first idea. Here it's the code, it could help someone one day!



void DragNDropQListWidget::startDrag(Qt::DropActions) {
int row = currentRow();

QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);

//We put the current row into datastream
dataStream << row;

QMimeData *mimeData = new QMimeData;
mimeData->setData("application/x-dndgroup", itemData);

QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);

drag->exec(Qt::MoveAction);
}

void DragNDropQListWidget::dropEvent(QDropEvent *event) {
if (event->mimeData()->hasFormat("application/x-dndgroup")) {
QListWidgetItem *itemToDrag;
QByteArray itemData = event->mimeData()->data("application/x-dndgroup");
QDataStream dataStream(&itemData, QIODevice::ReadOnly);
int previousRow;

//Will stock the target destination row
int currentDropRow = row(itemAt(event->pos()));

//We take the source row
dataStream >> previousRow;

//Beforhand, we've stock the itemWidget into a QList of QWidget*
QVBoxLayout *vLayoutA = refWidget->at(previousRow);
QWidget *wA = new QWidget;
wA->setLayout(vLayoutA);


QVBoxLayout *vLayoutTemp = refWidget->takeAt(previousRow);
refWidget->insert(currentDropRow, vLayoutTemp);

//We "remove" the item of the list
itemToDrag = takeItem(previousRow);
//Important, we have to remove the item widget, otherwise it will be blank widget.
removeItemWidget(itemToDrag);
//We insert the removed item into the destination
insertItem(currentDropRow, itemToDrag);
//And we reset the item widget.
setItemWidget(itemToDrag, wA);

setCurrentItem(itemToDrag);

if (event->source() == this) {
event->setDropAction(Qt::MoveAction);
event->accept();
} else {
event->ignore();
}
} else {
event->ignore();
}
}


For buttons who up and down items, use the same idea (save the widget created into a QList).