Skip to content

Latest commit

 

History

History
296 lines (187 loc) · 6.64 KB

9.拖放.md

File metadata and controls

296 lines (187 loc) · 6.64 KB

Drag and drop in wxPython

在计算机图形用户界面中,拖放是单击虚拟对象并将其拖动到不同位置或其他虚拟对象的动作(或支持动作)。 一般来说,它可以用来执行多种动作,或者在两个抽象对象之间创建各种类型的关联。

拖放操作使您能够直观地完成复杂的事情。

在拖放操作中,我们将一些数据从数据源拖动到数据目标。 所以我们必须有:

  • Some data
  • A data source
  • A data target

在wxPython中,我们有两个预定义的数据目标: wx.TextDropTarget and wx.FileDropTarget.

wx.TextDropTarget

wx.TextDropTarget 是处理文本数据的预定义放置目标。

dragdrop_text.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
ZetCode wxPython tutorial

In this example, we drag and drop text data.

author: Jan Bodnar
website: www.zetcode.com
last modified: May 2018
"""

from pathlib import Path
import os
import wx

class MyTextDropTarget(wx.TextDropTarget):

    def __init__(self, object):

        wx.TextDropTarget.__init__(self)
        self.object = object

    def OnDropText(self, x, y, data):

        self.object.InsertItem(0, data)
        return True


class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        splitter1 = wx.SplitterWindow(self, style=wx.SP_3D)
        splitter2 = wx.SplitterWindow(splitter1, style=wx.SP_3D)

        home_dir = str(Path.home())

        self.dirWid = wx.GenericDirCtrl(splitter1, dir=home_dir, 
                style=wx.DIRCTRL_DIR_ONLY)
                
        self.lc1 = wx.ListCtrl(splitter2, style=wx.LC_LIST)
        self.lc2 = wx.ListCtrl(splitter2, style=wx.LC_LIST)

        dt = MyTextDropTarget(self.lc2)
        self.lc2.SetDropTarget(dt)
        
        self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.OnDragInit, id=self.lc1.GetId())

        tree = self.dirWid.GetTreeCtrl()

        splitter2.SplitHorizontally(self.lc1, self.lc2, 150)
        splitter1.SplitVertically(self.dirWid, splitter2, 200)

        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelect, id=tree.GetId())

        self.OnSelect(0)

        self.SetTitle('Drag and drop text')
        self.Centre()

    def OnSelect(self, event):

        list = os.listdir(self.dirWid.GetPath())

        self.lc1.ClearAll()
        self.lc2.ClearAll()

        for i in range(len(list)):

            if list[i][0] != '.':
                self.lc1.InsertItem(0, list[i])

    def OnDragInit(self, event):

        text = self.lc1.GetItemText(event.GetIndex())
        tdo = wx.TextDataObject(text)
        tds = wx.DropSource(self.lc1)

        tds.SetData(tdo)
        tds.DoDragDrop(True)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

在这个例子中,我们在 wx.GenericDirCtrl 中显示一个文件系统。所选目录的内容显示在右上方的列表控件中。 文件名可以拖放到右下角的列表控件中。

def OnDropText(self, x, y, data):

    self.object.InsertItem(0, data)
    return True    

当我们将文本数据拖放到目标上时,将使用 InsertItem() 方法将数据插入到列表控件中。

dt = MyTextDropTarget(self.lc2)
self.lc2.SetDropTarget(dt)  

放置目标被创建。 我们使用 SetDropTarget() 方法将放置目标设置为第二个列表控件。

self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.OnDragInit, id=self.lc1.GetId()) 

当拖动操作开始时,调用 OnDragInit() 方法。

def OnDragInit(self, event):

    text = self.lc1.GetItemText(event.GetIndex())
    tdo = wx.TextDataObject(text)
    tds = wx.DropSource(self.lc1)
    ...

OnDragInit() 方法中,我们创建了一个 wx.TextDataObject,它包含我们的文本数据。 从第一个列表控件创建放置源 drop source。

tds.SetData(tdo)
tds.DoDragDrop(True)

我们使用 SetData() 将数据设置到放置源,并使用 DoDragDrop() 启动拖放操作。

wx.FileDropTarget

wx.FileDropTarget 是一个放置目标,它接受从文件管理器拖动的文件。

dragdrop_file.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
ZetCode wxPython tutorial

In this example, we drag and drop files.

author: Jan Bodnar
website: www.zetcode.com
last modified: May 2018
"""

import wx

class FileDrop(wx.FileDropTarget):

    def __init__(self, window):

        wx.FileDropTarget.__init__(self)
        self.window = window

    def OnDropFiles(self, x, y, filenames):

        for name in filenames:

            try:
                file = open(name, 'r')
                text = file.read()
                self.window.WriteText(text)

            except IOError as error:

                msg = "Error opening file\n {}".format(str(error))
                dlg = wx.MessageDialog(None, msg)
                dlg.ShowModal()

                return False

            except UnicodeDecodeError as error:

                msg = "Cannot open non ascii files\n {}".format(str(error))
                dlg = wx.MessageDialog(None, msg)
                dlg.ShowModal()

                return False

            finally:

                file.close()

        return True

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.text = wx.TextCtrl(self, style = wx.TE_MULTILINE)
        dt = FileDrop(self.text)

        self.text.SetDropTarget(dt)

        self.SetTitle('File drag and drop')
        self.Centre()


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

该示例创建一个简单的 wx.TextCtrl。 我们可以将文本文件从文件管理器拖到控件中。

def OnDropFiles(self, x, y, filenames):

    for name in filenames:
    ...

我们可以一次拖放多个文件。

try:
    file = open(name, 'r')
    text = file.read()
    self.window.WriteText(text)

我们以只读模式打开文件,获取其内容并将内容写入文本控制窗口。

except IOError as error:

    msg = "Error opening file\n {}".format(str(error))
    dlg = wx.MessageDialog(None, msg)
    dlg.ShowModal()

    return False

如果出现输入/输出错误,我们将显示消息对话框并终止操作。

self.text = wx.TextCtrl(self, style = wx.TE_MULTILINE)
dt = FileDrop(self.text)

self.text.SetDropTarget(dt)

wx.TextCtrl 是放置目标。

在本章中,我们使用 wxPython 进行了拖放操作。