2

カスタム モデルに基づいてドラッグ アンド ドロップ QTreeView を実装しています。すべて正常に動作し、ツリーにデータが表示され、ドラッグ アンド ドロップが有効になり、ドラッグされたデータをドロップして転送する最後のステップが目の前にあります。これを行うには、モデルに mimeTypes、mimeData、および dropMimeData メソッドを実装する必要があります。そして今、私の質問: QMimeData を介して任意の Python オブジェクトを渡す簡単な標準的な方法はありますか? Python クラス Person の階層を表示する QTreeView 内で内部移動を行っています。そして、それらを並べ替えたいと思います。アプリケーションの外部にドラッグ アンド ドロップすることはできません。制御できない場合でも同様です。1 つのチュートリアルのみが見つかりました: link text。しかし、それが唯一の方法ですか?Python オブジェクトを ByteArray にエンコードしないと実行できません。唯一のクラスの Person には、本当に簡単なソリューションが必要です。ありがとうございました。

4

2 に答える 2

2

基礎となる Python オブジェクトの親を変更して、ドラッグ アンド ドロップを実装しようとしないでください。ドラッグがプロセスの外から来る場合、これは機能しません。また、コピー操作でも機能しません (ノード オブジェクトがツリー内の複数の場所に存在することはおそらくありません)。

ドラッグ アンド ドロップの「移動」を 3 つの操作と考えてください。

  1. データを何らかのバイト文字列にシリアライズする
  2. 新しいインデックス (または新しいインデックス) に逆シリアル化する
  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)
于 2010-12-11T10:06:08.177 に答える
1

わかりました、私はあなたのために可能な解決策を持っていると思います.

私はこの分野の完全な初心者であるため、彼の 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
于 2010-11-23T00:20:19.650 に答える