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 使用事件循环来处理各种用户交互事件,如按键、鼠标点击、窗口大小调整等。事件循环的工作方式是不断地检查事件队列,取出事件并分发给相应的处理函数进行响应。
事件循环的运行大致分为以下几个步骤:
- 事件捕获:当用户进行某些操作时,如点击鼠标或按键,系统会生成一个事件。
- 事件排队:生成的事件会被放入到一个事件队列中。
- 事件分发:事件循环从事件队列中取出事件,根据事件类型和相关联的控件,将事件分发到相应的事件处理函数。
- 事件处理:事件处理函数根据传入的事件对象的属性和方法执行相应的逻辑,并返回结果。
以下是一个简化的代码示例,展示如何在 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()

最低0.47元/天 解锁文章
718

被折叠的 条评论
为什么被折叠?



