Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python tkinter SpinBox:更新显示值和关联StringVar之间的延迟_Python_Python 3.x_Tkinter - Fatal编程技术网

Python tkinter SpinBox:更新显示值和关联StringVar之间的延迟

Python tkinter SpinBox:更新显示值和关联StringVar之间的延迟,python,python-3.x,tkinter,Python,Python 3.x,Tkinter,小结:单击tkinter SpinBox箭头可增加GUI中的数字,但与条目关联的StringVar()的检查滞后于单击 我创建了复合小部件,其中包含数字条目,在提交条目更改时调用模型计算。我不想每次更改条目时都简单地调用模型,因为计算可能会很慢。因此,实际代码在、等上使用绑定(从下面的示例代码中省略),并且仅在这样的“提交”上调用模型 我查看的SpinBox文档没有显示绑定到SpinBox本身的向上/向下箭头按钮的方法。因此,我有用于单击和释放鼠标按钮的绑定。单击并释放时,将最后一个存储值与当前

小结:单击tkinter SpinBox箭头可增加GUI中的数字,但与条目关联的StringVar()的检查滞后于单击

我创建了复合小部件,其中包含数字条目,在提交条目更改时调用模型计算。我不想每次更改条目时都简单地调用模型,因为计算可能会很慢。因此,实际代码在
等上使用绑定(从下面的示例代码中省略),并且仅在这样的“提交”上调用模型

我查看的SpinBox文档没有显示绑定到SpinBox本身的向上/向下箭头按钮的方法。因此,我有用于单击和释放鼠标按钮的绑定。单击并释放时,将最后一个存储值与当前StringVar值进行比较,如果它们不同,则更新存储值并调用模型。所涉及的关键方法有
绑定条目
发布
刷新
条目更改
,以及
保存条目
。(按时的
和发布时的
中有注释掉的代码,这将允许在按下SpinBox箭头时刷新模型;保留该代码是为了明确预期的最终行为,但不需要复制错误)

