PDA

View Full Version : QTableWidget fails to display column/row content correctly after MainWindow resize.



Milo47
1st October 2020, 14:44
Hi,

I needed to implement the QTableWidget where I can drag and drop files. So made my own QDropTableWidget that inherits from QTableWidget where I then implemented dragEnterEvent(),
dragLeaveEvent(), and dropEvent().

I then placed a QTableWidget inside the layout with QDesigner and promoted it to QDropTableWidget and now I'm able to drop files inside the widget and populate the table this way.

However now I have a weird issue where the table stops displaying some rows or columns after I resize the MainWindow (and layout containing the table).
In only resets after I manually resize columns on the table. I tried to update,repain refresh table->viewPort() but the issue remains.

Here is the picturer of before and after resize:

Before:
13552

After:
13553

The items will also flicker while mouse cursor is dragged over them.

This however doesn't happen when QTableWidget is not promoted to QDropTableWidget.

d_stranz
1st October 2020, 17:18
What else did you change / add when you added drag / drop event handlers?

QTableWidget already has built-in support for drag and drop, so the changes you made are possibly interfering with the default behavior. It is also possible that you aren't correctly clearing out the existing QTableWidgetItems used by the table widget's internal model when you replace the contents with what was dropped.

Milo47
5th October 2020, 11:21
Here's the heeder and source code.


#ifndef DROPAREA_H
#define DROPAREA_H

#include <QTableWidget>

class QMimeData;

class QDropTableWidget : public QTableWidget
{
Q_OBJECT

public:
QDropTableWidget(QWidget *parent = 0);

public slots:
void clear();

signals:
void changed(const QMimeData *mimeData = 0);
void dropped(const QMimeData *mimeData = 0);
void test(const QMimeData *mimeData);
void OnDrop(QStringList list, int row);


protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dropEvent(QDropEvent *event);
void resizeEvent(QResizeEvent *event) override;

private:
QTableWidget *tablewidget;
};

#endif

Source:




#include <QtGui>
#include "qdroptablewidget.h"
#include <qheaderview.h>

QDropTableWidget::QDropTableWidget(QWidget *parent) : QTableWidget(parent)
{
//set widget default properties:
setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
setEditTriggers(QAbstractItemView::NoEditTriggers) ;
setDragDropMode(QAbstractItemView::DropOnly);
setAlternatingRowColors(true);
setShowGrid(true);
setWordWrap(false);

QHeaderView *vh = this->verticalHeader();
vh->setSectionResizeMode(QHeaderView::Fixed);
vh->setDefaultSectionSize(20);

setSelectionBehavior(QAbstractItemView::SelectRows );
//setUpdatesEnabled( true ) ;



}

void QDropTableWidget::dragEnterEvent(QDragEnterEvent *event) {

event->acceptProposedAction();
emit changed(event->mimeData());
}

void QDropTableWidget::dragMoveEvent(QDragMoveEvent *event) {
event->acceptProposedAction();
}

void QDropTableWidget::dropEvent(QDropEvent *event)
{

event->acceptProposedAction();
int row = this->rowAt(event->pos().y());

QStringList list;

if (event->mimeData()->hasUrls())
{
foreach (QUrl url, event->mimeData()->urls())
{

printf("%s\n",url.toString().toStdString().c_str());
list.push_back(url.toLocalFile());

}
}

//emit dropped(event->mimeData());
emit OnDrop(list, row);


//emit (event->mimeData());
}

void QDropTableWidget::dragLeaveEvent(QDragLeaveEvent *event)
{
event->accept();
}

void QDropTableWidget::clear()
{
emit changed();
}





void QDropTableWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);


viewport()->update();
viewport()->repaint();
}

d_stranz
5th October 2020, 21:54
By overriding the drag/drop events for QTableWidget, you are preventing the normal behavior from taking place. You should probably be calling QTableWidget's handlers for these events in addition to your own.

Who is listening for the OnDrop() signal, and what is happening there?

Milo47
6th October 2020, 09:00
It's connected to the MainWindow's DropToPlaylist();


connect(ui.tablePlaylist, SIGNAL(OnDrop(QStringList, int)), this, SLOT(DropToPlayList(QStringList, int)));

After which the playlist is populated from the QStringList.

But if there's a way to natively work with QTableWidget and use Drag&Drop like that, I would rather use that. But all the examples I managed to find on how to do
it just say to make your own and inherit from QTableWidget.

d_stranz
6th October 2020, 20:31
But if there's a way to natively work with QTableWidget and use Drag&Drop like that, I would rather use that. But all the examples I managed to find on how to do
it just say to make your own and inherit from QTableWidget.

I am not sure, but I think QTableWidget's drag and drop support is mostly to move contents from one cell to another, not to import from files. It is sort of impossible for the table widget to know what could be the contents of any file dropped on it and how to map the content into cells.

What does the DropToPlaylist method do? I still think that your problem is how you update the table after a drop.

Milo47
7th October 2020, 09:45
It just populates the list with strings.

This issue is not limited to D&D. It happens with all data. So if I just populate the list on showEvent() in MainWindow the same will happen. Data rows will show fine, but after resize the same will happen.

Would you mind trying your self? The entire code for QDragDropWidget is in my previous post. So just place QTableWidget in resizable layout and promote it to QDDW. I'm interested to see of anyone else has this issue.

d_stranz
7th October 2020, 16:44
Would you mind trying your self? The entire code for QDragDropWidget is in my previous post. So just place QTableWidget in resizable layout and promote it to QDDW. I'm interested to see of anyone else has this issue.

No, because I am trying to get you to understand that the problem is not in your widget, it is how you are populating the widget with items after you have dropped something. Fine, you are populating a QStringList. You can't build the contents of a QTableWidget by passing in a QStringList, you have to create QTableWidgetItem instances and add each one to the table.

I have asked you to show how you are doing that, because that is very likely where your error lies. Especially since you now say it happens both with and without D&D. The finger isn't pointing at your widget, it is pointing at how you are using the widget.

Milo47
8th October 2020, 09:53
This is the function that populates the list:



void MainWindow::DropToPlayList(QStringList list, int row) // row is the location of the row where the files are dropped
{
if (row < 0)
row = 0;

for (int c=0;c<list.count();c++)
{
ui.tablePlaylist->insertRow(row+c);

// create all items for the row
uint32_t duration = 0;
for (int i=0;i<ui.tablePlaylist->columnCount();i++)
{
ui.tablePlaylist->setItem(row+c,i, new QTableWidgetItem("")); // create all column items for row
}


ui.tablePlaylist->item(row+c,COLUMN_START_TIME)->setText("00:00:00:00");
ui.tablePlaylist->item(row+c,COLUMN_DURATION)->setText("duration");
ui.tablePlaylist->item(row+c,COLUMN_TITLE)->setText("title");
ui.tablePlaylist->item(row+c,COLUMN_LOCATION)->setText("location");
ui.tablePlaylist->item(row+c,COLUMN_CATEGORY)->setText("category");

}

}

Milo47
27th October 2020, 15:34
Solution:

QTableWidget::resizeEvent(event);

instead of QWidget::resizeEvent(event);

d_stranz
27th October 2020, 16:46
Solution:

QTableWidget::resizeEvent(event);

instead of QWidget::resizeEvent(event);

Ah. Sometimes you don't notice the obvious things until they punch you in the nose. Thanks for posting your solution.