wxPython 实践(四)事件响应

wxPython 实践(一)概述
wxPython 实践(二)基础控件
wxPython 实践(三)页面布局
wxPython 实践(四)事件响应
wxPython 实践(五)高级控件
wxPython 实践(六)对话框
wxPython 实践(七)GDI 介绍
wxPython 实践(八)其他


官网
https://docs.wxpython.org/wx.1moduleindex.html
https://www.w3ccoo.com/wxpython/wxpython_major_classes.html
系列文章:
https://wintel.blog.youkuaiyun.com/?type=blog

1. 事件驱动编程模型

1.1. 事件循环机制解析

在 GUI 编程中,事件循环是程序响应用户操作的基础。
wxPython 使用事件循环来处理各种用户交互事件,如按键、鼠标点击、窗口大小调整等。事件循环的工作方式是不断地检查事件队列,取出事件并分发给相应的处理函数进行响应。
事件循环的运行大致分为以下几个步骤:

  1. 事件捕获:当用户进行某些操作时,如点击鼠标或按键,系统会生成一个事件。
  2. 事件排队:生成的事件会被放入到一个事件队列中。
  3. 事件分发:事件循环从事件队列中取出事件,根据事件类型和相关联的控件,将事件分发到相应的事件处理函数。
  4. 事件处理:事件处理函数根据传入的事件对象的属性和方法执行相应的逻辑,并返回结果。

以下是一个简化的代码示例,展示如何在 wxPython 应用中启动事件循环:

import wx
 
def OnQuit(event):
    print("退出程序")
    wx.GetApp().Exit()
 
# 创建应用实例
app = wx.App(False)
# 创建一个窗口
frame = wx.Frame(None, title="事件循环示例")
# 绑定事件
frame.Bind(wx.EVT_CLOSE, OnQuit)
 
# 显示窗口
frame.Show()
# 进入事件循环
app.MainLoop()

在这个例子中,我们创建了一个 wx.Frame 窗口对象,并将其绑定到了关闭事件 EVT_CLOSE 上,事件处理函数为 OnQuit 。当窗口收到关闭事件时,会调用 OnQuit 函数,并退出程序。

1.2. 事件处理函数的设计原则

设计良好的事件处理函数是构建高效、稳定 GUI 应用程序的关键。以下是一些设计事件处理函数的基本原则:

  • 专注单一功能 :每个事件处理函数应该只负责一种类型事件的处理,避免函数过于复杂。
  • 代码可重用性 :尽量编写通用的代码片段,使其能够用于多个事件处理函数。
  • 避免阻塞操作 :不要在事件处理函数中进行长时间的计算或耗时操作,这将阻塞事件循环,影响 GUI 的响应性。
  • 合理使用回调和委托 :对于一些耗时操作,可以采用回调函数或委托给其他线程处理。

例如,在处理文本输入框的输入事件时,可以使用如下方式设计事件处理函数,确保程序响应性:

def OnTextEnter(event):
    text_content = event.GetEventObject().GetValue()
    print(f"输入内容为: {
     
     text_content}")
    # 其他处理逻辑...

通过上述原则设计的事件处理函数,能够确保事件响应流程的高效性和程序的稳定性。

2. 事件绑定和响应函数编写

2.1. 绑定事件

在 GUI 应用中,事件绑定是将特定事件与事件处理函数关联起来的过程。wxPython 提供了多种方式来绑定事件:

  • 直接绑定 :使用控件的 Bind() 方法直接绑定事件类型和对应的事件处理函数。这是最常见的方式,适用于大多数情况。
Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)
event 是一个EVT_*对象,它用于指定事件类型;
handler 为事件处理程序,就是程序绑定到事件的方法;
source 当我们希望区分来自不同控件的相同事件类型时,这时候需要使用 source 参数。
id 参数在有多个按钮、菜单项等时使用。id 用于区分它们。
id2 当需要将一个处理程序绑定到一个 id 范围时,例如 EVT_MENU_RANGE,则使用id2。
  • 通过类内部绑定 :在 wx.App 派生类中使用 init 方法或者 init.EventTable 方法绑定。
class MyApp(wx.App):
    def __init__(self, redirect=False, filename=None):
        wx.App.__init__(self, redirect, filename)
        self.InitEventTable()
    def InitEventTable(self):
        self.Bind(wx.EVT_BUTTON, self.OnButtonClick, self.button)
 
app = MyApp()
  • 使用 EVT_CMD_* 宏 :这种方式更底层一些,用于更复杂的事件绑定场景。
  • 使用 event.Unbind() 解绑 :如果需要取消已经绑定的事件,可以使用 Unbind 方法。

绑定事件需要明确指定事件类型和对应的处理函数。每个控件都有自己的事件类型,例如 wx.EVT_BUTTON 用于按钮点击事件。事件处理函数则根据事件对象的类型来执行不同的逻辑。

2.2. 事件传播(Skip)

在 wxPython 中,有两种类型的事件,基本事件和命令事件,这两者的传播方式是不同的:

  • 命令事件可以传播,它沿子控件向父控件进行传播;
  • 基本事件则不会传播到父控件,比如对于 wx.CloseEvent,这是一个基本事件,将其传播到父控件是没有意义的。

在默认情况下,在事件处理程序中捕获事件后,事件将停止传播。为了继续传播,可以调用 Skip() 方法使事件继续传播。

def OnButtonClicked(self, e):
        print("event reached button class")
        e.Skip()

通过 Skip,可以将按钮事件,一层一层传播出去。

2.3. 否决事件(Veto)

在某些时候,我们需要终止事件处理,在这种情况下,我们可以调用方法Veto()来实现这个功能。

import wx
 
class MyEvent(wx.Frame):
    def __init__(self, parent, title):
        # super(MyWin, self).__init__(parent, title)
        super().__init__(parent, title = title) 
        self.SetTitle(title=title)

        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

        self.Centre()
        self.Show()

    def OnCloseWindow(self, e):
        dlg = wx.MessageDialog(None, "确定要退出?", "问题", wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION)
        ret = dlg.ShowModal()
 
        if(ret == wx.ID_YES):
            self.Destroy()
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值