PDA

View Full Version : Drag & Drop using QTableWidget



Israa
25th February 2007, 17:57
I'm trying to implement Drag & Drop using a QTableWidget and I haven't been having much luck. I've been trying to get a hold of the QTableWidgetItem that the cursor is over using the itemAt(int x, int y) function using the QMouseEvent event but I keep getting a NULL pointer.


void table_widget::mousePressEvent(QMouseEvent *event) {
QMenu *popupMenu = new QMenu(this);
popupMenu->addAction("Drag");
popupMenu->addAction("Drop");

if (event->button() == Qt::RightButton) {
popupMenu->popup(QPoint(event->x()+216,event->y()+130), 0);
printf("%x\n",itemAt(event->x()+216,event->y()+130));
}
}


The 216 and 130 are just offsets from the top left corner of the GUI to the top left corner of the first cell in the table.

Any suggestions?

jpn
25th February 2007, 19:18
For drag and drop, take a look at Using Drag and Drop with Item Views - Using Convenience Views (http://doc.trolltech.com/4.2/model-view-dnd.html#using-convenience-views).

For context menu, you might want to reimplement contextMenuEvent() instead. More or less something like this:


void table_widget::contextMenuEvent(QContextMenuEvent *event) {
QMenu popupMenu(this);
popupMenu.addAction(...);
popupMenu.exec(event->globalPos());
}

Israa
26th February 2007, 19:39
I fixed that problem, I just had to create a new QTableWidgetItem for each cell in the table.
I did have another question though, for dropEvent, it doesnt seem like the function is being called. I have it set up so that it prints a message when it enters that function but the message is never displayed. What could be wrong?
Here's the code for that function:



void table_widget::dropEvent(QDropEvent *event)
{
printf("dropEvent\n");
event->acceptProposedAction();
}


I even tried inserting if (event->mimeData()->hasText()) before the printf() statement but that doesnt really do anything.

guilugi
27th February 2007, 08:42
Hello,

You have to do those two steps :

1 - call setAcceptDrops(true) on your tablewidget
2 - reimplement dragEnterEvent method, and accept it !

I'm not sure if the second step is absolutely necessary for a tablewidget, but the first is, for sure :)

Guilugi

Israa
3rd March 2007, 20:23
I just had to reimplement dragMoveEvent() and it worked fine, thanks.

Now I'm having another 'problem'. In my project I'm trying to drag and drop from one QTableWidget to another but I can't quite get it right. The dragEnterEvent acknowledges when I've entered another QTableWidget but thats about it. Here's what I'm working with:



void table_widget::dragEnterEvent(QDragEnterEvent *event)
{
QTableWidgetItem* test = itemAt(event->pos());
if (test != 0)
{
if ( event->source() == this ) // same table, move entry
{
event->setDropAction( Qt::MoveAction );
event->accept();
}
else // different table, add entry
{
printf("Different table\n");
event->acceptProposedAction();
}

source = itemAt(event->pos());
source->setText(itemAt(event->pos())->text());
}
}

void table_widget::dropEvent(QDropEvent *event)
{
printf("I'm in dropEvent\n");
itemAt(event->pos())->setText(source->text());
if(source != itemAt(event->pos()))
source->setText("");
event->acceptProposedAction();
}

void table_widget::dragMoveEvent(QDragMoveEvent *event)
{
event->setDropAction(Qt::MoveAction);
event->accept();
}


Any suggestions?

ghorwin
8th March 2007, 04:41
I have exactly the same problem. I called set setAcceptDrops(true) and reimplemented dragEnterEvent(QDragEnterEvent *event), which gets called and I accept the proposed copy-action.

However, my reimplemented dropEvent function is never called. The documentation and examples say it will be called, but I couldn't get this to work :-(

Btw, this is Qt Open Source 4.2.2.

Any suggestions?

ghorwin
8th March 2007, 04:48
Correction to my last post: It is Qt Open Source 4.2.1

I believe I have found the problem. In qtablewidget.h, in the class declaration for QTableWidget the function dropEvent() is not declared as virtual, thus our reimplemented dropEvent() function will never be called.

I guess I have to check with 4.2.2 and see if this was fixed...

Andreas

jpn
8th March 2007, 09:40
I believe I have found the problem. In qtablewidget.h, in the class declaration for QTableWidget the function dropEvent() is not declared as virtual, thus our reimplemented dropEvent() function will never be called.
It's declared virtual in QWidget.
http://www.qtcentre.org/forum/p-reimplement-qsplashscreendrawcontents-post24086/postcount5.html

ghorwin
8th March 2007, 15:21
Yes, that's why it works when you inherit from QTableView... however, QTableWidget provides its own implementation of dropEvent() without declaring it virtual. Therefore classes deriving from QTableWidget will not be able to reimplement that function, or if they do the function will never get called.

Andreas

jpn
8th March 2007, 15:47
Actually, it doesn't matter if QTableWidget marks it virtual or not. It has already been declared as virtual in the base class, in QWidget that is.

Once a method was declared as virtual, it will be virtual in all subclasses, regardless if one uses the "virtual" keyword or not.

ghorwin
8th March 2007, 19:30
jpn: I have to agree. The problem must lie elsewhere.

A test-implementation using QTableView showed the same behavior - the dragEnterEvent() is called correctly but despite the fact, that acceptProposedAction() is called, the reimplemented dropEvent() function is never called.

Did anyone manage to implement drag&drop with QTableView or QTableWidget already? What is missing to get this to work?

Andreas

jpn
8th March 2007, 20:30
A test-implementation using QTableView showed the same behavior - the dragEnterEvent() is called correctly but despite the fact, that acceptProposedAction() is called, the reimplemented dropEvent() function is never called.
Is the drag move event accepted?

Israa
9th March 2007, 16:27
Bump. ghorwin 'hijacked' my thread!

ghorwin
10th March 2007, 15:40
Israa: Sorry for hijacking, but you asked excactly the same question that I had, so figured opening a new thread would be non-sense.

Jpn: dragMoveEvent() is called correctly.

So it seems something prevents the dropping...

If I read the documentation correctly, only the widget itself, that should accept the drop, needs to call setAcceptDrop(), right? Or do I also have to tell the parent dialog to accept drops?

Anyway, I'm clueless. Should I post a simple test-program?

jpn
10th March 2007, 15:45
Jpn: dragMoveEvent() is called correctly.
Yes, but do you accept the event? :)

