I'm attempting a Python frame class with a lable that updates every time period. I can't seem to get he configure thing to work for me. Thanks
from tkinter import * # get base widget set
from tkinter.messagebox import askokcancel
from datetime import datetime
class SensorUpdate(Frame) :
def __init__(self) :
Frame.__init__(self)
self.pack()
Label(self, text="Sensors").pack(anchor=NW)
self.timeLabel = Label(self,
text=datetime.now().strftime("%H:%M:%S")).pack(anchor=NW)
Button(self, text="Shut Down",command=(lambda :self.shutDown())).pack(side=RIGHT)
self.after(500,self.updateImage) #updates Frame Image
def shutDown(self):
print("in shutDown")
ans = askokcancel('Verify', "Really quit?")
if ans:
print("made it here")
SensorUpdate.quit(self)
def updateImage(self):
print(" Updating Image")
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print(current_time)
#self().timeLabel.configure(text='Test') # object not callable
#self.timeLabel.configure(text='Test') # object has no attribute timeLabel
#timeLabel.configure(text='Test') # timeLabel not found
self.after(10,self.updateImage)
root = Tk()
app = SensorUpdate()
app.mainloop()
root.destroy()
After spending some quality time with 3000 pages of Lutz texts, I've found a solution using two classes one for the basics of display and one for the update using the (after) command. Any help on my first method is apprecieated. I can make this work at least even if I'm not sure why the first one doesn't
from tkinter import * # get base widget set
from tkinter.messagebox import askokcancel
from datetime import datetime
class SensorConfig:
size = 200
bg, fg = 'beige', 'brown'
class IndicatorDisplay(Frame):
def __init__(self, parent, cfg):
Frame.__init__(self, parent)
self.timeLabel = Label(self)
self.timeLabel.config(bd=20,relief=SUNKEN,bg=cfg.bg,fg=cfg.fg)
self.timeLabel.pack(side=LEFT)
Button(self, text="Shut Down",command=(lambda :self.shutDown())).pack(side=RIGHT)
def shutDown(self):
print("in shutDown")
ans = askokcancel('Verify', "Really quit?")
if ans:
print("made it here")
self.quit()
def onUpdate(self, curTime):
self.timeLabel.config(text=curTime)
class Sensor(Frame):
def __init__(self, config=SensorConfig, parent=None):
Frame.__init__(self, parent)
self.pack(expand=YES, fill = BOTH)
self.cfg = config
self.display = IndicatorDisplay(self, self.cfg)
self.display.pack(side=TOP)
self.updateLabels()
def updateLabels(self):
print("make time change")
self.display.onUpdate(datetime.now().strftime("%H:%M:%S"))
self.after(500, self.updateLabels)
if __name__ == '__main__':
config = SensorConfig()
mySensor = Sensor(config)
mySensor.mainloop()
Related
I'm trying to make this code close all windows which are opened on windows class. At this moment it only closes few of them. Code works perfectly, but it just dont remove all windows which needs to be removed. Can someone please help me to make this script working?
import tkinter as tk
from tkinter import *
from PIL import Image, ImageTk
import webbrowser
import time
import random
def closeall():
global close
close = True
self = selfstr
parent = parentstr
Window.__init__(self, parent)
class Window(tk.Toplevel):
def __init__(self, parent):
if close == True:
self.destroy()
else:
global selfstr
selfstr = self
global parentstr
parentstr = parent
plusminus_list = ["+", "-"]
plusminus = random.choice(plusminus_list)
plusminus2 = random.choice(plusminus_list)
location = random.randint(1, 1000)
location2 = random.randint(1, 1000)
super().__init__(parent)
self.geometry(f'256x256{plusminus}{location}{plusminus2}{location2}')
self.title('NOESCAPE')
frame = Frame(self, width=256, height=256)
frame.pack()
frame.place(anchor='center', relx=0.5, rely=0.5)
img_list = ["jeff2", "jeff3", "jeff4", "jeff5", "jeff6"]
randomimg = random.choice(img_list)
img = ImageTk.PhotoImage(Image.open(f"{randomimg}.jpg"))
label = Label(frame, image = img)
label.pack()
def on_closing():
plusminus_list = ["+", "-"]
onlywayout()
plusminus = random.choice(plusminus_list)
plusminus2 = random.choice(plusminus_list)
location = random.randint(1, 1000)
location2 = random.randint(1, 1000)
img_list = ["jeff2", "jeff3", "jeff4", "jeff5", "jeff6"]
randomimg = random.choice(img_list)
img = ImageTk.PhotoImage(Image.open(f"{randomimg}.jpg"))
Window(self)
self.protocol("WM_DELETE_WINDOW", on_closing)
self.mainloop()
So you cannot access all Window instances you created for some reason? Then you could save a list with all instances in the Window class as a class attribute. With this list you should be able to destroy all Window instances. Your approach with using the constructor and global variables is a very bad coding style and you shouldn't do anything like this.
Here I created a classmethod so that you don't need the extra function closeall():
import tkinter
class Window(tkinter.Toplevel):
instances = [] # class attribute
def __init__(self, parent):
super().__init__(parent)
self.instances.append(self) # save current instance to the list
# ...
#classmethod
def destroy_all_instances(cls):
for window in cls.instances:
window.destroy()
# Destroy all Window instances:
Window.destroy_all_instances()
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 want to start a webserver if the user does click on a button. Therefore I have written the following code:
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import messagebox
import time
from multiprocessing import Process
class MainWindow(ttk.Frame):
def __init__(self, parent):
self.parent = parent
ttk.Frame.__init__(self, master=self.parent)
self.parent.grab_set()
self.parent.title("Test_Program")
self.parent.geometry("500x500")
ttk.Button(self.parent, text="Start Web-Server", command=self.start_webserver).pack()
def start_webserver(self):
if __name__ == '__main__':
loading_screen = LoadingScreen(self)
result = [0]
sub_process = Process(target=start_webserver, args=(result,))
sub_process.start()
sub_process.join()
sub_process.terminate()
loading_screen.destroy()
if result[0] == 0:
messagebox.showinfo("Webserver Status", "Webserver is running!")
else:
messagebox.showerror("Webserver Status", "Webserver can't be started an Error occured!")
class LoadingScreen(tk.Toplevel):
def __init__(self, parent):
self.parent = parent
tk.Toplevel.__init__(self, master=self.parent)
self.geometry("200x50")
self.title("Loading Screen")
self.transient(self.parent)
self.grab_set()
ttk.Label(self, text="Copying data!").pack()
status_bar = ttk.Progressbar(self, length=180, mode="indeterminate")
status_bar.start(5)
status_bar.pack()
def __del__(self):
if isinstance(self.parent, tk.Toplevel):
self.parent.grab_set()
def start_webserver(result):
time.sleep(2) # This does represent the time thats necessary to start the webserver
result[0] = 1
def main():
root = tk.Tk()
main_window = MainWindow(root)
main_window.pack()
root.mainloop()
if __name__ == "__main__":
main()
If I click on "start webserver" its two seconds frozen because of time.sleep(2) and no progress bar does get displayed. Afterwards its done. I don't know why there is no progressbar displayed. I have used an array named "result" as parameter to get the return value of start_webserver(result) from sub_process to main_process. Unfortunately this is not working too because the value of "result[0]" stays 0. I don't know what to do. The idea of using an array I have found on stackoverflow too.
Here is the Link:
how to get the return value from a thread in python?
I have found out an answer by my own. Thanks for your help join() wasn't right. I have done it a different way and closing the "loading_screen" as well as opening the messagebox after the job has been done in the second thread.
That's the Code:
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import messagebox
import time
from threading import Thread
class MainWindow(ttk.Frame):
def __init__(self, parent):
self.parent = parent
ttk.Frame.__init__(self, master=self.parent)
self.parent.grab_set()
self.parent.title("Test_Program")
self.parent.geometry("200x50")
ttk.Button(self.parent, text="Start Web-Server", command=self.start_webserver).pack()
def start_webserver(self):
if __name__ == '__main__':
loading_screen = LoadingScreen(self)
thread = Thread(target=start_webserver, args=(loading_screen, ))
thread.start()
class LoadingScreen(tk.Toplevel):
def __init__(self, parent):
self.parent = parent
tk.Toplevel.__init__(self, master=self.parent)
self.geometry("200x50")
self.title("Loading Screen")
self.transient(self.parent)
self.grab_set()
ttk.Label(self, text="Copying data!").pack()
status_bar = ttk.Progressbar(self, length=180, mode="indeterminate")
status_bar.start(2)
status_bar.pack()
def __del__(self):
if isinstance(self.parent, tk.Toplevel):
self.parent.grab_set()
def start_webserver(widget):
return_val = do_some_stuff()
if return_val:
widget.destroy()
messagebox.showinfo("Webserver Status", "Webserver is running!")
else:
widget.destroy()
messagebox.showerror("Webserver Status", "Webserver can't be started an Error occured!\n"
"Please look inside 'Logfiles/logfile' for more details.")
def do_some_stuff():
time.sleep(2) # This does represent the time thats necessary to start the webserver
return True
def main():
root = tk.Tk()
main_window = MainWindow(root)
main_window.pack()
root.mainloop()
if __name__ == "__main__":
main()
I am struggling with a seemingly simple problem: I want to be able to update the maximum value of a progress bar in tkinter by manually changing the value of an entry. What happens is that the initial value, 100, does not change. OK, I thought that by invoking set in the method count I would be able to update the maximum value. It didn't work. What is the problem?
import tkinter as tk
from tkinter import ttk
from time import sleep
class Window():
def __init__(self, master):
self.master = master
self.configure()
self.create_widgets()
def configure(self):
self.master.title('Progress bar')
self.master.minsize(height=100, width=500)
def create_widgets(self):
self.progress = tk.DoubleVar()
self.number = tk.StringVar()
self.number.set('100')
self.max = tk.IntVar()
self.max.set(eval(self.number.get()))
b1 = tk.Button(self.master, text='Count!', command=self.count)
b1.pack()
e1 = tk.Entry(self.master, textvariable=self.number, width=5)
e1.pack()
p = ttk.Progressbar(self.master, orient='horizontal', length=200, mode='determinate', variable=self.progress, value=1, maximum=self.max.get())
p.pack()
def count(self):
self.max.set(eval(self.number.get()))
for i in range(eval(self.number.get())):
sleep(0.01)
print(i)
self.progress.set(i)
self.master.update()
def main():
root = tk.Tk()
app = Window(root)
root.mainloop()
main()
You're struggling probably because you've overcomplicated the issue. Why do you use 3 separate Variable classes when you need none? Currently what happens is you create a progress bar with a static maximum of 100, and then you're changing how long to progress in that window by setting the entry's value.
Here's a minimal example that updates the maximum value of progress bar:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
import tkinter.ttk as ttk
except ImportError:
import Tkinter as tk
import ttk
class RestartableProgress(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master, *args, **kwargs)
self.max_input = tk.Entry(self)
self.restart_button = tk.Button(self, text="Restart",
command=self.restart)
self.progressbar = ttk.Progressbar(self)
self.max_input.pack()
self.restart_button.pack()
self.progressbar.pack()
def restart(self):
self.progressbar['value'] = 0
self.progress()
def progress(self):
max_val = self.max_input.get()
if max_val:
self.progressbar['maximum'] = int(max_val)
if self.progressbar['value'] < self.progressbar['maximum']:
self.progressbar['value'] += 1
self.after(10, self.progress)
def main():
root = tk.Tk()
rp = RestartableProgress(root)
rp.pack()
tk.mainloop()
if __name__ == '__main__':
main()
Just looking for some advice on a little GUI I'm practising with.
I'm trying to make a GUI for bending moments with a view to expand at some point...What I'm looking for is a method to grab the data from all the entry boxes using one button. I can get something working by having an individual button per entry box but I'd much rather have a simple 'submit' button...
Any help or advice is much appreciated,
cheers
current code:
import Tkinter as tk
class beam(tk.Tk):
def __init__(self,parent):
tk.Tk.__init__(self,parent)
self.parent = parent
self.initUI()
def initUI(self):
self.grid()
self.ent1 = tk.Entry(self)
self.ent1.grid(row=10,column=2)
self.ent2 = tk.Entry(self)
self.ent2.grid(row=12,column=2)
self.ent3 = tk.Entry(self)
self.ent3.grid(row=14,column=2)
self.ent4 = tk.Entry(self)
self.ent4.grid(row=16,column=2)
self.ent5 = tk.Entry(self)
self.ent5.grid(row=18,column=2)
cls_btn = tk.Button(self,text='close', command=self.cls_win)
cls_btn.grid(row = 30, column = 2)
lbE = tk.Label(self,text='Youngs Modulus')
lbE.grid(row=10,column=1)
lbD = tk.Label(self,text='Outer diameter')
lbD.grid(row=12,column=1)
lbd = tk.Label(self,text='Inner diameter')
lbd.grid(row=14,column=1)
lbL = tk.Label(self,text='Length')
lbL.grid(row=16,column=1)
lbw = tk.Label(self,text='UDL')
lbw.grid(row=18,column=1)
def btns(self):
self.ent1 = float(self.ent1.get())
self.ent2 = float(self.ent2.get())
self.ent3 = float(self.ent3.get())
self.ent4 = float(self.ent4.get())
self.ent5 = float(self.ent5.get())
def cls_win(self):
self.destroy()
def main():
app = beam(None)
w, h = app.winfo_screenwidth(), app.winfo_screenheight()
app.geometry("%dx%d+0+0" % (w, h))
app.title('Beam app')
app.mainloop()
if __name__ == '__main__':
main()
I can get each entry box to submit using:
self.btn1 = tk.Button(parent, text='Submit', command=self.btns)
You have a clear problem in the code in the following function:
def btns(self):
self.ent1 = float(self.ent1.get())
self.ent2 = float(self.ent2.get())
self.ent3 = float(self.ent3.get())
self.ent4 = float(self.ent4.get())
self.ent5 = float(self.ent5.get())
Here you are overwriting the self.ent? attributes, meaning that you can only execute btns once. Executing it twice will give an AttributeError, specifically:
AttributeError: 'float' object has no attribute 'get'
To answer your question, you are already getting the all of the entry boxes values with one button, so it is hard to tell what the problem is. However a minimal example of what you describe would be:
import Tkinter as tk
root = tk.Tk()
e1 = tk.Entry(root)
e1.pack()
e2 = tk.Entry(root)
e2.pack()
# This function is executed by the submit button
# it retrieves the outputs of both entry boxes
def submit():
print e1.get()
print e2.get()
tk.Button(root,text="submit",command=submit).pack()
root.mainloop()
You have to create Entry box first and grid it at last will work.
For example
import tkinter,tkinter.messagebox,tkinter.simpledialog as tk
from tkinter import ttk
import sqlite3
large_font=("Verdana",12)
class way(tk.Tk):
def __init__(self,*args,**kwargs):
a=tk.Tk.__init__(self,*args,**kwargs)
container=tk.Frame(a)
container.grid(row=0,column=0)
self.menu = tk.Menu(a, tearoff=0)
self.menu.add_command(label="Beep", command=self.bell)
self.menu.add_command(label="Exit")
self.bind("<Button-3>", self.showMenu)
self.frames={}
for f in (pa1,pa2,pa3,pa4,pa5,pa6,pa7,pa8,pa9,pa10):
frame=f(container,self)
self.frames[f]=frame
frame.grid(row=0,column=0,sticky='nsew')
self.show_frame(pa1)
menu=tk.Menu(self)
self.config(menu=menu)
file=tk.Menu(menu)
file.add_command(label='Exit',command=self.over)
menu.add_cascade(label='File',menu=file)
def show_frame(self,cont):
frame=self.frames[cont]
frame.tkraise()
def over(self):
self.destroy()
def sample(self,ev):
print(ev)
def showMenu(self, e):
self.menu.post(e.x_root, e.y_root)
class pa1(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
a=ttk.Button(self,text='Dealer',command=lambda:con.show_frame(pa2)).grid(row=0,column=0)
b=ttk.Button(self,text='Branch',command=lambda:con.show_frame(pa3)).grid(row=1,column=0)
c=ttk.Button(self,text='Customer',command=lambda:con.show_frame(pa4)).grid(row=2,column=0)
#I like to use bind but it does not support please tell me the reason why it does not support it.
class pa2(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
l1=tkinter.ttk.Label(self,text='Enter dealer id :',width=20)
l2=tkinter.ttk.Label(self,text='Enter dealer password :',width=20)
e1=tkinter.ttk.Entry(self)
e2=tkinter.ttk.Entry(self)
print(type(e1),type(e2),type(tkinter.ttk.Entry()))
b1=ttk.Button(self,text="Back",command=lambda:con.show_frame(pa1)).grid(row=2,column=0)
b2=ttk.Button(self,text='Submit',command=lambda:self.check(e1,e2)).grid(row=2,column=1)
l1.grid(row=0,column=0)
l2.grid(row=1,column=0)
e1.grid(row=0,column=1)
e2.grid(row=1,column=1)
def check(self,e1,e2):
try:
a=e1.get()
b=e2.get()
except Exception as e:
print(e)
else:
print('No error')
class pa3(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
b=ttk.Button(self,text="back",command=lambda:con.show_frame(pa1)).grid(row=0,column=0)
class pa4(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
b=ttk.Button(self,text="back",command=lambda:con.show_frame(pa1)).grid(row=0,column=0)
class pa5(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
class pa6(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
class pa7(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
class pa8(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
class pa9(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
class pa10(tk.Frame):
def __init__(self,parent,con):
tk.Frame.__init__(self,parent);
a=way()
a.mainloop()