2

我正在构建一个带有树视图的应用程序,并创建了一个派生自 QAbstractItemModel 的模型。我可以通过拖放文件(将文件从应用程序外部拖到应用程序中)和在树中拖放项目来操作树。

问题是文件放到应用程序中并不总是有效,因为我重新实现了该功能mimeData(const QModelIndexList &indexes)有时且仅当树中有一个选定的项目(它为函数提供有效的项目索引mimeData)时,文件删除不起作用,因为函数mimeData被调用但函数dropMimeData从未被调用。

我必须重新实现该函数mimeData才能创建自己的 mimeData,该 mimeData 在树内拖放期间使用。这个 mimeData 用在函数dropMimeData中,效果很好。

看起来mimeData在文件删除期间不应调用该函数,因为应用程序已经知道 mimeData 格式:text/uri-list

我的函数dropMimeData处理我自己的 mimeData 格式和text/uri-list格式。

有没有人有同样的问题或对此有任何想法?再一次,它不像它根本不工作,它只是在某些时候失败。

任何帮助或想法都会很棒。

干杯。

以下可能完全不相关,这是我在尝试调试时遇到的。看起来可能与窗口的状态有关:QEvent::WindowActivateQEvent::WindowDeactivate。在文件放置期间,窗口变为非活动状态并再次活动,但当窗口无法再次变为活动状态时似乎会出现问题。?

我添加了源代码来重现问题。将文件拖放到应用程序中。选择树中的项目。删除更多文件。有时滴不工作???

// main.cpp
#include "dragdropmainwindow.h"
#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    DragDropMainWindow w;
    w.show();
    return a.exec();
}

 // dragdropmainwindow.h

  #ifndef DRAGDROPMAINWINDOW_H
  #define DRAGDROPMAINWINDOW_H

  #include <QtGui/QMainWindow>
  #include "ui_dragdropmainwindow.h"

  #include "ControlTreeView.h"

  class DragDropMainWindow : public QMainWindow
  {
      Q_OBJECT

  public:
      DragDropMainWindow(QWidget *parent = 0, Qt::WFlags flags = 0);
      ~DragDropMainWindow();

  private:
      Ui::DragDropMainWindowClass m_ui;

      ControlTreeView  *m_controlTree;
  };

  #endif // DRAGDROPMAINWINDOW_H


  // dragdropmainwindow.cpp

  #include "dragdropmainwindow.h"

  DragDropMainWindow::DragDropMainWindow(QWidget *parent, Qt::WFlags flags)
      : QMainWindow(parent, flags)
  {
     m_ui.setupUi(this);

     // Create a model to control the view
     m_controlTree = new ControlTreeView(NULL);
     m_ui.m_treeView->setModel(m_controlTree);
  }

  DragDropMainWindow::~DragDropMainWindow()
  {

  }


// ControlTreeView.h

  #pragma once

  #include <QAbstractItemModel>
  #include <QModelIndex>
  #include <QStringList>
  #include <QVector>
  #include <QList>

  class TreeItem
  {
  public:
     TreeItem(const QVector<QVariant> &data, TreeItem *parent = 0);
     ~TreeItem();

     TreeItem *child(int number);
     int childCount() const;
     int columnCount() const;
     QVariant data(int column) const;
     bool insertChildren(int position, int count, int columns);
     bool insertColumns(int position, int columns);
     TreeItem *parent();
     bool removeChildren(int position, int count);
     bool removeColumns(int position, int columns);
     int childNumber() const;
     bool setData(int column, const QVariant &value);

  private:
     QList<TreeItem*>     childItems;
     QVector<QVariant>    itemData;
     TreeItem             *parentItem;
  };


  class ControlTreeView : public QAbstractItemModel
  {
     Q_OBJECT

  public:

     enum TREE_COLUMNS
     {
        eCOLUMN_FILENAME
     };


     ControlTreeView(QObject *parent);
     ~ControlTreeView(void);

     QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
     QModelIndex parent (const QModelIndex & index) const;
     int rowCount (const QModelIndex & parent = QModelIndex()) const;
     int columnCount (const QModelIndex & parent = QModelIndex()) const;
     QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
     Qt::ItemFlags flags (const QModelIndex & index) const;
     bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
     QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
     bool insertRows (int row, int count, const QModelIndex & parent = QModelIndex());
     //bool insertColumns (int column, int count, const QModelIndex & parent = QModelIndex());
     bool removeRows (int row, int count, const QModelIndex & parent = QModelIndex());
     //bool removeColumns (int column, int count, const QModelIndex & parent = QModelIndex());


     bool dropMimeData (const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent);
     Qt::DropActions supportedDropActions() const;
     QStringList mimeTypes () const;
     QMimeData *mimeData(const QModelIndexList &indexes) const;

     bool setHeaderData(int section, Qt::Orientation orientation,
                       const QVariant &value, int role);

  private:
     TreeItem *getItem(const QModelIndex &jobIndex) const;

     TreeItem             *m_rootItem;      // Root of the view tree
  };