ghorwin
10th March 2007, 15:46
Guys, got it to work!!!

The trick is to call

setDragDropMode(QAbstractItemView::DropOnly);
in addition to

setAcceptDrops(true);
(wasn't mentioned in the docu, but I just went back to the abstract view class)...

Now dropEvent is called alright!

ghorwin
10th March 2007, 16:12
Still something strange about the dropping...

Explain that: When I reimplement the dragMoveEvent() (even with an empty function), I can drop anywhere in my table. If I don't reimplement it, I can only drop when the cursor is exactly on the frame around the content rows (so at the bottom of the header row and at the top of the horizontal scroll bar). That's weird, if you ask me.

So, the recipe for dropping on QTableWidget is:

1. setup your table in the constructor

setDragDropMode(QAbstractItemView::DropOnly);
setAcceptDrops(true);


2. re-implement the functions dragEnterEvent(...), dragMoveEvent(...) and dropEvent(...), for example:


void MyTable::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}

void MyTable::dragMoveEvent ( QDragMoveEvent * ) {
// nothing to do, function just has to exist...
}

void MyTable::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasUrls()) {
QList<QUrl> urls = event->mimeData()->urls();
for (int i=0; i<urls.count(); ++i) {
int row = rowCount();
insertRow(row);
QTableWidgetItem *newItem = new QTableWidgetItem(urls[i].toString());
setItem(row, 0, newItem);
}

event->accept();
}
}


At least that's what worked for me.

Israa
12th March 2007, 15:04
I still haven't gotten an answer to my question, would anyone know what I need to do to enable drag & drop to and from 2 QTableWidgets? I create a class that inherits QTableWidget and I place the two objects on either side of a QSplitter. I can drag & drop in the same table, but not to the other table.

jpn
12th March 2007, 15:23
Using Drag and Drop with Item Views - Using Convenience Views (http://doc.trolltech.com/4.2/model-view-dnd.html#using-convenience-views):


For example, we can enable drag and drop in a list widget with the following lines of code:



QListWidget *listWidget = new QListWidget(this);
listWidget->setSelectionMode(QAbstractItemView::SingleSelectio n);
listWidget->setDragEnabled(true);
listWidget->setAcceptDrops(true);
listWidget->setDropIndicatorShown(true);


The same applies for a table widget.

para
9th April 2007, 15:38
I still haven't gotten an answer to my question, would anyone know what I need to do to enable drag & drop to and from 2 QTableWidgets? I create a class that inherits QTableWidget and I place the two objects on either side of a QSplitter. I can drag & drop in the same table, but not to the other table.
I am having the same problem, trying to drag&drop from one table to another.


Using Drag and Drop with Item Views - Using Convenience Views (http://doc.trolltech.com/4.2/model-view-dnd.html#using-convenience-views):

The same applies for a table widget.
I am having trouble following the page you linked. I have tried the function calls that enable drag&drop functionality, but I am still having issues dropping to a different table than was dragged from. Is there any way some short example code could be provided? Nothing complicated, I'd just like to see a working example.

Thanks.

jpn
11th April 2007, 21:40
I am having the same problem, trying to drag&drop from one table to another.
Does this work for you?


#include <QtGui>

QTableWidget* createTableWidget(QWidget* parent)
{
QTableWidget* tableWidget = new QTableWidget(4, 4, parent);
tableWidget->setSelectionMode(QAbstractItemView::SingleSelectio n);
tableWidget->setDragEnabled(true);
tableWidget->setAcceptDrops(true);
tableWidget->setDropIndicatorShown(true);
return tableWidget;
}

int main(int argc, char* argv[])
{
QApplication a(argc, argv);
QSplitter splitter;
splitter.addWidget(createTableWidget(&splitter));
splitter.addWidget(createTableWidget(&splitter));
splitter.show();
return a.exec();
}

para
12th April 2007, 19:35
Does this work for you?
Yeah that worked, thanks a lot. I must have missed something.

:D