【问题标题】:Updating a value in a Python TKinter Entry Box更新 Python TKinter 输入框中的值
【发布时间】:2020-05-16 06:44:30
【问题描述】:

我正在使用 Python 3.8.1 和 tkinter 版本 8.6。

我有一个 GUI 类 Pressureinput,它接受压力传感器模拟器的输入。我希望条目以 kPa 为单位(传感器的本机单位),但我也希望用户知道 psi 等效值是多少。因此,当用户更新 kpa 值时,我希望更新 psi 值,但我不希望用户能够手动更新 psi 值。我对两者都使用了一个输入框。它们以 242 kPa 的默认值开始。

我正在尝试使用validate="focusout" 在 kpa 输入框失去焦点后触发事件。

这是我的代码,因此您可以看到我正在尝试做什么。基本上,如果他们输入任何不是正数甚至整数的东西,我希望它自动将输入框中的值四舍五入,然后我还希望它更新等效的 psi。

我意识到我在 pressurevalid 函数中使用的方法不起作用,因为输入框对象 kpa 和 psi 是不可变的,它不会改变原始对象。

请注意,我已经设置了 StringVar 变量 psitextkpatext。但是,每次我尝试在 pressurevalid 函数中使用它们时,都会收到错误消息,提示它们不存在。

我尝试过的所有其他方法都以无法运行的错误告终,我认为这至少说明了我想要做什么:

import tkinter as tkGUI

#global constants for conversion
global psi2kpa
global kpa2psi
psi2kpa = 6.894757
kpa2psi = 1 / psi2kpa

class Pressureinput(tkGUI.Frame):

    def __init__(self,parent):
            tkGUI.Frame.__init__(self,parent)
            self.parent = parent
            self.initialize()

    def initialize(self):

            kpatext = tkGUI.StringVar()
            psitext = tkGUI.StringVar()

            self.IDlabel = tkGUI.Label(self,text="Sensor ID (hex):")
            self.IDlabel.grid(row=0, column=0)
            self.ID = tkGUI.Entry(self)
            self.ID.insert(0,"AABBCCDD")
            self.ID.grid(row=0, column=1)

            self.kpalabel = tkGUI.Label(self,text="Pressure (kPa):")
            self.kpalabel.grid(row=1, column=0)
            self.kpa = tkGUI.Entry(self)
            self.kpa.insert(0,242)
            self.kpa.grid(row=1, column=1)

            self.psilabel = tkGUI.Label(self,text="Pressure (PSI):")
            self.psilabel.grid(row=2, column=0)
            self.psi = tkGUI.Entry(self, textvariable=psitext)
            self.psi.insert(0,float(self.kpa.get())*kpa2psi)
            self.psi.grid(row=2, column=1)
            self.psi.config(state='disabled') #state = 'normal' to restore

            vpressure = self.register(self.pressurevalid(self.kpa,self.psi))
            self.kpa = tkGUI.Entry(self, textvariable=kpatext, validate="focusout", validatecommand=vpressure)

            self.sendbutton = tkGUI.Button(self,text="Send Transmission",state="disabled",command=self.send_data)
            self.sendbutton.grid(row=9,columnspan=2)

    def pressurevalid(self,kpa,psi):
            if len(kpa.get()) < 1:
                    kpa.delete(0,tkGUI.END)
                    kpa.insert(0,"0");
            elif 2*int(round(float(kpa.get())) / 2) != int(kpa.get()):
                    kpa.delete(0,tkGUI.END)
                    kpa.insert(0,2 * int(round(float(kpa.get()))) / 2)

            psi.config(state='normal')
            psi.delete(0,tkGUI.END)
            psi.insert(0,float(kpa.get())*kpa2psi)
            psi.config(state='disabled')
            return True

    def send_data(self):
            ID = int(self.ID.get(),16)
            pressure = int(self.kpa.get())
            if pressure >= 510:
                    pressure = 255
            else:
                 pressure = int(round(pressure/2))

            sendstring =  str(ID) + "," + str(function_code) + "," + str(pressure)
            print (sendstring)

【问题讨论】:

    标签: python python-3.x tkinter tkinter-entry


    【解决方案1】:

    由于您对条目使用StringVar,因此您可以在变量上设置跟踪,以便在值更改时调用函数。这将不断更新值,而不是等待焦点事件。

    首先,您需要将变量转换为类的属性,而不是使它们成为局部变量:

    self.kpatext = tkGUI.StringVar()
    self.psitext = tkGUI.StringVar()
    

    您还必须调整引用这些变量的其他地方:

    self.psi = tkGUI.Entry(..., textvariable=self.psitext, ...)
    self.kpa = tkGUI.Entry(..., textvariable=self.kpatext, ...)
    

    接下来,在创建变量后立即在 self.kpatext 上设置跟踪:

    self.kpatext.trace("w", self.update_psi)
    

    最后,编写方法self.update_psi。如果无法转换 kPa 的当前值,以下代码会将 PSI 设置为空字符串。

    def update_psi(self, *args):
        try:
            psi = int(self.kpatext.get())*kpa2psi
            self.psitext.set(psi)
        except Exception as e:
            self.psitext.set("")
    

    有关跟踪函数的参数是什么的更多信息,请参阅What are the arguments to Tkinter variable trace method callbacks?。在这个例子中我们不需要它们,但函数仍然必须接受它们。


    注意,您的代码定义了两次self.kpa——一次不使用textvariable,一次使用。我不明白你为什么要这样做,因为第二个从来没有通过 pack/place/grid 添加到屏幕上。我的解决方案是在您打算使用原始 self.kpa 的假设下工作的。

    【讨论】:

    • 如果我添加跟踪,我假设我可以从我的 self.kpa 定义中删除 validate 和 validatecommand? (注意:self.kpa 的第二个定义是一种蹩脚的尝试,以规避我在定义对象的顺序时遇到的一些错误)
    • @Trashman:是的,如果您不想进行任何输入验证,可以删除验证功能。我建议保留验证,但仅将其用于验证 - 例如,只允许数字和一位小数。
    • 好的,代码在 kpa 改变时非常适合更新 psi 值。我对其进行了一些修改,以将 kpa 值更改为有效值(即使是整数),效果也很好。由于它会在更改后立即更新,因此我根本无法输入奇数。所以,如果我想要 254 kPa,它将首先输入 244,然后我必须使用光标将中间的 4 更改为 5。我能做些什么来改变轨迹,使其像“focusout”一样工作而不正确直到用户离开盒子?
    • 所以,我创建了两个函数,现在分别调用它们。按照您的建议,我使用跟踪的 update_psi 。我已经重新添加了我的 vpressure(现在作为 self.vpressure - 我认为我最初的最大问题是没有使用足够的“self”引用)功能作为对“focusout”的验证操作 - 它似乎有效,但似乎只工作一次。我第一次在框中输入数据时,它会修复它。如果我再次返回该框,我可以输入任何我想要的内容,但它不会再次验证/修复它。
    • @Trashman:tkinter 将在某些条件下删除验证函数 - 特别是当验证函数返回错误时。此外,您不应更改验证函数中的值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-17
    • 2014-06-09
    相关资源
    最近更新 更多