Home > Back-end >  python multithreading problem with tkinter
python multithreading problem with tkinter

Time:06-17

I have quite complex app with two, separated language version. I'm trying to make fluent switch between two versions. I'm trying to make it with multi threding to maintain tkinter GUI.

import time
import threading
from tkinter import *

language = ''

class PolishApp:
    def _init__(self):
        pass
    def do_something(self):
        while language == 'polish':
            print('working in polish...')
            time.sleep(0.5)

class EnglishApp:
    def _init__(self):
        pass

    def do_something(self):
        while language == 'english':
            print('working in english...')
            time.sleep(0.5)

def change_to_polish():
    print('change to polish')
    langauge = 'polish'
    polish_app.do_something()

def change_to_english():
    print('change to english')
    langauge = 'english'
    english_app.do_something()

english_app = EnglishApp()
polish_app = PolishApp()
window = Tk()
window.title("choose language")
window.geometry('350x200')
btn = Button(window, text="ENGLISH", command=threading.Thread(target=change_to_english).start())
btn2 = Button(window, text="POLISH", command=threading.Thread(target=change_to_polish).start())
btn.grid(column=1, row=0)
btn2.grid(column=2, row=0)
print(language)
window.mainloop()

When I run the code, it immediately executes functions: change_to_polish(), change_to_english() and do nothing when I click buttons.

output

Does anybody know how it is possible? I probably messed something up with multi threading concept.

CodePudding user response:

there are multiple problems with your program, starting from this line

btn = Button(window, text="ENGLISH", command=threading.Thread(target=change_to_english).start())

the command=threading.Thread(target=change_to_english).start() the right part of the expression is evaluated first, which calls the function, then its return is passed as the command argument, which is not what you want. you want the function itself to be the argument, not its return, so you should've removed the () brackets at the end so that the function itself is passed as an argument, instead of its return ..... which will still not work as expected because only one instance of threading.Thread is created, and therefore the function will only work once.

what you instead want is whenever the button is pressed, a new thread would be created to execute this, so you should use lambda functions to do this

btn = Button(window, text="ENGLISH", command=lambda: threading.Thread(target=change_to_english).start())

which is equivalent to:

def func():
    threading.Thread(target=change_to_english).start()
btn = Button(window, text="ENGLISH", command=func)

this would work as intended, because each time func is called, a new threading.Thread is created, but there's also another typo keeping your program from functioning as you want, which is langauge and language are two different variables and are local to the function in which they are called, so instead you should have them named the same, and also make them both global at the start of the functions using them so that they aren't local to the functions which use them.

CodePudding user response:

As "Ahmed AEK" said there are multiple problems in there. I've come up with the idea where both Apps are running paralell and however the language changes the App does it too.

import time
import threading
from tkinter import *

class PolishApp:
    def _init__(self):
        pass
    def do_something(self):
        while True:
            if language == 'polish':
                print('working in polish...')
                time.sleep(0.5)

class EnglishApp:
    def _init__(self):
        pass

    def do_something(self):
        while True:
            if language == 'english':
                print('working in english...')
                time.sleep(0.5)

def change_to_polish():
    global language
    print('change to polish')
    language = 'polish'

def change_to_english():
    global language
    print('change to english')
    language = 'english'

language = ''
EN = EnglishApp()
PL = PolishApp()

thread_english = threading.Thread(target=EN.do_something)
thread_english.start()
thread_polish = threading.Thread(target=PL.do_something)
thread_polish.start()

english_app = EnglishApp()
polish_app = PolishApp()
window = Tk()
window.title("choose language")
window.geometry('350x200')
btn = Button(window, text="ENGLISH", command=change_to_english)
btn2 = Button(window, text="POLISH", command=change_to_polish)
btn.grid(column=1, row=0)
btn2.grid(column=2, row=0)
print(language)
window.mainloop()
  • Related