カスタム モデルに基づいてドラッグ アンド ドロップ QTreeView を実装しています。すべて正常に動作し、ツリーにデータが表示され、ドラッグ アンド ドロップが有効になり、ドラッグされたデータをドロップして転送する最後のステップが目の前にあります。これを行うには、モデルに mimeTypes、mimeData、および dropMimeData メソッドを実装する必要があります。そして今、私の質問: QMimeData を介して任意の Python オブジェクトを渡す簡単な標準的な方法はありますか? Python クラス Person の階層を表示する QTreeView 内で内部移動を行っています。そして、それらを並べ替えたいと思います。アプリケーションの外部にドラッグ アンド ドロップすることはできません。制御できない場合でも同様です。1 つのチュートリアルのみが見つかりました: link text。しかし、それが唯一の方法ですか?Python オブジェクトを ByteArray にエンコードしないと実行できません。唯一のクラスの Person には、本当に簡単なソリューションが必要です。ありがとうございました。
2 に答える
基礎となる Python オブジェクトの親を変更して、ドラッグ アンド ドロップを実装しようとしないでください。ドラッグがプロセスの外から来る場合、これは機能しません。また、コピー操作でも機能しません (ノード オブジェクトがツリー内の複数の場所に存在することはおそらくありません)。
ドラッグ アンド ドロップの「移動」を 3 つの操作と考えてください。
- データを何らかのバイト文字列にシリアライズする
- 新しいインデックス (または新しいインデックス) に逆シリアル化する
- (オプション: 「コピー」ではなく「移動」の場合) 古いインデックスを削除します
mineData() および dropMimeData() は、ユーザーが提供するシリアライズおよびデシリアライズ操作です。Python はそれらを実装する簡単な方法をいくつか提供しています -- pickle モジュールのドキュメントを確認してください。運が良ければ、 pickle.dumps() と pickle.loads() がすぐに使えるでしょう。
編集:コメントにコードを貼り付ける方法がわからなかったので、コメントが参照している解決策を次に示します。これは、ルールに違反した場合にクラッシュを引き起こす代わりに、KeyError をスローして失敗するという意味で安全です。
# drag: store off the data in a safe place, and serialize a cooky
# that the drop target can use to retrieve the data.
self.__tmp_storage_dct = { self.__tmp_storage_cooky: stuff }
m.setData(self.rowlistptr_mime_type, QByteArray(pickle.dumps(self.__tmp_storage_cooky)))
self.__tmp_storage_cooky += 1
# drop:
if mime.hasFormat(self.rowlistptr_mime_type):
print "got tmpstorage"
cooky = pickle.loads(mime.data(self.rowlistptr_mime_type).data())
nodes = self.__tmp_storage_dct.pop(cooky)
わかりました、私はあなたのために可能な解決策を持っていると思います.
私はこの分野の完全な初心者であるため、彼の a) 動作 b) まともな解決策である c) 「本物の」プログラマーが昼食を投げ出さないという保証はありません。
私がしたことは、特定のアイテムの祖先ツリー全体を、行と列のペアのテキスト リストに変換することでした。(つまり、ドラッグされたアイテムの行と列、その親の行と列、その親の親の行と列などをリストします...無効なインデックス、つまりルートに到達するまで)
これは次のようになります (この例は、ドラッグされたアイテムが 4 レベルの深さであることを示しています)。
2;0,1;0,5;0,1,0
^ ^ ^ ^
| | | |
| | | great grandparent (and child of the root item)
| | |
| | grandparent
| |
| parent
|
item being dragged
その後、dropMimeData 関数でリストを反転し (ルートからドラッグされた項目まで読み戻されるように)、最初にドラッグされた項目に戻るまで、一度に 1 つずつインデックスを作成します。
これをすべて機能させるコードのスニペットを次に示します。繰り返しますが、これが良いアイデアであることを保証することはできません。動作しているように見え、Python オブジェクトを ByteArray にシリアル化する必要がないということだけです。
お役に立てれば。
#---------------------------------------------------------------------------
def mimeTypes(self):
"""
Only accept the internal custom drop type which is plain text
"""
types = QtCore.QStringList()
types.append('text/plain')
return types
#---------------------------------------------------------------------------
def mimeData(self, index):
"""
Wrap the index up as a list of rows and columns of each
parent/grandparent/etc
"""
rc = ""
theIndex = index[0] #<- for testing purposes we only deal with 1st item
while theIndex.isValid():
rc = rc + str(theIndex.row()) + ";" + str(theIndex.column())
theIndex = self.parent(theIndex)
if theIndex.isValid():
rc = rc + ","
mimeData = QtCore.QMimeData()
mimeData.setText(rc)
return mimeData
#---------------------------------------------------------------------------
def dropMimeData(self, data, action, row, column, parentIndex):
"""
Extract the whole ancestor list of rows and columns and rebuild the
index item that was originally dragged
"""
if action == QtCore.Qt.IgnoreAction:
return True
if data.hasText():
ancestorL = str(data.text()).split(",")
ancestorL.reverse() #<- stored from the child up, we read from ancestor down
pIndex = QtCore.QModelIndex()
for ancestor in ancestorL:
srcRow = int(ancestor.split(";")[0])
srcCol = int(ancestor.split(";")[1])
itemIndex = self.index(srcRow, srcCol, pIndex)
pIndex = itemIndex
print itemIndex.internalPointer().get_name()
return True