WxPythonを使用してノードインターフェイスを作成する例。 パート4:ドラッグアンドドロップの実装

短いシリーズの記事では、WxPythonを使用して、ユーザーインターフェイスを開発するという非常に具体的なタスクを解決する方法と、このソリューションをユニバーサルにする方法について説明します。 このチュートリアルは、すでにこのライブラリの研究を始めており、最も単純な例よりも複雑で全体的なものを見たい人向けに設計されています(ただし、比較的単純なものから始まります)。



このパートでは、アプリケーションにドラッグ&ドロップサポートを追加し、この方法で新しいノードを作成する方法を教えます。

パート1:描画の学習
パート2:マウスイベントの処理
パート3:機能の追加とキーボード処理の継続
パート4:ドラッグアンドドロップの実装
パート5:ノードの接続

誰も気にせず、猫の下で歓迎…


9.ドラッグアンドドロップのサポートを追加する


ドラッグアンドドロップのサポートは便利で人気のあるものですが、ここではその目的ではなく使用します。 このようにして、新しいノードを作成します。 このビジネスは非常に簡単に機能します。 クラス「wx.TextDropTarget」のオブジェクトを作成し、それをキャンバスの継承元であるクラス「wx.Window」の「SetDropTarget」メソッドに渡す必要があります。 したがって、ドロップ時に「wx.TextDropTarget.OnDropText」メソッドが呼び出されますが、これを実装する必要があります。 テストでは、このクラスの実装は次のようになります。
class TextDropTarget(wx.TextDropTarget): def __init__(self): wx.TextDropTarget.__init__(self) def OnDropText(self, x, y, data): print x, y, data 

これで、テキストをウィンドウにスローすると、位置とテキスト自体を含むメッセージがコンソールに印刷されます。 ご想像のとおり、ファイルを受け入れるために、同様に機能する同様のクラス「wx.FileDropTarget」、またはすべてを受け入れることができるクラス「wx.PyDropTarget」があります。

10.ドラッグアンドドロップでノードを作成する


テキストを入力するだけではあまり便利ではないため、結果のテキストを使用してノードを作成します。 ただし、最初にアーキテクチャを少し変更し、ノードファクトリを追加する必要があります(これは将来便利になります)。 現時点では、非常に単純なファクトリーになります。
 class NodesFactory(object): def __init__(self): pass def CreateNodeFromDescription(self, nodeDescription): return SimpleTextBoxNode(text=nodeDescription) 

「SimpleTextBoxNode」のインスタンスを作成するだけです。これは常に「SimpleBoxNode」の高度な子孫です。
 class SimpleTextBoxNode(SimpleBoxNode): def __init__(self, **kwargs): super(SimpleTextBoxNode, self).__init__(**kwargs) self.text = kwargs.get("text", "No text") def Render(self, gc): super(SimpleTextBoxNode, self).Render(gc) gc.DrawText(self.text, self.position[0]+10, self.position[1]+10) 

次に、長方形のノードの上に指定されたテキストをレンダリングします。
キャンバスにメソッドを追加して、説明から新しいノードを追加できます。
  def CreateNodeFromDescriptionAtPosition(self, nodeDescription, pos): node = self._nodesFactory.CreateNodeFromDescription(nodeDescription) if node: node.position = pos self._canvasObjects.append(node) self.Render() 

TextDropTargetをわずかにアップグレードして、テキストが到着したときにこのメソッドを呼び出すようにします。
 class TextDropTarget(wx.TextDropTarget): def __init__(self, canvas): wx.TextDropTarget.__init__(self) self._canvas = canvas def OnDropText(self, x, y, data): print x, y, data self._canvas.CreateNodeFromDescriptionAtPosition(data, [x, y]) 

これで、テキストフラグメントをキャンバスにスローするだけで、新しいテキストノードを作成できます。
次のようになります。

いつものように、コードはGitHubの対応するコミットで見つけることができます。

11.ドラッグアンドドロップでノードを複製する


ただし、ノードの作成に加えて、ドラッグアンドドロップを使用して、コピーノードを整理することもできます。これは非常に簡単です。 ユーザーがノードのドラッグ中にCtrlキーを押したままにした場合、ドラッグアンドドロップの開始を開始し、ノードの説明を入力するだけです。 そして、ノード作成コードが残りの作業を行います。 ドラッグアンドドロップを開始するには、次のコードを左クリックハンドラーに追加します。
  if evt.ControlDown() and self._objectUnderCursor.clonable: text = self._objectUnderCursor.GetCloningNodeDescription() data = wx.TextDataObject(text) dropSource = wx.DropSource(self) dropSource.SetData(data) dropSource.DoDragDrop(wx.Drag_AllowMove) 

ここでは、ドラッグアンドドロップのソースを作成し、ノードから受け取った説明を提供します。 ノードにGetCloningNodeDescriptionメソッドを実装することは残り、すべての準備が整います。 しかし、最初に、インターフェイスを実装します。
 class ClonableObject(CanvasObject): def __init__(self, **kwargs): super(ClonableObject, self).__init__(**kwargs) self.clonable = True def GetCloningNodeDescription(self): """ GetNodeDescription should return a dictionary that contains all information required for cloning this node at another position """ raise NotImplementedError() 

そして、ノードのメソッドの実装:
  def GetCloningNodeDescription(self): return self.text 

それは彼女のテキストを与えるだけです。
現在のバージョンのコードはここにあります

12.スケーラブルなノード


さて、4番目の部分を完了する前に、最後の小さなものを追加します。 テキストに合わせてノードを拡大してみましょう。 これを行うには、テキストノードのレンダリング方法をわずかに変更します。
  def Render(self, gc): textDimensions = gc.GetTextExtent(self.text) self.boundingBoxDimensions = [textDimensions[0]+20, textDimensions[1]+20] super(SimpleTextBoxNode, self).Render(gc) gc.DrawText(self.text, self.position[0]+10, self.position[1]+10) 

この場合のGetTextExtentメソッドは、テキストが占める長方形のサイズを返します。 したがって、ノードをレンダリングする前に、各辺のテキストよりも10ピクセル大きくなるように寸法を更新します。 これが、このプロセス全体の外観です。


コードはGitHubのこのコミットに含まれています

PS:誤字については個人で書いてください。

Source: https://habr.com/ru/post/J201784/


All Articles