回调方法的工厂-Python TKinter
编写一个模拟PIO行的测试应用程序,我有一个非常简单的Python/TKGUI应用程序。使用数字键1至8模拟PIO引脚1至8。按下键=PIO高,释放键=PIO低。我需要它的原因不是问题。我试图利用工厂来创建按键回拨功能,这让我陷入了困境 下面是一些简化的代码:回调方法的工厂-Python TKinter,python,methods,factory,Python,Methods,Factory,编写一个模拟PIO行的测试应用程序,我有一个非常简单的Python/TKGUI应用程序。使用数字键1至8模拟PIO引脚1至8。按下键=PIO高,释放键=PIO低。我需要它的原因不是问题。我试图利用工厂来创建按键回拨功能,这让我陷入了困境 下面是一些简化的代码: #!usr/bin/env python """ Python + Tk GUI interface to simulate a 8 Pio lines. """ from Tkinter import * def cb_factor
#!usr/bin/env python
"""
Python + Tk GUI interface to simulate a 8 Pio lines.
"""
from Tkinter import *
def cb_factory(numberic_key):
"""
Return a call back function for a specific keyboard numeric key (0-9)
"""
def cb( self, event, key=numberic_key ):
bit_val = 1<<numberic_key-1
if int(event.type) == 2 and not (bit_val & self.bitfield):
self.bitfield |= bit_val
self.message("Key %d Down" % key)
elif int(event.type) == 3 and (bit_val & self.bitfield):
self.bitfield &= (~bit_val & 0xFF)
self.message("Key %d Up" % key)
else:
# Key repeat
return
print hex(self.bitfield)
self.display_bitfield()
return cb
class App( Frame ):
"""
Main TK App class
"""
cb1 = cb_factory(1)
cb2 = cb_factory(2)
cb3 = cb_factory(3)
cb4 = cb_factory(4)
cb5 = cb_factory(5)
cb6 = cb_factory(6)
cb7 = cb_factory(7)
cb8 = cb_factory(8)
def __init__(self, parent):
"Init"
self.parent = parent
self.bitfield = 0x00
Frame.__init__(self, parent)
self.messages = StringVar()
self.messages.set("Initialised")
Label( parent, bd=1,
relief=SUNKEN,
anchor=W,
textvariable=self.messages,
text="Testing" ).pack(fill=X)
self.bf_label = StringVar()
self.bf_label.set("0 0 0 0 0 0 0 0")
Label( parent, bd=1,
relief=SUNKEN,
anchor=W,
textvariable=self.bf_label,
text="Testing" ).pack(fill=X)
# This Doesn't work! Get a traceback saying 'cb' expected 2 arguements
# but only got 1?
#
# for x in xrange(1,9):
# cb = self.cb_factory(x)
# self.parent.bind("<KeyPress-%d>" % x, cb)
# self.parent.bind("<KeyRelease-%d>" % x, cb)
self.parent.bind("<KeyPress-1>", self.cb1)
self.parent.bind("<KeyRelease-1>", self.cb1)
self.parent.bind("<KeyPress-2>", self.cb2)
self.parent.bind("<KeyRelease-2>", self.cb2)
self.parent.bind("<KeyPress-3>", self.cb3)
self.parent.bind("<KeyRelease-3>", self.cb3)
self.parent.bind("<KeyPress-4>", self.cb4)
self.parent.bind("<KeyRelease-4>", self.cb4)
self.parent.bind("<KeyPress-5>", self.cb5)
self.parent.bind("<KeyRelease-5>", self.cb5)
self.parent.bind("<KeyPress-6>", self.cb6)
self.parent.bind("<KeyRelease-6>", self.cb6)
self.parent.bind("<KeyPress-7>", self.cb7)
self.parent.bind("<KeyRelease-7>", self.cb7)
self.parent.bind("<KeyPress-8>", self.cb8)
self.parent.bind("<KeyRelease-8>", self.cb8)
def display_bitfield(self):
"""
Display the PIO lines (1 for on, 0 for off)
"""
bin_lst = []
for x in xrange(8):
bit = 1 << x
if bit & self.bitfield:
bin_lst.append("1")
else:
bin_lst.append("0")
bin_lst.reverse()
bin_str = " ".join( bin_lst )
self.bf_label.set( bin_str )
def message( self, msg_txt ):
"set"
self.messages.set( msg_txt )
def cb_factory(self, numberic_key ):
"""
Return a call back function for a specific keyboard numeric key (0-9)
"""
def cb( self, event, key=numberic_key ):
bit_val = 1<<numberic_key-1
if int(event.type) == 2:
self.bitfield |= bit_val
self.message("Key %d Down" % key)
else:
self.bitfield &= (~bit_val & 0xFF)
self.message("Key %d Up" % key)
print hex(self.bitfield)
self.display_bitfield()
return cb
##########################################################################
if __name__ == "__main__":
root = Tk()
root.title("PIO Test")
theApp = App( root )
root.mainloop()
#!usr/bin/env python
"""
Python+Tk GUI界面,用于模拟8条Pio线。
"""
从Tkinter进口*
def cb_工厂(数字键):
"""
返回特定键盘数字键(0-9)的回拨功能
"""
def cb(自身、事件、键=数字键):
bit_val=1cb期望“自我”和“事件”。可能它只从绑定中获取事件?这是经过修改的代码,考虑到了SPLIF的答案。我觉得这在美学上更令人愉悦,但我不明白它是如何工作的,这让我很烦。那么,对于额外的学分,有人能解释一下这是如何工作的吗
#!usr/bin/env python
"""
Python + Tk GUI interface to simulate a 8 Pio lines.
"""
from Tkinter import *
from pio_handler import *
class App( Frame ):
"""
Main TK App class
"""
def __init__(self, parent):
"Init"
self.parent = parent
self.bitfield = 0x00
Frame.__init__(self, parent)
self.messages = StringVar()
self.messages.set("Initialised")
Label( parent, bd=1,
relief=SUNKEN,
anchor=W,
textvariable=self.messages,
text="Testing" ).pack(fill=X)
self.bf_label = StringVar()
self.bf_label.set("0 0 0 0 0 0 0 0")
Label( parent, bd=1,
relief=SUNKEN,
anchor=W,
textvariable=self.bf_label,
text="Testing" ).pack(fill=X)
# This is the clever bit!
# Use a factory to assign a callback function for keys 1 to 8
for x in xrange(1,9):
cb = self.cb_factory(x)
self.parent.bind("<KeyPress-%d>" % x, cb)
self.parent.bind("<KeyRelease-%d>" % x, cb)
def display_bitfield(self):
"""
Display the PIO lines (1 for on, 0 for off)
"""
bin_lst = []
for x in xrange(8):
bit = 1 << x
if bit & self.bitfield:
bin_lst.append("1")
else:
bin_lst.append("0")
bin_lst.reverse()
bin_str = " ".join( bin_lst )
self.bf_label.set( bin_str )
def message( self, msg_txt ):
"set"
self.messages.set( msg_txt )
def cb_factory(self, numeric_key ):
"""
Return a call back function for a specific keyboard numeric key (0-9)
"""
def cb( event, key=numeric_key ):
bit_val = 1<<numeric_key-1
if int(event.type) == 2:
self.bitfield |= bit_val
self.message("Key %d Down" % key)
else:
self.bitfield &= (~bit_val & 0xFF)
self.message("Key %d Up" % key)
print hex(self.bitfield)
self.display_bitfield()
return cb
##########################################################################
if __name__ == "__main__":
root = Tk()
root.title("PIO Test")
theApp = App( root )
root.mainloop()
#!usr/bin/env python
"""
Python+Tk GUI界面,用于模拟8条Pio线。
"""
从Tkinter进口*
从pio_处理程序导入*
类应用程序(框架):
"""
主TK应用程序类
"""
定义初始化(自身,父级):
“初始化”
self.parent=parent
self.bitfield=0x00
帧。\uuuu初始化(自,父)
self.messages=StringVar()
self.messages.set(“初始化”)
标签(父项,bd=1,
浮沉,
锚=W,
textvariable=self.messages,
text=“测试”).pack(填充=X)
self.bf_label=StringVar()
self.bf_label.set(“0 0 0 0”)
标签(父项,bd=1,
浮沉,
锚=W,
textvariable=self.bf\u标签,
text=“测试”).pack(填充=X)
#这是聪明的一点!
#使用工厂为键1到键8分配回调函数
对于x范围内的x(1,9):
cb=自身。cb_工厂(x)
self.parent.bind(“%x,cb)
self.parent.bind(“%x,cb)
def显示_位字段(自身):
"""
显示PIO线(1表示打开,0表示关闭)
"""
bin_lst=[]
对于x范围内的x(8):
bit=1回答您的后续问题
我不确定您不了解哪一部分,但我猜您不太了解事件回调的工作方式?如果是这样,那就很容易了。Tk在循环中运行,查找事件(按键、鼠标点击等)。当您将回调/函数绑定到事件时,您只是告诉它调用您的函数并将事件对象作为其参数传递。然后,您可以查询事件对象以了解实际发生的情况的更多详细信息。您当前正在构建单独的回调函数,并将每个回调函数绑定到18个键事件(在键1-9上向下释放)。我认为您可以重写它,将cb作为类的一个方法,因为事件对象几乎肯定也包含键代码
class:
def __init__(self):
for x in xrange(8):
self.parent.bind("<KeyPress-%d>" % x, self.keyaction)
self.parent.bind("<KeyRelease-%d>" % x, self.keyaction)
def keyaction(self, event):
key = event.keycode # attribute may have another name, I haven't checked tk docs
... do stuff ...
类:
定义初始化(自):
对于x范围内的x(8):
self.parent.bind(“%x,self.keyaction)
self.parent.bind(“%x,self.keyaction)
def键动作(自身、事件):
key=event.keycode#属性可能有另一个名称,我没有检查tk文档
... 做些事情。。。
因为我们现在使用self.keyaction作为回调,所以它应该将self作为第一个参数。它从事件对象获取其键代码。现在,在创建函数时,两个值都不需要“内置”到函数中,这样就不需要为每个键实际创建不同的回调,代码也就更容易理解了。是的,就是这样!在“cb_工厂”返回的“cb”方法中,“self”是多余的。我将发布修改后的代码以显示工作示例。如果有人能给我解释一下,我的大脑很痛!它的key=event.char,但我更感兴趣的是,为什么工厂生成的“cb”方法不需要“self”作为第一个参数。因为它从工厂函数继承了self的含义,几乎像一个全局变量。self未在cb中定义,但在上述范围(对象方法)中定义