【问题标题】:Separating Tkinters GUI and control of the application分离 Tkinter GUI 和应用程序的控制
【发布时间】:2020-02-03 14:24:01
【问题描述】:

1) 我的目标是什么: 我正在创建一个应用程序,它应该每 60 秒从 ModBusServer 读取一次数据,将这些数据附加到 Graphs 中,然后在应用程序关闭时将数据保存到 excel 文件中。

网站说明: 从 ModBusServer 读取数据并将其附加到图形的过程应在按下开始按钮后开始。 并在按下停止按钮或 ModBusServer 发送停止请求后结束。

2) 我目前所拥有的: 我以“GUI_komora”类的形式创建了没有任何重大问题的 GUI。 那里的一切都很好。

3) 问题是什么: 但是现在我迷失了如何处理“每 60 秒读取一次数据”,以及如何控制应用程序。

我对线程进行了一些研究,但我仍然对如何在我的应用程序中实现这一点感到困惑。 我在这个tutorial 中学习了如何让函数同时运行。 还有如何使用这个question每隔几秒调用一次函数。

但它们都没有帮助我学习如何控制应用程序的整体流程。

如果您可以将我重定向到某个地方或告诉我更好的方法,我会非常高兴。

我的一些代码:

from tkinter import *

from GUI_komora import GUI

root = Tk()
my_gui = GUI(root) #my GUI class instance

#main loop
root.mainloop()

"""

How do I achieve something like this???

whenToEnd = False
while whenToEnd:
    if step == "Inicialzation":
        #inicializace the app

    if step == "ReadData":
        #read data every 60 seconds and append them to graphs

    if step == "EndApp"
        #save data to excel file and exit app
        whenToEnd = True 


"""

【问题讨论】:

  • 读取数据的代码执行需要多长时间?它会运行几秒钟,还是只运行几毫秒?答案将有助于确定适当的解决方案。如果它只是几百毫秒或更短,则不需要线程。
  • 大约在一秒钟左右。但有时可能会更长,因为 modbuserver 是通过以太网连接的。
  • 如何在不使用线程的情况下解决这个问题?我真的不知道...:/

标签: python-3.x multithreading tkinter


【解决方案1】:

这是一个循环示例(在您的情况下每 60 秒)做出决定并将决定的结果推送到 tkinter GUI:https://github.com/shorisrip/PixelescoPy/blob/master/base.py 零件:

  1. 主线程 - 启动 tkinter 窗口
  2. 控制线程 - 读取一些数据并决定在 GUI 中显示什么
  3. GUI 类 - 有一个方法“add_image”,它接受输入图像并显示在 GUI 上。(可能在您的情况下是 add_data_to_graph)。控制线程每次都会调用此方法。

片段:

def worker(guiObj, thread_dict):
    # read some data and make decision here
    time.sleep(60)
    data_to_show = <outcome of the decision>
    while some_logic:
        pictureObj = Picture(chosen, timer)
        pictureObj.set_control_thread_obj(thread_dict["control_thread"])
        guiObj.set_picture_obj(pictureObj)
        pictureObj.display(guiObj)
        # do post display tasks
    guiObj.quit_window()

# Keep GUI on main thread and everything else on thread
guiObj = GuiWindow()
thread_list = []
thread_dict = {}
thread_for_image_control = threading.Thread(target=worker, args=(guiObj,
                                                                 thread_dict))
thread_dict["control_thread"] = thread_for_image_control
thread_list.append(thread_for_image_control)
thread_for_image_control.start()
guiObj.run_window_on_loop()
# thread_for_image_control.join()

图片类代码:

class Picture:
    def __init__(self, path, timer):
        self.path = path
        self.timer = timer
        self.control_thread_obj = None

    def set_control_thread_obj(self, thread_obj):
        self.control_thread_obj = thread_obj

    def display(self, guiObj):
        image_path = self.path
        guiObj.add_image(image_path)
        time.sleep(self.timer)

GUI类代码

class GuiWindow():
    def __init__(self):
        self.picture_obj = None
        self.root = Tk()
        self.image_label = None
        self.image = None
        self.folder_path = None
        self.timer = None
        self.root.protocol("WM_DELETE_WINDOW", self.exit_button)

    def add_image(self, image_path):
        resized_img = self.resize(image_path)
        image_obj = ImageTk.PhotoImage(resized_img)
        image_label = Label(self.root, image=image_obj,
                            height=resized_img.height,
                            width=resized_img.width)
        self.image = image_obj # DO NOT REMOVE - Garbage collector error
        if self.image_label is not None:
            self.remove_image()
        image_label.grid(row=0, column=0, columnspan=3)
        self.image_label = image_label

根据我的控制循环线程,我正在更改 tkinter GUI 的图像(在您的情况下是图形数据)。 这有帮助吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    • 2013-07-13
    相关资源
    最近更新 更多