// ControlTreeView.cpp
  #include "ControlTreeView.h"

  #include <QtGui>
  #include <QtGui/QGraphicsView>

  class TreeColumn
  {
  public:
     ControlTreeView::TREE_COLUMNS   m_enumColumn;
     QString                                   m_header;
     int                                       m_index;
  };


  static const int NUMBER_COLUMNS = 1;
  static TreeColumn s_columns[NUMBER_COLUMNS];

  TreeItem::TreeItem(const QVector<QVariant> &data, TreeItem *parent)
  {
     parentItem = parent;
     itemData = data;
  }

  TreeItem::~TreeItem()
  {
     qDeleteAll(childItems);
  }

  TreeItem *TreeItem::parent()
  {
     return parentItem;
  }

  TreeItem *TreeItem::child(int number)
  {
     return childItems.value(number);
  }

  int TreeItem::childCount() const
  {
     return childItems.count();
  }

  int TreeItem::childNumber() const
  {
     if (parentItem)
        return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));

     return 0;
  }

  int TreeItem::columnCount() const
  {
     return itemData.count();
  }

  QVariant TreeItem::data(int column) const
  {
     return itemData.value(column);
  }

  bool TreeItem::setData(int column, const QVariant &value)
  {
     if (column < 0 || column >= itemData.size())
        return false;

     itemData[column] = value;
     return true;
  }

  bool TreeItem::insertChildren(int position, int count, int columns)
  {
     if (position < 0 || position > childItems.size())
        return false;

     for (int row = 0; row < count; ++row) 
     {
        QVector<QVariant> data(columns);
        TreeItem *item = new TreeItem(data, this);
        childItems.insert(position, item);
     }

     return true;
  }

  bool TreeItem::removeChildren(int position, int count)
  {
     if (position < 0 || position + count > childItems.size())
        return false;

     for (int row = 0; row < count; ++row)
        delete childItems.takeAt(position);

     return true;
  }

  bool TreeItem::insertColumns(int position, int columns)
  {
     if (position < 0 || position > itemData.size())
        return false;

     for (int column = 0; column < columns; ++column)
        itemData.insert(position, QVariant());

     foreach (TreeItem *child, childItems)
        child->insertColumns(position, columns);

     return true;
  }



  ControlTreeView::ControlTreeView(QObject *parent) :
     QAbstractItemModel(parent)
  {
     QStringList headers;

     s_columns[ControlTreeView::eCOLUMN_FILENAME].m_header = QObject::tr("File");
     s_columns[ControlTreeView::eCOLUMN_FILENAME].m_index = 0;

     for (unsigned int index = 0; index < NUMBER_COLUMNS; index++)
        headers.append(s_columns[index].m_header);

     QVector<QVariant> rootData;
     foreach (QString header, headers)
        rootData << header;

     m_rootItem = new TreeItem(rootData);

  }

  ControlTreeView::~ControlTreeView()
  {
     delete m_rootItem;
  }

  int ControlTreeView::columnCount(const QModelIndex & parent) const 
  { 
     return NUMBER_COLUMNS; 
  };

  TreeItem *ControlTreeView::getItem(const QModelIndex &index) const
  {
     if (index.isValid()) 
     {
        TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
        if (item) return item;
     }
     return m_rootItem;
  }

  int ControlTreeView::rowCount(const QModelIndex &parent) const
  {
     TreeItem *parentItem = getItem(parent);

     return parentItem->childCount();
  }


  Qt::ItemFlags ControlTreeView::flags(const QModelIndex &index) const
  {
     //if (!index.isValid())
     //   return 0;

     //return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled;

      Qt::ItemFlags defaultFlags = Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;

      if (index.isValid())
          return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
      else
          return Qt::ItemIsDropEnabled | defaultFlags;
  }

  QModelIndex ControlTreeView::index(int row, int column, const QModelIndex &parent) const
  {
     if (parent.isValid() && parent.column() != 0)
        return QModelIndex();

     TreeItem *parentItem = getItem(parent);

     TreeItem *childItem = parentItem->child(row);
     if (childItem)
        return createIndex(row, column, childItem);
     else
        return QModelIndex();
  }

  QModelIndex ControlTreeView::parent(const QModelIndex &index) const
  {
     if (!index.isValid())
        return QModelIndex();

     TreeItem *childItem = getItem(index);
     TreeItem *parentItem = childItem->parent();

     if (parentItem == m_rootItem)
        return QModelIndex();

     return createIndex(parentItem->childNumber(), 0, parentItem);
  }

  QVariant ControlTreeView::data(const QModelIndex & index, int role) const
  {
     if (!index.isValid())
        return QVariant();

     switch (role)
     {
        case Qt::DisplayRole:
        case Qt::EditRole:
           {
              TreeItem *item = getItem(index);
              return item->data(index.column());
           }
           break;

        case Qt::DecorationRole:
           {
              if (index.column() == 0)
              {
                 if (!index.parent().isValid())   // Only decorate for 
                 {
                    //QString file = m_jobList->GetJobSrcFileName(index.row());
                    //if (!file.isEmpty())
                    //   return IconCache::Get().Load(file);
                 }
              }
           }
           break;
     }

     return QVariant();
  }


  bool ControlTreeView::setHeaderData(int section, Qt::Orientation orientation,
                       const QVariant &value, int role)
  {
     if (role != Qt::EditRole || orientation != Qt::Horizontal)
        return false;

     bool result = m_rootItem->setData(section, value);

     if (result)
        emit headerDataChanged(orientation, section, section);

     return result;
  }

  QVariant ControlTreeView::headerData(int section, Qt::Orientation orientation, int role) const
   {
       if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
           return m_rootItem->data(section);

       return QVariant();
   }


  QStringList ControlTreeView::mimeTypes () const
  {
     QStringList mimeTypes;

     mimeTypes += "text/uri-list";
     mimeTypes +=  "text/conversion-job-tree";

     return mimeTypes;
  }

  QMimeData *ControlTreeView::mimeData(const QModelIndexList &indexes) const
  {
     qDebug() << __FUNCTION__;
     QMimeData *mimeData = 0;

     // If the window is out off focus a file is dragged from outside of the app
     // This is not normal behaviour as this function should not be call if
     // the drag comes from outside of the app (??). 
     mimeData = new QMimeData();
     QByteArray encodedData;

     QDataStream stream(&encodedData, QIODevice::WriteOnly);

     foreach (QModelIndex index, indexes) {

        if (index.isValid() &&  !index.parent().isValid()) 
        {
           stream << index.row();
        }
        else
           if (index.parent().isValid())
              stream << -1;
     }

     mimeData->setData("text/conversion-job-tree", encodedData);

     return mimeData;
  }

  Qt::DropActions ControlTreeView::supportedDropActions() const
  {
     return Qt::CopyAction;
  }


  bool ControlTreeView::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
  {
     qDebug() << __FUNCTION__;

     if (action == Qt::IgnoreAction)
        return true;

     bool success = false;

     if (action == Qt::CopyAction)
     {
        if (data->hasFormat("text/uri-list"))
        {
           QList<QUrl>     urls = data->urls();

           for (int i = 0; i < urls.size(); ++i)
           {
              QString file = urls[i].toLocalFile();

              if (file != "")
              {
                 // Check if the file is already in the table

                 int insertRow = -1;

                 if (parent.isValid())
                    insertRow = parent.row();

                 if (insertRow == -1)
                    if (row == -1)
                       insertRow = m_rootItem->childCount();
                    else
                       insertRow = row;

                 insertRows(insertRow, 1, QModelIndex());

                 setData(index(insertRow, s_columns[ControlTreeView::eCOLUMN_FILENAME].m_index), file, Qt::EditRole);

                 success = true;
              }
           }
        }
        else
        {
           // Different MineData used for drop tree items
           if (data->hasFormat("text/conversion-job-tree"))
           {
              // Only drop on a job
              if (parent.isValid() && parent.parent().isValid())
                 return false;

              int insertRow = -1;

              if (parent.isValid())
                 insertRow = parent.row();

              if (insertRow == -1)
                 if (row == -1)
                    insertRow = m_rootItem->childCount();
                 else
                    insertRow = row;

              QByteArray encodedData = data->data("text/conversion-job-tree");
              QDataStream stream(&encodedData, QIODevice::ReadOnly);

              int srcRowIndex = -1;

              while (!stream.atEnd()) {
                 stream >> srcRowIndex;
              }

              // Exit if the source is not valid
              if (srcRowIndex == -1)
                 return false;

              if (srcRowIndex < insertRow)
              {
                 insertRow--;
                 if (insertRow < 0)
                    insertRow = 0;
              }            

              if (srcRowIndex == insertRow)
                 return false;

              // Remove the original raw
              removeRows(srcRowIndex,1);

              // Insert a new raw
              insertRows(insertRow, 1, QModelIndex());

              //setData(index(insertRow, s_columns[ConversionJobTreeViewCtrl::eCOLUMN_FILENAME].m_index), m_jobList->At(insertRow)->GetBaseSrcFileName(), Qt::EditRole);

              return success;
           }
        }
     }
     else
        success = false;

     return success;
  }

  bool ControlTreeView::insertRows(int position, int rows, const QModelIndex &parent)
  {
     TreeItem *parentItem = getItem(parent);
     bool success;

     beginInsertRows(parent, position, position + rows - 1);
     success = parentItem->insertChildren(position, rows, m_rootItem->columnCount());
     endInsertRows();

     return success;
  }

   bool ControlTreeView::removeRows(int position, int rows, const QModelIndex &parent)
   {
       TreeItem *parentItem = getItem(parent);
       bool success = true;

       beginRemoveRows(parent, position, position + rows - 1);
       success = parentItem->removeChildren(position, rows);
       endRemoveRows();

       return success;
   }

  bool ControlTreeView::setData(const QModelIndex &index, const QVariant &value, int role)
  {
     if (role != Qt::EditRole)
        return false;

     TreeItem *item = getItem(index);
     bool result = item->setData(index.column(), value);

     if (result)
        emit dataChanged(index, index);

     return result;
  }
4

0 回答 0