after going through some stack overflow and external guides still was stuck with an odd problem thread starts but function not executing but used same type of setup in unity c# and visual studio C# windows application but works there fine any help would be appreciated
import tkinter
import threading
import PIL
import time
from datetime import datetime
from PIL import Image
import pyscreenshot as ImageGrab
from tkinter import *
from tkinter import messagebox
from tkinter import Tk, Label, Button, Entry
running=False
class app:
def __init__(self, master):
self.master = master
self.thread1=threading.Thread(target=self.screenshot)
master.title("Screenshot Taker")
Label(master, text="Interval between screenshots").grid(row=0,sticky=W)
self.E1=Spinbox(master, from_ = 5, to = 1000,state = "readonly")
self.E1.grid(row=0,column=2,padx=10)
Label(master, text="File prefix").grid(row=1,sticky=W)
self.E2=Entry(master)
self.E2.grid(row=1,column=2,padx=10)
self.B1=Button(master, text="start" ,command = self.start)
self.B1.grid(row=2,column=0,columnspan=3)
self.B2=Button(master, text="stop" ,command = self.stop)
self.B2.grid(row=2,column=1,columnspan=3)
def screenshot(self):
while(running):
im=ImageGrab.grab()
dt_string = datetime.now().strftime("%d_%m_%Y_%H_%M_%S")
name=str(self.E2.get())+str(dt_string)
logging.debug(name)
im.save(name+".png")
time.sleep(int(self.E1.get()))
def start(self):
running=True
self.thread1.start()
def stop(self):
running=False
self.thread1.join()
root = Tk()
app = app(root)
root.resizable(False, False)
root.mainloop()```
To access a global variable in python, you need to use "global var_name" in each function that needs to access it:
import tkinter
import threading
import PIL
import time
from datetime import datetime
from PIL import Image
import pyscreenshot as ImageGrab
from tkinter import *
from tkinter import messagebox
from tkinter import Tk, Label, Button, Entry
running=False
class app:
def __init__(self, master):
self.master = master
self.thread1=threading.Thread(target=self.screenshot)
master.title("Screenshot Taker")
Label(master, text="Interval between screenshots").grid(row=0,sticky=W)
self.E1=Spinbox(master, from_ = 5, to = 1000,state = "readonly")
self.E1.grid(row=0,column=2,padx=10)
Label(master, text="File prefix").grid(row=1,sticky=W)
self.E2=Entry(master)
self.E2.grid(row=1,column=2,padx=10)
self.B1=Button(master, text="start" ,command = self.start)
self.B1.grid(row=2,column=0,columnspan=3)
self.B2=Button(master, text="stop" ,command = self.stop)
self.B2.grid(row=2,column=1,columnspan=3)
def screenshot(self):
global running
while(running):
im=ImageGrab.grab()
dt_string = datetime.now().strftime("%d_%m_%Y_%H_%M_%S")
name=str(self.E2.get())+str(dt_string)
logging.debug(name)
im.save(name+".png")
time.sleep(int(self.E1.get()))
def start(self):
global running
running=True
self.thread1.start()
def stop(self):
global running
running=False
self.thread1.join()
root = Tk()
app = app(root)
root.resizable(False, False)
root.mainloop()
Related
i'm a new programmer and there are certainly several errors but this shouldn't be difficult to spot. I need to create a simple window with a field named "Concorrente 1:" and an entry field displayed by function named lacopertina(). I don't understand where is the error:
import tkinter as tk
from tkinter import *
from tkinter.ttk import *
from tkinter import ttk
class schermoiniziale(tk.Frame):
def lacopertina():
print(gio1)
#return (tot1)
def __init__(self):
global gio1
#tot1=0
#schermo1=Tk()
self.gio1=tk.StringVar()
lab1=ttk.Label(self, text="Concorrente 1:")
lab1.pack()
ent1=ttk.Entry(self, textvariable=self.gio1)
ent1.pack()
pulsante = ttk.Button(self, text="Inizio", textvariable=self.gio1, command=self.lacopertina)
pulsante.pack()
def main():
schermoiniziale().mainloop()
if __name__== "__main__":
main()
I would suggest you to go through some tutorials on Python OOP.
I have modified your code as below with some comment:
# avoid using wildcard import
import tkinter as tk
from tkinter import ttk
class schermoiniziale(tk.Frame):
def __init__(self, master, **kw):
# need to call __init__() of inherited class
super().__init__(master, **kw)
self.gio1 = tk.StringVar()
lab1 = ttk.Label(self, text="Concorrente 1:")
lab1.pack()
ent1 = ttk.Entry(self, textvariable=self.gio1)
ent1.pack()
# removed textvariable=self.gio1 as I think you actually don't need it
pulsante = ttk.Button(self, text="Inizio", command=self.lacopertina)
pulsante.pack()
def lacopertina(self):
# use .get() to get the content of a StringVar
print(self.gio1.get())
def main():
# need to create the root window before creating other widget
root = tk.Tk()
# pass root window as the parent of the widget
frame = schermoiniziale(root)
frame.pack()
# start the tkinter mainloop
root.mainloop()
if __name__== "__main__":
main()
I have a launcher application that is suppose to call functions from separate modules using a button. I have a module named "image_viewer" containing a class function that is suppose to display an image after clicking a button. The image_viewer function works fine in its original module but when I try to call it from my Launcher module I receive the error "_tkinter.TclError: image "pyimage1" doesn't exist". I have included my code for the launcher and image_viewer modules for your reference below.
image_viewer module:
from PIL import ImageTk, Image
import tkinter as tk
class ImageViewer:
def __init__(self, root, image_filename):
self.root = root
self.image_filename = image_filename
self.root.title('ImageViewer')
self.root.geometry('400x350')
self.canvas = tk.Canvas(self.root, width=300, height=300)
self.canvas.place(x=10, y=10)
self.btnView = tk.Button(text='View', command=self.view_image)
self.btnView.place(x=20, y=265)
self.btnClose = tk.Button(text='close', command=lambda:[self.destroy(), self.clear()])
self.btnClose.place(x=65, y=265)
def view_image(self):
self.img = ImageTk.PhotoImage(Image.open(self.image_filename)) # Keep ref to image.
self.canvas.create_image(20, 20, anchor=tk.NW, image=self.img)
def destroy(self):
self.root.destroy()
def clear(self):
self.btnClose.destroy()
self.btnView.destroy()
def main(image_filename):
root = tk.Tk()
ImageViewer(root, image_filename)
root.mainloop()
if __name__ == '__main__':
main('../raw/as.png')
Launcher module:
from audioplayer import audioplayer
from texteditor import editor
from imageviewer import image_viewer
import tkinter as tk
class Launcher:
def __init__(self, win):
self.root = win
self.root.title('Launcher')
self.root.geometry('400x350')
self.btnEditor = tk.Button(text='Editor', command=self.editor, padx=10)
self.btnEditor.pack(side=tk.LEFT)
self.btnEditor.place(x=5, y=315)
self.btnAudio = tk.Button(text='AudioPlayer', command=self.audioplayer, padx=10)
self.btnAudio.pack(side=tk.LEFT)
self.btnAudio.place(x=75, y=315)
self.btnImage = tk.Button(text='ImageViewer', command=self.imageviewer, padx=10)
self.btnImage.pack(side=tk.LEFT)
self.btnImage.place(x=178, y=315)
self.quit_button = tk.Button(text = "Quit", command=self.quit, padx=10)
self.quit_button.pack(side=tk.LEFT)
self.quit_button.place(x=340, y=315)
def editor(self):
editor.main()
def audioplayer(self):
audioplayer.main()
def imageviewer(self):
image_viewer.main('../raw/as.png')
def quit(self):
self.root.destroy()
def main():
root = tk.Tk()
Launcher(root)
root.mainloop()
if __name__ == '__main__':
main()
I have just started using kivy and Tkinter to develop simple apps for starters. Recently, I created a digital Clock program that can be used on desktop. It works fine because it is simple with just a few lines of codes. I wanted to add one functionality which is Alarm. Can anyone please guide me on how to go about it.
It is my first time, so am not sure if I posted this question the right way or not. So below is the code I used to get my output.
import tkinter as tk
from tkinter.ttk import *
# I imported strftime to use for formatting time details of the program.
from time import strftime
import datetime
# creating tkinter window
root = tk.Tk()
root.title('Clock')
root.attributes('-topmost', True) # This line here sets our app to be the
topmost in the window screen.
# root.attributes('-topmost', False) When this line is added, the app will
no longer have that topmost privilege.
# This function will show us the calender on the program.
def datetime():
string1 = strftime('%d/%b/%Y') # This line can be joined with the other one below with \n and it will work.
lbl1.config(text=string1)
lbl1.after(1000, datetime)
lbl1 = Label(root, font=('verdana', 20, 'bold'), background='black',
foreground='#808000')
lbl1.pack(fill=tk.BOTH)
datetime()
# This function is used to display time on our label
def time():
string = strftime('%H:%M:%S %p')
lbl.config(text=string)
lbl.after(1000, time) # updating the label.
# Giving the Label some style.
lbl = Label(root, font=('verdana', 22, 'bold'), background='#050929',
foreground='silver')
# packing the Label to the center.
# of the tkinter window
lbl.pack(anchor=tk.CENTER)
time()
root.mainloop()
For a procedural solution just add the after method of tkinter.
import tkinter as tk
import datetime
def tick():
showed_time = ''
current_time = datetime.datetime.now().strftime("%H:%M:%S")
if showed_time != current_time:
showed_time = current_time
clock.configure(text=current_time)
clock.after(1000, tick)
if showed_time == '10:00:00': #10 o'clock print alarm
print('alarm')
root=tk.Tk()
clock = tk.Label(root)
clock.pack()
tick()
root.mainloop()
An object orientated solution could be this:
import tkinter as tk
from tkinter import ttk as ttk
import datetime
root=tk.Tk()
class AlarmClock(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.all_alarms = []
self.ini_body()
self.ini_clock()
self.ini_mid()
self.ini_table()
def ini_body(self):
self.up_frame = tk.Frame(self)
self.mid_frame= tk.Frame(self)
self.dow_frame= tk.Frame(self)
self.up_frame.pack(side='top')
self.mid_frame.pack(side='top',fill='x')
self.dow_frame.pack(side='top')
def ini_clock(self):
self.clock = tk.Label(self.up_frame, text='00:00:00')
self.clock.pack(side='top', fill='x')
self.tick()
def tick(self):
self.showed_time = ''
self.current_time = datetime.datetime.now().strftime("%H:%M:%S")
if self.showed_time != self.current_time:
self.showed_time = self.current_time
self.clock.configure(text=self.current_time)
if self.showed_time in self.all_alarms:
self.invoke_alarm(self.showed_time)
self.after(1000, self.tick)
def ini_table(self):
self.table = ttk.Treeview(self.dow_frame,height=10,columns=('#1'))
self.table.heading('#0', text='Alarm ID')
self.table.heading('#1', text='Alarm time')
self.table.pack()
def ini_mid(self):
self.alarm_id = tk.Entry(self.mid_frame,justify='center')
self.alarm_id.insert('end','Alarm ID')
self.alarm_time = tk.Entry(self.mid_frame,justify='center')
self.alarm_time.insert('end','HH:MM')
self.set_button = tk.Button(self.mid_frame, text='set alarm',
command=self.set_alarm)
self.cancel_button=tk.Button(self.mid_frame, text='cancel alarm',
command=self.cancel_alarm)
self.alarm_time.grid(column=1,row=0,sticky='ew')
self.alarm_id.grid(column=0,row=0, sticky='we')
self.set_button.grid(column=0, row=1, sticky='ew')
self.cancel_button.grid(column=1, row=1, sticky='ew')
self.mid_frame.columnconfigure(0, weight=1)
self.mid_frame.columnconfigure(1, weight=1)
def set_alarm(self):
Id = self.alarm_id.get()
time = self.alarm_time.get()
self.table.insert('','end', iid=Id, text=Id,
values=time, tags=time)
self.register_alarm()
def cancel_alarm(self):
Id = self.alarm_id.get()
time = self.alarm_time.get()
if self.table.exists(Id):
tag = self.table.item(Id, "tags")[0]
alarm_time=tag+":00"
self.all_alarms.remove(alarm_time)
self.table.delete(Id)
elif self.table.tag_has(time):
Id = self.table.tag_has(time)[0]
tag = self.table.item(Id, "tags")[0]
alarm_time=tag+":00"
self.all_alarms.remove(alarm_time)
self.table.delete(Id)
def register_alarm(self):
self.all_alarms.append(f'{self.alarm_time.get()}:00')
def invoke_alarm(self, time):
self.alarm_window = tk.Toplevel()
self.alarm_window.title('Alarm!')
self.message = tk.Label(self.alarm_window,
text=f"ALARM!! It's {time[:5]} o'clock!")
self.message.pack(fill='both')
alarm = AlarmClock(root)
alarm.pack()
root.mainloop()
Hope you enjoy and let me know if you have any question about it.
I want to write a program using Tkinter GUI, which performs a certain task in a thread. When an error occurs during the execution of the task, the program should pop up an error-window, for example using tkMessageBox. Of course the program crashes when it should pop up the messagebox from the new thread, since Tkinter isn't thread safe, but I hope that there is a solution to this problem.
Here is an easy example of a not working code (edited):
from tkinter import *
import tkMessageBox
from threading import *
import time
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button = Button(frame, text = "Task", command = self.thread_task)
self.button.pack(side=LEFT)
def thread_task(self):
thread = Thread(target = self.task)
thread.start()
def task(self):
#perform task...
time.sleep(1) #Just as a filler in the code
#command to open an error popup, e.g. tkMessageBox.showerror("Error", "Problem occured")
root = Tk()
app = App(root)
root.mainloop()
You can use try-except inside a thread.
Here is an example based on your code (edited to work with Python 2):
from Tkinter import *
import tkMessageBox
from threading import *
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button = Button(frame, text="Task", command=self.thread_task)
self.button.pack(side=LEFT)
def thread_task(self):
thread = Thread(target=self.task)
thread.start()
def task(self):
try:
time.sleep(1)
self.button["text"] = "Started"
self.button["state"] = "disabled"
raise ValueError # or anything else
except:
tkMessageBox.showerror("Error", "Problem occured")
self.button["text"] = "Task"
self.button["state"] = "normal"
if __name__ == "__main__":
root = Tk()
app = App(root)
root.mainloop()
Hi Python and Tkinter Gurus,
I am trying to build a simple GUI which has two buttons. When the Button is clicked, a thread is started to do some work. This work normally takes 10s/15s. And the GUI also works fine.
But I want to implement a pop-up to notify which thread has been completed. I have checked t.isAlive() function and could not implement it because I don't know how to trigger an event based on isAlive in the main loop.
Here is my sample code
from threading import Thread
from time import sleep
import Tkinter
import ttk
class SmallGui:
def __init__(self, master):
self.master = master
self.master.title('test gui')
self.button_1 = ttk.Button(self.master,
text='Start 1',
command=lambda: self.init_thread(1))
self.button_2 = ttk.Button(self.master,
text='Start 2',
command=lambda: self.init_thread(2))
self.button_1.pack()
self.button_2.pack()
def init_thread(self, work):
if work == 1:
t = Thread(target=self.work_1)
t.start()
else:
t = Thread(target=self.work_2)
t.start()
#staticmethod
def work_1():
print 'Work 1 started'
# Do some Task and return a list
sleep(10)
#staticmethod
def work_2():
print 'Work 2 Started'
# Do some Task and return a list
sleep(15)
if __name__ == '__main__':
root = Tkinter.Tk()
run_gui = SmallGui(root)
root.mainloop()
You can use tkinter's messagebox. Tkinter has a built in method that can be used for all kinds of pop-up messages or questions. Here we will use messagebox.showinfo.
I am working on Python 3.X so I added a import method that will work for both 3.X and 2.X versions of python.
from threading import Thread
from time import sleep
try:
import Tkinter as tk
import tkMessageBox as mb
import ttk
except ImportError:
import tkinter as tk
from tkinter import messagebox as mb
import tkinter.ttk as ttk
class SmallGui:
def __init__(self, master):
self.master = master
self.master.title('test gui')
self.button_1 = ttk.Button(self.master,
text='Start 1',
command=lambda: self.init_thread(1))
self.button_2 = ttk.Button(self.master,
text='Start 2',
command=lambda: self.init_thread(2))
self.button_1.pack()
self.button_2.pack()
def init_thread(self, work):
if work == 1:
t = Thread(target=self.work_1)
t.start()
else:
t = Thread(target=self.work_2)
t.start()
#staticmethod
def work_1():
print ('Work 1 started')
# Do some Task and return a list
sleep(1)
mb.showinfo("test", "Work 1 complete")
#staticmethod
def work_2():
print ('Work 2 Started')
# Do some Task and return a list
sleep(1)
mb.showinfo("test", "Work 2 complete")
if __name__ == '__main__':
root = tk.Tk()
run_gui = SmallGui(root)
root.mainloop()
UPDATE:
For whatever reason my above solution works in python 3 but no in 2.7.14.
The below example however does work in 2.7.14 and should work for you.
What I have done here is create 2 class attributes to monitor each thread.
I have created a method that will check ever 1 second if a thread is active and if the thread becomes inactive a messagebox will popup.
from threading import Thread
from time import sleep
import Tkinter as tk
import tkMessageBox as mb
import ttk
class SmallGui(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.master.title('test gui')
self.button_1 = ttk.Button(self.master,
text='Start 1',
command=lambda: self.init_thread(1))
self.button_2 = ttk.Button(self.master,
text='Start 2',
command=lambda: self.init_thread(2))
self.button_1.pack()
self.button_2.pack()
self.work1_status = None
self.work2_status = None
def init_thread(self, work):
if work == 1:
self.work1_status = Thread(target=self.work_1)
self.work1_status.start()
self.check_thread(self.work1_status, work)
else:
self.work2_status = Thread(target=self.work_2)
self.work2_status.start()
self.check_thread(self.work2_status, work)
def check_thread(self, pass_thread, thread_name):
if pass_thread.isAlive() == False:
pass_thread = None
mb.showinfo("test", "Work {} complete".format(thread_name))
else:
self.after(1000, lambda: self.check_thread(pass_thread, thread_name))
#staticmethod
def work_1():
print ('Work 1 started')
# Do some Task and return a list
sleep(5)
#staticmethod
def work_2():
print ('Work 2 Started')
# Do some Task and return a list
sleep(5)
if __name__ == '__main__':
root = tk.Tk()
run_gui = SmallGui(root)
root.mainloop()