百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

wxPython - 在程序中使用拖放 python拖拽控件

bigegpt 2024-10-05 13:40 3 浏览

实战wxPython系列-052

在GUI程序中,拖放是单击虚拟对象并将其拖到不同位置或另一个虚拟对象上的操作(或对该操作的支持)。一般来说,它可用于调用多种类型的操作,或在两个抽象对象之间创建各种类型的关联。

拖放是图形用户界面中最直观的操作,通过它可以做很多复杂的事情。在拖放中,我们将一些数据从一个源位置移动到目标位置,所以我们必须有:

  • 一些数据。
  • 一个数据来源。
  • 一个数据目标。

wxPython提供了几种不同类型的拖放,它们是:

  • wx.FileDropTarget。
  • wx.TextDropTarget。
  • wx.PyDropTarget。

一、文件拖放wx.FileDropTarget

wx.FileDropTarget是一个拖放目标,它接受从文件管理器中拖出的文件。wxPython工具包使得创建拖放目标非常简单。我们子类化wx. FileDropTarget, 创建类MyFileDropTarget,重载方法OnDropFiles。它接受鼠标的x/y位置和被删除的文件路径,然后将它们写到文本控件中。在MyDnDPanel类调用文本控件的SetDropTarget方法并将其设置为拖放目标类的实例。

#文件拖放操作

import wx

class MyFileDropTarget(wx.FileDropTarget):

    def __init__(self, window):
        wx.FileDropTarget.__init__(self)
        self.window = window

    def OnDropFiles(self, x, y, filenames):
        self.window.SetInsertionPointEnd()
        self.window.UpdateText("\n%d file(s) dropped at %d, %d:\n" % (len(filenames), x, y))
        for filepath in filenames:
            self.window.UpdateText(filepath + "\n")

class MyDnDPanel(wx.Panel):
    
    def __init__(self, parent):
        wx.Panel.__init__(self, parent=parent)

        file_drop_target = MyFileDropTarget(self)
        lbl = wx.StaticText(self, label="拖一些文件到这里:")
        self.fileTextCtrl = wx.TextCtrl(self, style = wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY)
        self.fileTextCtrl.SetDropTarget(file_drop_target)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(lbl, 0, wx.ALL, 5)
        sizer.Add(self.fileTextCtrl, 1, wx.EXPAND|wx.ALL, 5)
        self.SetSizer(sizer)

    def SetInsertionPointEnd(self):
        """
        将插入点放在文本控件的末尾,以防止覆盖
        """
        self.fileTextCtrl.SetInsertionPointEnd()

    def UpdateText(self, text):
        """
        向文本控件添加文本
        """
        self.fileTextCtrl.WriteText(text)

class SampleFileDnD(wx.Frame):

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

        self.InitUi()

    def InitUi(self):
        self.SetTitle("实战wxPython: 文件拖放操作演示")
        self.SetSize(600, 400)

        panel = MyDnDPanel(self)

        self.Centre()

def main():
    app = wx.App()
    sample = SampleFileDnD(None)
    sample.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()

在实例代码中,在面板类MyDnDPanel中创建了一个wx.TextCtrl, 它用来显示从外部拖入文件的名称。

def OnDropFiles(self, x, y, filenames):
        self.window.SetInsertionPointEnd()
        self.window.UpdateText("\n%d file(s) dropped at %d, %d:\n" % (len(filenames), x, y))
        for filepath in filenames:
            self.window.UpdateText(filepath + "\n")

我们可以用文件管理器拖入一个或者多个文件,并在wx.TextCtrl中显示这些拖入文件的完整路径名称。

二、文本拖放wx.TextDropTarget

wx.TextDropTarget是一个预定义的拖放目标,用于接收文本数据。常见的例子之一是将网页上的URL拖到地址栏,或者将一些文本拖到浏览器的搜索框中。

# 文本拖放演示

import os
from pathlib import Path
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 SampleDropText(wx.Frame):

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

        self.InitUi()

    def InitUi(self):
        self.SetTitle("实战wxPython: 文本拖放演示")
        self.SetSize(600, 400)

        spliter1 = wx.SplitterWindow(self, style=wx.SP_3D)
        spliter2 = wx.SplitterWindow(spliter1, style=wx.SP_3D)

        home_dir = str(Path.home())

        self.dirWid = wx.GenericDirCtrl(spliter1, dir=home_dir, style=wx.DIRCTRL_DIR_ONLY)

        self.lc1 = wx.ListCtrl(spliter2, style = wx.LC_LIST)
        self.lc2 = wx.ListCtrl(spliter2, 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()

        spliter2.SplitHorizontally(self.lc1, self.lc2, 150)
        spliter1.SplitVertically(self.dirWid, spliter2, 200)

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

        self.OnSelect(0)

        self.Centre()

    def OnSelect(self, e):
        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, e):
        text = self.lc1.GetItemText(e.GetIndex())
        tdo = wx.TextDataObject(text)
        tds = wx.DropSource(self.lc1)

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

