Python / Tkinter:有没有办法不断“扫描”输入?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python / Tkinter:有没有办法不断“扫描”输入?相关的知识,希望对你有一定的参考价值。

我是python和tkinter的新手,并编写了一个简单的程序,用户可以使用输入填充4个变量,并可以通过单击按钮将其打印出来。现在我想知道:有没有办法让程序不断扫描用户输入窗口并在用户更改输入后立即刷新输出?

这是我的计划:

from tkinter import *

def calc():
    val1 = e1.get()
    val2 = e2.get()
    val3 = e3.get()
    val4 = e4.get()
    res = val1 + " " + val2 + " " + val3 + " " + val4
    label2 = Label(master)
    label2["text"] = res
    label2.grid(row=4, column = 1)

master = Tk()

Label(master, text="Main Value").grid(row=0, sticky = E)
Label(master, text="Second Value").grid(row=1, sticky = E)
Label(master, text="Third Value").grid(row=2, sticky = E)
Label(master, text="Fourth Value").grid(row=3, sticky = E)

e1 = Entry(master)
e2 = Entry(master)
e3 = Entry(master)
e4 = Entry(master)

e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
e3.grid(row=2, column=1)
e4.grid(row=3, column=1)

button1 = Button(master, text="Calculate", command=calc)
button1.grid(row=4, column=0, sticky=W, pady=4)

master.mainloop()

我想在用户更改其中一个输入后立即更改输出。

答案

我会利用trace_addtkinter variable classes函数。这确保了每次更改Entry的内容时都会调用该函数。这样做的缺点是您需要为每个条目创建一个StringVar对象,但是您确定捕获所有更改,不需要时不调用该函数且没有延迟。

接下来,您每次调用calc时都会创建一个新的Label小部件。您应该制作一个Label并在calc中更新其文本,而不是每次都创建一个新的Label。

将这些变化放在一起:

from tkinter import *


# Let calc accept the arguments passes by trace_add
def calc(*args):
    # Get the values from the StringVar objects
    val1 = v1.get()
    val2 = v2.get()
    val3 = v3.get()
    val4 = v4.get()
    res = val1 + " " + val2 + " " + val3 + " " + val4
    # Only change the text of the existing Label
    label2["text"] = res

master = Tk()

# make this Label once
label2 = Label(master)
label2.grid(row=4, column=1)

Label(master, text="Main Value").grid(row=0, sticky=E)
Label(master, text="Second Value").grid(row=1, sticky=E)
Label(master, text="Third Value").grid(row=2, sticky=E)
Label(master, text="Fourth Value").grid(row=3, sticky=E)

# Create StringVars
v1 = StringVar()
v2 = StringVar()
v3 = StringVar()
v4 = StringVar()

e1 = Entry(master, textvariable=v1)
e2 = Entry(master, textvariable=v2)
e3 = Entry(master, textvariable=v3)
e4 = Entry(master, textvariable=v4)

# Trace when the StringVars are written
v1.trace_add("write", calc)
v2.trace_add("write", calc)
v3.trace_add("write", calc)
v4.trace_add("write", calc)

e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
e3.grid(row=2, column=1)
e4.grid(row=3, column=1)

master.mainloop()
另一答案

是的,有可能这样做。

这是我的方式

您可以使用window.after(ms, func=None, args)to继续在后台运行,这将更新用户输入而无需按下按钮。

更新的代码

from tkinter import *

def calc():
    val1 = e1.get()
    val2 = e2.get()
    val3 = e3.get()
    val4 = e4.get()
    res = val1 + " " + val2 + " " + val3 + " " + val4
    label2["text"] = res

    # This will run the function in every 100ms (0.1 secs).
    master.after(100, calc)

master = Tk()

Label(master, text="Main Value").grid(row=0, sticky = E)
Label(master, text="Second Value").grid(row=1, sticky = E)
Label(master, text="Third Value").grid(row=2, sticky = E)
Label(master, text="Fourth Value").grid(row=3, sticky = E)

e1 = Entry(master)
e2 = Entry(master)
e3 = Entry(master)
e4 = Entry(master)

e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
e3.grid(row=2, column=1)
e4.grid(row=3, column=1)

button1 = Button(master, text="Calculate", command=calc)
button1.grid(row=4, column=0, sticky=W, pady=4)

label2 = Label(master)
label2.grid(row=4, column = 1)

# Run the function and it will keep running in the background.
calc()

master.mainloop()
另一答案

Trace是正确的方法,tkinter负责这些变化。我会将它与数据结构一起使用,然后立即创建小部件,然后立即跟踪,因为它的代码要少得多。以下是来自GUI的完整示例,该GUI使用许多实时监控输入,并在创建时添加了跟踪。跟踪条目中的每个更改或单击“检查”按钮,并触发对处理更改的方法的调用。

这是一个全python> = 3 tkinter跟踪研究示例:

# inputpanel.py derived and improved from my Coolprop GUI on github
#
from tkinter import *
import tkinter.ttk as ttk

