Drag and drop to a Pushbutton
-
I am having an issue trying to figure out how to drag and drop from a query view or a table view to the text label on a push button. I have been able to drag from one list to another or a column list to another, but not a table list to another table. I will try that later. I have always been able to make it work as long as I'm going from like lists to another, but not to different types even though it is all QString data that I am dragging.
I really have no Idea how to do this, I am new to the drag and drop aspects of QT.
If anyone has an example of how to drag text from a view to text on a push button, it would be helpful. Maybe it is not possible, I do not know.
Thanks in advance,
jdc -
Hi,
You will have to subclass QPushButton in order to accept what you are dragging over it.
What you think is text might be something different. For example, a QTableView cell is different from a QListView item.
Check the mime type of what you are dragging around in order to be able to properly accept it.
The drag and drop documentation is a good starting point. With the corresponding item view chapter.
-
Hi,
You will have to subclass QPushButton in order to accept what you are dragging over it.
What you think is text might be something different. For example, a QTableView cell is different from a QListView item.
Check the mime type of what you are dragging around in order to be able to properly accept it.
The drag and drop documentation is a good starting point. With the corresponding item view chapter.
@SGaist Thank you for the feedback, I have looked at the documentation and the examples provided and have only had success with column views for drag and drop operations. They are fairly simple and straight forward. The examples look as I would expect as well, although I have to admit that because of the issues I am having it may be clouding my understanding of the process. My issue comes when I am trying to drag and drop from a QTableView to anything including an identical copy of the view. I set break-points at the mouse event and the drag entered event when using the Column Views and they are triggered, but when I use the Table Views nothing happens using the same application and window that are used in the column views. I use the same settings in the ui for the panel for both the column view and the table view. One works the other doesn't trigger the events.
I am lost. Help
-
Hi,
You will have to subclass QPushButton in order to accept what you are dragging over it.
What you think is text might be something different. For example, a QTableView cell is different from a QListView item.
Check the mime type of what you are dragging around in order to be able to properly accept it.
The drag and drop documentation is a good starting point. With the corresponding item view chapter.
-
@SGaist Also I cannot find an actual example of dragging from one QTableView to another to reference.
Lost
-
@SGaist Also I cannot find an actual example of dragging from one QTableView to another to reference.
Lost
@dencla I have attached some code that exhibits the same issue I am having with the sql tables.
This is compiled with Qmake.
#include <QWidget>
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlTableModel>
#include <QSqlError>
#include <QSqlRecord>
#include <QSqlField>
#include <QSqlRelationalTableModel>
#include <QTableView>
#include <QMimeData>
#include <QDrag>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QDebug>
#include <QMessageBox>QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
class CustomSqlTableModel : public QSqlTableModel {
public:
CustomSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase())
: QSqlTableModel(parent, db) {}Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; } Qt::ItemFlags flags(const QModelIndex &index) const override { Qt::ItemFlags defaultFlags = QSqlTableModel::flags(index); if (index.isValid()) return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; return defaultFlags; } QStringList mimeTypes() const override { return QStringList("application/vnd.text.list"); } QMimeData *mimeData(const QModelIndexList &indexes) const override { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const QModelIndex &index : indexes) { if (index.isValid()) { QString text = data(index, Qt::DisplayRole).toString(); stream << text; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; }
};
class CustomSqlTableView : public QTableView {
public:
CustomSqlTableView(QWidget *parent = nullptr) : QTableView(parent) {
setAcceptDrops(true);
}protected:
void mousePressEvent(QMouseEvent *event) override {
if (event->button() == Qt::LeftButton) {
QModelIndex index = indexAt(event->pos());
if (index.isValid()) {
QMimeData *mimeData = new QMimeData;
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
stream << model()->data(index, Qt::DisplayRole).toString();
mimeData->setData("application/vnd.text.list", encodedData);QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); } } } void dragEnterEvent(QDragEnterEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) event->accept(); else event->ignore(); } void dragMoveEvent(QDragMoveEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) { event->setDropAction(Qt::CopyAction); event->accept(); } else { event->ignore(); } } void dropEvent(QDropEvent *event) override { const QMimeData *mimeData = event->mimeData(); if (mimeData->hasFormat("application/vnd.text.list")) { QByteArray encodedData = mimeData->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList items; while (!stream.atEnd()) { QString text; stream >> text; items.append(text); } qDebug() << "Dropped Items:" << items; // Insert the dropped items into the model of the target view if (auto *model = dynamic_cast<QSqlTableModel*>(this->model())) { QSqlRecord record; for (const QString &item : items) { record.setValue("name", item); if (!model->insertRecord(-1, record)) { qDebug() << "Failed to insert record:" << record; } } } } }
};
static bool createConnection()
{
// QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
if (!db.open()) {
QMessageBox::critical(nullptr, QObject::tr("Cannot open database"),
QObject::tr("Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information how "
"to build it.\n\n"
"Click Cancel to exit."), QMessageBox::Cancel);
return false;
}QSqlQuery query; query.exec("create table person (id int primary key, " "firstname varchar(20), lastname varchar(20))"); query.exec("insert into person values(101, 'Danny', 'Young')"); query.exec("insert into person values(102, 'Christine', 'Holand')"); query.exec("insert into person values(103, 'Lars', 'Gordon')"); query.exec("insert into person values(104, 'Roberto', 'Robitaille')"); query.exec("insert into person values(105, 'Maria', 'Papadopoulos')"); query.exec("create table items (id int primary key," "imagefile int," "itemtype varchar(20)," "description varchar(100))"); query.exec("insert into items " "values(0, 0, 'Qt'," "'Qt is a full development framework with tools designed to " "streamline the creation of stunning applications and " "amazing user interfaces for desktop, embedded and mobile " "platforms.')"); query.exec("insert into items " "values(1, 1, 'Qt Quick'," "'Qt Quick is a collection of techniques designed to help " "developers create intuitive, modern-looking, and fluid " "user interfaces using a CSS & JavaScript like language.')"); query.exec("insert into items " "values(2, 2, 'Qt Creator'," "'Qt Creator is a powerful cross-platform integrated " "development environment (IDE), including UI design tools " "and on-device debugging.')"); query.exec("insert into items " "values(3, 3, 'Qt Project'," "'The Qt Project governs the open source development of Qt, " "allowing anyone wanting to contribute to join the effort " "through a meritocratic structure of approvers and " "maintainers.')"); query.exec("create table images (itemid int, file varchar(20))"); query.exec("insert into images values(0, 'images/qt-logo.png')"); query.exec("insert into images values(1, 'images/qt-quick.png')"); query.exec("insert into images values(2, 'images/qt-creator.png')"); query.exec("insert into images values(3, 'images/qt-project.png')"); return true;
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);// Replace the database name with your database file path if (!createConnection()) return EXIT_FAILURE; if (!db.open()) { qDebug() << "Error: " << db.lastError().text(); return -1; } CustomSqlTableModel model1; model1.setTable("table1"); model1.select(); CustomSqlTableModel model2; model2.setTable("table2"); model2.select(); CustomSqlTableView view1; view1.setModel(&model1); CustomSqlTableView view2; view2.setModel(&model2); view1.setGeometry(100, 100, 300, 200); view2.setGeometry(500, 100, 300, 200); view1.show(); view2.show(); return app.exec();
}
-
@dencla The item view documentation I linked shows how to configure views for both operations. Granted it's for a list view however the technique is the same for a table view.
@SGaist
Sorry I sent the attached code to myself first.#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlTableModel>
#include <QSqlError>
#include <QSqlRecord>
#include <QSqlField>
#include <QSqlRelationalTableModel>
#include <QTableView>
#include <QMimeData>
#include <QDrag>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QDebug>
#include <QMessageBox>class CustomSqlTableModel : public QSqlTableModel {
public:
CustomSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase())
: QSqlTableModel(parent, db) {}Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; } Qt::ItemFlags flags(const QModelIndex &index) const override { Qt::ItemFlags defaultFlags = QSqlTableModel::flags(index); if (index.isValid()) return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; return defaultFlags; } QStringList mimeTypes() const override { return QStringList("application/vnd.text.list"); } QMimeData *mimeData(const QModelIndexList &indexes) const override { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const QModelIndex &index : indexes) { if (index.isValid()) { QString text = data(index, Qt::DisplayRole).toString(); stream << text; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; }
};
#include <QMouseEvent>
class CustomSqlTableView : public QTableView {
public:
CustomSqlTableView(QWidget *parent = nullptr) : QTableView(parent) {
setAcceptDrops(true);
}protected:
void mousePressEvent(QMouseEvent *event) override {
if (event->button() == Qt::LeftButton) {
m_startPos = event->pos();
QModelIndex index = indexAt(event->pos());
if (index.isValid()) {
m_draggedItem = model()->data(index, Qt::DisplayRole).toString();
}
}
QTableView::mousePressEvent(event);
}void mouseMoveEvent(QMouseEvent *event) override { if (event->buttons() & Qt::LeftButton) { int distance = (event->pos() - m_startPos).manhattanLength(); if (distance >= QApplication::startDragDistance()) { performDrag(); } } QTableView::mouseMoveEvent(event); } void performDrag() { if (!m_draggedItem.isEmpty()) { QMimeData *mimeData = new QMimeData; QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); stream << m_draggedItem; mimeData->setData("application/vnd.text.list", encodedData); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); } } void dragEnterEvent(QDragEnterEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) event->accept(); else event->ignore(); } void dragMoveEvent(QDragMoveEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) { event->setDropAction(Qt::CopyAction); event->accept(); } else { event->ignore(); } } void dropEvent(QDropEvent *event) override { const QMimeData *mimeData = event->mimeData(); if (!mimeData->hasFormat("application/vnd.text.list")) { event->ignore(); return; } QByteArray encodedData = mimeData->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList items; while (!stream.atEnd()) { QString text; stream >> text; items.append(text); } qDebug() << "Dropped Items:" << items; // Insert the dropped items into the model of the target view if (auto *model = dynamic_cast<QSqlTableModel*>(this->model())) { QSqlRecord record; for (const QString &item : items) { record.setValue("name", item); if (!model->insertRecord(-1, record)) { qDebug() << "Failed to insert record:" << record; } } } event->accept(); // Refresh the view after dropping items reset(); }
private:
QPoint m_startPos;
QString m_draggedItem;
};int main(int argc, char *argv[]) {
QApplication app(argc, argv);// Replace the database name with your database file path
// if (!createConnection())
// return EXIT_FAILURE;
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");if (!db.open()) { qDebug() << "Error: " << db.lastError().text(); return -1; } else { QSqlQuery query; query.exec("create table person (id int primary key, " "firstname varchar(20), lastname varchar(20))"); query.exec("insert into person values(101, 'Danny', 'Young')"); query.exec("insert into person values(102, 'Christine', 'Holand')"); query.exec("insert into person values(103, 'Lars', 'Gordon')"); query.exec("insert into person values(104, 'Roberto', 'Robitaille')"); query.exec("insert into person values(105, 'Maria', 'Papadopoulos')"); query.exec("create table items (id int primary key," "imagefile int," "itemtype varchar(20)," "description varchar(100))"); query.exec("insert into items " "values(0, 0, 'Qt'," "'Qt is a full development framework with tools designed to " "streamline the creation of stunning applications and " "amazing user interfaces for desktop, embedded and mobile " "platforms.')"); query.exec("insert into items " "values(1, 1, 'Qt Quick'," "'Qt Quick is a collection of techniques designed to help " "developers create intuitive, modern-looking, and fluid " "user interfaces using a CSS & JavaScript like language.')"); query.exec("insert into items " "values(2, 2, 'Qt Creator'," "'Qt Creator is a powerful cross-platform integrated " "development environment (IDE), including UI design tools " "and on-device debugging.')"); query.exec("insert into items " "values(3, 3, 'Qt Project'," "'The Qt Project governs the open source development of Qt, " "allowing anyone wanting to contribute to join the effort " "through a meritocratic structure of approvers and " "maintainers.')"); } CustomSqlTableModel model1; model1.setTable("person"); model1.setEditStrategy(QSqlTableModel::OnManualSubmit); model1.select(); model1.setHeaderData(0, Qt::Horizontal, QObject::tr("ID")); model1.setHeaderData(1, Qt::Horizontal, QObject::tr("First name")); model1.setHeaderData(2, Qt::Horizontal, QObject::tr("Last name")); CustomSqlTableModel model2; model2.setTable("person"); model2.setEditStrategy(QSqlTableModel::OnManualSubmit); model2.select(); model2.setHeaderData(0, Qt::Horizontal, QObject::tr("ID")); model2.setHeaderData(1, Qt::Horizontal, QObject::tr("First name")); model2.setHeaderData(2, Qt::Horizontal, QObject::tr("Last name")); CustomSqlTableView view1; view1.setModel(&model1); view1.setStyleSheet("color:white"); CustomSqlTableView view2; view2.setModel(&model2); view1.setGeometry(100, 100, 300, 200); view2.setGeometry(500, 100, 300, 200); view1.show(); view2.show(); return app.exec();
}
-
@SGaist
Sorry I sent the attached code to myself first.#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlTableModel>
#include <QSqlError>
#include <QSqlRecord>
#include <QSqlField>
#include <QSqlRelationalTableModel>
#include <QTableView>
#include <QMimeData>
#include <QDrag>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QDebug>
#include <QMessageBox>class CustomSqlTableModel : public QSqlTableModel {
public:
CustomSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase())
: QSqlTableModel(parent, db) {}Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; } Qt::ItemFlags flags(const QModelIndex &index) const override { Qt::ItemFlags defaultFlags = QSqlTableModel::flags(index); if (index.isValid()) return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; return defaultFlags; } QStringList mimeTypes() const override { return QStringList("application/vnd.text.list"); } QMimeData *mimeData(const QModelIndexList &indexes) const override { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const QModelIndex &index : indexes) { if (index.isValid()) { QString text = data(index, Qt::DisplayRole).toString(); stream << text; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; }
};
#include <QMouseEvent>
class CustomSqlTableView : public QTableView {
public:
CustomSqlTableView(QWidget *parent = nullptr) : QTableView(parent) {
setAcceptDrops(true);
}protected:
void mousePressEvent(QMouseEvent *event) override {
if (event->button() == Qt::LeftButton) {
m_startPos = event->pos();
QModelIndex index = indexAt(event->pos());
if (index.isValid()) {
m_draggedItem = model()->data(index, Qt::DisplayRole).toString();
}
}
QTableView::mousePressEvent(event);
}void mouseMoveEvent(QMouseEvent *event) override { if (event->buttons() & Qt::LeftButton) { int distance = (event->pos() - m_startPos).manhattanLength(); if (distance >= QApplication::startDragDistance()) { performDrag(); } } QTableView::mouseMoveEvent(event); } void performDrag() { if (!m_draggedItem.isEmpty()) { QMimeData *mimeData = new QMimeData; QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); stream << m_draggedItem; mimeData->setData("application/vnd.text.list", encodedData); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); } } void dragEnterEvent(QDragEnterEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) event->accept(); else event->ignore(); } void dragMoveEvent(QDragMoveEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) { event->setDropAction(Qt::CopyAction); event->accept(); } else { event->ignore(); } } void dropEvent(QDropEvent *event) override { const QMimeData *mimeData = event->mimeData(); if (!mimeData->hasFormat("application/vnd.text.list")) { event->ignore(); return; } QByteArray encodedData = mimeData->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList items; while (!stream.atEnd()) { QString text; stream >> text; items.append(text); } qDebug() << "Dropped Items:" << items; // Insert the dropped items into the model of the target view if (auto *model = dynamic_cast<QSqlTableModel*>(this->model())) { QSqlRecord record; for (const QString &item : items) { record.setValue("name", item); if (!model->insertRecord(-1, record)) { qDebug() << "Failed to insert record:" << record; } } } event->accept(); // Refresh the view after dropping items reset(); }
private:
QPoint m_startPos;
QString m_draggedItem;
};int main(int argc, char *argv[]) {
QApplication app(argc, argv);// Replace the database name with your database file path
// if (!createConnection())
// return EXIT_FAILURE;
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");if (!db.open()) { qDebug() << "Error: " << db.lastError().text(); return -1; } else { QSqlQuery query; query.exec("create table person (id int primary key, " "firstname varchar(20), lastname varchar(20))"); query.exec("insert into person values(101, 'Danny', 'Young')"); query.exec("insert into person values(102, 'Christine', 'Holand')"); query.exec("insert into person values(103, 'Lars', 'Gordon')"); query.exec("insert into person values(104, 'Roberto', 'Robitaille')"); query.exec("insert into person values(105, 'Maria', 'Papadopoulos')"); query.exec("create table items (id int primary key," "imagefile int," "itemtype varchar(20)," "description varchar(100))"); query.exec("insert into items " "values(0, 0, 'Qt'," "'Qt is a full development framework with tools designed to " "streamline the creation of stunning applications and " "amazing user interfaces for desktop, embedded and mobile " "platforms.')"); query.exec("insert into items " "values(1, 1, 'Qt Quick'," "'Qt Quick is a collection of techniques designed to help " "developers create intuitive, modern-looking, and fluid " "user interfaces using a CSS & JavaScript like language.')"); query.exec("insert into items " "values(2, 2, 'Qt Creator'," "'Qt Creator is a powerful cross-platform integrated " "development environment (IDE), including UI design tools " "and on-device debugging.')"); query.exec("insert into items " "values(3, 3, 'Qt Project'," "'The Qt Project governs the open source development of Qt, " "allowing anyone wanting to contribute to join the effort " "through a meritocratic structure of approvers and " "maintainers.')"); } CustomSqlTableModel model1; model1.setTable("person"); model1.setEditStrategy(QSqlTableModel::OnManualSubmit); model1.select(); model1.setHeaderData(0, Qt::Horizontal, QObject::tr("ID")); model1.setHeaderData(1, Qt::Horizontal, QObject::tr("First name")); model1.setHeaderData(2, Qt::Horizontal, QObject::tr("Last name")); CustomSqlTableModel model2; model2.setTable("person"); model2.setEditStrategy(QSqlTableModel::OnManualSubmit); model2.select(); model2.setHeaderData(0, Qt::Horizontal, QObject::tr("ID")); model2.setHeaderData(1, Qt::Horizontal, QObject::tr("First name")); model2.setHeaderData(2, Qt::Horizontal, QObject::tr("Last name")); CustomSqlTableView view1; view1.setModel(&model1); view1.setStyleSheet("color:white"); CustomSqlTableView view2; view2.setModel(&model2); view1.setGeometry(100, 100, 300, 200); view2.setGeometry(500, 100, 300, 200); view1.show(); view2.show(); return app.exec();
}
@dencla
Could you please use the forum's Code tags (</>
button) when pasting blocks of code.What actually goes wrong in your code? If you have a question about "Drag and drop to a Pushbutton" I don't see how that can be related to whether you are using SQL or not.
-
Why are you reimplementing the drag manually for your custom view ? Just enable it.
-
@SGaist Because when I just enable it nothing happens when I use QTableViews, but when I do the same for Column Views it does work by enabling it only.
Even when I do as the example I have shown, the drag works and the debug shows that it executed the drop but nothing changes in the table where it was dropped.
I feel that I need to figure out how to get it to drag and drop to similar items as I did with column views, before I try dissimilar objects like push buttons.
I can make it work by using column views that are populated from the database and transfer the information from the second column to the object, but that seems redundant.
-
@dencla
Could you please use the forum's Code tags (</>
button) when pasting blocks of code.What actually goes wrong in your code? If you have a question about "Drag and drop to a Pushbutton" I don't see how that can be related to whether you are using SQL or not.
@JonB
Do you mean like this?void dropEvent(QDropEvent *event) override { const QMimeData *mimeData = event->mimeData(); if (!mimeData->hasFormat("application/vnd.text.list")) { event->ignore(); return; } QByteArray encodedData = mimeData->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList items; while (!stream.atEnd()) { QString text; stream >> text; items.append(text); } qDebug() << "Dropped Items:" << items; // Insert the dropped items into the model of the target view if (auto *model = dynamic_cast<QSqlTableModel*>(this->model())) { QSqlRecord record; for (const QString &item : items) { record.setValue("name", item); if (!model->insertRecord(-1, record)) { qDebug() << "Failed to insert record:" << record; } } } event->accept(); // Refresh the data in the model if (auto *model = dynamic_cast<QSqlTableModel*>(this->model())) { model->select(); } } code_text
Sorry I didn't know, I will try to remember.
-
@SGaist I changed the drop action code below, and now it works in the example program. But I still don't understand why it is not as simple as the Column View to implement.
void dropEvent(QDropEvent *event) override { const QMimeData *mimeData = event->mimeData(); if (!mimeData->hasFormat("application/vnd.text.list")) { event->ignore(); return; } QByteArray encodedData = mimeData->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList items; while (!stream.atEnd()) { QString text; stream >> text; items.append(text); } qDebug() << "Dropped Items:" << items; // Get the model associated with the table view QSqlTableModel *model = qobject_cast<QSqlTableModel*>(this->model()); if (!model) { event->ignore(); return; } // Get the row and column where the items are dropped QModelIndex index = indexAt(event->pos()); int row = index.isValid() ? index.row() : model->rowCount(); int column = index.isValid() ? index.column() : 0; // Insert the dropped items into the model of the target view for (int i = 0; i < items.size(); ++i) { // Ensure we have enough rows and columns for the dropped items if (row + i >= model->rowCount()) { model->insertRows(row + i, 1); } if (column + i >= model->columnCount()) { model->insertColumns(column + i, 1); } // Set the data at the appropriate row and column model->setData(model->index(row + i, column + i), items.at(i)); // Adjust the column index according to your needs } // Emit signal to notify the view of the changes model->layoutChanged(); event->accept(); }
I'll keep trying now I will try to do the same for a QPushButton
-
@dencla The item view documentation I linked shows how to configure views for both operations. Granted it's for a list view however the technique is the same for a table view.
@SGaist I have discovered an issue With my drop implementation. When I use my CustomSqlTableModel with my CustomSqlTableView everything works correctly. When I use my CustomSqlQueryModel the drop in the CustomSqlTable Model says it dropped the item, but in reality it fails on model->insertrows() call and the model->setData() call, co the data never gets dropped. As far as I can tell the model calls are valid. What am I missing?
I have the text below:
#include <QApplication> #include <QSqlTableModel> #include <QTableView> #include <QMimeData> #include <QMouseEvent> #include <QDrag> #include <QDebug> class CustomSqlTableModel : public QSqlTableModel { public: CustomSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase()) : QSqlTableModel(parent, db) {} Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; } Qt::ItemFlags flags(const QModelIndex &index) const override { Qt::ItemFlags defaultFlags = QSqlTableModel::flags(index); if (index.isValid()) return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; return defaultFlags; } QStringList mimeTypes() const override { return QStringList("application/vnd.text.list"); } QMimeData *mimeData(const QModelIndexList &indexes) const override { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const QModelIndex &index : indexes) { if (index.isValid()) { QString text = data(index, Qt::DisplayRole).toString(); stream << text; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; } }; #include <QMouseEvent> class CustomSqlTableView : public QTableView { public: CustomSqlTableView(QWidget *parent = nullptr) : QTableView(parent) { setAcceptDrops(true); } protected: void mousePressEvent(QMouseEvent *event) override { if (event->button() == Qt::LeftButton) { m_startPos = event->pos(); QModelIndex index = indexAt(event->pos()); if (index.isValid()) { m_draggedItem = model()->data(index, Qt::DisplayRole).toString(); } } QTableView::mousePressEvent(event); } void mouseMoveEvent(QMouseEvent *event) override { if (event->buttons() & Qt::LeftButton) { int distance = (event->pos() - m_startPos).manhattanLength(); if (distance >= QApplication::startDragDistance()) { performDrag(); } } QTableView::mouseMoveEvent(event); } void performDrag() { if (!m_draggedItem.isEmpty()) { QMimeData *mimeData = new QMimeData; QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); stream << m_draggedItem; mimeData->setData("application/vnd.text.list", encodedData); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); } } void dragEnterEvent(QDragEnterEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) event->accept(); else event->ignore(); } void dragMoveEvent(QDragMoveEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) { event->setDropAction(Qt::CopyAction); event->accept(); } else { event->ignore(); } } void dropEvent(QDropEvent *event) override { const QMimeData *mimeData = event->mimeData(); if (!mimeData->hasFormat("application/vnd.text.list")) { event->ignore(); return; } QByteArray encodedData = mimeData->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList items; while (!stream.atEnd()) { QString text; stream >> text; items.append(text); } qDebug() << "Dropped Items:" << items; // Get the model associated with the table view QSqlTableModel *model = Qobject_cast<QSqlTableModel*>(this->model()); if (!model) { QSqlQueryModel *model = Qobject_cast<QSqlQueryModel*>(this->model()); if (!model) { event->ignore(); return; } } // Get the row and column where the items are dropped QModelIndex index = indexAt(event->pos()); int row = index.isValid() ? index.row() : 5; // *int row = index.isValid() ? index.row() : model->rowCount();* int column = index.isValid() ? index.column() : 0; // Insert the dropped items into the model of the target view for (int i = 0; i < items.size(); ++i) { // Ensure we have enough rows and columns for the dropped items if (row + i >= model->rowCount()) { if(model->insertRows(row + i, 1)) qDebug() << "inserted row"; } if (column + i >= model->columnCount()) { if(model->insertColumns(column + i, 1)) qDebug() << "inserted column"; } // Set the data at the appropriate row and column *if(model->setData(model->index(row + i, column + i), items.at(i))) qDebug() << "inserted data";* // Adjust the column index according to your needs } // Emit signal to notify the view of the changes emit model->layoutChanged(); event->accept(); } private: QPoint m_startPos; QString m_draggedItem; };
I have marked the problematic code. Below is how they are called:
CustomSqlTableModel model1; model1.setTable("person"); model1.setEditStrategy(QSqlTableModel::OnManualSubmit); model1.select(); model1.setHeaderData(0, Qt::Horizontal, QObject::tr("ID")); model1.setHeaderData(1, Qt::Horizontal, QObject::tr("First name")); model1.setHeaderData(2, Qt::Horizontal, QObject::tr("Last name")); CustomSqlQueryModel *model2 = new CustomSqlQueryModel; model2->setQuery("SELECT * FROM people "); CustomSqlTableView view1; view1.setModel(&model1); CustomSqlTableView view2; view2.setModel(model2); view1.setGeometry(100, 100, 300, 200); view2.setGeometry(500, 100, 300, 200); view1.show(); view2.show();
I'm sure that it has something to do with the model assignment, but I'm not sure what?
Thanks any help will be appreciated.
-
@SGaist Here is the CustomSqlQueryModel code:
#include <QSqlQueryModel> #include <QMimeData> #include <QDataStream> class CustomSqlQueryModel : public QSqlQueryModel { public: CustomSqlQueryModel(QObject *parent = nullptr) : QSqlQueryModel(parent) {} Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; } Qt::ItemFlags flags(const QModelIndex &index) const override { Qt::ItemFlags flags = QSqlQueryModel::flags(index); if (index.isValid()) { return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | flags; } return flags; } QStringList mimeTypes() const override { return QStringList("application/vnd.text.list"); } QMimeData *mimeData(const QModelIndexList &indexes) const override { QMimeData *mimeData = new QMimeData; QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const QModelIndex &index : indexes) { if (index.isValid()) { QString text = data(index, Qt::DisplayRole).toString(); stream << text; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; } bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override { if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat("application/vnd.text.list")) { return false; } if (column > 0) { return false; } int beginRow; if (row != -1) { beginRow = row; } else if (parent.isValid()) { beginRow = parent.row(); } else { beginRow = rowCount(QModelIndex()); } QByteArray encodedData = data->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList newItems; while (!stream.atEnd()) { QString text; stream >> text; newItems << text; } insertRows(beginRow, newItems.count(), QModelIndex()); foreach (const QString &text, newItems) { QModelIndex idx = index(beginRow, 0, QModelIndex()); setData(idx, text); beginRow++; } return true; } };
-
@SGaist I have discovered an issue With my drop implementation. When I use my CustomSqlTableModel with my CustomSqlTableView everything works correctly. When I use my CustomSqlQueryModel the drop in the CustomSqlTable Model says it dropped the item, but in reality it fails on model->insertrows() call and the model->setData() call, co the data never gets dropped. As far as I can tell the model calls are valid. What am I missing?
I have the text below:
#include <QApplication> #include <QSqlTableModel> #include <QTableView> #include <QMimeData> #include <QMouseEvent> #include <QDrag> #include <QDebug> class CustomSqlTableModel : public QSqlTableModel { public: CustomSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase()) : QSqlTableModel(parent, db) {} Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; } Qt::ItemFlags flags(const QModelIndex &index) const override { Qt::ItemFlags defaultFlags = QSqlTableModel::flags(index); if (index.isValid()) return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; return defaultFlags; } QStringList mimeTypes() const override { return QStringList("application/vnd.text.list"); } QMimeData *mimeData(const QModelIndexList &indexes) const override { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const QModelIndex &index : indexes) { if (index.isValid()) { QString text = data(index, Qt::DisplayRole).toString(); stream << text; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; } }; #include <QMouseEvent> class CustomSqlTableView : public QTableView { public: CustomSqlTableView(QWidget *parent = nullptr) : QTableView(parent) { setAcceptDrops(true); } protected: void mousePressEvent(QMouseEvent *event) override { if (event->button() == Qt::LeftButton) { m_startPos = event->pos(); QModelIndex index = indexAt(event->pos()); if (index.isValid()) { m_draggedItem = model()->data(index, Qt::DisplayRole).toString(); } } QTableView::mousePressEvent(event); } void mouseMoveEvent(QMouseEvent *event) override { if (event->buttons() & Qt::LeftButton) { int distance = (event->pos() - m_startPos).manhattanLength(); if (distance >= QApplication::startDragDistance()) { performDrag(); } } QTableView::mouseMoveEvent(event); } void performDrag() { if (!m_draggedItem.isEmpty()) { QMimeData *mimeData = new QMimeData; QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); stream << m_draggedItem; mimeData->setData("application/vnd.text.list", encodedData); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); } } void dragEnterEvent(QDragEnterEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) event->accept(); else event->ignore(); } void dragMoveEvent(QDragMoveEvent *event) override { if (event->mimeData()->hasFormat("application/vnd.text.list")) { event->setDropAction(Qt::CopyAction); event->accept(); } else { event->ignore(); } } void dropEvent(QDropEvent *event) override { const QMimeData *mimeData = event->mimeData(); if (!mimeData->hasFormat("application/vnd.text.list")) { event->ignore(); return; } QByteArray encodedData = mimeData->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList items; while (!stream.atEnd()) { QString text; stream >> text; items.append(text); } qDebug() << "Dropped Items:" << items; // Get the model associated with the table view QSqlTableModel *model = Qobject_cast<QSqlTableModel*>(this->model()); if (!model) { QSqlQueryModel *model = Qobject_cast<QSqlQueryModel*>(this->model()); if (!model) { event->ignore(); return; } } // Get the row and column where the items are dropped QModelIndex index = indexAt(event->pos()); int row = index.isValid() ? index.row() : 5; // *int row = index.isValid() ? index.row() : model->rowCount();* int column = index.isValid() ? index.column() : 0; // Insert the dropped items into the model of the target view for (int i = 0; i < items.size(); ++i) { // Ensure we have enough rows and columns for the dropped items if (row + i >= model->rowCount()) { if(model->insertRows(row + i, 1)) qDebug() << "inserted row"; } if (column + i >= model->columnCount()) { if(model->insertColumns(column + i, 1)) qDebug() << "inserted column"; } // Set the data at the appropriate row and column *if(model->setData(model->index(row + i, column + i), items.at(i))) qDebug() << "inserted data";* // Adjust the column index according to your needs } // Emit signal to notify the view of the changes emit model->layoutChanged(); event->accept(); } private: QPoint m_startPos; QString m_draggedItem; };
I have marked the problematic code. Below is how they are called:
CustomSqlTableModel model1; model1.setTable("person"); model1.setEditStrategy(QSqlTableModel::OnManualSubmit); model1.select(); model1.setHeaderData(0, Qt::Horizontal, QObject::tr("ID")); model1.setHeaderData(1, Qt::Horizontal, QObject::tr("First name")); model1.setHeaderData(2, Qt::Horizontal, QObject::tr("Last name")); CustomSqlQueryModel *model2 = new CustomSqlQueryModel; model2->setQuery("SELECT * FROM people "); CustomSqlTableView view1; view1.setModel(&model1); CustomSqlTableView view2; view2.setModel(model2); view1.setGeometry(100, 100, 300, 200); view2.setGeometry(500, 100, 300, 200); view1.show(); view2.show();
I'm sure that it has something to do with the model assignment, but I'm not sure what?
Thanks any help will be appreciated.
@dencla said in Drag and drop to a Pushbutton:
but in reality it fails on model->insertrows() call and the model->setData() call, co the data never gets dropped.
Are you saying if you get rid of all drop stuff etc. you cannot call
insertrows()
with successful return result on yourCustomSqlTableModel
?Back a while
class CustomSqlTableModel : public QSqlTableModel {
now
class CustomSqlQueryModel : public QSqlQueryModel {
Have you changed this without saying anything?? A
QSqlTableModel
is editable, aQSqlQueryModel
is not, now I don't know which you have. -
@dencla said in Drag and drop to a Pushbutton:
but in reality it fails on model->insertrows() call and the model->setData() call, co the data never gets dropped.
Are you saying if you get rid of all drop stuff etc. you cannot call
insertrows()
with successful return result on yourCustomSqlTableModel
?Back a while
class CustomSqlTableModel : public QSqlTableModel {
now
class CustomSqlQueryModel : public QSqlQueryModel {
Have you changed this without saying anything?? A
QSqlTableModel
is editable, aQSqlQueryModel
is not, now I don't know which you have.@JonB I have both, it is when I have created the view with a queryModel that it does not work. Are you saying that it is because it is a query model that it is not working? It allows me to create a call to a query model to insert a row.
QSqlTableModel tmodel; tmodel.insertRows(0,1,QModelIndex()); QSqlQueryModel qmodel; qmodel.insertRows(0,1,QModelIndex());
It would make sense if that is the case, so why can I create the call.
-
@JonB I have both, it is when I have created the view with a queryModel that it does not work. Are you saying that it is because it is a query model that it is not working? It allows me to create a call to a query model to insert a row.
QSqlTableModel tmodel; tmodel.insertRows(0,1,QModelIndex()); QSqlQueryModel qmodel; qmodel.insertRows(0,1,QModelIndex());
It would make sense if that is the case, so why can I create the call.
@dencla
insertRows()
returns abool
result, why don't you print that out? Being able to call something from C++ versus what result it might return if it does not work are two different things.https://doc.qt.io/qt-6/qabstractitemmodel.html#insertRows
On models that support this, inserts count rows into the model before the given row.
Returns true if the rows were successfully inserted; otherwise returns false.
https://doc.qt.io/qt-6/qsqlquerymodel.html
The QSqlQueryModel class provides a read-only data model for SQL result sets.
https://doc.qt.io/qt-6/qsqltablemodel.html
The QSqlTableModel class provides an editable data model for a single database table.
What would be the point of alteration or drag and drop into for a
QSqlQueryModel
? -
@dencla
insertRows()
returns abool
result, why don't you print that out? Being able to call something from C++ versus what result it might return if it does not work are two different things.https://doc.qt.io/qt-6/qabstractitemmodel.html#insertRows
On models that support this, inserts count rows into the model before the given row.
Returns true if the rows were successfully inserted; otherwise returns false.
https://doc.qt.io/qt-6/qsqlquerymodel.html
The QSqlQueryModel class provides a read-only data model for SQL result sets.
https://doc.qt.io/qt-6/qsqltablemodel.html
The QSqlTableModel class provides an editable data model for a single database table.
What would be the point of alteration or drag and drop into for a
QSqlQueryModel
? -
@dencla
insertRows()
returns abool
result, why don't you print that out? Being able to call something from C++ versus what result it might return if it does not work are two different things.https://doc.qt.io/qt-6/qabstractitemmodel.html#insertRows
On models that support this, inserts count rows into the model before the given row.
Returns true if the rows were successfully inserted; otherwise returns false.
https://doc.qt.io/qt-6/qsqlquerymodel.html
The QSqlQueryModel class provides a read-only data model for SQL result sets.
https://doc.qt.io/qt-6/qsqltablemodel.html
The QSqlTableModel class provides an editable data model for a single database table.
What would be the point of alteration or drag and drop into for a
QSqlQueryModel
? -
@JonB I think that you are correct. It does return false for the qmodel. so why does the query model allow calls to edit it?
@dencla said in Drag and drop to a Pushbutton:
so why does the query model allow calls to edit it?
Because QSqlQueryModel is derived from QAbstractTableModel if you are asking about compilation. At runtime we have already said it returns an unsuccessful result if you call it. Some model types allow editing, some do not.
When I create a ui->CustomTableView nothing is displayed, but when I create a normal tableView it does display the database.
I don't know what this means. If a
QTableView
works but aCustomTableView
derived from that does not look at your code differences in the custom view. I don't know what this has to do withQSqlQueryModel
vsQSqlTableModel
, nor with drag and drop.