def main():
    app = wx.App()
    sample = SampleDropText(None)
    sample.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()

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

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, e):
        text = self.lc1.GetItemText(e.GetIndex())
        tdo = wx.TextDataObject(text)
        tds = wx.DropSource(self.lc1)

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

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

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

三、一般对象拖放wx.PyDropTarget

下面是例子中,我们使用一些基于URLDragAndDrop演示的代码来解释PyDropTarget。

# 一般对象拖放演示

import wx

class MyURLDropTarget(wx.PyDropTarget):

    def __init__(self, window):
        wx.PyDropTarget.__init__(self)
        self.window = window

        self.data = wx.URLDataObject()
        self.SetDataObject(self.data)

    def OnDragOver(self, x, y, d):
        return wx.DragLink

    def OnData(self, x, y, d):
        if not self.GetData():
            return wx.DragNone

        url = self.data.GetURL()
        self.window.AppendText(url + "\n")

        return d

class MyDnDPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent=parent)

        font = wx.Font(12, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False)

        # 创建并设置第一组控件
        lbl = wx.StaticText(self, label="从浏览器中拖一些url到这里:")
        lbl.SetFont(font)
        self.dropText = wx.TextCtrl(self, size=(200,200), style=wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY)

        dt = MyURLDropTarget(self.dropText)
        self.dropText.SetDropTarget(dt)
        firstSizer = self.AddWidgetsToSizer([lbl, self.dropText])

        # 创建并设置第二组控件
        lbl = wx.StaticText(self, label="将这里的url拖到浏览器:")
        lbl.SetFont(font)
        self.draggableURLText = wx.TextCtrl(self, value="https://cn.bing.com")
        self.draggableURLText.Bind(wx.EVT_MOTION, self.OnStartDrag)
        secondSizer = self.AddWidgetsToSizer([lbl, self.draggableURLText])

        # Add sizers to main sizer
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(firstSizer, 0, wx.EXPAND)
        mainSizer.Add(secondSizer, 0, wx.EXPAND)

        self.SetSizer(mainSizer)

    def AddWidgetsToSizer(self, widgets):

        sizer = wx.BoxSizer(wx.VERTICAL)
        for widget in widgets:
            if isinstance(widget, wx.TextCtrl):
                sizer.Add(widget, 1, wx.EXPAND|wx.ALL, 5)
            else:
                sizer.Add(widget, 0, wx.ALL, 5)

        return sizer

    def OnStartDrag(self, e):
        if e.Dragging():
            url = self.draggableURLText.GetValue()
            data = wx.URLDataObject()
            data.SetURL(url)

            dropSource = wx.DropSource(self.draggableURLText)
            dropSource.SetData(data)
            dropSource.DoDragDrop()

class SampleFileDnD(wx.Frame):
    
    def __init__(self, *args, **kw):
        super(SampleFileDnD, self).__init__(*args, **kw)

        self.InitUi()

    def InitUi(self):
        self.SetTitle("实战wxPython: 一般对象拖放操作演示")
        self.SetSize(480, 360)

        panel = MyDnDPanel(self)

        self.Centre()

def main():
    app = wx.App()
    sample = SampleFileDnD(None)
    sample.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()

在这个例子中,我们不仅创建了一个可以接受拖放文本的控件,还可以将一些文本从另一个控件拖到浏览器中,如果该文本是一个合法的地址,则浏览器将打开该地址。

self.data = wx.URLDataObject()
self.SetDataObject(self.data)

创建存储URL信息的wx.URLDataObject的实例,然后设置为wx.PyDropTarget的数据对象。

def OnData(self, x, y, d):
        if not self.GetData():
            return wx.DragNone

        url = self.data.GetURL()
        self.window.AppendText(url + "\n")

在OnData方法中,提取URL并将其附加到绑定的文本控件。

dt = MyURLDropTarget(self.dropText)
self.dropText.SetDropTarget(dt)

创建一个拖放目标。使用SetDropTarget()方法将下拉目标设置为面板控件。

self.draggableURLText.Bind(wx.EVT_MOTION, self.OnStartDrag)

绑定鼠标移动事件

def OnStartDrag(self, e):
        if e.Dragging():
            url = self.draggableURLText.GetValue()
            data = wx.URLDataObject()
            data.SetURL(url)
            ...

在鼠标移动事件处理程序(OnStartDrag)中,我们检查以确保用户正在拖动。如果是,那么我们从文本框中获取值,并将其添加到新创建的URLDataObject中。

dropSource = wx.DropSource(self.draggableURLText)
 dropSource.SetData(data)
 dropSource.DoDragDrop()

