【问题标题】:Shortening GUI code by passing parameters to definitions [duplicate]通过将参数传递给定义来缩短 GUI 代码 [重复]
【发布时间】:2016-07-28 11:38:56
【问题描述】:

我一直在编写 wxpython 中的 GUI 代码,它或多或少地重复相同的信息 4 次。屏幕上有很多按钮我必须将事件绑定到,我发现我有很多看起来几乎相同的 on_button_click 定义。所以,我想知道是否有办法在将按钮绑定到事件并删除 3 个定义时只传递一个参数。这是一个例子:

self.VDBenchSlot1 = wx.Button(self, -1, "Slot 1 VDBench")
sizer.Add(self.VDBenchSlot1,(1, 5), (1, 5), wx.EXPAND)
self.VDBenchSlot1.Bind(wx.EVT_BUTTON, self.VDBenchSlot1_clicked)

self.VDBenchSlot2 = wx.Button(self, -1, "Slot 2 VDBench")
sizer.Add(self.VDBenchSlot2,(1, 5), (1, 5), wx.EXPAND)
self.VDBenchSlot2.Bind(wx.EVT_BUTTON, self.VDBenchSlot2_clicked)

self.VDBenchSlot3 = wx.Button(self, -1, "Slot 3 VDBench")
sizer.Add(self.VDBenchSlot3,(1, 5), (1, 5), wx.EXPAND)
self.VDBenchSlot3.Bind(wx.EVT_BUTTON, self.VDBenchSlot3_clicked)

self.VDBenchSlot4 = wx.Button(self, -1, "Slot 4 VDBench")
sizer.Add(self.VDBenchSlot4,(1, 5), (1, 5), wx.EXPAND)
self.VDBenchSlot4.Bind(wx.EVT_BUTTON, self.VDBenchSlot4_clicked)

def VDBenchSlot1_clicked(self, event):       
    global diskchange
    if diskchange[1] == 'No Disk':
        self.TextSlot1.AppendText("No Disk is currently in the slot so you cannot run this! \n")
    else:  
        # Open the file startDisk#VD.sh that has the setup to start running VDBench
        os.system("echo pcieRocks | sudo -S gnome-terminal --profile=VDbench --working-directory=/home/pciedev3ubuntu/Documents -e './vdbench -f disk%dVDscript.txt -vr' &" %diskchange[1])

def VDBenchSlot2_clicked(self, event):
    global diskchange

    if diskchange[2] == 'No Disk':
        self.TextSlot2.AppendText("No Disk is currently in the slot so you cannot run this! \n")
    else:   
        # Open the file startDisk#VD.sh that has the setup to start running VDBench
        os.system("echo pcieRocks | sudo -S gnome-terminal --profile=VDbench --working-directory=/home/pciedev3ubuntu/Documents -e './vdbench -f disk%dVDscript.txt -vr' &" %diskchange[2])

def VDBenchSlot3_clicked(self, event):
    global diskchange

    if diskchange[3] == 'No Disk':
        self.TextSlot3.AppendText("No Disk is currently in the slot so you cannot run this! \n") 
    else:   
        # Open the file startDisk#VD.sh that has the setup to start running VDBench
        os.system("echo pcieRocks | sudo -S gnome-terminal --profile=VDbench --working-directory=/home/pciedev3ubuntu/Documents -e './vdbench -f disk%dVDscript.txt -vr' &" %diskchange[3])

def VDBenchSlot4_clicked(self, event):
    global diskchange

    if diskchange[4] == 'No Disk':
        self.TextSlot4.AppendText("No Disk is currently in the slot so you cannot run this! \n")
    else:   
        # Open the file startDisk#VD.sh that has the setup to start running VDBench
        os.system("echo pcieRocks | sudo -S gnome-terminal --profile=VDbench --working-directory=/home/pciedev3ubuntu/Documents -e './vdbench -f disk%dVDscript.txt -vr' &" %diskchange[4])

