0

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 threading 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')
    language = 'polish'
    polish_app.do_something()

def change_to_english():
    print('change to english')
    language = '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.

1
  • Callbacks should be functions or methods, not threads. Commented Jun 17, 2022 at 8:58

2 Answers 2

1

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.

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

2 Comments

Thank you! I have one concern, you wrote "every time func is called, a new thread is created", so if I will switch between version let's say 10 times, there will be 10 threads??
yes if they were not terminated. when the function executed by a thread is over (because the loop ends) the thread is terminated and deleted, so it's safe to assume only 2 threads will be ultimately running, one for the gui (main thread) and the other for backend/computation.
0

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()

Comments

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.