创建一个DropSource实例,并将我们的第二个文本控件传递给它,因为它是源。我们将源数据设置为URLDataObject。最后,在dropSource (文本控件)上调用DoDragDrop,它将通过移动、复制、取消或失败来响应。如果将URL拖到浏览器的地址栏,它会复制。否则它可能不会起作用。

四、本文知识点

  • 了解拖放操作的基本流程。
  • 操作文件拖放。
  • 操作文本拖放。
  • 操作其他对象的拖放。

前一篇:wxPython - 自定义控件

欢迎关注,评论,收藏,点赞,和转发。

相关推荐

C#.NET Autofac 详解(c# autoit)

简介Autofac是一个成熟的、功能丰富的.NET依赖注入(DI)容器。相比于内置容器,它额外提供:模块化注册、装饰器(Decorator)、拦截器(Interceptor)、强o的属性/方法注...

webapi 全流程(webapi怎么部署)

C#中的WebAPIMinimalApi没有控制器,普通api有控制器,MinimalApi是直达型,精简了很多中间代码,广泛适用于微服务架构MinimalApi一切都在组控制台应用程序类【Progr...

.NET外挂系列:3. 了解 harmony 中灵活的纯手工注入方式

一:背景1.讲故事上一篇我们讲到了注解特性,harmony在内部提供了20个HarmonyPatch重载方法尽可能的让大家满足业务开发,那时候我也说了,特性虽然简单粗暴,但只能解决95%...

C# 使用SemanticKernel调用本地大模型deepseek

一、先使用ollama部署好deepseek大模型。具体部署请看前面的头条使用ollama进行本地化部署deepseek大模型二、创建一个空的控制台dotnetnewconsole//添加依赖...

C#.NET 中间件详解(.net core中间件use和run)

简介中间件(Middleware)是ASP.NETCore的核心组件,用于处理HTTP请求和响应的管道机制。它是基于管道模型的轻量级、模块化设计,允许开发者在请求处理过程中插入自定义逻辑。...

IoC 自动注入:让依赖注册不再重复劳动

在ASP.NETCore中,IoC(控制反转)功能通过依赖注入(DI)实现。ASP.NETCore有一个内置的依赖注入容器,可以自动完成依赖注入。我们可以结合反射、特性或程序集扫描来实现自动...

C#.NET 依赖注入详解(c#依赖注入的三种方式)

简介在C#.NET中,依赖注入(DependencyInjection,简称DI)是一种设计模式,用于实现控制反转(InversionofControl,IoC),以降低代码耦合、提高可...

C#从零开始实现一个特性的自动注入功能

在现代软件开发中,依赖注入(DependencyInjection,DI)是实现松耦合、模块化和可测试代码的一个重要实践。C#提供了优秀的DI容器,如ASP.NETCore中自带的Micr...

C#.NET 仓储模式详解(c#仓库货物管理系统)

简介仓储模式(RepositoryPattern)是一种数据访问抽象模式,它在领域模型和数据访问层之间创建了一个隔离层,使得领域模型无需直接与数据访问逻辑交互。仓储模式的核心思想是将数据访问逻辑封装...

C#.NET 泛型详解(c# 泛型 滥用)

简介泛型(Generics)是指在类型或方法定义时使用类型参数,以实现类型安全、可重用和高性能的数据结构与算法为什么需要泛型类型安全防止“装箱/拆箱”带来的性能损耗,并在编译时检测类型错误。可重用同一...

数据分析-相关性分析(相关性 分析)

相关性分析是一种统计方法,用于衡量两个或多个变量之间的关系强度和方向。它通过计算相关系数来量化变量间的线性关系,从而帮助理解变量之间的相互影响。相关性分析常用于数据探索和假设检验,是数据分析和统计建模...

geom_smooth()函数-R语言ggplot2快速入门18

在每节,先运行以下这几行程序。library(ggplot2)library(ggpubr)library(ggtext)#用于个性化图表library(dplyr)#用于数据处理p...

规范申报易错要素解析(规范申报易错要素解析)

为什么要规范申报?规范申报是以满足海关监管、征税、统计等工作为目的,纳税义务人及其代理人依法向海关如实申报的行为,也是海关审接单环节依法监管的重要工作。企业申报的内容须符合《中华人民共和国海关进出口货...

「Eurora」海关编码归类 全球海关编码查询 关务服务

  海关编码是什么?  海关编码即HS编码,为编码协调制度的简称。  其全称为《商品名称及编码协调制度的国际公约》(InternationalConventionforHarmonizedCo...

9月1日起,河南省税务部门对豆制品加工业试行新政7类豆制品均适用投入产出法

全媒体记者杨晓川报道9月2日,记者从税务部门获悉,为减轻纳税人税收负担,完善农产品增值税进项税额抵扣机制,根据相关规定,结合我省实际情况,经广泛调查研究和征求意见,从9月1日起,我省税务部门对豆制品...