I want to write a program which every time accept a message pop-up a window at the corner of the desktop.
I use the web server to accept message.
And my Tk code is like this:
import threading
from Tkinter import *
import time
def alert():
alert = Tk()
alert.protocol("WM_DELETE_WINDOW", alert.quit)
alert.mainloop()
def run():
th = threading.Thread(target=alert)
th.start()
if __name__ == 'main':
run()
time.sleep(5)
run()
time.sleep(5)
run()
When I ran this, only one window pop-up. It seems that the program hang-up when the second thread went 'alert = Tk()', I'm not sure.
The third thread never ran.
If I didn't close the window before the second thread started, the window would be out of response.
I want to know what's wrong with my code and how tkinter works.
Thanks
Related
My program needs to track the user input at all times. For that i think the input() command is the easiest solution. The problem is: At the same time there should be a Tkinter GUI in fullscreen mode running. I've tried a few things, but nothing really worked out. Here is a simplified program, which shows the problems:
from tkinter import *
import tkinter as tk
from threading import Thread
def GUI():
root=tk.Tk()
Text = Label(master=root, text="Test").pack(side="top")
Button = Button(master=root, text="Button").pack(side="top")
root.mainloop()
def input_loop():
x = input()
print(x)
t1 = Thread(target=GUI)
t2 = Thread(target=input_loop)
t1.start()
t2.start()
Even though now both loops work, i still can't type into the console unless I manually select the console window. Other solutions like the entry widget in tkinter won't work because there is no place for them in my actual program. Please let me know if you find something which works reliably.
i didn't get your problem clearly but i will try to help .
so you are saying the program running on full screen but you want to run it on some resolution?
from tkinter import *
import tkinter as tk
from threading import Thread
def GUI():
root=tk.Tk()
# Program title
root.title("Title")
# Preventing user from fullscreen/resize the window
root.resizable(0, 0)
# Resolution of the windows in pixles
root.geometry(f"{820}x{460}")
Text = Label(master=root, text="Test").pack(side="top")
Btn = Button(master=root, text="Button").pack(side="top")
root.mainloop()
def input_loop():
x = input()
print(x)
t1 = Thread(target=GUI)
t2 = Thread(target=input_loop)
t1.start()
t2.start()
also i changed button function to btn because i faced an error with it , and you can now complete the program and play with the resolution of the buttons and windows so on .
for my project I have implemented a graphical interface that interfaces with wearable sensors.
I wrote a code (multi.py) that interfaces directly with 3 sensors. then I wrote some code for the graphical interface (GUI.py) which calls me different portions of multi.py when I click the buttons.
when I call "configure_clicked ()" and "download_clicked ()" form respective button the GUI freezes (continuing to work), because functions are called (multi.configure & multi.download ) that take some time to finish (connecting to devices and downloading data from devices). I know that I have to do another "thread"--> MULTITHREAD. please,Can anyone help me to create a multithread???
I also have "PROGRESS BAR" which should start at the start of each function but this does not happen for "configure_clicked ()" and "download_clicked ()", while I manage to slide it between "start_clicked" and "stop_clicked".
I am attaching the code.
thank in advance whoever will help me.
from tkinter import *
from tkinter import messagebox, ttk
import multi_sensor_acc_gyro1 as multi
class GUI:
def __init__(self,master):
self.master=master
self.states=[]
...
...
#configure button
self.btn_configure=Button(self.quadro_pulsanti_sx,relief=RAISED,command=self.configure_clicked)
#start button
self.btn_start=Button(self.quadro_pulsanti_dx,command=self.start_clicked,relief=RAISED)
#stop button
self.btn_stop=Button(self.quadro_pulsanti_dx,command=self.stop_clicked,relief=RAISED)
#download button
self.btn_download=Button(self.quadro_pulsanti_dx,command=self.download_clicked,relief=RAISED)
#save button
self.btn_save=Button(self.quadro_pulsanti_dx,relief=RAISED,command=self.save_clicked)
#reset button
self.btn_reset=Button(self.quadro_pulsanti_sx,relief=RAISED,command=self.reset_clicked)
#progress bar
self.pb=ttk.Progressbar(self.quadro_pulsanti_basso,orient=HORIZONTAL,length=350,mode="indeterminate")
self.label_pb=Label(self.quadro_pulsanti_basso,text="")
def configure_clicked(self):
mac_address=["F7:64:55:AD:0A:19","F2:A1:3A:E2:F2:ED","F9:8E:32:DD:1A:EB"]
output_1=multi.configure(mac_address)
self.states=output_1[0]
self.loggers_acc=output_1[1]
self.loggers_gyro=output_1[2]
self.label_pb.configure(text="")
messagebox.showinfo("CONFIGURE clicked","the sensors have been configured\n\nclick OK to continue")
def start_clicked(self):
multi.start(self.states)
self.pb.start()
self.label_pb.configure(text="registration in progress...")
def stop_clicked(self):
self.pb.stop()
self.label_pb.configure(text="")
multi.stop(self.states)
def download_clicked(self):
#self.pb.start()
#self.label_pb.configure(text="Download in progress...")
output_2=multi.download(self.states,self.loggers_acc,self.loggers_gyro)
self.df_tr_tot=output_2[0]
self.df_gd_tot=output_2[1]
self.df_gs_tot=output_2[2]
#self.label_pb.configure(text="")
#self.pb.stop()
messagebox.showinfo("DOWNLOAD clicked","the data has been downloaded\n\nclick OK to continue")
def save_clicked(self):
#self.txt_pz.focus_set()
#self.txt_pz.get()
self.txt_pz.focus_set()
id_pz=self.txt_pz.get()
multi.save(self.df_tr_tot,self.df_gd_tot,self.df_gs_tot,id_pz)
messagebox.showinfo("SAVE clicked","I dati sono stati salvati\n\ncliccare OK per continuare")
window = Tk()
window.title(" Grafic User Interface for MMR")
window.iconbitmap('C:/Users/salvo/Documents/MetaWear-SDK-Python/examples/favicon.ico')
height=560
width=540
left=(window.winfo_screenwidth()-width)/2
top=(window.winfo_screenheight()-height)/2
geometry="%dx%d+%d+%d" % (width,height,left,top)
window.geometry(geometry)
gui=GUI(window)
window.mainloop()
This is how you make sure tkinter doesn't stop responding while running a long task:
import threading
from time import sleep
def operation():
# Create a new thread
new_thread = threading.Thread(target=_operation, daemon=True)
# Start the thread
new_thread.start()
# continue code or run this:
while new_thread.is_alive(): # While the new thread is still running
# Here you can also add a loading screen
# Make sure tkinter doesn't say that it isn't responding
tkinter_widget.update() # `tkinter_widget` can be any tkinter widget/window
sleep(0.1) # A bit of delay so that it doesn't use 300% of your CPU
def _operation()
# Here you can do the operation that will take a long time
pass
When you need to run the operation call operation and it will start the new thread. NOTE: make sure that you don't have any tkinter stuff in the new thread because tkinter would crash.
What is happening is that your calculations and Tkinter all exist in the same thread so in order to perform calculations execution of Tkinter's mainloop() has to be paused until those processes have completed. The simplest solution is to add some helper methods and call them in separate threads when buttons are pressed:
from threading import Thread
def configure_clicked(self):
t = Thread(target=self._configure_clicked)
t.start()
def _configure_clicked(self):
mac_address=["F7:64:55:AD:0A:19","F2:A1:3A:E2:F2:ED","F9:8E:32:DD:1A:EB"]
output_1=multi.configure(mac_address)
self.states=output_1[0]
self.loggers_acc=output_1[1]
self.loggers_gyro=output_1[2]
self.label_pb.configure(text="")
messagebox.showinfo("CONFIGURE clicked","the sensors have been configured\n\nclick OK to continue")
And you do similar things to all other methods. After that all shall work fine.
My app has the following structure:
import tkinter as tk
from threading import Thread
class MyWindow(tk.Frame):
... # constructor, methods etc.
def main():
window = MyWindow()
Thread(target=window.mainloop).start()
... # repeatedly draw stuff on the window, no event handling, no interaction
main()
The app runs perfectly, but if I press the X (close) button, it closes the window, but does not stop the process, and sometimes even throws a TclError.
What is the right way to write an app like this? How to write it in a thread-safe way or without threads?
Main event loop should in main thread, and the drawing thread should in the second thread.
The right way to write this app is like this:
import tkinter as tk
from threading import Thread
class DrawingThread(Thread):
def __init__(wnd):
self.wnd = wnd
self.is_quit = False
def run():
while not self.is_quit:
... # drawing sth on window
def stop():
# to let this thread quit.
self.is_quit = True
class MyWindow(tk.Frame):
... # constructor, methods etc.
self.thread = DrawingThread(self)
self.thread.start()
on_close(self, event):
# stop the drawing thread.
self.thread.stop()
def main():
window = MyWindow()
window.mainloop()
main()
I ran into a strange problem when working on my project. I have a GUI and a QTextEdit that serves as a status browser. When a button is clicked, I want the QTextEdit to display a 10 second countdown while another function is happening in a separate thread. Even though I emit a signal every second, the QTextEdit hangs for 9 seconds, then displays the last countdown number.
I thought this might have something to do with stuff happening in a separate thread, so I created a separate example to test this out. In my simple example, there are two things: a QTextEdit and a Button. When the button is clicked, the status browser should display '5' for two seconds, then '4'.
Here is the code:
import sys
from PyQt4 import QtGui, uic
from PyQt4.QtCore import QObject, pyqtSignal
import time
class MainUI(QObject):
status_signal = pyqtSignal(str)
def __init__(self, window):
super(QObject, self).__init__()
self.ui = uic.loadUi(r'L:\internal\684.07\Mass_Project\Software\PythonProjects\measure\testing\status_test.ui', window)
self.ui.statusBrowser.setReadOnly(True)
self.ui.statusBrowser.setFontPointSize(20)
self.status_signal.connect(self.status_slot)
self.ui.button.clicked.connect(self.counter)
window.show()
def status_slot(self, message):
self.ui.statusBrowser.clear()
self.ui.statusBrowser.append(message)
def counter(self):
print 'clicked'
i = 5
self.status_signal.emit(str(i))
time.sleep(2)
self.status_signal.emit(str(i-1))
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
app.setStyle("cleanlooks")
main_window = QtGui.QDialog()
main_ui = MainUI(main_window)
sys.exit(app.exec_())
In this example, the same thing happens. The status browser hangs for 2 seconds, then only displays '4'. When I alter the status_slot function so that it doesn't clear the status browser before appending to it, the status browser waits for 2 seconds, then emits both signals at once, displaying '5 \n 4'. Does anyone know why this is happening and what I can do to constantly update the display? Thanks in advance!
time.sleep() blocks the Qt main loop so it can't process window redraw events. Use a QTimer to periodically call a method which emits your signal so that control is returned to the Qt event loop regularly.
I'm trying to run a simple Tkinter program that opens a program when you click a button. The code is listed below. I use a command to call a program that then calls a fortran program. However, when I click on the button, it opens the program but the menu of the program i'm calling goes into an infinite loop......the offending code seems to be in the button1Click module.
Any help is greatly appreciated.
Thanks
from Tkinter import *
import os, sys
from win32com.client import Dispatch
xlApp=Dispatch('Excel.Application')
_PSSBINPATH=r"C:\Program Files\PTI\PSSE32\PSSBIN"
os.environ['PATH']=_PSSBINPATH+';'+os.environ['PATH']
sys.path.insert(0,_PSSBINPATH)
import redirect; redirect.psse2py()
import psspy
class MyApp:
def __init__(self, parent):
self.myParent = parent ### (7) remember my parent, the root
self.myContainer1 = Frame(parent)
self.myContainer1.pack()
self.button1 = Button(self.myContainer1)
self.button1.configure(text="OK", background= "green")
self.button1.pack(side=LEFT)
self.button1.bind("<Button-1>", self.button1Click) ### (1)
self.button2 = Button(self.myContainer1)
self.button2.configure(text="Cancel", background="red")
self.button2.pack(side=RIGHT)
self.button2.bind("<Button-1>", self.button2Click) ### (2)
def button1Click(self,event): ### (3)
psspy.runiplanfile(r"C:\MNTACT\Contingency Program\work\contingency-31-4.irf")
if self.button1["background"] == "green": ### (4)
self.button1["background"] = "yellow"
else:
self.button1["background"] = "green"
def button2Click(self, event): ### (5)
self.myParent.destroy() ### (6)
root = Tk()
myapp = MyApp(root)
root.mainloop()
What makes you think there's an infinite loop happening? I see no loop in button1Click, unless the loop is in runiplanfile. Are you using "infinite loop" to mean simply that the GUI has stopped responding?
Tkinter is single threaded and cannot process events except via the event loop. If one event takes a long time to process, the GUI will hang until the processing of that event is completed. If you're exec'ing an external process and waiting for it to complete, your GUI will appear to be frozen until that process finishes.