2013-06-24 14 views
1

Моя проблема в том, что у меня есть два QTreeWidgets, и я бы хотел перетащить их из одного в другое (и наоборот). Я могу перетаскивать QTreeWidgetItems, но, когда я бросаю QTreeWidgetItem, у которого есть дочерние элементы, я теряю их, и только родительский палец.Перетаскивание между двумя QTreeWidgets

Я действительно не вижу, как это сделать. Единственный способ, которым я нашел, - это переопределить dropEvent и уничтожить все потерянные объекты и переконструировать их. Но мне не нравится это решение, потому что оно медленное, а объекты не являются одинаковыми, поэтому это усложняет реализацию Undo/повтор функция ...

Ну, это то, что у меня есть:

#include <QApplication> 
#include <QDebug> 
#include <QObject> 
#include <QWidget> 
#include <QString> 
#include <QTextStream> 
#include <QIODevice> 
#include <QMainWindow> 
#include <QVBoxLayout> 


#include "KTreeWidget.h" 
#include "KAbstractItem.h" 
#include "KItem.h" 
#include "KItemGroup.h" 

int main(int argc, char* argv[]){ 

QApplication app(argc, argv); 

QMainWindow *window = new QMainWindow(); 
QWidget* central = new QWidget(window); 
QVBoxLayout *layout = new QVBoxLayout(); 

KTreeWidget* kv = new KTreeWidget(window); 
KTreeWidget* trash = new KTreeWidget(window); 

layout->addWidget(kv); 
layout->addWidget(trash); 

central->setLayout(layout); 

KItem* kiarr[5]; 
for (int i = 0 ; i < 5 ; i++){ 
    kiarr[i] = new KItem(kv); 
    kiarr[i]->setText(0,QString("Item %1").arg(i)); 
} 
KItemGroup* kgarr[5]; 
for (int i = 0 ; i < 5 ; i++){ 
    kgarr[i] = new KItemGroup(trash); 
    kgarr[i]->setText(0,QString("Group %1").arg(i)); 
} 

window->setCentralWidget(central); 
window->show(); 

return app.exec(); 
} 

Мои QTreeWidget: KtreeWidget.h

#ifndef _KTW_H_ 
#define _KTW_H_ 

#include <QTreeWidget> 

class KTreeWidget: public QTreeWidget{ 
Q_OBJECT 

private: 
QTreeWidgetItem* _header; 

public: 
KTreeWidget(QWidget* w = NULL); 
}; 

#endif 

и KTreeWidget.cc:

#include "KTreeWidget.h" 

KTreeWidget::KTreeWidget(QWidget* w):QTreeWidget(w){ 
setColumnCount(3); 
_header = new QTreeWidgetItem(NULL); 
_header->setText(0,"Title"); 
_header->setText(1,"Edit"); 
_header->setText(2,"Open"); 
this->setDefaultDropAction(Qt::MoveAction); 
setHeaderItem(_header); 
setDragEnabled(true); 
setAcceptDrops(true); 
} 

и элементы (3 классов, для того, чтобы различать группы и листья): KAbstractItem.h

#ifndef _KABSI_H_ 
#define _KABSI_H_ 

#include <QObject> 
#include <QTreeWidgetItem> 
#include <QTreeWidget> 

class KAbstractItem : public QObject, public QTreeWidgetItem{ 
Q_OBJECT 
public: 
KAbstractItem(QTreeWidget* p = NULL); 
}; 

#endif 

и KAbstractItem.cc

#include "KAbstractItem.h" 
KAbstractItem::KAbstractItem(QTreeWidget* p):QTreeWidgetItem(p){} 

KItem.h

#ifndef _KI_H_ 
#define _KI_H_ 

#include "KAbstractItem.h" 

class KItem : public KAbstractItem{ 
Q_OBJECT 
public: 
KItem(QTreeWidget* p); 
}; 

#endif 

и KItem.cc

#include "KItem.h" 

KItem::KItem(QTreeWidget* p):KAbstractItem(p){ 
setFlags(Qt::ItemIsSelectable 
    | Qt::ItemIsEditable 
    | Qt::ItemIsDragEnabled 
    | Qt::ItemIsUserCheckable 
    | Qt::ItemIsEnabled); 
} 

