2

so I used threading so I can use a while loop inside Tkinter. the code as follows (the main idea is to have a intro screen, where you can press a botton and it opens up the game):

def start_game_thread():
threading.Thread(Target=root.after(3000,start_game()).start())

def searching_loop(start_point, goal):
while True:
    pure_goal = goal.current_url
    start_point_temp = start_point.current_url
    if pure_goal != goal.current_url:
        goal.get(pure_goal)
        print("I am the goal, you cannot change me")
    if start_point_temp != start_point.current_url:
        start_point_temp = start_point.current_url
        if goal.current_url == start_point.current_url:
            start_point.quit()
            goal.quit()



def start_game():
    start_point = exction()
    set_main_page(start_point, 'https://en.wikipedia.org/wiki/Main_Page')
    goal = exction()
    set_main_page(goal, 'https://en.wikipedia.org/wiki/Main_Page')
    clicker(start_point, 'Random article')
    clicker(goal, 'Random article')
    searching_loop(start_point, goal)

and here is the main :

root = Tk()
root.geometry("1920x1080")
EnterTheGame = Button(root, text="Enter The Game", command=lambda :start_game_thread())
EnterTheGame.place(x=960, y=540)
root.mainloop()

for some reason, it just doesn't seem to work, I am new to threading and any help can help me out :)

Update 1 :

def start_game():
    root.withdraw()
    start_point = execution()
    set_main_page(start_point, 'https://en.wikipedia.org/wiki/Main_Page')
    goal = execution()
    set_main_page(goal, 'https://en.wikipedia.org/wiki/Main_Page')
    clicker(start_point, 'Random article')
    clicker(goal, 'Random article')
    searching_loop(start_point, goal)
    root.deiconify()

after doing this, the problem is solved and the web browser runs right after I clicked the button with no problem, but the problem begins when I try to reopen my root after the game was complete.

[WinError 10061] No connection could be made because the target machine actively refused it

the screen does work but it keeps printing a lot of errors and also slow down my CPU.

update 2: adding a break to the searching_loop loop managed to solve the error problem, but the deiconify() retrieves me back to the intro screen

update 3: as @ TheLizzard suggested, I just changed my button using .config(text="") and it worked perfectly :)

Thank you A lot.

jeff style
  • 61
  • 1
  • 7
  • 1
    Look at `.after` scripts. You can implement a `.after` script loop. Also don't use `tkinter` from multiple threads. Some times `tkinter` can crash without even giving a traceback. – TheLizzard Jul 18 '21 at 19:06
  • 1
    I am still new to Tkinter, do you mind if we can discuss it in a private room or so? I don't want to spam the comments here. – jeff style Jul 18 '21 at 19:10
  • 2
    This is not a private consulting service. If you have questions, others have the same questions, and they can benefit by your discussion. ALL GUI actions must be from the main thread. If you have a button action that needs to run a long process, then have the button call a function, and have that function call the thread. In your case, you should call `root.after` in the main thread, and create your thread in THAT function. – Tim Roberts Jul 18 '21 at 19:14
  • 1
    There is nothing that I can say/do unless you give a minimal working example. Also try looking at [this](https://stackoverflow.com/a/29851899/11106801). Look at how they implemented a while loop there. – TheLizzard Jul 18 '21 at 19:15
  • 1
    @TimRoberts It doesn't have to be in the main thread. It just has to be in the same thread that you created the `Tk()` window. But that's just a small note – TheLizzard Jul 18 '21 at 19:16
  • @TimRoberts it's obvious to me that it's not a private consulting service, but spamming the comments with my questions seems like spamming to me. anyway - isn't it exactly what I'm doing? I am using the button to call a function and that function to call the thread, do you mind giving an example? Like I said I'm both new to Tkinter and Threading its still not solid to me(my first time running those modules) – jeff style Jul 18 '21 at 19:19
  • It's not spamming if you're asking relevant questions. The code you show here never calls `root.mainloop()`, so that must not be all there is. – Tim Roberts Jul 18 '21 at 19:25
  • @TimRoberts sorry It was deleted for some reason, Updated it now :) – jeff style Jul 18 '21 at 19:27
  • There is no point to starting a thread that will only start a `.after` script. `.after` scripts run in the same thread as where you called `.mainloop()`. Also another thing: your brackets are really messed up there. I think you should check out [this](https://stackoverflow.com/q/5767228/11106801) problem. – TheLizzard Jul 18 '21 at 19:34
  • 1
    @jeffstyle Are you sure that the `while True` loop has the correct logic? You said that the CPU usage when up a lot. That might be because the `while True` loop isn't stopping and is taking up all of your computer's resources. – TheLizzard Jul 18 '21 at 20:18
  • I can't believe saying this But adding a simple break solves the problem! but there is a slight problem, with.deiconify(), it retrieves my back to the intro screen, is there any way for it to display a different screen? (I want it to display a congratulations screen :)) – jeff style Jul 18 '21 at 20:33
  • If you have access to all of the widgets' variables, you can call `.destroy()`. If you don't you can just use: `for widget in root.winfo_children(): widget.destroy()`. Then you can create the new widgets for the `congratulations screen`. – TheLizzard Jul 18 '21 at 20:38
  • but if I wont be able to make a restart button if I am correct – jeff style Jul 18 '21 at 20:54
  • 1
    @jeffstyle What exactly do you want the *congratulations screen* to look like? Does it have any widgets in common with your main screen? If you want to remove a widget, use `.destroy()`. If you want to change a parameter like `text` on a widget, use ``. You can also create new widgets. I don't see any problems with it? – TheLizzard Jul 18 '21 at 20:58
  • the widget. config was the best answer! thank you so much! – jeff style Jul 18 '21 at 21:04
  • 1
    @jeffstyle Does that fully answer all of your questions now? – TheLizzard Jul 18 '21 at 21:05
  • indeed , I have an other thing i am trying to solve tho, But I think I will need a different query – jeff style Jul 18 '21 at 21:06
  • Believe it or not, you can emulate most while loops with `root.after()` – Delrius Euphoria Jul 18 '21 at 23:32

1 Answers1

-1

I have not yet run your code, but this should get you closer. Remember when you are passing a function to thread, you don't want to CALL the function. When you say threading.Thread(Target=start_game()), that immediately calls the "start_game" function (in the current thread), and passes its return value to threading.Thread.

def start_game_button():
    root.after(3000,start_game_thread)
def start_game_thread():
    threading.Thread(Target=start_game).start()
...
EnterTheGame = Button(root, text="Enter The Game", command=start_game_button)
Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
  • 1
    It would be a bad idea to add `daemon=True` inside the `Thread(...)`. Also shouldn't it be `target` not `Target`? – TheLizzard Jul 18 '21 at 19:36
  • it didn't work for some reason, I don't mind "destroying" the root window after I press the button because I'm opening a web browser window, but I do want to "revive" the window once you managed to achieve the goal in the web browser – jeff style Jul 18 '21 at 20:03
  • 1
    @jeffstyle If you call `root.withdraw()` it will hide the window (so it isn't going to become unresponsive). Then you call `root.deiconify()` to show the window again. – TheLizzard Jul 18 '21 at 20:10
  • Ill update the code again so you can see what I did, for some reason I am getting a really bizarre and long error – jeff style Jul 18 '21 at 20:13