wxpython 将变量传递给回调事件。Lambda地带

3 投票
3 回答
1408 浏览
提问于 2025-04-18 01:24

我是不是对lambda表达式理解错了?还是说我想传递的变量GetValue()是空的?这样的话,直接创建一个global palletNumberText会不会更好呢?在createWidgets()里,我绑定了一个EVT_TEXT事件,这样当在TextCtrl里输入文本时,就会调用onPalletNumberText(event, variable_here)这个函数。

我在以下这行代码上遇到了困难:

palletNumberText.Bind(wx.EVT_TEXT, lambda event, temp_str=palletNumberText.GetValue(): self.onPalletNumberText( event, temp_str ))

在这个代码片段里:

class ClassName(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title)
        self.panel = wx.Panel(self)
        self.PhotoMaxSize = 240
        self.createWidgets()
        self.Show()

    def createWidgets(self):
        .
        .
        .
        palletNumberText = wx.TextCtrl(self.panel, size=(80,-1))
        # THIS LINE
        palletNumberText.Bind(wx.EVT_TEXT, lambda event, temp_str=palletNumberText.GetValue(): self.onPalletNumberText( event, temp_str ))
        .
        .
        .

    def onPalletNumberText(self, event, palletNumber):
        '''
        save palletNumbertTxt Value when text is entered
        '''
        print palletNumber
        print "This is a test"
        # Store Value

        return

我查阅了一些资料:

不过我的结果是:

results

谢谢。

3 个回答

2

问题确实出在你提到的那一行代码上。问题在于,temp_str的默认值是在调用Bind方法时计算的,而不是在事件触发时计算的。当你绑定事件时,palletNumberText字段是空的,因为你刚刚创建了这个palletNumberText控件。

这一行代码的效果和下面这两行是一样的:

default_value = palletNumberText.GetValue() # will always be "", you've only just created it 
palletNumberText.Bind(wx.EVT_TEXT, lambda event, temp_str=default_value: self.onPalletNumberText( event, temp_str ))

解决这个问题的一种方法是把palletNumberText.GetValue()的调用放到一个lambda表达式的内部,并为temp_str参数使用一个默认值,比如None

palletNumberText.Bind(wx.EVT_TEXT, lambda event, temp_str=None: self.onPalletNumberText( event, palletNumberText.GetValue() if temp_str is None else temp_str ))

不过,这一行代码变得比较长,可能更好的是创建一个函数,而不是试图把太多代码塞进一个lambda表达式里。另一种选择是把palletNumberText作为你的ClassName类的一个属性,然后让self.onPalletNumberText方法检查它的内容。

3

你的默认参数是在程序开始时就被计算的

lambda event, temp_str=None: self.onPalletNumberText( event, 
                             temp_str if temp_str is not None else palletNumberText.GetValue() )

我觉得这样可以工作

但你真正想要的可能更像是

lambda event, txt_instance=palletNumberText: self.onPalletNumberText( event, txt_instance.GetValue() )  
1

问题在于你在你的lambda表达式里面调用了GetValue方法。这样做会立即执行,也就是说它会在文本控件还没显示出来之前就获取值。换句话说,它获取的值总是空的。这个方法并不是每次事件触发时都会被调用。

相反,你应该直接在事件处理函数里面调用GetValue():

import wx

class ClassName(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title)
        self.panel = wx.Panel(self)
        self.PhotoMaxSize = 240
        self.createWidgets()
        self.Show()

    def createWidgets(self):
        self.palletNumberText = wx.TextCtrl(self.panel, size=(80,-1))

        self.palletNumberText.Bind(wx.EVT_TEXT, self.onPalletNumberText)


    def onPalletNumberText(self, event):
        '''
        save palletNumbertTxt Value when text is entered
        '''
        print self.palletNumberText.GetValue()
        print "This is a test"
        # Store Value

        return

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = ClassName(None, "Test")
    app.MainLoop()

撰写回答