Im trying to make a program and i need to link two process together. if one of them stoped the other one stops too and for some reason my gui lagging when trying to browse process and check the conditions i made for it.here is the short video from my problem enter link description here.
import tkinter as tk
from tkinter import messagebox
import psutil
import os
class myapp():
def __init__(self):
self.win = tk.Tk()
self.win.title("test")
self.win.geometry('200x100')
self.win.config(bg='black')
self.win.resizable(False,False)
self.ctr = 0
self.tk_var = tk.StringVar()
self.tk_var.set("0")
lab=tk.Label(self.win, textvariable=self.tk_var,
bg='black', fg='#FF0000')
lab.place(x=90, y=45)
btn = tk.Button(self.win,text='test',command='',
bd=0,bg='#7E1600',width=10,
activebackground='#6D0000')
btn.pack(pady=20)
self.upd()
self.test()
self.win.mainloop()
def upd(self):
self.ctr += 1
self.tk_var.set(str(self.ctr))
self.win.after(50,self.upd)
def test(self):
self.service = "notepad.exe" in (i.name() for i in psutil.process_iter())
if self.service != True :
er = messagebox.showerror(title='error', message='notepad.exe has been stopped')
if er == 'ok':
self.win.destroy()
else:
self.win.after(500,self.test)
os.popen('notepad')
myapp()
problem
I'm still working on my English.
import tkinter as tk
from tkinter import messagebox
import psutil
import os
class myapp():
def __init__(self):
self.win = tk.Tk()
self.win.title("test")
self.win.geometry('200x100')
self.win.config(bg='black')
self.win.resizable(False, False)
self.ctr = 0
self.tk_var = tk.StringVar()
self.tk_var.set("0")
lab = tk.Label(self.win, textvariable=self.tk_var,
bg='black', fg='#FF0000')
lab.place(x=90, y=45)
btn = tk.Button(self.win, text='test', command='',
bd=0, bg='#7E1600', width=10,
activebackground='#6D0000')
btn.pack(pady=20)
self.upd()
self.win.mainloop()
def upd(self):
self.ctr += 1
self.tk_var.set(str(self.ctr))
self.win.after(50, self.test)
def test(self):
self.service = "notepad.exe" in (i.name() for i in psutil.process_iter())
if self.service != True:
er = messagebox.showerror(title='error', message='notepad.exe has been stopped')
if er == 'ok':
self.win.destroy()
self.win.after(500, self.upd)
os.popen('notepad')
myapp()
upd->test->upd->test... just It only takes one call upd. No need to call test. Also, the after function call is wrong. See my modified code. It's hard to explain in my short English.
I renamed some functions in my example for better understanding...
I see that your check is too fast, which can cause lag on lower computers, also, keep in mind that when you call the 'check_notepad' function when initializing the class, whenever you click on the 'test' button it adds a new check , that is, another check loop comes into action and this cascades making your app increasingly heavy in memory...
My solution, in addition to some improvements in the code, is just to start the checker once, so as not to create cascades of checks, and from that your app does not lag anymore, if you need to leave it 'on' using a checkbox instead of a button can do more sense...
import os
import tkinter as tk
from tkinter import messagebox
import psutil
class myapp(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# styles
self.geometry('200x100')
# vars
self.timer = 500
# widgets
self.tk_var = tk.IntVar(value=0)
lab = tk.Label(self, textvariable=self.tk_var)
lab.place(x=90, y=45)
self.check_var = tk.BooleanVar()
btn = tk.Checkbutton(self, text='Test', variable=self.check_var)
btn.pack(pady=20)
# Starts
self.update_label()
self.check_notepad()
def update_label(self):
self.tk_var.set(self.tk_var.get() + 1)
self.after(self.timer, self.update_label)
def check_notepad(self):
if self.check_var.get():
if not notepad_is_open():
er = messagebox.showerror(title='error',
message='notepad.exe has been stopped')
if er == 'ok':
self.destroy()
# call back loop
self.after(self.timer, self.check_notepad)
def notepad_is_open():
service = "notepad.exe" in (i.name() for i in psutil.process_iter())
return service
if __name__ == '__main__':
if not notepad_is_open():
os.popen('notepad')
myapp = myapp()
myapp.mainloop()
Related
I am building a real time monitoring project where information is given in the first window and that's keep on updating in the second window. I am trying to monitor the updated information in parallel from a different window using the same code, but as I pressed the new button and given the new information it is updating in the previous window also but I wanted monitor window to be completely different, so that I can monitor the different information in parallel using the same code. Please have a look at the sample code and help me with the ideas.
The sample code:
import time
import threading
import tkinter.messagebox
from tkinter import ttk
import queue
from tkinter import *
class Demo1:
data=[]
def __init__(self, master):#Python scrollbar on text widget
self.master = master
self.t=tkinter.Text(self.master,height=20,width=50)
self.t.grid(row=1, column=1)
self.button = tkinter.Button(self.master,height=3,width=10, text="OK", command = self.new_window)
self.button.grid(row=2,column=1)
def new_window(self):
self.inputValue=self.t.get("1.0",'end-1c')
Demo1.data1=self.inputValue.split("\n")
self.master.destroy() # close the current window
self.master = tkinter.Toplevel() # create another Tk instance
self.app = Demo2(self.master) # create Demo2 window
self.master.mainloop()
class Demo2:
t1 = []
s1 = True
display = []
display1 = []
i=0
kas = True
num=0
j1=0
def __init__(self, master):
self.master = master
self.button = tkinter.Button(self.master,height=2,width=11, text="new",command=self.new).place(x=0,y=0)
self.label = tkinter.Label(self.master, text="monitor", font=("Arial",20)).grid(row=0, columnspan=3)
cols = ('aa','bb')
self.listBox = ttk.Treeview(self.master, columns=cols)
for col in cols:
self.listBox.heading(col, text=col)
self.listBox.column(col,minwidth=0,width=170)
self.listBox.grid(row=1, column=0)
self.a()
def a(self):
self._img=tkinter.PhotoImage(file="green1.gif")
a=Demo1.data1
for i,(a) in enumerate(a): #here I have some function which runs repeatedlly
self.listBox.insert('', 'end',image=self._img, value=(a))
threading.Timer(1.0, self.a).start()
def new(self):
main()
def main():
root = tkinter.Toplevel()
app = Demo1(root)
root.mainloop()
if __name__ == '__main__':
main()
I have given the pppp information to monitor but as a pressed new button and added the xx information its updating in the previous window also. Please help me with the idea so that the link between these window will be vanished.
Output:
You have some major issues with your program. Including how you are trying to use your classes. The Toplevel() object was giving me issue, so I used Tk(). This should show you how to properly use the classes with the window. Most importantly your second window needs to be created from global not the first window. Also Demo1.data is a reference to your class definition not the actual data you loaded. I hope this example is helpful.
from tkinter import *
# your second window should be created in global
def create_demo2():
global app, app2
root2 = Tk()
app2 = Demo2(root2, app)
class Demo1:
def __init__(self, window):
self.window = window
self.data = ""
self.button = Button(self.window, text="New Window",
command=create_demo2)
self.button.pack()
def set_data(self):
self.data = "data"
class Demo2:
# you could just use app from global scope, but I like to pass so that it is explicit.
def __init__(self, window, app1):
self.window = window
self.button_set = Button(self.window, text="Set", command=app1.set_data)
self.button_use = Button(self.window, text="Use", command=self.use_data)
self.app = app1
self.label = Label(self.window)
self.button_set.pack()
self.button_use.pack()
self.label.pack()
def use_data(self):
self.label.configure(text=self.app.data)
root = Tk()
app = Demo1(root)
app2 = None
root.mainloop()
I created a GUI using Python, Tkinter. Everything seems to be fine. I have added several options to my Menu tab. In the File section I have added a feature to exit the GUI by clickinh onto the Exit button(not the button though, but a menu option). Here is the code that I have written.
from tkinter import *
from tkinter import filedialog, RIGHT
class Filedialog:
def directory(self):
content = filedialog.askdirectory()
return content
class Main(Frame):
def __init__(self):
self.opening_times = 0
self.current_image = 0
self.images = []
self.root = Tk()
self.root.title("Y")
self.root.configure(bg='pale turquoise')
self.root.geometry("800x800")
self.frame = Frame(self.root)
self.frame.pack(side=RIGHT)
self.frame = Frame.__init__(self, self.root)
self.widgets()
self.root.mainloop()
def widgets(self):
self.menu = Menu(self.root)
self.root.config(menu=self.menu)
self.filemenu = Menu(self.menu, tearoff=False)
self.menu.add_cascade(label="File", menu=self.filemenu)
self.filemenu.add_separator()
self.filemenu.add_command(label="Save")
self.filemenu.add_separator()
self.filemenu.add_command(label="Exit", command=self.onExit)
#self.editmenu = Menu(self.menu, tearoff=0)
#self.menu.add_cascade(label='Edit', menu=self.editmenu)
#self.editmenu.add_command(label="Undo")
#self.editmenu.add_command(label="Redo")
def onExit(self):
self.root.quit()
if __name__ == "__main__":
Main()
I have almost succeeded. But the problem arises when I click on the exit. The function does what it has to. But the GUI window was not closing, also it freezes there. There was no response at all until I force the window to close externally.
I also tried doing:
self.quit()
/
self.exit()
But the response is the same as the GUI freezes and not letting me do any other activities. I had to close complete program to get the access again.
I am not getting the error at least, to know what is wrong.
Please help me find out what is wrong/solve this problem.
Thank you for your time.
Let me correct your code
from sys import exit
from tkinter import *
from tkinter import filedialog, RIGHT
class Filedialog:
def directory(self):
content = filedialog.askdirectory()
return content
class Main(Frame):
def __init__(self):
self.opening_times = 0
self.current_image = 0
self.images = []
self.root = Tk()
self.root.title("Y")
self.root.configure(bg='pale turquoise')
self.root.geometry("800x800")
self.frame = Frame(self.root)
self.frame.pack(side=RIGHT)
self.frame = Frame.__init__(self, self.root)
self.widgets()
self.root.mainloop()
def widgets(self):
self.menu = Menu(self.root)
self.root.config(menu=self.menu)
self.filemenu = Menu(self.menu, tearoff=False)
self.menu.add_cascade(label="File", menu=self.filemenu)
self.filemenu.add_separator()
self.filemenu.add_command(label="Save")
self.filemenu.add_separator()
self.filemenu.add_command(label="Exit", command=self.onExit)
#self.editmenu = Menu(self.menu, tearoff=0)
#self.menu.add_cascade(label='Edit', menu=self.editmenu)
#self.editmenu.add_command(label="Undo")
#self.editmenu.add_command(label="Redo")
def onExit(self):
self.root.destroy()
exit()
if __name__ == "__main__":
Main()
You need to use destroy() instead of quit() and you should use exit to quit from the console
The method you have to use is destroy. For example:
def onExit(self):
self.root.destroy()
Use destroy() method instead of quit.
You can use the method tk.destroy() to close a window. The built-in functions exit() and quit() close the Python console.
Working example
from tkinter import *
tk = Tk()
tk.title("Closing window demonstration")
def close_window():
tk.destroy()
quit = Button(tk, text = "Quit", command = close_window)
quit.pack()
tk.mainloop()
I am trying to execute a Tkinter ttk Button method while the button is pressed, meaning I want the method to keep executing when the button is pressed and stop when I release it, but i can't quite figure it out. Here is the code.
from tkinter import *
from tkinter import ttk
class stuff (object):
def __init__(self, master):
master.title("Grid Master")
master.frame_1 = ttk.Frame(master)
master.frame_1.pack()
master.configure(background = "#FFFFFF")
self.button = ttk.Button(master, text = 'Press', command = self.callback)
self.button.pack()
def callback(self):
print ("Hello world")
def main():
root = Tk()
loop = stuff(root)
root.mainloop()
if __name__ == '__main__':
main()
You can see in the code that the method only prints "Hello world" and I want this function to execute and keep going, printing Hello world until I release the button.
You can use root.after() to repeatedly schedule a job to perform the required task. Note that I have changed the button event to activate when the button is pressed, and to terminate the "after" job when the button is released.
try:
from tkinter import *
from tkinter import ttk
except ImportError:
# Python 2, probably
from Tkinter import *
import ttk
class stuff (object):
def __init__(self, master):
self._master = master
master.title("Grid Master")
master.frame_1 = ttk.Frame(master)
master.frame_1.pack()
master.configure(background = "#FFFFFF")
self.button = ttk.Button(master, text = 'Press')
self.button.bind("<Button-1>", self.button_pressed)
self.button.bind("<ButtonRelease-1>", self.button_released)
self.button.pack()
self.hello_world_frequency = 1 # milliseconds
def hello_world(self):
print ("Hello world")
self._job = self._master.after(self.hello_world_frequency, self.hello_world)
def button_pressed(self, event):
print ("Button down")
self.hello_world()
def button_released(self, event):
print ("Button released")
self._master.after_cancel(self._job)
def main():
root = Tk()
loop = stuff(root)
root.mainloop()
if __name__ == '__main__':
main()
You can make a custom repeating ttk button class that inherits from ttk.Button but adds basic repeating functionality.
Try this. you can use it like
self.button = RepeatButton(master, text='Press', command=self.callback)
and you can set the repeatdelay and repeatinterval arguments, which default to 300 and 100.
class RepeatButton(ttk.Button):
def __init__(self, *args, **kwargs):
self.callback = kwargs.pop('command', None)
self.repeatinterval = kwargs.pop('repeatinterval', 100)
self.repeatdelay = kwargs.pop('repeatdelay', 300)
ttk.Button.__init__(self, *args, **kwargs)
if self.callback:
self.bind('<ButtonPress-1>', self.click)
self.bind('<ButtonRelease-1>', self.release)
def click(self, event=None):
self.callback()
self.after_id = self.after(self.repeatdelay, self.repeat)
def repeat(self):
self.callback()
self.after_id = self.after(self.repeatinterval, self.repeat)
def release(self, event=None):
self.after_cancel(self.after_id)
I'm trying to build a simple program to remind me to take breaks while using the computer. I have a reasonable understanding of python but have never played with GUI programming or threading before, so the following is essentially copying/pasting from stackoverflow:
import threading
import time
import Tkinter
class RepeatEvery(threading.Thread):
def __init__(self, interval, func, *args, **kwargs):
threading.Thread.__init__(self)
self.interval = interval # seconds between calls
self.func = func # function to call
self.args = args # optional positional argument(s) for call
self.kwargs = kwargs # optional keyword argument(s) for call
self.runable = True
def run(self):
while self.runable:
self.func(*self.args, **self.kwargs)
time.sleep(self.interval)
def stop(self):
self.runable = False
def microbreak():
root = Tkinter.Tk()
Tkinter.Frame(root, width=250, height=100).pack()
Tkinter.Label(root, text='Hello').place(x=10, y=10)
threading.Timer(3.0, root.destroy).start()
root.mainloop()
return()
thread = RepeatEvery(6, microbreak)
thread.start()
This gives me the first break notification but fails before giving me a second break notification.
Tcl_AsyncDelete: async handler deleted by the wrong thread
fish: Job 1, “python Documents/python/timer/timer.py ” terminated by
signal SIGABRT (Abort)
Any ideas? I'm happy to use something other than tkinter for gui-stuff or something other than threading to implement the time stuff.
Based on the answers below, my new working script is as follows:
import Tkinter as Tk
import time
class Window:
def __init__(self):
self.root = None
self.hide = 10 #minutes
self.show = 10 #seconds
def close(self):
self.root.destroy()
return
def new(self):
self.root = Tk.Tk()
self.root.overrideredirect(True)
self.root.geometry("{0}x{1}+0+0".format(self.root.winfo_screenwidth(), self.root.winfo_screenheight()))
self.root.configure(bg='black')
Tk.Label(self.root, text='Hello', fg='white', bg='black', font=('Helvetica', 30)).place(anchor='center', relx=0.5, rely=0.5)
#Tk.Button(text = 'click to end', command = self.close).pack()
self.root.after(self.show*1000, self.loop)
def loop(self):
if self.root:
self.root.destroy()
time.sleep(self.hide*60)
self.new()
self.root.mainloop()
return
Window().loop()
I think it would be easier for you to achieve this without threads, which Tkinter does not integrate with very well. Instead, you can use the after and after_idle methods to schedule callbacks to run after a certain timeout. You can create one method that shows the window and schedules it to be hidden, and another that hides the window and schedules it to be shown. Then they'll just call each other in an infinite loop:
import tkinter
class Reminder(object):
def __init__(self, show_interval=3, hide_interval=6):
self.hide_int = hide_interval # In seconds
self.show_int = show_interval # In seconds
self.root = Tkinter.Tk()
tkinter.Frame(self.root, width=250, height=100).pack()
tkinter.Label(self.root, text='Hello').place(x=10, y=10)
self.root.after_idle(self.show) # Schedules self.show() to be called when the mainloop starts
def hide(self):
self.root.withdraw() # Hide the window
self.root.after(1000 * self.hide_int, self.show) # Schedule self.show() in hide_int seconds
def show(self):
self.root.deiconify() # Show the window
self.root.after(1000 * self.show_int, self.hide) # Schedule self.hide in show_int seconds
def start(self):
self.root.mainloop()
if __name__ == "__main__":
r = Reminder()
r.start()
I agree with dano. I thought i'd also contribute though, as my way is somewhat smaller than dano's, but uses time for the gap between when the window is visible. hope this helps #vorpal!
import Tkinter
import time
root = Tkinter.Tk()
def close():
root.destroy()
def show():
root.deiconify()
button.config(text = 'click to shutdown', command = close)
def hide():
root.withdraw()
time.sleep(10)
show()
button = Tkinter.Button(text = 'click for hide for 10 secs', command = hide)
button.pack()
root.mainloop()
This maybe a silly question to ask. I have a label in Tkinter GUI and i want it to be updated through time.
Example:
Msglabel=Tkinter.Label(... text="")
Msglabel.Cofigure(text=" EXAMPLE!")
Wait(5sec)
Msglabel.Configure(text=" NEW EXAMPLE!")
I've read about the after() method but im looking for something like Wait.
You'll need to hand over control to Tkinter during your wait period since Tkinter updates the UI in a single threaded loop.
Sleeping between the configure calls will hang the UI.
As you mentioned, after is the method you want. Try something like this:
try:
import Tkinter as tkinter # Python 2
except ImportError:
import tkinter # Python 3
import itertools
class MyApplication(object):
def __init__(self):
# Create and pack widgets
self.root = tkinter.Tk()
self.label = tkinter.Label(self.root)
self.button = tkinter.Button(self.root)
self.label.pack(expand=True)
self.button.pack()
self.label['text'] = 'Initial'
self.button['text'] = 'Update Label'
self.button['command'] = self.wait_update_label
# Configure label values
self.label_values = itertools.cycle(['Hello', 'World'])
def launch(self):
self.root.mainloop()
def wait_update_label(self):
def update_label():
value = next(self.label_values)
self.label['text'] = value
update_period_in_ms = 1500
self.root.after(update_period_in_ms, update_label)
self.label['text'] = 'Waiting...'
if __name__ == '__main__':
app = MyApplication()
app.launch()