【问题标题】:Why drag&drop does not called dropEvent?为什么拖放不调用dropEvent?
【发布时间】:2022-08-18 21:06:09
【问题描述】:

我想没有人知道这件事。我问同样的问题两天了,没有人回答。

我找到了一个关于拖放的 toDoList 项目。我想知道我能得到拖放的项目吗?我正在阅读文档 2 天。我实施这些方法。

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

有 2 个列表视图和工具栏。我将添加和删除添加到工具栏。
我可以拖放,但我无法获取拖动项目的文本。这是主要代码。 我真的很想知道,我们是否正确地覆盖了方法。但是我们没有将方法与某事联系起来。该方法如何工作?

todolist::todolist(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::todolist)
{
    QWidget* pWidget = new QWidget(this);
        pWidget->setStyleSheet(\"background-color: #ECF0F1\");
        setCentralWidget(pWidget);

        QVBoxLayout* pMainLayout = new QVBoxLayout();
        pWidget->setLayout(pMainLayout);

        QLabel* pwTitle = new QLabel(\"To Do List\", this);
        pMainLayout->addWidget(pwTitle);
        pwTitle->setAlignment(Qt::AlignCenter);
        pwTitle->setStyleSheet(\"font-size: 30pt; margin: 10%;\");

        QHBoxLayout* pHLayoutLabels = new QHBoxLayout();
        pMainLayout->addLayout(pHLayoutLabels);

        QLabel* plblPending = new QLabel(\"Pending\", this);
        plblPending->setStyleSheet(\"font-size: 15pt;\");
        pHLayoutLabels->addWidget(plblPending);

        QLabel* plblCompleted = new QLabel(\"Completed\", this);
        plblCompleted->setStyleSheet(\"font-size: 15pt;\");
        pHLayoutLabels->addWidget(plblCompleted);

        QHBoxLayout* pHLayout = new QHBoxLayout();
        pMainLayout->addLayout(pHLayout);

        m_pwPending = new QListView(this);
        m_pwPending->setDragEnabled(true);
        m_pwPending->setAcceptDrops(true);
        m_pwPending->setDropIndicatorShown(true);
        m_pwPending->setDefaultDropAction(Qt::MoveAction);
        pHLayout->addWidget(m_pwPending);

        m_pwCompleted = new QListView(this);
        m_pwCompleted->setDragEnabled(true);
        m_pwCompleted->setAcceptDrops(true);
        m_pwCompleted->setDropIndicatorShown(true);
        m_pwCompleted->setDefaultDropAction(Qt::MoveAction);
        pHLayout->addWidget(m_pwCompleted);

        m_pwPending->setModel(new QStringListModel());
        m_pwCompleted->setModel(new QStringListModel());

        m_pwPending->setStyleSheet
        (\"QListView { font-size: 20pt; font-weight: bold; }\"
         \"QListView::item { background-color: #E74C3C; padding: 10%;\"
         \"border: 1px solid #C0392B; }\"
         \"QListView::item::hover { background-color: #C0392B }\");

        m_pwCompleted->setStyleSheet
        (\"QListView { font-size: 20pt; font-weight: bold; }\"
         \"QListView::item { background-color: #2ECC71; padding: 10%;\"
         \"border: 1px solid #27AE60; }\"
         \"QListView::item::hover { background-color: #27AE60 }\");


        QToolBar* pToolBar = new QToolBar(this);
        addToolBar(pToolBar);

        m_pActAdd = new QAction(this);
            m_pActAdd->setIcon(QIcon(\":/resources/add.png\"));
            connect(m_pActAdd, &QAction::triggered, this, &todolist::onAdd);

            m_pActRemove = new QAction(this);
            m_pActRemove->setIcon(QIcon(\":/resources/remove.png\"));
            connect(m_pActRemove, &QAction::triggered, this, &todolist::onRemove);

        pToolBar->addAction(m_pActAdd);
        pToolBar->addAction(m_pActRemove);

        setAcceptDrops(true);
}

void todolist::onAdd()
{
    m_pwPending->model()->insertRow(m_pwPending->model()->rowCount());
    QModelIndex oIndex = m_pwPending->model()->index(
    m_pwPending->model()->rowCount() - 1, 0);

    m_pwPending->edit(oIndex);

}

void todolist::onRemove()
{
    QModelIndex oIndex = m_pwPending->currentIndex();
    m_pwPending->model()->removeRow(oIndex.row());
}
void todolist::dropEvent(QDropEvent* event) {
    const QMimeData* mimeData = event->mimeData();
    QString temp;
    if(mimeData->hasText()) {
        temp = mimeData->text();
    }

    QMessageBox::information(this,\"x\",temp);
}

void todolist::dragEnterEvent(QDragEnterEvent *anEvent)
{
    anEvent->setAccepted(true);
}

void todolist::dragMoveEvent(QDragMoveEvent *anEvent)
{

}

void todolist::dragLeaveEvent(QDragLeaveEvent *anEvent)
{

}
todolist::~todolist()
{
    delete ui;
}

  • 你描述了你是如何准备水槽的,即东西掉在哪里。您还必须准备源,即您打算从哪里拖动东西(无论源和接收器是相同类还是不同类的实例)。你知道吗?拖放不是很容易的东西,但在 Qt 文档中有一些有价值的教程。关于这个。因此,MVC 小部件(QTreeViewQTableView 等)提供了额外的 DnD 功能,但双方仍需要或多或少的自定义代码来启用拖放。
  • @Scheff\'sCat 我知道这并不容易。但我正在搜索它 3 天。你的意思是我必须覆盖dragEnterEvent?给我一些起点,我可以继续。
  • 您必须肯定覆盖dragEnterEvent()如果该事件被忽略,小部件将不会收到任何拖动移动事件。然而,这是在放置站点上调用的东西。在拖动站点上,您必须准备拖动的数据,例如通过提供覆盖mimeData() 的自定义模型。 (我不知道默认的 impl. 做了什么。它对我的意图从来没有用处。)
  • 我必须承认,关于mimeTypes(),我也有一些困惑。 AFAIR,mimeTypes() 并不重要。即使返回一个空字符串列表也没有任何负面影响。 (我刚刚重新审视了我的工作实施,以确保不会说错话。)

标签: c++ qt drag-and-drop draggable qlistview


【解决方案1】:

我使用推荐的网站Qt Doc. - Model/View Programming - Using Drag and Drop with Item Views 为 OP 的要求编写了一个小型示例应用程序。

我的 MCVE testQListViewDragNDrop.cc:

#include <QtWidgets>

class ListModel: public QStringListModel {

  public:
    using QStringListModel::QStringListModel;

  protected:
    // for drag site
  
    // encodes dragged items (different from default).
    virtual QMimeData* mimeData(const QModelIndexList& qMIndices) const override;
    
    // for drop site

    // returns which kind of drop actions are supported.
    virtual Qt::DropActions supportedDropActions() const override
    {
      return Qt::MoveAction;
    }

    // checks whether certain dragged MIME data is droppable.
    virtual bool canDropMimeData(
      const QMimeData* pQMimeData, // dragged data
      Qt::DropAction action, // not evaluated
      int row, // not evaluated
      int column, // uninteresting for lists (but relevant for tables and trees)
      const QModelIndex& qMIndex) // uninteresting for lists (but relevant for trees)
      const override
    {
      return pQMimeData->hasText();
    }

    // drops dragged MIME data into model.
    virtual bool dropMimeData(
      const QMimeData* pQMimeData, // dropped data
      Qt::DropAction action, // not evaluated
      int row, // where to insert
      int column, // uninteresting for lists (but relevant for tables and trees)
      const QModelIndex& qMIndex) // uninteresting for lists (but relevant for trees)
      override;
};

QMimeData* ListModel::mimeData(const QModelIndexList& qMIndices) const
{
  QMimeData* const pQMimeData = new QMimeData;
  QString qText;
  for (const QModelIndex& qMIndex : qMIndices) {
    qText += data(qMIndex, Qt::DisplayRole).toString() + "\n";
  }
  pQMimeData->setText(qText);
  return pQMimeData;
}

bool ListModel::dropMimeData(
  const QMimeData* pQMimeData, Qt::DropAction action,
  int row, int, const QModelIndex& qMIndex)
{
  // get text from mime data
  const QString qText = pQMimeData->text().trimmed();
  if (qText.isEmpty()) return true;
  // split text into lines
  const QStringList qLines = qText.split(QChar('\n'));
  const int n = qLines.size();
  // fix row
  if (qMIndex.isValid()) row = qMIndex.row(); // dropped on row
  if (row < 0 || row > rowCount()) row = rowCount();
  // insert list into list model
  if (insertRows(row, n)) {
    for (const QString& qLine : qLines) {
      setData(index(row, 0), qLine);
    }
  }
  // done
  return true;
}

QStringList makeSampleData()
{
  QStringList qList;
  qList
    << "Read the Qt doc."
    << "Write CMakeLists.txt"
    << "Write testQListViewDragNDrop.cc"
    << "Test and Debug"
    << "Fix bugs"
    << "Test and Debug"
    << "Fix bugs"
    << "Test and Debug"
    << "Fix bugs"
    << "Test and Debug"
    << "Fix bugs"
    << "Test and Debug"
    << "Fix bugs"
    << "Write SO answer";
  return qList;
}

int main(int argc, char** argv)
{
  QApplication app(argc, argv);
  // setup GUI
  QWidget qWinMain;
  qWinMain.setWindowTitle("Test QListView Drag & Drop");
  qWinMain.resize(640, 480);
  QGridLayout qGrid;
  qGrid.addWidget(new QLabel("<b>To Do</b>"), 0, 0);
  qGrid.addWidget(new QLabel("<b>Done</b>"), 0, 1);
  qGrid.setRowStretch(1, 1);
  QListView qListToDo; // drag site
  ListModel qListModelToDo;
  qListModelToDo.setStringList(makeSampleData());
  qListToDo.setModel(&qListModelToDo);
  qListToDo.setDragEnabled(true); // allow drag in ToDo list
  qGrid.addWidget(&qListToDo, 1, 0);
  QListView qListDone; // drop site
  ListModel qListModelDone;
  qListDone.setModel(&qListModelDone);
  qListDone.viewport()->setAcceptDrops(true); // allow drops
  qListDone.setDropIndicatorShown(true); // adjust drop indicator
  qGrid.addWidget(&qListDone, 1, 1);
  qWinMain.setLayout(&qGrid);
  qWinMain.show();
  // run-time loop
  return app.exec();
}

演示会议:

笔记:

  • 不需要自定义列表视图。 &emdash;可以使用QListView,但必须配置拖放和拖放。因此,QListView 可以配置为拖动与我的示例代码相比下降。
  • 与我在 cmets 中的建议相反,无可否认,没有必要覆盖 dragEnterEvent()(或公司)。这些事件已经在QListView 中被覆盖,并请参阅相应的模型以获得拖放支持。
  • 甚至不需要自定义字符串列表模型。在为拖放配置列表视图后,它也开始与QStringListModel 一起使用。我派生了QStringListModel 来演示如何自定义拖放。
  • 覆盖函数mimeData()canDropMimeData()dropMimeData() 也不是必需的。即使没有它们,拖放也可以工作。 (我在添加它们之前对此进行了测试。)我不知道使用什么 MIME 数据来传达拖动的内容。由于拖动站点和放置站点在我的示例中是同一个小部件类,因此可以放置拖动的数据(但它是在内部存储的)也就不足为奇了。

【讨论】:

    猜你喜欢
    • 2011-07-09
    • 2017-01-19
    • 2015-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-12
    相关资源
    最近更新 更多