0

I create a simple window with tkinter and start it as thread to keep the main program running next to the window. This is a shortened version of it:

import tkinter as tk
import threading

class mainWindow(threading.Thread):
    def __init__(self, winWidth=500, winHeight=300):
        threading.Thread.__init__(self)
        self.winWidth = winWidth
        self.winHeight = winHeight

        # Save all drawn objects, to move or delete them later
        self.bricks = []

        self.start()                    #start thread

    def run(self):
        # parent object for all windows
        self.master = tk.Tk()
        self.master.protocol("WM_DELETE_WINDOW", self.callback)
        self.show()

    def callback(self):
        self.master.quit()

    # Initialize everything important
    def show(self, tileSize=10):
        # create main window
        self.w = tk.Canvas(
                self.master,
                width=self.winWidth,
                height=self.winHeight,
                background="white")

        self.w.pack()

        # draw brick
        color = "gray49"
        posX = 200
        posY = 100
        self.bricks.append(self.w.create_rectangle(posX, posY, posX+20, posY+20, fill=color))
        tk.mainloop()

    def move_brick(self, x,y):
        self.w.move(self.brick, x, y)


mainWindow = mainWindow()
mainWindow.move_brick(100,100)

When I run the shown code the window opens correctly, but when I try to move the rectangle with move_brick(...) I get this error:

AttributeError: 'mainWindow' object has no attribute 'w'

Why can't the object find my Canvas w?

1 Answer 1

1

You probably have a race condition, which is common for threaded applications. The main thread is likely calling move_brick before the worker thread has a chance to create the widget.

You can probably see this happening if you add print statements right before and after creating the widget, and in your move_brick function.

Even if you fix this, this code likely won't work because all tkinter code needs to run in a single thread. Creating the GUI in one thread and calling move_brick in another thread is not the right way to use tkinter.

Sign up to request clarification or add additional context in comments.

3 Comments

I am new to tkinter and use it just to debug some processes. How could I achieve to change the GUI from my main program?
I checked with the print statements, if I call move_brick()late enough after initializing the window, it works fine.
@Jonas: re "How could I achieve to change the GUI" depends on what you're really trying to do. If all you're doing is moving a few hundred bricks around you don't need threads. Tkinter has a method (after) which can be used to run things periodically, such as moving items on the screen.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.