来自tkinter import的
#技术上不好的做法,但很常见
SpinBoxFrame类(框架):
"""
一个tkinter框架,其中包含一个带有附加行为的标记条目小部件。
EntryFrame将调用函数(在参数中作为“model”提供)
提交条目值的更改时。
参数(除标准框架选项外):
名称——用于小部件标签和内省
数组——一个二维数组(列表列表,[[],[]
coord—要读取/写入的数组的坐标
from、to、increment:SpinBox参数(最小值和最大值,
每次箭头单击时的增量更改)
"""
定义初始化(self,parent=None,name='',model=None,
数组=无,坐标=(0,0),
从=0.00到=100.00,增量=1,
**选项):
框架.\uuuu初始化(自、父、**选项)
self.name=名称
self.model=model
self.array=array
self.row,self.col=coord
self.spinbox_kwargs={'from_u0;:from_0;,
"到":到,,
“增量”:增量}
self.initialize()
self.add_标签()
self.add_条目()
self.bind_条目()
self.validate_条目()
def初始化(自):
self.value_var=StringVar()
self.value=self.array[self.row][self.col]
self.value\u变量集(self.value)
def添加_标签(自身):
标签(self,text=self.name,bg='white',bd=0).pack(side=TOP)
def添加_条目(自身):
self.entry=Spinbox(self,宽度=7,
验证='key',#检查按键上的数字
**self.spinbox_-kwargs)
self.entry.pack(侧面=顶部,填充=X)
self.entry.config(textvariable=self.value\u var)
def绑定_条目(自身):
self.entry.bind(“”,lambda事件:self.refresh())
self.entry.bind(“”,lambda事件:self.on_press())
self.entry.bind(“”,lambda事件:self.on_release())
def刷新(自我):
如果self.entry_已更改():
打印('值更改')
self.save_条目()
打印('Saved new',self.name',value')
self.model()
def条目已更改(自身):
打印('self.name',was',self.value的旧值)
print('self.name'的当前值为',
float(self.value\u var.get())
返回self.value!=float(self.value\u var.get())
def保存_条目(自身):
如果不是self.value_var.get():#如果条目留空,
self.value_var.set(0.00)#用零填充
self.value=float(self.value\u var.get())
self.array[self.row][self.col]=self.value
def on_按下(自):
打印('按钮按下')
#self.loop_refresh()#取消注释以启用实时刷新
def循环_刷新(自):
self.refresh()
self.button\u hold\u job=self.\u root().after(50,self.loop\u刷新)
def on_释放(自):
打印('按钮已释放')
#在on_press()中启用循环时取消注释
#self.\u root()。\u取消后(self.button\u保持\u作业)
self.refresh()
def验证_条目(自身):
"""
基本EntryFrame类假定条目内容应该是数字的
"""
#检查每个按键的新结果是否为数字
self.entry['validatecommand']=(self.register(self.is_编号),“%P”)
#如果按键不正确,请按“铃”
self.entry['invalidcommand']='bell'
@静力学方法
def是_编号(条目):
"""
测试以查看条目是否可接受(为空或可以为空)
转换为浮点数。)
"""
如果没有输入:
返回True#空字符串:如果删除了整个条目,则确定
尝试:
浮动(输入)
返回真值
除值错误外:
返回错误
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
虚拟数组=[[1,42],[0,0]]
root=Tk()
类TestFrame(框架):
“”“模拟一个工具栏对象,该对象保存条目小部件并传递它们的
模型“”上的条目
def uuu init uuu(自、父、**选项):
框架.\uuuu初始化(自、父、**选项)
def call_型号(自):
打印('从模型中请求计算,使用:')
打印(虚拟数组)
主窗口=测试帧(根)
mainwindow.pack()
box1=SpinBoxFrame(主窗口,数组=虚拟数组,坐标=(0,0),
name='Box 1',model=main窗口。
from tkinter import *  # technically bad practice, but common


class SpinBoxFrame(Frame):
    """
    A tkinter Frame that holds a labeled entry widget with added behavior.
    EntryFrame will call the function (provided as 'model' in the arguments)
    when a change in the entry's value is committed.

    Arguments (in addition to standard Frame options):
        name-- for widget label and introspection
        array-- a 2D array ( list of lists, [[],[]]
        coord-- the coordinate of the array to be read from/written to
        from_, to, increment: SpinBox arguments (minimum and maximum values,
        and incremental change on each arrow click)
    """

    def __init__(self, parent=None, name='', model=None,
                 array=None, coord=(0, 0),
                 from_=0.00, to=100.00, increment=1,
                 **options):

        Frame.__init__(self, parent, **options)
        self.name = name
        self.model = model
        self.array = array
        self.row, self.col = coord
        self.spinbox_kwargs = {'from_': from_,
                               'to': to,
                               'increment': increment}
        self.initialize()
        self.add_label()
        self.add_entry()
        self.bind_entry()
        self.validate_entry()

    def initialize(self):
        self.value_var = StringVar()
        self.value = self.array[self.row][self.col]
        self.value_var.set(self.value)

    def add_label(self):
        Label(self, text=self.name, bg='white', bd=0).pack(side=TOP)

    def add_entry(self):
        self.entry = Spinbox(self, width=7,
                             validate='key',  # check for number on keypress
                             **self.spinbox_kwargs)
        self.entry.pack(side=TOP, fill=X)
        self.entry.config(textvariable=self.value_var)

    def bind_entry(self):
        self.entry.bind('<FocusOut>', lambda event: self.refresh())
        self.entry.bind('<ButtonPress-1>', lambda event: self.on_press())
        self.entry.bind('<ButtonRelease-1>', lambda event: self.on_release())

    def refresh(self):
        if self.entry_is_changed():
            print('VALUE CHANGE')
            self.save_entry()
            print('Saved new ', self.name, ' value')
            self.model()

    def entry_is_changed(self):
        print('Old value of ', self.name, ' was ', self.value)
        print('Current value of ', self.name, ' is ',
              float(self.value_var.get()))
        return self.value != float(self.value_var.get())

    def save_entry(self):
        if not self.value_var.get():  # if entry left blank,
            self.value_var.set(0.00)  # fill it with zero
        self.value = float(self.value_var.get())
        self.array[self.row][self.col] = self.value

    def on_press(self):
        print('Button pressed')
        # self.loop_refresh()  # uncomment to enable real-time refreshing

    def loop_refresh(self):
        self.refresh()
        self.button_held_job = self._root().after(50, self.loop_refresh)

    def on_release(self):
        print('Button released')
        # uncomment if loop enabled in on_press()
        # self._root().after_cancel(self.button_held_job)
        self.refresh()

    def validate_entry(self):
        """
        The base EntryFrame class assumes the entry contents should be numerical
        """
        # check on each keypress if new result will be a number
        self.entry['validatecommand'] = (self.register(self.is_number), '%P')
        # sound 'bell' if bad keypress
        self.entry['invalidcommand'] = 'bell'

    @staticmethod
    def is_number(entry):
        """
        tests to see if entry is acceptable (either empty, or able to be
        converted to a float.)
        """
        if not entry:
            return True  # Empty string: OK if entire entry deleted
        try:
            float(entry)
            return True
        except ValueError:
            return False

if __name__ == '__main__':
    dummy_array = [[1, 42], [0, 0]]
    root = Tk()


    class TestFrame(Frame):
        """Mimics a toolbar object that holds entry widgets and passes their
        entries on to a model"""
        def __init__(self, parent, **options):
            Frame.__init__(self, parent, **options)

        def call_model(self):
            print('requesting calculation from the model, using:')
            print(dummy_array)

    mainwindow = TestFrame(root)
    mainwindow.pack()

    box1 = SpinBoxFrame(mainwindow, array=dummy_array, coord=(0, 0),
                                 name='Box 1', model=mainwindow.call_model)
    box1.pack(side=LEFT)
    box2 = SpinBoxFrame(mainwindow, array=dummy_array, coord=(0, 1),
                        name='Box 2', model=mainwindow.call_model)
    box2.pack(side=LEFT)

    # workaround fix for Tk problems and mac mouse/trackpad:
    while True:
        try:
            root.mainloop()
            break
        except UnicodeDecodeError:
            pass
def on_release(self):
    print('Button released')
    # uncomment if loop enabled in on_press()
    # self._root().after_cancel(self.button_held_job)
    self.after(1, self.refresh)