How do I continue after the mainloop() in Tkinter? - python

I am making a Non-malicious Twitch TV bot that runs a few commands in chat. I have been using the bot for 2 months and decided to create a small GUI for basic changes to variables whilst it is running. Both the GUI and the Bot work fine separately but I am having issues making them work together.
I have used Tkinter to create the GUI and it requires a Loop to make the window remain open. This loop therefore stops the rest of the code continuing on and launching the bot. I need to work out how to keep the loop running but also continuing on to the rest of the Bot and run that behind the GUI.
This is the start of the Bot where it launches the GUI;
app = Geekster_Bot_GUI(None)
app.title('Geekster_Bot')
app.geometry('450x100')
app.mainloop()
It then continues to the bot connecting to the IRC.
How do I continue after the mainloop()?

You can use threading or multiprocessing. Simple example:
import Tkinter
import threading
def create_frame():
MessFrame = Tkinter.Tk()
MessFrame.geometry('800x400+200+200')
MessFrame.title('Main Frame')
Framelabel = Tkinter.Label(MessFrame, text='Text Here', fg= 'red')
Framelabel.place(x=10,y=10)
MessFrame.mainloop()
t1 = threading.Thread(target=create_frame)
t1.start()
#continue
print 1234
But...it's generally best to keep the GUI in the main thread.

Related

Running non Tkinter code along side Tkinter code

I am writing a server/client encrypted chat service and have decided to spruce up my server code using Tkinter to display connected addresses. However, because of the Tkinter aspect, it's all that runs. I was wondering if I could run both simultaneously. I am already using .after() to update the client list every 5 seconds. I am already using threading to manage connections. Is threading a valid way to run both easily?
My two main piece of code that need running here are:
window.mainloop()
and
if __name__ == '__main__':
SERVER.listen(7)
client_thread = Thread(target=accept_connections)
client_thread.start()
client_thread.join()
SERVER.close()

Read analog value from Arduino and display it on a Tkinter GUI in real time

I'm trying to create a Python Tkinter GUI for a simple data transmission between an Arduino and a PC via Serial communication (I'm using pySerial package). I can input and send data from the GUI to the Arduino correctly. In a separated code file, I can also read data sent from Arduino correctly, but I have a problem with integrating this real-time data reading feature into the Tkinter GUI program and display it on the GUI. From my experiment, to properly read data sent from the Arduino, the reading need to be run in a loop. Tkinter also has its own loop. So to avoid being stuck in the data reading loop, I've been trying to run them in parallel using concurrent.futures, but it still doesn't work as I want. Please help!
Here's my code: https://drive.google.com/file/d/1xHOV-qXjg2iEA-PXa52d1_66bOpdbnzv/view?usp=sharing
(Please understand that I'm still learning Python, Tkinter and multiprocessing. So there could be some mistakes on conventions and terminology.)
And this is what the GUI looks like:
Arduino-PC Serial Communication GUI
Tkinter windows have a after method that can be used to run your own code as part of the Tkinter loop, for example:
from tkinter import Tk
window = Tk()
def do_something():
print("doing something!")
window.after(1000, do_something) # every 1000 milliseconds
# start the do_something function immediately when the window starts
window.after(0, do_something)
window.mainloop()

Python: Show message 'Waiting for player...' while socket listens for connection

Making a very simple tic-tac-toe game in Python using a P2P architecture with sockets. Currently my GUI has button that says 'Create' that will open up and draw a new game board window, create a socket, bind, listen, and accept a connection. The 'Join' button will open and draw a new gameboard and connect to that 'server'.
I'm trying to have it show a message saying 'Waiting for player...' when you create a game, a cancel button to stop and go back to the main menu, and have it disappear on it's own if a connection has been accepted.
I tried using tkMessageBox but the script stops until the user clears the message so there's no way for me to listen/accept until the user presses something.
What other way is there for me to accomplish this?
Thanks!
Sounds like a threading issue.
I'm unfamiliar with TK graphics, but I'd imagine what you need to do is start the window showing the "waiting for player" message. That window then loops waiting for something to happen.
When the message box displays you need to have the "listening" done on another thread, which signals back to the main message box when someone's connected using a semaphore or a queue.
On your main GUI thread you need to make the loop:
check the queue or semaphore for values. If there's a value on there that you expect, close the box. This would need to be non-blocking so that the GUI thread can still check for input from the user.
check for user input. That's probably done using callback functions though.

Tkinter window says (not responding) but code is running

I have a program that runs a long process after you click an action button. As the process is running the root window will say that it is not responding even though I know the program is running in the background. This program is going to be released to a few people that I work with and I want to make sure they don't freak out and close the window when they see this. The solution I have is sitting a root.update in the loop of the process that is running but I am not sure this was the best fix.
Using the python 3.3
Here is a sample of the code so you get an idea of what I am doing, this is called from the main loop:
def combine(boxes_to, boxes_from, frame):
to_value,to_pos = gui.checkBoxes(boxes_to)
from_value,from_pos = gui.checkBoxes(boxes_from)
frame.destroy()
running = Label(root,text="Running please do not close..",font = (16))
running.pack()
root.update()
map_to = open("map_to",'r')
for line in map_to:
root.update()
process(line)
running.destroy()
map_to.close()
finish = Button(root, text="Done",command=gui.stop)
finish.pack()
While you can call root.update() in your loop, this will still produce some (potentially) undesirable side-effects.
The program may act laggy, meaning it takes a long time to respond to user input.
You will only be able to run this one action. Any other action has to wait for this to finish.
As an alternative I would suggest that you implement simple multi-threading. Python multithreading is pretty simple, and will prevent both of these drawbacks. You will be able to execute your long running code, while still providing a clean and responsive UI.
If your application is trivially parallelizable, you could use multiple threads to decrease running time. Ex. Thread 1 handles entries 1-100, while thread 2 handles entries 101-200.
The best you can do here is to use multithreading in Python. Here's how to do this:
Let's say you have a function named combine() due to which the window is freezing, which is being used as a command for a button named 'btn' as shown here:
btn = Button(root, text="Click Me", command=combine)
Now, when btn is pressed you might be getting the 'not responding' problem. To fix this, edit the code as shown below:
import threading
btn = Button(root, text="Click Me", command=threading.Thread(target=combine).start)
Here threading.Thread creates a separate thread in which the combine() method is executed, so the GUI can continue to keep responding while the command is being executed.

How to hard quit a Tkinter program

My Python program consists of two parts, one gets user credentials through an Tkinter and passes it to the other script which then processes them.
It works fine but the only problem is that although my GUI passes data and then the processing script starts its work, The GUI starts not-responding and causes havoc as it freezes until the download completes (which could potentially take hours)
I create an object of the Interface class in the processing script by importing the GUI script
root = Tk.Tk()
root.title('Coursera-dl')
root.geometry("345x100")
app = GUI.Interface(root)
app.mainloop()
This is my GUI script's destruct method defined in a Class which is executed automatically after the data has been received by the processing script: However when the user clicks 'OK' the GUI freezes and doesn't exit and If I force quit it, the processing script also ends as python.exe is terminated
*code*
....................................
def destruct(self):
if tkMessageBox.askokcancel(title=None,message='Download would start upon closing the Interface, If any changes are to be made to the credentials Please do so by selecting Cancel'):
self.quit()
How can I make my program so that when the user clicks on 'OK' the GUI quits safely and the processing script does its work
root.quit() just Bypasses the root.mainloop() i.e root.mainloop() will still be running in background if quit() command is executed.
Use root.destroy()
this will stop root.mainloop() itself but it wont close the python program and everything will still be ran just without the GUI

Categories