我尝试将 VDBenchslotx_clicked 更改为 VDBenchslotx_clicked() 并将参数传递给它,但是发生了两种情况之一;它告诉我输入的参数与 def 的参数不匹配,或者它让我的程序运行但它在程序启动时而不是在按下按钮时自动执行 def,然后按钮无法正常工作。

【问题讨论】:

  • 我不知道 wxpython,但似乎你不能这样做,这很烦人:即使是不起眼的 Tkinter 也允许你在将回调绑定到小部件时传递额外的 arg。但是,this question 的最佳答案显示了如何实现您想要的。
  • 顺便说一句,您可以通过创建一个构建按钮的辅助函数来减少重复。一种常见的技术是在创建小部件的方法(通常是 __init__ 方法)中定义此类辅助函数,这样它就可以访问方法的局部变量,而无需在函数调用中传递这些变量。
  • 我不确定你所说的辅助函数是什么意思,因为我对此很陌生......你有一个很好的链接可以作为例子提供吗?
  • Here 是我使用 GTK2+ GUI 框架编写的一些代码。辅助函数名为make_button。尽管 GTK 与 wxPython 完全不同,但希望这会给您一个大致的概念。我会在这里放一个简短的例子,使用你问题中的代码。

标签: python function user-interface wxpython


【解决方案1】:

dbc(和the linked question)展示了如何实现你想要的。但这是我在上面的评论中提到的辅助函数概念的简短演示。

def make_button(text, callback):
    button = wx.Button(self, -1, text)
    sizer.Add(button, (1, 5), (1, 5), wx.EXPAND)
    button.Bind(wx.EVT_BUTTON, callback)
    return button

self.VDBenchSlot1 = make_button("Slot 1 VDBench", self.VDBenchSlot1_clicked)
self.VDBenchSlot2 = make_button("Slot 2 VDBench", self.VDBenchSlot2_clicked)

请注意,make_button 没有在其签名中包含 self。那是因为它不是一个方法,它是一个定义在方法内部的函数。有关 GTK2+ 中完整运行的示例,请参阅this answer

另外请注意,我的代码是基于您的原始代码,但您应该很容易适应它以使用 dbc 的新 VDBenchSlot_clicked 回调方法。

【讨论】:

  • 啊,好吧,我明白了大意。我很确定我想把 sizer.Add 排除在 def 之外,对吗?因为否则我将继续在同一位置创建所有这些按钮。
  • @TreverWagenhals:我已经修复了我的代码。很抱歉之前的混乱。 :oops:
  • 对您的帖子进行了一些编辑,以反映我对 sizer.Add 的担忧。展示了两种情况的外观,因此您可以更好地理解我的意思。不过感谢您,在这两次调整之间,我已经废弃了大约 300 行代码。
【解决方案2】:

使用 lambda 表达式将参数传递给绑定函数。例如:

self.VDBenchSlot1.Bind(wx.EVT_BUTTON, lambda event: self.VDBenchSlot_clicked(event, 1))

def VDBenchSlot_clicked(self, event, position):   
    if position == 1:
        text_slot = self.TextSlot1
    elif position == 2:
        text_slot = self.TextSlot2
    elif position == 3:
        text_slot = self.TextSlot3
    elif position == 4:
        text_slot = self.TextSlot4    
    global diskchange
    if diskchange[position] == 'No Disk':
        text_slot.AppendText("No Disk is currently in the slot so you cannot run this! \n")
    else:  
        # Open the file startDisk#VD.sh that has the setup to start running VDBench
        os.system("echo pcieRocks | sudo -S gnome-terminal --profile=VDbench --working-directory=/home/pciedev3ubuntu/Documents -e './vdbench -f disk%dVDscript.txt -vr' &" %diskchange[position])

【讨论】:

  • 在实施您的编辑后,我收到以下错误消息:TypeError: VDBenchSlot_clicked() 恰好需要 2 个参数(给定 3 个)
  • 没关系,我想通了。它应该只是 VDBenchSlot1_clicked(1),而不是 (event, 1)。非常感谢您!
猜你喜欢
  • 2014-04-09
  • 1970-01-01
  • 2021-08-26
  • 1970-01-01
  • 2018-08-11
  • 2019-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多