и KItemGroup.h

#ifndef _KIG_H_ 
#define _KIG_H_ 

#include "KAbstractItem.h" 

class KItemGroup : public KAbstractItem{ 
Q_OBJECT 
public: 
KItemGroup(QTreeWidget* p); 
}; 

#endif 

и KItemGroup.h #include "KItemGroup.h"

KItemGroup::KItemGroup(QTreeWidget* p):KAbstractItem(p){ 
setFlags(Qt::ItemIsSelectable 
    | Qt::ItemIsEditable 
    | Qt::ItemIsDragEnabled 
    | Qt::ItemIsDropEnabled 
    | Qt::ItemIsUserCheckable 
    | Qt::ItemIsEnabled); 
} 

Всякий раз, когда я делаю каплю одного из элементов в первой WTreeWifget внутри одной из групп второй, он работает, но затем я перемещаю группу на верхний QTreeWidget, я теряю всех детей ...

Не могли бы вы рассказать мне, что я делаю неправильно? Спасибо заранее!

ответ

1

Итак, я проверил его, и он не работает по мере необходимости, вы не ошибаетесь.

Я, кажется, проблема заключается в том, что QAbstractItemModel (в Wich QTreeWidget relies для кодирования перетаскиваемых данных внутренне) mimeData() метода is not considering nested items (себе, что он просто закодировать строку + столбец, но не родитель.

Это может быть даже это мнение только передавая QModelIndex перетаскиваемого элемента, в mimeData, подумал, что это может быть лучше, поэтому не учитывать родительскую информацию ...

Единственное решение, которое я вижу, - это повторное выполнение dropevent. Но у вас нет для уничтожения предметов. Использование

QTreeWidgetItem * QTreeWidgetItem::takeChild (int index) QTreeWidgetItem * QTreeWidget::takeTopLevelItem (int index)

принять перетаскиваемый элемент

и

void QTreeWidgetItem::insertChild (int index, QTreeWidgetItem * child)

уронить его

Я проверил, что это как дети перемещаются вправо , (См this gist)

+0

Привет, извините, я раньше не был. Навсегда получил уведомление по электронной почте! Я на самом деле нашел решение, и это больше похоже на ваш :) Я даю свое полное решение чуть ниже, так что другие люди могут его увидеть;) – ddeunagomez

0

Это, как я ее решил: Когда вы перетаскивать, В создает новый объект, диффере, чем у вас с теми же значениями для текстов, но это другой объект, и ваш просто удаляется но память не освобождается.

Первое, что нужно сделать, это переопределить removeChild, поскольку оно основано на индексах, а не на адресах, поэтому это не сработает с тем, что мы будем делать последним. (http://sourceforge.net/p/ckmapper/code/4/tree/trunk/src/KViewer/KAbstractItem.cc#l39)

Тогда нам нужно переопределить dropEvent QTreeWidget. Стартовым является следующее:

  1. получить все выбранные элементы, которые нужно перетаскивать, но не только Qt.
  2. позволяет Qt выполнять его сброс.
  3. Найдите предметы на цели, которые могут содержать новые объекты, созданные Qt. это можно сделать с помощью itemAt (event-> pos).
  4. Найдите среди детей тех элементов, которые являются отброшенными: это можно сделать с помощью dynamic_cast <>, потому что те, что созданы Qt, являются ATreeWidgetItems и наши наследуют от этого класса.
  5. Получить индекс.
  6. Удалите элемент «паразита» и удалите его.
  7. Вставьте выбранные предметы в индекс от паразита.

Мы отказались переопределить removeChild, потому что мы удаляем детей вручную (выбранные элементы), а Qt удаляет элементы (также выбранные элементы), которые он должен отбрасывать последними (но это не так). Итак, если вы проверите Qt-код, вы увидите, что он основан на индексах, и это небезопасно, тогда как удаление элементов на основе их адреса более безопасно. Я отправлю свой код последним здесь, я забыл его совершить;)

В любом случае, решение Trompa также действует и кажется мне более простым. Я просто хотел поделиться своим решением;)

+1

Вы можете заставить QT игнорировать событие. И возьмите родителя вместе с остальными предметами. Кажется проще. – Trompa