wxPython(Phoenix)中有没有 wx.EVT_CHAR 或 event.GetKeyCode() 的等效方法?

2 投票
1 回答
2162 浏览
提问于 2025-04-18 09:42

我刚开始学习Python,所以尽量不想用Python 2。现在我在用wxPython学习图形用户界面(GUI)元素。Python 3的文档还没有入门部分,所以我在用Python 2的“入门”文档,并在需要的地方转换成Python 3。

我现在在这个部分。这里有一个关于wx.EVT_CHAR的部分,用于处理当焦点对象检测到按键时的事件。我在对比表CommandEvent文档,以及wx.TextCtrl文档的“这个类发出的事件”部分都没有找到相关的参考。我已经能把大部分其他的非Python 3代码转换过来,比如SizerFlags,但找不到这个的对应部分。

这是我正在处理的代码。

import wx
class ExampleFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)
        baseSizer = wx.BoxSizer(wx.VERTICAL)

        # Create an editable text field
        self.textfield = wx.TextCtrl(self)
        # Attach event handlers to text field
        # Event for when the text changes
        self.Bind(wx.EVT_TEXT, self.OnChange, self.textfield)
        # Event for when a key is pressed, for example an arrow key should fire this event but not the EVT_TEXT event
        self.Bind(wx.EVT_CHAR, self.OnKeyPress, self.textfield)

        # Create a button that will clear the textfield
        clearButton = wx.Button(self, wx.ID_CLEAR, "Clear")
        # Attach event handler on the clearButton to call OnClear()
        self.Bind(wx.EVT_BUTTON, self.OnClear, clearButton)

        # Multiline text field for seeing the events fire
        self.logger = wx.TextCtrl(self, -1, style= wx.TE_MULTILINE | wx.TE_READONLY )

        # Add items to frame sizer
        baseSizer.Add(self.textfield, wx.SizerFlags(0).Expand())
        baseSizer.Add(clearButton, wx.SizerFlags(0).Expand())
        baseSizer.Add(self.logger, wx.SizerFlags(1).Expand())

        # Set sizer for frame
        self.SetSizer(baseSizer)

        # Show 
        self.Show()

    def OnClear(self, e):
        # Clear all text entered into the textfield and return focus
        self.textfield.SetValue("")
        self.textfield.SetFocus()

    def OnChange(self, e):
        # Log every time this event is fired
        self.logger.AppendText("OnChange: " + e.GetString() + '\n')

    def OnKeyPress(self, e):
        # Log every key press in the textfield
        self.logger.AppendText("OnKeyPress: " + e.GetKeyCode() + '\n')

app = wx.App(False)
ExampleFrame(None)
app.MainLoop()

OnChange()每次文本框里的文本改变时都会触发。但是OnKeyPress从来没有触发过。如果我能让它触发,我在CommandEvent方法总结中也没有看到GetKeyCode()的对应方法。

编辑: 问题在Mike Driscoll的帮助下解决了。我实现了他的建议,把这个:

self.Bind(wx.EVT_CHAR, self.OnKeyPress, self.textfield)

改成这个:

self.textfield.Bind(wx.EVT_CHAR, self.OnKeyPress, self.textfield)  

另外,我还需要在OnKeyPress函数中添加e.Skip()。否则它会记录按键,但不会把文本添加到文本框中。其他事件在不使用Skip()的情况下也能正常工作,能够将事件传递给控制树中的其他监听器。

1 个回答

1

你在这个情况下绑定事件的方式不对。你应该用

self.textfield.Bind(wx.EVT_CHAR, self.OnKeyPress, self.textfield)

而不是

self.Bind(wx.EVT_CHAR, self.OnKeyPress, self.textfield)

下面是它在具体上下文中的样子:

import wx
class ExampleFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)
        baseSizer = wx.BoxSizer(wx.VERTICAL)

        # Create an editable text field
        self.textfield = wx.TextCtrl(self)
        # Attach event handlers to text field
        # Event for when the text changes
        self.Bind(wx.EVT_TEXT, self.OnChange, self.textfield)
        # Event for when a key is pressed, for example an arrow key should fire this event but not the EVT_TEXT event
        self.textfield.Bind(wx.EVT_CHAR, self.OnKeyPress, self.textfield)

        # Create a button that will clear the textfield
        clearButton = wx.Button(self, wx.ID_CLEAR, "Clear")
        # Attach event handler on the clearButton to call OnClear()
        self.Bind(wx.EVT_BUTTON, self.OnClear, clearButton)

        # Multiline text field for seeing the events fire
        self.logger = wx.TextCtrl(self, -1, style= wx.TE_MULTILINE | wx.TE_READONLY )

        # Add items to frame sizer
        baseSizer.Add(self.textfield, 1, flag=wx.EXPAND)
        baseSizer.Add(clearButton,0)
        baseSizer.Add(self.logger, 1, flag=wx.EXPAND)

        # Set sizer for frame
        self.SetSizer(baseSizer)

        # Show 
        self.Show()

    def OnClear(self, e):
        # Clear all text entered into the textfield and return focus
        self.textfield.SetValue("")
        self.textfield.SetFocus()
        e.Skip()

    def OnChange(self, e):
        # Log every time this event is fired
        self.logger.AppendText("OnChange: " + e.GetString() + '\n')
        e.Skip()

    def OnKeyPress(self, e):
        # Log every key press in the textfield
        self.logger.AppendText("OnKeyPress: " + str(e.GetKeyCode()) + '\n')
        e.Skip()

app = wx.App(False)
ExampleFrame(None)
app.MainLoop()

你可能还想看看下面这个维基页面,了解不同的绑定方法:

至于你问的另一个问题,虽然我不能确定,但如果在Phoenix里没有OnKeyPress的话,我会非常惊讶。即使文档里没有提到,我也建议你试试看,因为我猜它应该还是有的。

撰写回答