Python Forum
TKinter restarting the mainloop when button pressed
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
TKinter restarting the mainloop when button pressed
#1
Hello. I have a complex program running in Python and I want to be able to interrupt it and restart the mainloop at any time I want.

I have made a simplified example of my program which illustrates my problem:

import tkinter as tk
from tkinter import Button,Entry,Canvas,Label,ttk


class Application(tk.Frame): 
    def __init__(self,master=None):
        super().__init__(master)
        self.master = master
    def Create_canvas(self,canvas_width,canvas_height):
        global canvas#described as global because used outside class
        canvas = tk.Canvas(self.master,bg='papaya whip',width=canvas_width,height=canvas_height)
       
    def Application_Intro(self):
        print("starting new app")
        restart_program_button = tk.Button(canvas, text="Restart_program",font='Helvetica 12 bold', width=20, height=2, command =self.Restart)
        start_program_button = tk.Button(canvas, text="Start_program",font='Helvetica 12 bold', width=20, height=2, command =self.Start_program)     
        canvas.create_text(960,20,text="MY PROGRAM",font='Helvetica 16 bold')
        canvas.create_window(710,300,window = restart_program_button)
        canvas.create_window(710,500,window = start_program_button)
        canvas.pack()
        master.mainloop()
        
        
        
    def Start_program(self):
        print("Program start")
        master.after(1000,self.Start_program)
        
    def Restart(self):
        print("HERE I WANT TO INTERRUPT START PROGRAM AND RETURN TO IDLE STATE")
        #WHAT TO DO IN THIS FUNCTION TO GO BACK TO INITIAL MAINLOOP STATE??
        return


master = tk.Tk()
app = Application(master=master)
app.Create_canvas(1920,1080)

app.Application_Intro()    
        
        
The program above will create a simple GUI with 2 buttons. Initially, the program will IDLE and wait for user to start an Application. When application is started, it will call itself recursively ( checking various states and doing other complex operations in my real program), however, I Want to be able to interrupt this operation and stop it at any time. That is why I have created a button "RESTART" which should restart the program back to its initial state where I am waiting for user to start and application again. How can I return out of the Start_program function after the button is pressed?


https://ibb.co/djMd5TW

Can someone help me understand what needs to happen in Restart function to get back to idle state in my mainloop
Reply
#2
This sounds like a bad idea. What are you trying to achieve?
Reply
#3
(Jan-22-2021, 12:31 PM)deanhystad Wrote: This sounds like a bad idea. What are you trying to achieve?

Why is that a bad idea? I simply need to be able to stop an operation whilst is running. I am developing a system simmilar to pick to light where user scans a barcode and then the sequence of LED's will turn ON indicating what items to pick. The program is designed in a recursive to make use of a tkinter mainloop and after method, it also ensures that the user completes the operation before starting a new one. However, if there is something wrong happening, I must be able to have a way to restart a task to its initial state which may not happen often but I still require to have contorl over that. I dont want to restart the whole tkitner script everytime? Surely there should be a simple way how to achieve that
Reply
#4
A GUI application runs all the time, though most of the time it is doing nothing but waiting for the user to click a mouse button or press a key. The windows or Linux desktop is a GUI. Do you stop and restart windows each time you want to run a program?

GUI's are event driven, and the user provides the events. I would expect your GUI to have some code that gets called when a button is pressed, and when the event handler code completes the GUI goes back to waiting for the next event. If you need to disable the button while the event is being processed, that is easily done. But the GUI is running all the time. No recursion. No stopping and restarting. Not even a loop as far as you are concerned.

If you already have code that does the complicated task you could write a very simple GUI application that runs your complicated application as a subprocess.
Reply
#5
(Jan-25-2021, 07:13 AM)deanhystad Wrote: A GUI application runs all the time, though most of the time it is doing nothing but waiting for the user to click a mouse button or press a key. The windows or Linux desktop is a GUI. Do you stop and restart windows each time you want to run a program?

GUI's are event driven, and the user provides the events. I would expect your GUI to have some code that gets called when a button is pressed, and when the event handler code completes the GUI goes back to waiting for the next event. If you need to disable the button while the event is being processed, that is easily done. But the GUI is running all the time. No recursion. No stopping and restarting. Not even a loop as far as you are concerned.

If you already have code that does the complicated task you could write a very simple GUI application that runs your complicated application as a subprocess.


OKay but how do you suggest solving this problem? I still need to be able to stop a task if I want to? How would I rewrite my GUI then?

When the user presses the button, it executes a function which waits for another user input and etc but I must be able to return to its initial state "idle" state if I want to.

You say "and when the event handler code completes the GUI goes back to waiting for the next event" What if the event not complete I jsut want to cancel it? According to that logic, when I start some task in windows, I cannot cancel it unless I complete it but thats not true. Every windows task has an cross at the top right corner and you can close it whenever you want to even if you havent completed the task, closing the task does not shut down my computer, it just closes that task, and thats what I need
Reply
#6
I have found a way how to go back to idle state with the following code:

