“运行时错误:从不同的单元调用 Tcl";tkinter 和线程 [英] "RuntimeError: Calling Tcl from different appartment" tkinter and threading

查看:116
本文介绍了“运行时错误:从不同的单元调用 Tcl";tkinter 和线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用线程和 tkinter (python 3.6) 来实现 GUI.
当我运行 GUIExecution.py 时,出现以下错误.
base_gui_class.py 中 self.root.mainloop() 上的RuntimeError: Calling Tcl from different appartment"
我是在类的基础上实现的,三个代码文件如下.
可执行文件是 GUIExecution.py.我花了很多时间试图修复错误,但我还没有修复它.
请多多指教.
另外,如果我在 python2 环境中运行以下代码,它可以正常工作而不会出错.

I want to implement GUI using threading and tkinter (python 3.6).
When I run GUIExecution.py, the following error occurs.
"RuntimeError: Calling Tcl from different appartment" on self.root.mainloop() in base_gui_class.py
I am implementing it on a class basis, and the three code files are as follows.
The executable file is GUIExecution.py. I spent a lot of time trying to fix the error, but I have not been able to fix it yet.
Please give a lot of advice.
Additionally, if I run the following code in a python2 environment, it works fine without error.

GUIExecution.py

GUIExecution.py

from base_gui_class import *

from base_class import *

speed = 1000
height = 500
width = 700

base_model = base_class()
gui = base_gui_class(base_model, speed, height, width)
base_model.visualize()

base_class.py

base_class.py

class base_class():
    genes = []
    dicLocations = {}
    gui = ''
    best = ''
    time = 0

    def __init__(self):
        pass

    def visualize(self):
        if self.gui != '':
            self.gui.start()

    def registerGUI(self, gui):
        self.gui = gui

base_gui_class.py

base_gui_class.py

import threading
import tkinter as tk
import math
import threading
import time
class base_gui_class(threading.Thread):
    root = ''
    canvas = ''
    speed = 0
    base_model = ''
def __init__(self, base_model, speed, h, w):
    threading.Thread.__init__(self)
    self.base_model = base_model
    base_model.registerGUI(self)

    self.root = tk.Tk()

    self.canvas = tk.Canvas(self.root, height=h, width=w)
    self.canvas.pack()

    self.root.title("Test")
    self.speed = 1 / speed
def run(self):
    self.root.mainloop()
def update(self):
    time.sleep(self.speed)
    width = int(self.canvas.cget("width"))
    height = int(self.canvas.cget("height"))
    self.canvas.create_rectangle(0, 0, width, height, fill='white')
def stop(self):
    self.root.quit()

推荐答案

Tk 的核心是单线程.它可以在多个线程中使用,但只能在 每个 线程中单独初始化它.在内部,它广泛使用特定于线程的变量来避免需要主锁(也就是说,它没有像大全局解释器锁那样的东西),但这意味着你不能作弊.任何初始化 Tk 上下文的线程都必须是与该 Tk 上下文交互的唯一线程.这包括加载 Tkinter 模块,因此您实际上只能在主线程中使用 Tkinter;解决这个问题是严肃的专家专用的东西.

To a very good first and second approximation, the core of Tk is single threaded. It can be used from multiple threads, but only by initialising it separately in each of those threads. Internally, it uses thread-specific variables extensively to avoid the need for major locking (that is, it has nothing like a big Global Interpreter Lock) but that means you must not cheat. Whatever thread initialises a Tk context must be the only thread that interacts with that Tk context. This includes loading the Tkinter module so you are effectively restricted to using Tkinter from your main thread only; working around this is serious expert's-only stuff.

我建议您通过使用队列(或以其他方式与临界区和条件变量互锁,但我发现队列在实践中更容易)向其发布事件来使您的工作线程对您的 GUI 进行更改.

I recommend that you make your worker threads make changes to your GUI by posting events to it using a queue (or otherwise interlock with critical sections and condition variables, though I find queues easier in practice).

这篇关于“运行时错误:从不同的单元调用 Tcl";tkinter 和线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