I'm developing an application for use on both windows (I'm using windows 10, Qt 5.12.4 and mingw 7.3.0 32bit) and mac (High Sierra, Qt 5.12.4 and Clang 64 bit).
A part of the application consists of a QListWidget where I want to be able to move items up and down by dragging them.
In addition I'd like to do a couple of other things:
1) intercept these internal drag'n'drop events with a slot
2) do operations on the items within the QListWidget in the window destructor before closing the application.
The problem is that while everything works fine on win, on macos when I drag'n'drop the items, the item being moved disappears at the drop.
I found that using the method setMovement(QListView::Snap) on the QListWidget fixes the drag'n'drop problem (items move fine also on mac), but completely breakes the rest of the behaviours: I cannot intercept the drag'n'drop events and when I try to access the items before closing the application I get a segfault.
Does anyone know what am I doing wrong or if is there a reasonable workaround?
Here's a small example to reproduce the issue:
dnd.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
To copy to clipboard, switch view to plain text mode
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
MainWindow w;
w.show();
return a.exec();
}
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
To copy to clipboard, switch view to plain text mode
mainwindow.ui (default form for a Qt widgets application, did nothing in here)
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar"/>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar"/>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
To copy to clipboard, switch view to plain text mode
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QListWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
{
Q_OBJECT
public:
MainWindow
(QWidget *parent
= nullptr
);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QListWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QVector <QListWidgetItem *> items;
};
#endif // MAINWINDOW_H
To copy to clipboard, switch view to plain text mode
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QBoxLayout>
#include <QDebug>
MainWindow
::MainWindow(QWidget *parent
) , ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setCentralWidget(w);
w->setLayout(vl);
this->layout()->addWidget(lw);
lw->setDefaultDropAction(Qt::MoveAction);
lw
->setMovement
(QListView::Snap);
// when this line is commented drag'n'drop does not work on mac, when it is uncommented features 1) and 2) do not work on both win and mac
lw->addItem(items[0]);
lw->addItem(items[1]);
lw->addItem(items[2]);
// feature 1) intercept drag'n'drop events
connect(model,
&QAbstractItemModel
::rowsMoved,
this,
[=] (const QModelIndex &,
int from,
int,
const QModelIndex &,
int to
) {
qDebug() << "moved item from" << from << "to" << to;
});
}
MainWindow::~MainWindow()
{
// feature 2) operate on items before closing the application
for (int i = 0; i < items.size(); i++)
{
qDebug() << items[i]->text();
}
delete ui;
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QBoxLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QWidget * w = new QWidget;
this->setCentralWidget(w);
QVBoxLayout * vl = new QVBoxLayout;
w->setLayout(vl);
QListWidget * lw = new QListWidget;
this->layout()->addWidget(lw);
lw->setDragDropMode(QAbstractItemView::InternalMove);
lw->setDefaultDropAction(Qt::MoveAction);
lw->setMovement(QListView::Snap); // when this line is commented drag'n'drop does not work on mac, when it is uncommented features 1) and 2) do not work on both win and mac
items.append(new QListWidgetItem("item 1"));
items.append(new QListWidgetItem("item 2"));
items.append(new QListWidgetItem("item 3"));
lw->addItem(items[0]);
lw->addItem(items[1]);
lw->addItem(items[2]);
// feature 1) intercept drag'n'drop events
QAbstractItemModel * model = lw->model();
connect(model, &QAbstractItemModel::rowsMoved, this, [=] (const QModelIndex &, int from, int, const QModelIndex &, int to)
{
qDebug() << "moved item from" << from << "to" << to;
});
}
MainWindow::~MainWindow()
{
// feature 2) operate on items before closing the application
for (int i = 0; i < items.size(); i++)
{
qDebug() << items[i]->text();
}
delete ui;
}
To copy to clipboard, switch view to plain text mode
Thanks a lot for any input!
Bookmarks