{"id":4684,"date":"2024-10-01T11:10:33","date_gmt":"2024-10-01T10:10:33","guid":{"rendered":"https:\/\/ibex.tech\/python\/?p=4684"},"modified":"2025-12-18T03:30:12","modified_gmt":"2025-12-18T03:30:12","slug":"use-tkinter-without-mainloop","status":"publish","type":"post","link":"https:\/\/ibex.tech\/python\/gui\/tkinter-tk-gui-toolkit\/basic-setup\/use-tkinter-without-mainloop","title":{"rendered":"Use tkinter without mainloop"},"content":{"rendered":"\n<p>Typically tkinter is used with its own main loop that takes over the main thread. You need to run your app code off its callbacks or in a different thread. But you can also call tkinter to update from your own main loop without it taking over the thread.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">ap_gui.py<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code>import tkinter as tk\n\n#GLOBAL VARIABLES\nroot = None\nlblStatus = None\ntxtEntryBox1 = None\n\n\n######################\n##### USING THIS #####\n######################\n#\n##----- INITIALISE THE GUI -----\n#ap_gui.gui_init()\n#\n##----- UPDATE THE GUI -----\n#ap_gui.gui_update()\n#if ap_gui.has_gui_been_closed():\n#    print(\"Exiting main loop\")\n#    break\n#\n##----- UPDATE THE GUI STATUS TEXT -----\n#ap_gui.gui_update_status_text(\"Running task...\")\n\n\n\n#************************************************\n#************************************************\n#********** CLOSE ROOT WINDOW CALLBACK **********\n#************************************************\n#************************************************\n#User has clicked the windows close button\n#We use this so tat we can set root to None and then test that from our main app to see if we need to close the app\ndef callback():\n    global root\n    \n    root.destroy()\n    root = None\n\n\n#****************************************\n#****************************************\n#*********** BUTTON 1 CLICKED ***********\n#****************************************\n#****************************************\ndef btnButton1Clicked():\n    global lblStatus\n    global txtEntryBox1\n\n    EnteredText = \"You entered: \" + txtEntryBox1.get()\n    lblStatus.configure(text = EnteredText)\n\n\n\n#********************************\n#********************************\n#********** INITIALISE **********\n#********************************\n#********************************\ndef gui_init():\n    global root\n    global lblStatus\n    global txtEntryBox1\n\n    root = tk.Tk()                                     #Create the root window\n    \n    root.protocol(\"WM_DELETE_WINDOW\", callback)     #Create callback for if the window is closed\n\n    root.title(\"My app\")\n    root.geometry('350x200')                        #Set the window size width x height\n    root.resizable(False, False)   #Lock size\n    root.minsize(350, 200)        #Enforce minimum\n    root.maxsize(350, 200)        #Enforce maximum\n\n    #Create status label\n    lblStatus = tk.Label(root, text = \"Idle\")\n    lblStatus.place(x=5, y=170)\n\n    #Create a Entry Field\n    txtEntryBox1 = tk.Entry(root, width=10)\n    txtEntryBox1.place(x=5, y=5)\n\n    #Create a button\n    btnButton1 = tk.Button(root, text = \"Button 1\", fg = \"red\", command=btnButton1Clicked)\n    btnButton1.place(x=5, y=30)\n\n\n    #Execute Tkinter\n    #root.mainloop()            #&lt;&lt;&lt;&lt;This stalls execution of this thread here and hands it to the GUI until the window is closed\n    root.update()               #For this app we are calling update in our main loop instead\n    \n\n\n#************************************\n#************************************\n#********** UPDATE THE GUI **********\n#************************************\n#************************************\n#This needs to be called reguarly from the main loop to keep the GUI responsive\ndef gui_update():\n    global root\n    \n    root.update()\n    \n    #Note there is also this function that can be useful in some situations as its less intesive than update()\n    #root.update_idletasks()\n    \n    \n    \n#**************************************************\n#**************************************************\n#********** HAS ROOT WINDOW BEEN CLOSED? **********\n#**************************************************\n#**************************************************\n#Call this from the apps main loop to see if we need to shutdown the app\ndef has_gui_been_closed():\n    if root == None:\n        return True\n    else:\n        return False\n        \n    \n#********************************************\n#********************************************\n#********** UPDATE OUR STATUS TEXT **********\n#********************************************\n#********************************************\ndef gui_update_status_text(StatusText):\n    global lblStatus\n    \n    lblStatus.configure(text = StatusText)\n    gui_update()\n\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Typically tkinter is used with its own main loop that takes over the main thread. You need to run your app code off its callbacks or in a different thread. But you can also call tkinter to update from your own main loop without it taking over the thread. ap_gui.py<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[371],"tags":[],"class_list":["post-4684","post","type-post","status-publish","format-standard","hentry","category-basic-setup"],"_links":{"self":[{"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/posts\/4684","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/comments?post=4684"}],"version-history":[{"count":6,"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/posts\/4684\/revisions"}],"predecessor-version":[{"id":4996,"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/posts\/4684\/revisions\/4996"}],"wp:attachment":[{"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/media?parent=4684"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/categories?post=4684"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ibex.tech\/python\/wp-json\/wp\/v2\/tags?post=4684"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}