import tkinter as tk
from tkinter import Button,Entry,Canvas,Label,ttk
import concurrent.futures




class Application(tk.Frame): 
    def __init__(self,master=None):
        self.master = master
        
    def Create_canvas(self,canvas_width,canvas_height):
        global canvas#described as global because used outside class
        canvas = tk.Canvas(master,bg='papaya whip',width=canvas_width,height=canvas_height)
       
    def Application_Intro(self):
        print("starting new app")
        restart_program_button = tk.Button(canvas, text="Restart_program",font='Helvetica 12 bold', width=20, height=2,
                                           command =self.Restart)
        start_program_button = tk.Button(canvas, text="Start_program",font='Helvetica 12 bold', width=20, height=2,
                                         command =self.Start_program)     
        canvas.create_text(960,20,text="MY PROGRAM",font='Helvetica 16 bold')
        canvas.create_window(710,300,window = restart_program_button)
        canvas.create_window(710,500,window = start_program_button)
        canvas.pack()
        master.mainloop()
        
        
        
    def Start_program(self):
        global restart
        print("Program start,checking if restart is required")
        if(restart == 1):
            print("GOING BACK TO IDLE STATE")
            restart = 0
            return
        else:
            master.after(1000,self.Start_program)
        
    def Restart(self):# IF TASK STARTED SET RESTART =1, IF NOT restart devices and refresh app
        global restart
        restart = 1
        print("HERE I WANT TO INTERRUPT START PROGRAM AND RETURN TO IDLE STATE")
        print("REFRESH GUI ELEMENTS, DESTROY ANY WIDGETS IF CREATED")
        print("RESET THE GLOBAL VARIABLE VALUES")

        
        #master.mainloop()
        #WHAT TO DO IN THIS FUNCTION TO GO BACK TO INITIAL MAINLOOP STATE??
        return

def main():
    global restart
    restart = 0

main()
master = tk.Tk()
app = Application(master=master)
app.Create_canvas(1920,1080)

app.Application_Intro()    
        
        
However, I do not think that this is the best way to achieve what I want. It works as expected, I have setup a global variable "restart" which I set to 1 when restart button is pressed. During the task which is calling itself recursively, I am checking whether restart is 1, if so, restart the task and go to idle state, if not, continue doing the same task.
I still think that this is not the best way to acomplish. If anyone got any other suggestions let me know! I would love to improve it
Reply
#7
Normally you enter all your information first, then perform the action that starts processing.

Interrupting the task depends on the task. If your processing can be broken into small pieces maybe you can do the processing within the context of the GUI. Another option is to perform a task in a a subprocess that is started by the GUI. The GUI would monitor the progress of the task and enable running another task when the task is complete. The GUI could provide a button for stopping the task.

What does your program do?
Reply
#8
The task is quite complex and is based on pick to light idea. The scans a barcode and starts a task. I then need to check various states of remote/devices, read database and etc.. The started task is monitoring whether it has received any response from the remote devices, if so, continue with the task, if not, keep checking for input.. There are more things happening at the same time but either way, I must be able to cancel the current task completely and start over again. Normally, that would not happen since user would complete a task but in case of some error or something else unexpected happening, user can just restart a task , scan a new barcode and continue doing his thing.

From what I read about muliprocessing, I am not sure whether its best option here since I am not sure if I can close or cancel the process unless its finished?
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] TKinter Remove Button Frame Nu2Python 8 816 Jan-16-2024, 06:44 PM
Last Post: rob101
  tkinter - touchscreen, push the button like click the mouse John64 5 746 Jan-06-2024, 03:45 PM
Last Post: deanhystad
  Centering and adding a push button to a grid window, TKinter Edward_ 15 4,378 May-25-2023, 07:37 PM
Last Post: deanhystad
  Can't get tkinter button to change color based on changes in data dford 4 3,363 Feb-13-2022, 01:57 PM
Last Post: dford
  Creating a function interrupt button tkinter AnotherSam 2 5,416 Oct-07-2021, 02:56 PM
Last Post: AnotherSam
  [Tkinter] Have tkinter button toggle on and off a continuously running function AnotherSam 5 4,919 Oct-01-2021, 05:00 PM
Last Post: Yoriz
  tkinter showing image in button rwahdan 3 5,520 Jun-16-2021, 06:08 AM
Last Post: Yoriz
  tkinter button image Nick_tkinter 4 3,959 Mar-04-2021, 11:33 PM
Last Post: deanhystad
  tkinter python button position problem Nick_tkinter 3 3,486 Jan-31-2021, 05:15 AM
Last Post: deanhystad
  tkinter touchscreen scrolling - button press makes unwanted scrolling nanok66 1 3,923 Dec-28-2020, 10:00 PM
Last Post: nanok66

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020