class InputFrame(LabelFrame):
    #
    # This input frame creates Entries and selects for Variables
    # contained in a Dictionary structure. It traces the inputs 
    # and keeps the values updated according to the type of the value.
    # 
    # datadict needs at least the three dicts and the list below
    # for one key must be an entry in every dict
    # the list order is used for processing
    # You can pass a list order with only one field e.g. to init
    # and only this field will be processed
    #  
    # datadict={
    #             'verbose_names':{},
    #             'values':{},
    #             'callback_vars':{},
    #             'order':[],
    #             }
    # 
    # if a dict units is added to the datadict, the units will be displayed behind the entry widgets
    #

    def __init__(self, parent,cnf={}, title=None,datadict=None,order=None,frameborder=5, InputWidth=60,**kwargs):
        #
        LabelFrame.__init__(self, parent)
        #
        self.InputWidth=InputWidth
        if datadict :
            self.datadict=datadict
        else:
            self.datadict={
                'verbose_names':{},
                'values':{},
                'callback_vars':{},
                'order':[],
                }
        #
        if order :
            self.order=order
        else:
            self.order=self.datadict['order']
        #
        if title :
            self.IFrame = LabelFrame(parent, relief=GROOVE, text=title,bd=frameborder,font=("Arial", 10, "bold"))
        else:
            self.IFrame = LabelFrame(parent, relief=GROOVE,bd=frameborder,font=("Arial", 10, "bold"))
        #
        self.IFrame.grid(row=1,column=1,padx=8,pady=5,sticky=W)
        #
        self.InputPanel(self.IFrame)

    def InputPanel(self, PanelFrame, font=("Arial", 10, "bold")):
        '''
        '''
        #
        order_number=1
        for Dkey in self.order :
            if self.datadict['verbose_names'][Dkey] :
                #
                self.datadict['callback_vars'][Dkey].trace("w", lambda name, index, mode,
                                                         var=self.datadict['callback_vars'][Dkey],
                                                         value=self.datadict['values'][Dkey],
                                                         key=Dkey: self.InputPanelUpdate(var, key, value)
                                                         )
                Label(PanelFrame, text=self.datadict['verbose_names'][Dkey], font=font).grid(column=1, row=order_number, padx=8, pady=5, sticky=W)
                if type(self.datadict['values'][Dkey])==type(True):
                    Checkbutton(PanelFrame, width=self.InputWidth, variable=self.datadict['callback_vars'][Dkey], font=font).grid(column=2, row=order_number, padx=8, pady=5, sticky=W)
                else:
                    Entry(PanelFrame, width=self.InputWidth, textvariable=self.datadict['callback_vars'][Dkey], font=font).grid(column=2, row=order_number, padx=8, pady=5, sticky=W)
                try:
                    Label(PanelFrame, text=self.datadict['units'][Dkey],font=font).grid(column=3, row=order_number,padx=8,pady=5,sticky=W)
                except KeyError :
                    Label(PanelFrame, text='       ',font=font).grid(column=3, row=order_number,padx=8,pady=5,sticky=W)
            else :
                Label(PanelFrame, text=' ', font=font).grid(column=1, row=order_number, padx=8, pady=5, sticky=W)
            #
            order_number+=1

    def InputPanelUpdate(self, tkVar, key, value):
        #
        # Called on ever button press in an entry or click in a Checkbutton
        #
        if type(self.datadict['values'][key])==type(True):
            # For booleans we misuse a string because it is so easy
            self.datadict['values'][key] = True if tkVar.get()=='1' else False
        elif type(self.datadict['values'][key])==type(1): 
            # int
            self.datadict['values'][key] = int(tkVar.getint())
        elif type(self.datadict['values'][key])==type(1.1):
            # float
            self.datadict['values'][key] = float(tkVar.getdouble())
        else:
            # all the rest
            self.datadict['values'][key] = tkVar.get()

这是一个为sphinx-quickstart创建参数的对话框。它不完整,但如果您不需要自定义模板,它就可以工作。添加包含SPInputFrame类的InputPaneUpdate方法参数的打印命令,您将通过监视控制台输出快速了解跟踪...

# sphinx_quickstartpanel.py
#
from tkinter import filedialog
from tkinter import messagebox
from tkinter import *
import tkinter.ttk as ttk

from tkinter.simpledialog import Dialog

from .inputpanel import InputFrame

import os
#
import subprocess
#
from django.template.defaultfilters import slugify


class SpInputFrame(InputFrame):
    #
    # Add local functions to InputPanelUpdate
    #
    def InputPanelUpdate(self, tkVar, key, value):
        #
 

以上是关于Python / Tkinter:有没有办法不断“扫描”输入?的主要内容,如果未能解决你的问题,请参考以下文章

如何从Tkinter,Python中的Text小部件中移除焦点

python tkinter怎么让顶层界面有scrollbar

如何使用 Tkinter 按钮运行 Python 脚本?

Centos7/RedHat7 下 python3使用cx-freeze打包matplotlib程序遇到的问题和解决办法

Python tkinter 标签方向

单击后更新按钮的位置? (Tkinter Python GUI)