【问题标题】:I'm using threading, so why get my gui all time frezzed O.o我正在使用线程,所以为什么让我的 gui 一直被冻结 O.o
【发布时间】:2019-04-02 15:24:13
【问题描述】:

好吧,我几天前就遇到了问题,有人帮我踩踏,但我的代码真的很丑(我对编码完全陌生)现在我试图以更聪明的方式让它变得更好,但现在我的 gui 一直都在发抖. 我试着像我上一个代码那样做,但这次它不起作用。 这次我该怎么办我无法理解但想理解它。 一些有用的提示和技巧? 还是更智能、更快、更强大的更好方法,或者 mybae the gui more Beautyfule?

import time
import sys
from tkinter import *
import threading


root = Tk()

root.geometry("600x400")


global start
start = 1


def startUp():
    user_input()
    thr = threading.Thread(target=user_input)
    thr.start()



def user_input():
    global nameInput
    global start
    nameInput = textBox.get("1.0","end-1c")
    start = 0
    if start < 1:
        while True:
            apex = ApexLegends("APIKey")
            player = apex.player(nameInput)
            print("Gesamt Kills: " + player.kills + "\n" + 'Gesamt Damage: ' + player.damage)
            time.sleep(3)
    else:
        print("stop")


anleitung=Label(text="Gib einen Spielernamen ein und drücke Start")
anleitung.pack()

textBox=Text(root, height=1, width=30)
textBox.pack()

startButton=Button(root, height=1, width=10, text="Start", command=lambda:startUp())
startButton.pack()



【问题讨论】:

  • 什么是ApexLegends?它是一个类还是一个函数?当您执行apex = ApexLegends("APIKey") 时,是否需要很长时间(其中“long”表示“大于 300 毫秒左右)?
  • 它是对一个库的访问,旨在更轻松地使用 Game Apex Legends 的 api
  • 我还是不知道那是什么意思。它是类还是函数调用?它是快还是慢?如果速度很快,就没有理由使用线程。
  • 我真的不知道看看这个会有助于找出它吗? prntscr.com/n6hjig

标签: python python-3.x tkinter


【解决方案1】:

Tkinter 并非设计为由多个线程访问。这是一个对 tcl & tk 的工作原理(tkinter 所依赖的库)有非常深刻理解的人的一个很好的答案,解释了为什么会这样。

Callback to python function from Tkinter Tcl crashes in windows

这是该答案中两段中的第一段:

每个 Tcl 解释器对象(即知道如何运行 Tcl 过程的上下文)只能从创建它的 OS 线程安全地使用。这是因为 Tcl 没有像 Python 那样使用全局解释器锁,而是广泛使用线程特定的数据来减少内部所需的锁数量。 (编写良好的 Tcl 代码可以利用这一点在合适的硬件上进行非常大的扩展。)

【讨论】:

  • 信息链接。我知道从不同的线程修改小部件是个坏主意,但我不确定像Text.get 这样的只读操作是否危险。 Danal 似乎没有区分变异和非变异,所以我想谨慎的做法是避免两者。
【解决方案2】:
def startUp():
    user_input()
    thr = threading.Thread(target=user_input)
    thr.start()

这看起来不对。您在主线程和子线程中都调用了user_input()。如果您只想让它在子线程中运行,请不要第一次调用它。

def startUp():
    thr = threading.Thread(target=user_input)
    thr.start()

【讨论】:

    【解决方案3】:

    嗨@Trason,我已经使用过你的代码,我建议采用 oo 方法。

    在下面的代码中,我尝试使功能脚本适应您的代码。

    首先我使用了一个变量作为

    self.nameInput = tk.IntVar()

    将用户输入存储在

    tk.Entry(w, bg='white', textvariable=self.nameInput).pack()

    我使用的是 Entry 小部件而不是 Text,但它应该是相同的。

    另外我使用一个类来管理线程的启动和停止操作。

    看,我用'check'更改了你的'start'变量,因为start是保留字

    在python线程模块中。

    我尝试重新创建您的代码的功能。

    尝试导入并使用您的 ApexLegends。

    import tkinter as tk
    
    import threading
    import queue
    import datetime
    import time
    
    class MyThread(threading.Thread):
    
        def __init__(self, queue,nameInput):
            threading.Thread.__init__(self)
    
            self.queue = queue
            self.nameInput = nameInput
            self.check = True
    
        def stop(self):
            self.check = False
    
        def run(self):
    
            while self.check:
                # apex = ApexLegends("APIKey")
                #player = apex.player(self.nameInput.get())
                x = "Gesamt Kills: " + "player.kills" + "\n" + 'Gesamt Damage: ' + "player.damage"+ "\n"
                s = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                msg = "{} datetime: {} nameInput {}".format(x,s,self.nameInput.get())
                time.sleep(3)
                self.queue.put(msg)
    
    
    class App(tk.Frame):
    
        def __init__(self,):
    
            super().__init__()
    
            self.master.title("Hello World")
            self.master.protocol("WM_DELETE_WINDOW",self.on_close)
    
            self.queue = queue.Queue()
    
            self.my_thread = None
            self.nameInput = tk.IntVar()
    
            self.init_ui()
    
        def init_ui(self):
    
            self.f = tk.Frame()
    
            w = tk.Frame()
    
            tk.Label(w, text = "Gib einen Spielernamen ein und drücke Start").pack()
            tk.Entry(w, bg='white', textvariable=self.nameInput).pack()
    
            w.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
    
            w = tk.Frame()
    
            tk.Button(w, text="Start", command=self.startUp).pack()
            tk.Button(w, text="Stop", command=self.stop_thread).pack()
            tk.Button(w, text="Close", command=self.on_close).pack()
    
            w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=0)
            self.f.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
    
        def startUp(self):
    
            if (threading.active_count()!=0):
    
                self.my_thread = MyThread(self.queue,self.nameInput)
                self.my_thread.start()
                self.periodiccall()
    
        def stop_thread(self):
    
         if(threading.active_count()!=1):
             self.my_thread.stop()
    
    
        def periodiccall(self):
    
            self.checkqueue()
            if self.my_thread.is_alive():
                self.after(1, self.periodiccall)
            else:
                pass
    
        def checkqueue(self):
            while self.queue.qsize():
                try:
                    ret = self.queue.get(0)
                    msg = "%s"%(ret)
                    print(msg)
                except queue.Empty:
                    pass                    
    
        def on_close(self):
            if(threading.active_count()!=0):
                if self.my_thread is not None:
                    self.my_thread.stop()
    
            self.master.destroy()
    
    if __name__ == '__main__':
        app = App()
        app.mainloop()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-14
      • 1970-01-01
      • 2020-01-05
      • 1970-01-01
      • 2015-11-21
      相关资源
      最近更新 更多