Python Tk : How to create a custom message box - python

Please give me advice.
Custom message box requirements include:
Be modal (Realized)
While the message box is displayed, the message box is on the front and other TK objects cannot be operated.
Wait for the return value of the message box
I want to wait for the message box input before moving on to the next action (display / hide widget etc.).
I want to continue processing the application(Realized)
The original Tk object wants to continue regular processing with the after method.
I want to adopt my own design(Realized)
In order to unify the design.
-Execution result-
If you close the message box, an error is displayed.
It will not proceed to the second line in the Btn_Messagebox_clicked method until self.MainWindow_obj is closed.
I don't know why I get an error. Also, if you close the message box, you won't know why it won't come back.
invalid command name "2291801753672dialog_mouse_release"
while executing
"2291801753672dialog_mouse_release 105 1 ?? ?? ?? 264 103442140 ?? 22 6 ?? 0 ?? ?? .!frame3.!button2 5 438 422 ??"
invoked from within
"if {"[2291801753672dialog_mouse_release 105 1 ?? ?? ?? 264 103442140 ?? 22 6 ?? 0 ?? ?? .!frame3.!button2 5 438 422 ??]" == "break"} break"
(command bound to event)
-code-
import tkinter as tk
from tkinter import ttk
from PIL import Image,ImageTk,ImageDraw,ImageFont
class CustomDialog(object):
def __init__(self):
self.title_bar_color = '#8FAADC'
self.item_ground_color = 'whitesmoke'
self.background_color = '#D9D9D9'
self.select_bar_color = '#BDD7EE'
self.isDrag_DlgMotion = False
self.drag_dx = 0
self.drag_dy = 0
def dialog_left_click(self,event):
dialog_x=self.dev_dialog.winfo_rootx()
dialog_y=self.dev_dialog.winfo_rooty()
point_x=self.dev_dialog.winfo_pointerx()
point_y=self.dev_dialog.winfo_pointery()
dx = point_x - dialog_x
dy = point_y - dialog_y
if (dx >= 0 and dx <= self.title_bar_width) and (dy >= 0 and dy <= self.title_bar_height):
self.drag_dx = dx
self.drag_dy = dy
self.isDrag_DlgMotion = True
return
def dialog_mouse_move_on(self,event):
if self.isDrag_DlgMotion:
X = event.x_root - self.drag_dx
Y = event.y_root - self.drag_dy
self.dev_dialog.geometry('+{0}+{1}'.format(X, Y))
pass
return
def dialog_mouse_release(self,event):
if self.isDrag_DlgMotion:
self.isDrag_DlgMotion = False
return
class CommonMessageBoxDialog(CustomDialog):
def __init__(self,title,message,state,parent = None):
self.return_state = None
if not isinstance(title,str) or not isinstance(message,str) or not isinstance(state,int):
return
if state < 1 or state > 3 :
return
root = ttk.tkinter.Tk()
#root = tk.Toplevel(parent)
#root.overrideredirect(True)
super().__init__()
self.box_state = state
self.box_message = message
self.box_title = title
W = 0
H = 1
self.dlg_size = [400,200]
self.title_bar_width = self.dlg_size[W]
self.title_bar_height = 40
self.btn_bar_height = 42
self.btn_32x32_size = 42
self.row_height = 28
self.btn_row_height = 32
self.frm_space = 10
self.parent = parent
self.CreateDialog(root)
root.wait_window(root)
#root.mainloop()
def CreateDialog(self,root):
W = 0
H = 1
if self.parent != None:
self.parent.update_idletasks()
ww=self.parent.winfo_screenwidth()
wh=self.parent.winfo_screenheight()
x=self.parent.winfo_rootx()
y=self.parent.winfo_rooty()
parent_w = self.parent.winfo_width()
parent_h = self.parent.winfo_height()
parent_x = self.parent.winfo_x()
parent_y = self.parent.winfo_y()
else:
root.update_idletasks()
ww=root.winfo_screenwidth()
wh=root.winfo_screenheight()
x=root.winfo_rootx()
y=root.winfo_rooty()
parent_w = root.winfo_width()
parent_h = root.winfo_height()
parent_x = root.winfo_x()
parent_y = root.winfo_y()
self.dev_dialog = root
dialog = self.dev_dialog
dialog.overrideredirect(True)
dlg_x = int((parent_x+parent_w) - (self.dlg_size[W]/2))
dlg_y = int((parent_y+parent_h) - (self.dlg_size[H]/2))
if dlg_x < 0 : dlg_x = 0
if dlg_y < 0 : dlg_y = 0
dialog.geometry('{}x{}+{}+{}'.format(self.dlg_size[W],self.dlg_size[H],dlg_x,dlg_y))
self.Title_Bar = tk.Frame(
dialog,
relief='flat',
bg = self.title_bar_color ,
)
self.Title_Label = tk.Label(
self.Title_Bar,
bg = self.title_bar_color ,
text = self.box_title,
)
dialog.bind('<Button-1>', self.dialog_left_click)
dialog.bind('<B1-Motion>', self.dialog_mouse_move_on)
dialog.bind('<ButtonRelease-1>',self.dialog_mouse_release)
self.MsgArea_frame = tk.Frame(
dialog,
relief='flat',
bg = self.select_bar_color,
)
self.message_frame = tk.Frame(
self.MsgArea_frame,
relief='flat',
bg = self.item_ground_color ,
)
self.label_message = tk.Label(
self.message_frame,
bg = self.item_ground_color ,
text = self.box_message,
)
self.BtnArea_frame = tk.Frame(
dialog,
relief='flat',
bg = self.item_ground_color,
)
self.btn_ok = tk.Button(
self.BtnArea_frame,
bg = self.item_ground_color,
text = 'OK',
command = lambda:self.btn_msgbox_clicked(1),
)
self.btn_yes = tk.Button(
self.BtnArea_frame,
bg = self.item_ground_color,
text = 'YES',
command = lambda:self.btn_msgbox_clicked(1),
)
self.btn_no = tk.Button(
self.BtnArea_frame,
bg = self.item_ground_color,
text = 'NO',
command = lambda:self.btn_msgbox_clicked(2),
)
self.btn_cancel = tk.Button(
self.BtnArea_frame,
bg = self.item_ground_color,
text = 'CANCEL',
command = lambda:self.btn_msgbox_clicked(3),
)
frm_space = self.frm_space
msg_frm_w = 4
btn_fram_h = 36
message_area_h = self.dlg_size[H] - self.title_bar_height - frm_space *2 - btn_fram_h
# Frame
self.Title_Bar.place(
x = 0, y = 0,
width = self.title_bar_width, height = self.title_bar_height
)
self.MsgArea_frame.place(
x = frm_space, y = self.title_bar_height + frm_space,
width = self.title_bar_width - frm_space*2, height = message_area_h
)
self.BtnArea_frame.place(
x = 0, y = self.title_bar_height + frm_space + message_area_h,
width = self.title_bar_width, height = btn_fram_h
)
self.Title_Label.grid(row = 0, column = 1,sticky = tk.W+tk.N+tk.S)
self.Title_Bar.columnconfigure(0,minsize = self.frm_space)
self.Title_Bar.rowconfigure(0,minsize = self.title_bar_height)
self.MsgArea_frame.columnconfigure(0,minsize = self.frm_space)
self.MsgArea_frame.rowconfigure(0,minsize = message_area_h)
self.BtnArea_frame.rowconfigure(0,minsize = btn_fram_h)
self.message_frame.place(
x = msg_frm_w, y = msg_frm_w,
width = self.title_bar_width - frm_space*2 - msg_frm_w*2, height = message_area_h - msg_frm_w*2,
)
# self.message_frame
self.label_message.grid(row = 0, column = 1,sticky = tk.W+tk.N+tk.S)
if self.box_state == 1:
self.btn_ok.place(
x = (self.title_bar_width/2) - 80/2 , y = btn_fram_h/2 - 24/2,
)
if self.box_state == 2:
self.btn_yes.place(
x = (self.title_bar_width/2) - (80 + frm_space) , y = btn_fram_h/2 - 24/2,
)
self.btn_no.place(
x = (self.title_bar_width/2) + frm_space , y = btn_fram_h/2 - 24/2,
)
if self.box_state == 3:
self.btn_yes.place(
x = (self.title_bar_width/2) - (80*1.5 + frm_space*2) , y = btn_fram_h/2 - 24/2,
)
self.btn_no.place(
x = (self.title_bar_width/2) - 80/2 , y = btn_fram_h/2 - 24/2,
)
self.btn_cancel.place(
x = (self.title_bar_width/2) + 80/2 + frm_space*2 , y = btn_fram_h/2 - 24/2,
)
#dialog.grab_set()
dialog.grab_set_global()
def btn_msgbox_clicked(self,state):
self.return_state = state
self.dev_dialog.grab_release()
self.dev_dialog.destroy()
def get_return_state(self):
return self.return_state
class CreateScreen(object):
def __init__(self):
self.cnt = 0
W = 0
H = 1
self.dlg_size = [400,200]
geo_string = '{}x{}'.format(self.dlg_size[W],self.dlg_size[H])
self.MainWindow_obj = ttk.tkinter.Tk()
self.MainWindow_obj.geometry(geo_string)
self.CntSting = tk.StringVar()
self.CntSting.set('...')
Label_Conter_text = tk.Label(
self.MainWindow_obj,
textvariable = self.CntSting,
)
self.MsgSting = tk.StringVar()
self.MsgSting.set(str(self.cnt))
Label_Message_text = tk.Label(
self.MainWindow_obj,
textvariable = self.MsgSting,
)
Btn_Messagebox = tk.Button(
self.MainWindow_obj,
text = 'Push',
command = self.Btn_Messagebox_clicked
)
Label_Conter_text.pack()
Label_Message_text.pack()
Btn_Messagebox.pack()
self.MainWindow_obj.after(1000,self.loop_msg)
self.MainWindow_obj.mainloop()
def Btn_Messagebox_clicked(self):
self.dlg = CommonMessageBoxDialog(title='Test',message='Do you remember ?',state=3,parent =self.MainWindow_obj)
ret = self.dlg.get_return_state()
if ret == 1:
self.MsgSting.set('Yes')
if ret == 2:
self.MsgSting.set('No')
if ret == 3:
self.MsgSting.set('Cancel')
return
def loop_msg(self):
self.cnt += 1
self.MsgSting.set(str(self.cnt))
self.MainWindow_obj.after(1000,self.loop_msg)
if __name__ == '__main__':
screen_obj = CreateScreen()

I solved it myself.
I'm binding mouse events for custom dialog navigation.
Therefore, after Destroy was called, the dialog with the mouse release event discarded was notified and an error occurred.
To solve this, I made self.isDestroy, and in the btn_msgbox_clicked method, changed self.isDestroy to True and connected the dialog_mouse_release method to the destroy method.
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from PIL import Image,ImageTk,ImageDraw,ImageFont
import datetime
class CustomDialog(object):
def __init__(self):
self.title_bar_color = '#8FAADC'
self.item_ground_color = 'whitesmoke'
self.background_color = '#D9D9D9'
self.select_bar_color = '#BDD7EE'
self.isDrag_DlgMotion = False
self.drag_dx = 0
self.drag_dy = 0
def dialog_left_click(self,event):
dialog_x=self.dev_dialog.winfo_rootx()
dialog_y=self.dev_dialog.winfo_rooty()
point_x=self.dev_dialog.winfo_pointerx()
point_y=self.dev_dialog.winfo_pointery()
dx = point_x - dialog_x
dy = point_y - dialog_y
if (dx >= 0 and dx <= self.title_bar_width) and (dy >= 0 and dy <= self.title_bar_height):
self.drag_dx = dx
self.drag_dy = dy
self.isDrag_DlgMotion = True
return
def dialog_mouse_move_on(self,event):
if self.isDrag_DlgMotion:
X = event.x_root - self.drag_dx
Y = event.y_root - self.drag_dy
self.dev_dialog.geometry('+{0}+{1}'.format(X, Y))
pass
return
def dialog_mouse_release(self,event):
if self.isDrag_DlgMotion:
self.isDrag_DlgMotion = False
return
class CommonMessageBoxDialog(CustomDialog):
def __init__(self,title,message,state,parent = None):
self.return_state = None
self.isDestroy = False
if not isinstance(title,str) or not isinstance(message,str) or not isinstance(state,int):
return
if state < 1 or state > 3 :
return
root = ttk.tkinter.Tk()
#root = tk.Toplevel(parent)
#root.overrideredirect(True)
super().__init__()
self.box_state = state
self.box_message = message
self.box_title = title
W = 0
H = 1
self.dlg_size = [400,200]
self.title_bar_width = self.dlg_size[W]
self.title_bar_height = 40
self.btn_bar_height = 42
self.btn_32x32_size = 42
self.row_height = 28
self.btn_row_height = 32
self.frm_space = 10
self.parent = parent
self.CreateDialog(root)
root.wait_window(root)
#root.mainloop()
def CreateDialog(self,root):
W = 0
H = 1
if self.parent != None:
self.parent.update_idletasks()
ww=self.parent.winfo_screenwidth()
wh=self.parent.winfo_screenheight()
x=self.parent.winfo_rootx()
y=self.parent.winfo_rooty()
parent_w = self.parent.winfo_width()
parent_h = self.parent.winfo_height()
parent_x = self.parent.winfo_x()
parent_y = self.parent.winfo_y()
else:
root.update_idletasks()
ww=root.winfo_screenwidth()
wh=root.winfo_screenheight()
x=root.winfo_rootx()
y=root.winfo_rooty()
parent_w = root.winfo_width()
parent_h = root.winfo_height()
parent_x = root.winfo_x()
parent_y = root.winfo_y()
self.dev_dialog = root
dialog = self.dev_dialog
dialog.overrideredirect(True)
dlg_x = int((parent_x+parent_w) - (self.dlg_size[W]/2))
dlg_y = int((parent_y+parent_h) - (self.dlg_size[H]/2))
if dlg_x < 0 : dlg_x = 0
if dlg_y < 0 : dlg_y = 0
dialog.geometry('{}x{}+{}+{}'.format(self.dlg_size[W],self.dlg_size[H],dlg_x,dlg_y))
self.Title_Bar = tk.Frame(
dialog,
relief='flat',
bg = self.title_bar_color ,
)
self.Title_Label = tk.Label(
self.Title_Bar,
bg = self.title_bar_color ,
text = self.box_title,
)
dialog.bind('<Button-1>', self.dialog_left_click)
dialog.bind('<B1-Motion>', self.dialog_mouse_move_on)
dialog.bind('<ButtonRelease-1>',self.dialog_mouse_release)
self.MsgArea_frame = tk.Frame(
dialog,
relief='flat',
bg = self.select_bar_color,
)
self.message_frame = tk.Frame(
self.MsgArea_frame,
relief='flat',
bg = self.item_ground_color ,
)
self.label_message = tk.Label(
self.message_frame,
bg = self.item_ground_color ,
text = self.box_message,
)
self.BtnArea_frame = tk.Frame(
dialog,
relief='flat',
bg = self.item_ground_color,
)
self.btn_ok = tk.Button(
self.BtnArea_frame,
bg = self.item_ground_color,
text = 'OK',
command = lambda:self.btn_msgbox_clicked(1),
)
self.btn_yes = tk.Button(
self.BtnArea_frame,
bg = self.item_ground_color,
text = 'YES',
command = lambda:self.btn_msgbox_clicked(1),
)
self.btn_no = tk.Button(
self.BtnArea_frame,
bg = self.item_ground_color,
text = 'NO',
command = lambda:self.btn_msgbox_clicked(2),
)
self.btn_cancel = tk.Button(
self.BtnArea_frame,
bg = self.item_ground_color,
text = 'CANCEL',
command = lambda:self.btn_msgbox_clicked(3),
)
frm_space = self.frm_space
msg_frm_w = 4
btn_fram_h = 36
message_area_h = self.dlg_size[H] - self.title_bar_height - frm_space *2 - btn_fram_h
# Frame
self.Title_Bar.place(
x = 0, y = 0,
width = self.title_bar_width, height = self.title_bar_height
)
self.MsgArea_frame.place(
x = frm_space, y = self.title_bar_height + frm_space,
width = self.title_bar_width - frm_space*2, height = message_area_h
)
self.BtnArea_frame.place(
x = 0, y = self.title_bar_height + frm_space + message_area_h,
width = self.title_bar_width, height = btn_fram_h
)
self.Title_Label.grid(row = 0, column = 1,sticky = tk.W+tk.N+tk.S)
self.Title_Bar.columnconfigure(0,minsize = self.frm_space)
self.Title_Bar.rowconfigure(0,minsize = self.title_bar_height)
self.MsgArea_frame.columnconfigure(0,minsize = self.frm_space)
self.MsgArea_frame.rowconfigure(0,minsize = message_area_h)
self.BtnArea_frame.rowconfigure(0,minsize = btn_fram_h)
self.message_frame.place(
x = msg_frm_w, y = msg_frm_w,
width = self.title_bar_width - frm_space*2 - msg_frm_w*2, height = message_area_h - msg_frm_w*2,
)
# self.message_frame
self.label_message.grid(row = 0, column = 1,sticky = tk.W+tk.N+tk.S)
if self.box_state == 1:
self.btn_ok.place(
x = (self.title_bar_width/2) - 80/2 , y = btn_fram_h/2 - 24/2,
)
if self.box_state == 2:
self.btn_yes.place(
x = (self.title_bar_width/2) - (80 + frm_space) , y = btn_fram_h/2 - 24/2,
)
self.btn_no.place(
x = (self.title_bar_width/2) + frm_space , y = btn_fram_h/2 - 24/2,
)
if self.box_state == 3:
self.btn_yes.place(
x = (self.title_bar_width/2) - (80*1.5 + frm_space*2) , y = btn_fram_h/2 - 24/2,
)
self.btn_no.place(
x = (self.title_bar_width/2) - 80/2 , y = btn_fram_h/2 - 24/2,
)
self.btn_cancel.place(
x = (self.title_bar_width/2) + 80/2 + frm_space*2 , y = btn_fram_h/2 - 24/2,
)
#dialog.grab_set()
dialog.grab_set_global()
def btn_msgbox_clicked(self,state):
self.return_state = state
self.isDestroy = True
def get_return_state(self):
return self.return_state
def dialog_mouse_release(self,event):
if self.isDrag_DlgMotion:
self.isDrag_DlgMotion = False
if self.isDestroy:
self._quit()
return
def _quit(self):
self.dev_dialog.grab_release()
self.dev_dialog.destroy()
class CreateScreen(object):
def __init__(self):
self.cnt = 0
W = 0
H = 1
self.dlg_size = [400,200]
geo_string = '{}x{}'.format(self.dlg_size[W],self.dlg_size[H])
self.MainWindow_obj = ttk.tkinter.Tk()
self.MainWindow_obj.geometry(geo_string)
self.CntSting = tk.StringVar()
self.CntSting.set(str(self.cnt))
Label_Conter_text = tk.Label(
self.MainWindow_obj,
textvariable = self.CntSting,
)
self.MsgSting = tk.StringVar()
self.MsgSting.set('...')
Label_Message_text = tk.Label(
self.MainWindow_obj,
textvariable = self.MsgSting,
)
Btn_Messagebox = tk.Button(
self.MainWindow_obj,
text = 'Push',
command = self.Btn_Messagebox_clicked
)
Label_Conter_text.pack()
Label_Message_text.pack()
Btn_Messagebox.pack()
self.MainWindow_obj.after(1000,self.loop_msg)
self.MainWindow_obj.mainloop()
def Btn_Messagebox_clicked(self):
self.dlg = CommonMessageBoxDialog(title='Test',message='Do you remember ?',state=3,parent =self.MainWindow_obj)
ret = self.dlg.get_return_state()
if ret == 1:
self.MsgSting.set('Yes')
if ret == 2:
self.MsgSting.set('No')
if ret == 3:
self.MsgSting.set('Cancel')
return
def loop_msg(self):
self.cnt += 1
self.CntSting.set(str(self.cnt))
self.MainWindow_obj.after(1000,self.loop_msg)
if __name__ == '__main__':
screen_obj = CreateScreen()

Related

What is the fastest Method to display an Image in a Frame?

I use 2 different Threads to Capture and to Display a Webcamstream.
I checked the FPS in the Capture and in the Display Function.
While the Capture Function can deliver full FPS, the Display Function is slower and getting slower with higher Resolutions.
Is there a faster Way to display the (now synced)Webcamstream in a TKinter Frame?
My goal would be getting synced 20 FPS in Display (and later in Record) after Resizing.
My Testprogramm:
global myfps
myfps = 0
global my_width
my_width = 640
global my_height
my_height = 480
def fakefunc():
_=7
def display_start():
print('display_start activated')
gv.test_wiedergabe = 'True'
mts = multi_thread_stream(ready)
def display_stop():
print('display_stop activated')
gv.test_wiedergabe = 'False'
def aufnahme_start():
aufnahme = 'True'
class multi_thread_stream:
def __init__(self, ready=None):
self.ready = ready
self.cap = cv2.VideoCapture(0)
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 2)
self.AIM_FPS = 1/25
self.AIM_FPS_MS = int(self.AIM_FPS * 1000)
self.cap.set(3, my_width)
self.cap.set(4, my_height)
self.frame = {}
self.fps = 0
self.wiedergabe = 'False'
#Create the Threads
self.t1 = threading.Thread(target=self.capture_stream)
self.t2 = threading.Thread(target=self.display_image)
self.t1.name = 'capture_thread'
self.t2.name = 'display_thread'
#die starts in eine funktion packen, für start und stop ?
self.t1.start()
self.t2.start()
#self.t1.join()
#self.t2.join()
self.aufnahme = 'False'
frames_per_second = 20
basepathinc = r'C:/Videotool/Videos'
isExist = os.path.exists(basepathinc)
print('path exists :',isExist)
print('video fullpath :',basepathinc)
if not isExist:
os.makedirs(basepathinc)
print(f'path {basepathinc} created')
os.chdir(basepathinc)
def set_res(key):
global my_width
global my_height
match key:
case 480:
my_width = 640
my_height = 480
print('480p selected')
case 720:
my_width = 1280
my_height = 720
print('720p selected')
case 1080:
my_width = 1920
my_height = 1080
print('1080p selected')
case 4:
my_width = 3840
my_height = 2160
print('4k selected')
case _:
print('wrong selection')
def capture_stream(self):
capture_counter = 1
old_seconds = 0
seconds = 0
while True:
self.ret, self.frame = self.cap.read()
self.ready.set()
now = datetime.now()
seconds = int(now.strftime("%S"))
#print(f'Frame: {capture_counter} in Second :{seconds}')
if seconds > old_seconds:
print(f'Captured Frames: {capture_counter-1} in Second : {old_seconds}')
capture_counter = 2
else:
capture_counter += 1
old_seconds = seconds
time.sleep(self.AIM_FPS)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
def display_image(self):
self.start_time = time.time()
self.framerate_trigger = 1
self.fps_counter = 0
display_counter = 0
old_seconds = 0
seconds = 0
while True:
# Display the resulting frame
if gv.test_wiedergabe == 'True':
self.ready.wait()
#_________________________________
now = datetime.now()
seconds = int(now.strftime("%S"))
if seconds > old_seconds:
print(f'Displayed Frames: {display_counter-1} in Second : {old_seconds}')
display_counter = 2
else:
display_counter += 1
old_seconds = seconds
#_________________________________
framexd=cv2.cvtColor(self.frame,cv2.COLOR_BGR2RGB)
self.ready.clear()
self.fps_counter+=1
if (time.time() - self.start_time) > self.framerate_trigger :
#print("FPS: ", self.fps_counter / (time.time() - self.start_time))
self.fps = round(int(self.fps_counter / (time.time() - self.start_time)))
self.fps_counter = 0
self.start_time = time.time()
global myfps
myfps = self.fps
stream_width = self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)
stream_height = self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
global_cam_display_fps = int(self.cap.get(cv2.CAP_PROP_FPS))
#print('FPS:',self.fps)
fps_x_string = str(self.fps)
font = cv2.FONT_HERSHEY_TRIPLEX
fontScale = 1
fontColor = (255,0,0)
thickness = 2
lineType = 2
frame_wfps = cv2.putText(framexd,fps_x_string, (0,30), font, fontScale,fontColor,thickness,cv2.LINE_AA)
framexd=Image.fromarray(framexd)
#framexd=Image.fromarray(framexd)
framexd=ImageTk.PhotoImage(framexd)
videolabel.configure(image=framexd)
videolabel.image=framexd
infolabel.configure(text = f'myFPS: {myfps} /n Auflösung: {stream_width}x{stream_height}')
#Aufnahme________________________________________________________________________________________
"""
if self.aufnahme == 'True':
self.out.write(frame_wtext_startup)
else:
self.out.release()
"""
#________________________________________________________________________________________________
if cv2.waitKey(1) & 0xFF == ord('q'):
break;
else:
self.cap.release()
#self.t1._stop() funkst erst wenn der thread daemonisch ist! also thread daemonisch öffnen
#self.t2._stop()
break
def __del__(self):
# When everything done, release the capture
self.cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
print('start.py was started directly')
ready = threading.Event()
ready = ready
root = Tk()
root.title('Test Videoverarbeitung')
root.geometry('800x600')
helv36 = font.Font(family='Helvetica', size=12, weight=font.BOLD)
mainframe = Frame(root)
mainframe.place(relheight = 1, relwidth = 1)
videoframe = Frame(mainframe)
videoframe.place(x = 0, y = 0, relheight = 1, relwidth = 0.8)
videolabel = Label(videoframe, text = "Videoframe")
videolabel.place(relx = 0.5, rely = 0.5, relwidth = 1, relheight = 1, anchor="center")
infolabel = Label(videoframe, text = "Videoframe")
infolabel.place(relx = 0, rely = 0.8, relwidth = 1, relheight = 0.2)
controlframe = Frame(mainframe)
controlframe.place(relx = 0.8, y = 0, relheight = 1, relwidth = 0.2)
button1 = Button(controlframe, width=50, text = "Wiedergabe", command=lambda:display_start(), bd = 2, relief = "groove", overrelief = "sunken", font = helv36)
button1.place(relx = 0, rely = 0, relheight=0.2, relwidth = 1)
button2 = Button(controlframe, width=50, text = "Wiedergabe Stop", command=lambda:display_stop(), bd = 2, relief = "groove", overrelief = "sunken", font = helv36)
button2.place(relx = 0, rely =0.2, relheight=0.2, relwidth = 1)
button3 = Button(controlframe, width=50, text = "Aufnahme", command=lambda:aufnahme_start(), bd = 2, relief = "groove", overrelief = "sunken", font = helv36)
button3.place(relx = 0, rely =0.4, relheight=0.2, relwidth = 1)
button3 = Button(controlframe, width=50, text = "Aufnahme Stop (oF)", command=lambda:fakefunc(), bd = 2, relief = "groove", overrelief = "sunken", font = helv36)
button3.place(relx = 0, rely =0.6, relheight=0.2, relwidth = 1)
checkbutton1 = Checkbutton(controlframe, text = '480p',command=lambda:multi_thread_stream.set_res(480))
checkbutton1.place(relx = 0, rely = 0.8)
checkbutton1 = Checkbutton(controlframe, text = '720p',command=lambda:multi_thread_stream.set_res(720))
checkbutton1.place(relx = 0, rely = 0.84)
checkbutton1 = Checkbutton(controlframe, text = '1080p',command=lambda:multi_thread_stream.set_res(1080))
checkbutton1.place(relx = 0, rely = 0.88)
checkbutton1 = Checkbutton(controlframe, text = '4k',command=lambda:multi_thread_stream.set_res(4))
checkbutton1.place(relx = 0, rely = 0.92)
root.mainloop()
else:
_=7
I am through many Threads about this, but didnt find a Solution.
I created this as my minimal Code Example, to prevent the "use Threads" Suggestion.
But to cut out the Part I would like to improve:
framexd=cv2.cvtColor(self.frame,cv2.COLOR_BGR2RGB)
self.ready.clear()
framexd=Image.fromarray(framexd)
framexd=ImageTk.PhotoImage(framexd)
videolabel.configure(image=framexd)
videolabel.image=framexd
This Part is working up to 50% slower then the Capture.
I would like to speed it up with other Ideas like Reducing Resolution and the Use of better Hardware.
Next Time I will avoid the bizarre Capitalizations in my Code.

Tkinter resize a rectange on Canvas using mouse

I want to create a simple GUI image labeler tool in Tkinter for my research project. Currently, I have working code that can load images from the directory and allows me to draw multiple bounding boxes. I want to modify the code such that I can resize the rectangle BB using a mouse when I click on it. I have searched online and couldn't find any resources to do that. Can someone help me understand how to do that?
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
from tkinter import ttk
from PIL import Image, ImageTk
import os
import glob
import random
# colors for the bboxes
COLORS = ['red', 'blue','pink', 'cyan', 'green', 'black']
# image sizes for the examples
SIZE = 256, 256
class LabelTool():
def __init__(self, master):
# set up the main frame
self.parent = master
self.parent.title("LabelTool")
self.frame = Frame(self.parent)
self.frame.pack(fill=BOTH, expand=1)
self.parent.resizable(width = FALSE, height = FALSE)
# initialize global state
self.imageDir = ''
self.imageList= []
self.egDir = ''
self.egList = []
self.outDir = ''
self.cur = 0
self.total = 0
self.category = 0
self.imagename = ''
self.labelfilename = ''
self.tkimg = None
self.currentLabelclass = ''
self.cla_can_temp = []
self.classcandidate_filename = 'class.txt'
# initialize mouse state
self.STATE = {}
self.STATE['click'] = 0
self.STATE['x'], self.STATE['y'] = 0, 0
# reference to bbox
self.bboxIdList = []
self.bboxId = None
self.bboxList = []
self.hl = None
self.vl = None
self.srcDirBtn = Button(self.frame, text="Image input folder", command=self.selectSrcDir)
self.srcDirBtn.grid(row=0, column=0)
# input image dir entry
self.svSourcePath = StringVar()
self.entrySrc = Entry(self.frame, textvariable=self.svSourcePath)
self.entrySrc.grid(row=0, column=1, sticky=W+E)
self.svSourcePath.set(os.getcwd())
# load button
self.ldBtn = Button(self.frame, text="Load Dir", command=self.loadDir)
self.ldBtn.grid(row=0, column=2, rowspan=2, columnspan=2, padx=2, pady=2, ipadx=5, ipady=5)
# label file save dir button
self.desDirBtn = Button(self.frame, text="Label output folder", command=self.selectDesDir)
self.desDirBtn.grid(row=1, column=0)
# label file save dir entry
self.svDestinationPath = StringVar()
self.entryDes = Entry(self.frame, textvariable=self.svDestinationPath)
self.entryDes.grid(row=1, column=1, sticky=W+E)
self.svDestinationPath.set(os.path.join(os.getcwd(),"Labels"))
# main panel for labeling
self.mainPanel = Canvas(self.frame, cursor='tcross')
self.mainPanel.bind("<Button-1>", self.mouseClick)
self.mainPanel.bind("<Motion>", self.mouseMove)
self.mainPanel.grid(row = 2, column = 1, rowspan = 4, sticky = W+N)
# showing bbox info & delete bbox
self.lb1 = Label(self.frame, text = 'Bounding boxes:')
self.lb1.grid(row = 3, column = 2, sticky = W+N)
self.listbox = Listbox(self.frame, width = 22, height = 12)
self.listbox.grid(row = 4, column = 2, sticky = N+S)
# control panel for image navigation
self.ctrPanel = Frame(self.frame)
self.ctrPanel.grid(row = 6, column = 1, columnspan = 2, sticky = W+E)
self.progLabel = Label(self.ctrPanel, text = "Progress: / ")
self.progLabel.pack(side = LEFT, padx = 5)
self.tmpLabel = Label(self.ctrPanel, text = "Go to Image No.")
self.tmpLabel.pack(side = LEFT, padx = 5)
self.idxEntry = Entry(self.ctrPanel, width = 5)
self.idxEntry.pack(side = LEFT)
# display mouse position
self.disp = Label(self.ctrPanel, text='')
self.disp.pack(side = RIGHT)
self.frame.columnconfigure(1, weight = 1)
self.frame.rowconfigure(4, weight = 1)
def selectSrcDir(self):
path = filedialog.askdirectory(title="Select image source folder", initialdir=self.svSourcePath.get())
self.svSourcePath.set(path)
return
def selectDesDir(self):
path = filedialog.askdirectory(title="Select label output folder", initialdir=self.svDestinationPath.get())
self.svDestinationPath.set(path)
return
def loadDir(self):
self.parent.focus()
# get image list
#self.imageDir = os.path.join(r'./Images', '%03d' %(self.category))
self.imageDir = self.svSourcePath.get()
if not os.path.isdir(self.imageDir):
messagebox.showerror("Error!", message = "The specified dir doesn't exist!")
return
extlist = ["*.JPEG", "*.jpeg", "*JPG", "*.jpg", "*.PNG", "*.png", "*.BMP", "*.bmp"]
for e in extlist:
filelist = glob.glob(os.path.join(self.imageDir, e))
self.imageList.extend(filelist)
#self.imageList = glob.glob(os.path.join(self.imageDir, '*.JPEG'))
if len(self.imageList) == 0:
print('No .JPEG images found in the specified dir!')
return
# default to the 1st image in the collection
self.cur = 1
self.total = len(self.imageList)
# set up output dir
#self.outDir = os.path.join(r'./Labels', '%03d' %(self.category))
self.outDir = self.svDestinationPath.get()
if not os.path.exists(self.outDir):
os.mkdir(self.outDir)
self.loadImage()
print('%d images loaded from %s' %(self.total, self.imageDir))
def loadImage(self):
# load image
imagepath = self.imageList[self.cur - 1]
self.img = Image.open(imagepath)
size = self.img.size
self.factor = max(size[0]/1000, size[1]/1000., 1.)
self.img = self.img.resize((int(size[0]/self.factor), int(size[1]/self.factor)))
self.tkimg = ImageTk.PhotoImage(self.img)
self.mainPanel.config(width = max(self.tkimg.width(), 400), height = max(self.tkimg.height(), 400))
self.mainPanel.create_image(0, 0, image = self.tkimg, anchor=NW)
self.progLabel.config(text = "%04d/%04d" %(self.cur, self.total))
# load labels
self.clearBBox()
#self.imagename = os.path.split(imagepath)[-1].split('.')[0]
fullfilename = os.path.basename(imagepath)
self.imagename, _ = os.path.splitext(fullfilename)
labelname = self.imagename + '.txt'
self.labelfilename = os.path.join(self.outDir, labelname)
bbox_cnt = 0
if os.path.exists(self.labelfilename):
with open(self.labelfilename) as f:
for (i, line) in enumerate(f):
if i == 0:
bbox_cnt = int(line.strip())
continue
#tmp = [int(t.strip()) for t in line.split()]
tmp = line.split()
tmp[0] = int(int(tmp[0])/self.factor)
tmp[1] = int(int(tmp[1])/self.factor)
tmp[2] = int(int(tmp[2])/self.factor)
tmp[3] = int(int(tmp[3])/self.factor)
self.bboxList.append(tuple(tmp))
color_index = (len(self.bboxList)-1) % len(COLORS)
tmpId = self.mainPanel.create_rectangle(tmp[0], tmp[1], \
tmp[2], tmp[3], \
width = 2, \
outline = COLORS[color_index])
#outline = COLORS[(len(self.bboxList)-1) % len(COLORS)])
self.bboxIdList.append(tmpId)
self.listbox.insert(END, '%s : (%d, %d) -> (%d, %d)' %(tmp[4], tmp[0], tmp[1], tmp[2], tmp[3]))
self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[color_index])
#self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)])
def mouseClick(self, event):
if self.STATE['click'] == 0:
self.STATE['x'], self.STATE['y'] = event.x, event.y
else:
x1, x2 = min(self.STATE['x'], event.x), max(self.STATE['x'], event.x)
y1, y2 = min(self.STATE['y'], event.y), max(self.STATE['y'], event.y)
self.bboxList.append((x1, y1, x2, y2, self.currentLabelclass))
self.bboxIdList.append(self.bboxId)
self.bboxId = None
self.listbox.insert(END, '%s : (%d, %d) -> (%d, %d)' %(self.currentLabelclass, x1, y1, x2, y2))
self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)])
self.STATE['click'] = 1 - self.STATE['click']
def mouseMove(self, event):
self.disp.config(text = 'x: %d, y: %d' %(event.x, event.y))
if self.tkimg:
if self.hl:
self.mainPanel.delete(self.hl)
self.hl = self.mainPanel.create_line(0, event.y, self.tkimg.width(), event.y, width = 2)
if self.vl:
self.mainPanel.delete(self.vl)
self.vl = self.mainPanel.create_line(event.x, 0, event.x, self.tkimg.height(), width = 2)
if 1 == self.STATE['click']:
if self.bboxId:
self.mainPanel.delete(self.bboxId)
COLOR_INDEX = len(self.bboxIdList) % len(COLORS)
self.bboxId = self.mainPanel.create_rectangle(self.STATE['x'], self.STATE['y'], \
event.x, event.y, \
width = 2, \
outline = COLORS[len(self.bboxList) % len(COLORS)])
def setClass(self):
self.currentLabelclass = self.classcandidate.get()
print('set label class to : %s' % self.currentLabelclass)
if __name__ == '__main__':
root = Tk()
tool = LabelTool(root)
root.resizable(width = True, height = True)
root.mainloop()
That's hardly "minimal" ... it's still over 200 lines long. I don't want to sort through it but I'll make a minimal example to show you how to bind to a canvas item:
import tkinter as tk
from functools import partial
class DrawShapes(tk.Canvas):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
image = self.create_rectangle(0, 0, 400, 300, width=5, fill='green')
self.tag_bind(image, '<Button-1>', self.on_click)
self.tag_bind(image, '<Button1-Motion>', self.on_motion)
def on_click(self, event):
"""fires when user clicks on the background ... creates a new rectangle"""
self.start = event.x, event.y
self.current = self.create_rectangle(*self.start, *self.start, width=5)
self.tag_bind(self.current, '<Button-1>', partial(self.on_click_rectangle, self.current))
self.tag_bind(self.current, '<Button1-Motion>', self.on_motion)
def on_click_rectangle(self, tag, event):
"""fires when the user clicks on a rectangle ... edits the clicked on rectange"""
self.current = tag
x1, y1, x2, y2 = self.coords(tag)
if abs(event.x-x1) < abs(event.x-x2):
# opposing side was grabbed; swap the anchor and mobile side
x1, x2 = x2, x1
if abs(event.y-y1) < abs(event.y-y2):
y1, y2 = y2, y1
self.start = x1, y1
def on_motion(self, event):
"""fires when the user drags the mouse ... resizes currently active rectangle"""
self.coords(self.current, *self.start, event.x, event.y)
def main():
c = DrawShapes()
c.pack()
c.mainloop()
if __name__ == '__main__':
main()

Python Tkinter Entry not placing

In Croatia we have competitions where you make apps. I'm making an app to help 1st and 2nd graders learn and revise math. I just started recently so it doesn't have almost anything.
The problem is that when variable: mode = "number" , entries aren't placed.
Btw when opening the app you will be presented with 4 options.
They are addition, subtraction, multiplication and division.
I translated it from Croatian to English so you can understand.
When you run the program press the Addition button.
Then you will see the task but entries missing.
If you change the value of the variable mode to mode = "result", entries are placed.
I tried everything but couldn't get it to work.
Here's the code:
import tkinter as tk
import random
wn = tk.Tk()
wn.config(width = 550, height = 500)
wn.resizable(False, False)
wn.title("Learn and Revise")
number1_1 = 0
number1_2 = 0
number2_1 = 0
number2_2 = 0
number3_1 = 0
number3_2 = 0
number4_1 = 0
number4_2 = 0
number5_1 = 0
number5_2 = 0
def makeRandomNumbers():
global number1_1, number1_2
global number2_1, number2_2
global number3_1, number3_2
global number4_1, number4_2
global number5_1, number5_2
if mode == "number":
while True:
number1_1 = random.randint(0, 10)
number1_2 = random.randint(0, 10)
if number1_1 > number1_2:
pass
else:
break
while True:
number2_1 = random.randint(0, 10)
number2_2 = random.randint(0, 10)
if number2_1 > number2_2:
pass
else:
break
while True:
number3_1 = random.randint(0, 10)
number3_2 = random.randint(0, 10)
if number3_1 > number3_2:
pass
else:
break
while True:
number4_1 = random.randint(0, 10)
number4_2 = random.randint(0, 10)
if number4_1 > number4_2:
pass
else:
break
while True:
number5_1 = random.randint(0, 10)
number5_2 = random.randint(0, 10)
if number5_1 > number5_2:
pass
else:
break
elif mode == "result":
number1_1 = random.randint(0, 10)
number1_2 = random.randint(0, 10)
number2_1 = random.randint(0, 10)
number2_2 = random.randint(0, 10)
number3_1 = random.randint(0, 10)
number3_2 = random.randint(0, 10)
number4_1 = random.randint(0, 10)
number4_2 = random.randint(0, 10)
number5_1 = random.randint(0, 10)
number6_2 = random.randint(0, 10)
def placeTasks(oper):
global operation
operation = oper
makeTasks()
wipeMenu()
button_check.place(x = 310, y = 225)
label1.place(x = 150, y = 125)
label2.place(x = 150, y = 175)
label3.place(x = 150, y = 225)
label4.place(x = 150, y = 275)
label5.place(x = 150, y = 325)
if mode == "number":
entry1.place(x = 240, y = 130)
entry2.place(x = 240, y = 180)
entry3.place(x = 240, y = 230)
entry4.place(x = 240, y = 280)
entry5.place(x = 240, y = 330)
elif mode == "result":
entry1.place(x = 240, y = 130)
entry2.place(x = 240, y = 180)
entry3.place(x = 240, y = 230)
entry4.place(x = 240, y = 280)
entry5.place(x = 240, y = 330)
task1 = 0
task2 = 0
task3 = 0
task4 = 0
task5 = 0
def makeTasks():
global task1, task2, task3, task4, task5
global label1, label2, label3, label4, label5
makeRandomNumbers()
operation_sign = ""
if operation == "addition":
operation_sign = '+'
elif operation == "subtraction":
operation_sign = '-'
elif operation == "multiplication":
operation_sign = '•'
elif operation == "division":
operation_sign = '÷'
if mode == "result":
task1 = "{} {} {} =".format(number1_1, operation_sign, number1_2)
task2 = "{} {} {} =".format(number2_1, operation_sign, number2_2)
task3 = "{} {} {} =".format(number3_1, operation_sign, number3_2)
task4 = "{} {} {} =".format(number4_1, operation_sign, number4_2)
task5 = "{} {} {} =".format(number5_1, operation_sign, number5_2)
elif mode == "number":
task1 = "{} {} = {}".format(number1_1, operation_sign, number1_2)
task2 = "{} {} = {}".format(number2_1, operation_sign, number2_2)
task3 = "{} {} = {}".format(number3_1, operation_sign, number3_2)
task4 = "{} {} = {}".format(number4_1, operation_sign, number4_2)
task5 = "{} {} = {}".format(number5_1, operation_sign, number5_2)
label1 = tk.Label(wn, text = task1, font = ("Arial", 15))
label2 = tk.Label(wn, text = task2, font = ("Arial", 15))
label3 = tk.Label(wn, text = task3, font = ("Arial", 15))
label4 = tk.Label(wn, text = task4, font = ("Arial", 15))
label5 = tk.Label(wn, text = task5, font = ("Arial", 15))
operation = ""
mode = "number"
button_check = tk.Button(wn, width = 20, text = "Check")
label1 = tk.Label(wn, text = task1, font = ("Arial", 15))
entry1 = tk.Entry(wn, width = 7)
label2 = tk.Label(wn, text = task2, font = ("Arial", 15))
entry2 = tk.Entry(wn, width = 7)
label3 = tk.Label(wn, text = task3, font = ("Arial", 15))
entry3 = tk.Entry(wn, width = 7)
label4 = tk.Label(wn, text = task4, font = ("Arial", 15))
entry4 = tk.Entry(wn, width = 7)
label5 = tk.Label(wn, text = task5, font = ("Arial", 15))
entry5 = tk.Entry(wn, width = 7)
def placeMenu():
menu_label1.place(x = 175, y = 75)
button1.place(x = 200, y = 150)
button2.place(x = 200, y = 200)
button3.place(x = 200, y = 250)
button4.place(x = 200, y = 300)
def wipeMenu():
menu_label1.destroy()
button1.destroy()
button2.destroy()
button3.destroy()
button4.destroy()
menu_label1 = tk.Label(wn, text = "Revise", font = ("Arial", 35))
button1 = tk.Button(wn, width = 20, text = "Addition", command = lambda: placeTasks("addition"))
button2 = tk.Button(wn, width = 20, text = "Subtraction")
button3 = tk.Button(wn, width = 20, text = "Multiplication")
button4 = tk.Button(wn, width = 20, text = "Division")
placeMenu()
wn.mainloop()
TL;DR
Postavi font prilikom inicijalizacije entrya, preimenuj if statement i ukloni globalnu varijablu te koristi lokalnu (oper)
Prvo što vidim je mnoštvo ponavljanja. Napravi funkciju s više parametara na kojima ćeš izvršavati for loopove - kod će biti kraći i čitljiviji 20 puta. Tkinter je jednostavan, ali nije praktičan ukoliko nije objektno orijentiran (preporučujem tk.Toplevel klase za prebacivanje prozora, onda samo switchaš screenove i nema potrebe za brisanjem i postavljanjem, što dodatno ubrzava izvrašavanje). Idealno bi bilo kreirati class za svaku aritmetičku operaciju i uz to ne koristiti (spore) lambda anonimne funkcije samo za pozivanje s atributima.
Dakle, kod bi izgledao otprilike ovako:
for (akcija, klasa) in zip(["Addition", "Substraction", ...], lista_klasi):
button = tk.Button(wn, width=20, text=akcija, command=klasa);
...
button.pack() # Izbjegavaj .place(), uvijek samo pack() ili grid()
...
class Solution(tk.Toplevel):
def __init__(self, atributi):
super().__init__()
self.attributes("-topmost", False)
self.solution = tk.Canvas(self, bg="white" ...)
self.solution.pack()
...
# Za najbolji izgled postavljaj widgete na canvas...
self.solution.create_window(w, h, window=atribut[neki])
# Također, ako želiš ostati u istom prozoru, spremi widgete i koristi:
self.canvas.delete("all")
Osobno koristim pack jer je najjednostavniji, u početku nezgodan jer ne dobivaš izgledom točno kako zamišljaš ali kad pohvataš sve ne bi se nikad vratio na place(), osim ako nije nužno :)
Zasad prvo prouči sve pojašnjene primjere ovdje.
Tek kad savladaš tkinter kreni na kivy ako misliš stvarno rasturit na natjecanju.

python 3 tkinter class variables and Spinboxes with Labels not updating

Can't figure out why my labels aren't updating from clicks on my Spinboxes
from tkinter import *
mainBackground = "#0047BF"
mainForeground = "#C2F2E6"
inputBackground = "#230E38"
window = Tk()
window.title("Gurps Game Manager")
window.geometry("700x600")
window.wm_iconbitmap('pyramid.ico')
window.configure(background = mainBackground)
# Creating Variable Classes and setting to base stat
strength = IntVar(window)
strength.set(10)
dexterity = IntVar(window)
dexterity.set(10)
intelligence = IntVar(window)
intelligence.set(10)
health = IntVar(window)
health.set(10)
hpMod = IntVar(window)
hpMod.set(0)
willMod = IntVar(window)
willMod.set(0)
perMod = IntVar(window)
perMod.set(0)
fpMod = IntVar(window)
fpMod.set(0)
bSpeedMod = IntVar(window)
bSpeedMod.set(0)
bMoveMod = IntVar(window)
bMoveMod.set(0)
hpTotal = IntVar(window)
hpTotal.set(10)
willTotal = IntVar(window)
willTotal.set(10)
perTotal = IntVar(window)
perTotal.set(10)
fpTotal = IntVar(window)
fpTotal.set(10)
bSpeedTotal = IntVar(window)
bSpeedTotal.set(5)
bMoveTotal = IntVar(window)
bMoveTotal.set(5)
bLift = IntVar(window)
bLift.set(20)
bThrust = StringVar(window)
bThrust.set('1d-2')
bSwing = StringVar(window)
bSwing.set('1d')
charPointTotal = IntVar(window)
charPointTotal.set(0)
charPointLimit = IntVar(window)
charPointLimit.set(250)
charPointDiff = IntVar(window)
charPointDiff.set(250)
# Functions to create widgets
def mainLabel(text):
label = Label(window, text = text, bg = mainBackground, fg = mainForeground,
font = ('Lucida Console', 14))
return label
def calcLabel(textVariable):
label = Label(window, textvariable = textVariable, bg = mainBackground, fg = mainForeground, font = ('Lucida Console', 14))
return label
def mainEntry(callback = None):
entry = Entry(window, bg = inputBackground, fg = mainForeground, insertbackground = mainForeground,
command = callback)
return entry
def mainSpinbox(callback, textVar, floor, ceiling, increment = 1):
spinbox = Spinbox(window, fg = mainForeground, state = 'readonly', readonlybackground = mainBackground,
from_ = floor, to = ceiling, increment = increment, textvariable = textVar, command = callback,
justify = 'center', border = '0', width = '5')
return spinbox
# Command function to set values on change
def charPointsCallback():
st = int(strength.get())
dx = int(dexterity.get())
iq = int(intelligence.get())
ht = int(health.get())
hp = int(hpMod.get())
will = int(willMod.get())
per = int(perMod.get())
fp = int(fpMod.get())
bSpeed = int(bSpeedMod.get())
bMove = int(bMoveMod.get())
hpTotal.set(st + hp)
willTotal.set(iq + will)
perTotal.set(iq + per)
fpTotal.set(ht + fp)
bSpeedTotal.set((ht + dx) / 4 + bSpeed)
bMoveTotal.set((ht + dx) // 4 + bMove)
bLift.set((st * st) / 5)
cpTotal = ((st - 10) * 10) + ((dx - 10) * 20) + ((iq - 10) * 20) + ((ht - 10) * 10) + (hp * 2) + (will * 5) + (
per * 5) + (fp * 5) + (bSpeed * 20) + (bMove * 5)
cpLimit = charPointLimit.get()
charPointTotal.set(cpTotal)
charPointDiff.set(cpLimit - cpTotal)
# Lists of strings and variables for loop to create widgets
coreStatLabels = ['ST', 'DX', 'IQ', 'HT']
coreStatVar = [strength, dexterity, intelligence, health]
modStatLabels = ['HP', 'Will', 'Per', 'FP', 'Basic Speed', 'Basic Move']
modStatVar = [hpMod, willMod, perMod, fpMod, bSpeedMod, bMoveMod]
totalStatVar = [hpTotal, willTotal, perTotal, fpTotal, bSpeedTotal, bMoveTotal]
derivedStatLabels = ['Basic Lift', 'Basic Thrust', 'Basic Swing', 'Character Point Total:']
derivedStatVar = [bLift, bThrust, bSwing, charPointTotal]
# Widgets
characterNameLbl = mainLabel('Character Name:')
characterNameLbl.grid(row = 0, column = 0, columnspan = 2)
characterNameEntry = mainEntry(charPointsCallback())
characterNameEntry.grid(row = 0, column = 2)
charPointLimitLbl = mainLabel('Character Point Limit:')
charPointLimitLbl.grid(row = 1, column = 0, columnspan = 2)
charPointLimitSpin = mainSpinbox(charPointsCallback(),charPointLimit, 100, 500, 10)
charPointLimitSpin.grid(row = 1, column = 2)
# Loops that create the widgets
for i in range(4):
row = range(2, 6)
coreStatLbl = mainLabel(coreStatLabels[i])
coreStatLbl.grid(row = row[i], column = 0)
coreStatSpin = mainSpinbox(charPointsCallback(), coreStatVar[i], 5, 15)
coreStatSpin.grid(row = row[i], column = 2)
for i in range(5):
row = range(6, 12)
modStatLbl = mainLabel(modStatLabels[i])
modStatLbl.grid(row = row[i], column = 0)
modStatSpin = mainSpinbox(charPointsCallback(), modStatVar[i], -5, 5)
modStatSpin.grid(row = row[i], column = 1)
totalStatLabel = calcLabel(totalStatVar[i])
totalStatLabel.grid(row = row[i], column = 2)
for i in range(4):
row = range(12,16)
derivedStatLbl = mainLabel(derivedStatLabels[i])
derivedStatLbl.grid(row = row[i], column = 0)
derivedStatCalc = calcLabel(derivedStatVar[i])
derivedStatCalc.grid(row = row[i], column = 2)
window.mainloop()
My understanding of variable classes is that any widget with a variable class set to it will update with the variable when it changes. I click on the up/down spinner, and nothing changes.
When you do this:
modStatSpin = mainSpinbox(charPointsCallback(), ...)
It is exactly the same as if you did this:
something = charPointsCallback()
modStatSpin = mainSpinbox(something, ...)
If you are passing in a callback toa function, you must pass in a reference to the function (ie: remove the trailing ())

A loop within tkinter - HELP!

this is my first time using this forum, hopefully, i can get a quick response with a detailed explanation.
Running:
Python 3.2
Tkinter 8.5 & Windows7 x64
My code:
from tkinter import *
import tkinter.messagebox
class Application(Frame):
def __init__(self, master):
super(Application, self).__init__(master)
self.grid()
self.lvl_one_att = 4
self.bttn_clicks = 2
self.bttn_clicks2 = 2
self.bttn_clicks3 = 1
self.bttn_clicks4 = 2
self.bttn_clicks5 = 1
self.bttn_clicks6 = 2
self.bttn_clicks7 = 1
self.bttn_clicks8 = 2
self.bttn_clicks9 = 2
self.level_one()
def level_one(self):
self.lbl1 = Label(self, text = "You must flip all the boxes to show the same colour!")
self.lbl1.grid(row = 0, column = 0, columnspan = 3)
self.levellbl = Label(self, text = "Level 1")
self.levellbl.grid(row = 4, column = 1, sticky = W, columnspan = 2)
self.rulesbttn = Button(self, text = "Instructions", command = self.rules)
self.rulesbttn.grid(row = 4, column = 0, sticky = W, columnspan = 1)
self.tlbttn = Button(self, bg = "red", width = 20, height = 10, command = self.callback1)
self.tlbttn.grid(row = 1, column = 0, columnspan = 1)
self.tmbttn = Button(self, bg = "red", width = 20, height = 10, command = self.callback2)
self.tmbttn.grid(row = 1, column = 1, columnspan = 1)
self.trbttn = Button(self, bg = "blue", width = 20, height = 10, command = self.callback3)
self.trbttn.grid(row = 1, column = 2, columnspan = 1)
self.mlbttn = Button(self, bg = "red", width = 20, height = 10, command = self.callback4)
self.mlbttn.grid(row = 2, column = 0, columnspan = 1)
self.mmbttn = Button(self, bg = "blue", width = 20, height = 10, command = self.callback5)
self.mmbttn.grid(row = 2, column = 1, columnspan = 1)
self.mrbttn = Button(self, bg = "red", width = 20, height = 10, command = self.callback6)
self.mrbttn.grid(row = 2, column = 2, columnspan = 1)
self.blbttn = Button(self, bg = "blue", width = 20, height = 10, command = self.callback7)
self.blbttn.grid(row = 3, column = 0, columnspan = 1)
self.bmbttn = Button(self, bg = "red",width = 20, height = 10, command = self.callback8)
self.bmbttn.grid(row = 3, column = 1, columnspan = 1)
self.brbttn = Button(self, bg = "red", width = 20, height = 10, command = self.callback9)
self.brbttn.grid(row = 3, column = 2, columnspan = 1)
def callback1(self):
self.lvl_one_att -= 1
self.color_change1()
self.color_change2()
self.color_change4()
self.color_change5()
def callback2(self):
self.lvl_one_att -= 1
self.color_change1()
self.color_change2()
self.color_change3()
self.color_change5()
self.color_change4()
self.color_change6()
def callback3(self):
self.lvl_one_att -= 1
self.color_change2()
self.color_change3()
self.color_change6()
self.color_change5()
def callback4(self):
self.lvl_one_att -= 1
self.color_change1()
self.color_change2()
self.color_change4()
self.color_change5()
self.color_change7()
self.color_change8()
def callback5(self):
self.lvl_one_att -= 1
self.color_change1()
self.color_change2()
self.color_change3()
self.color_change6()
self.color_change9()
self.color_change4()
self.color_change5()
self.color_change7()
self.color_change8()
def callback6(self):
self.lvl_one_att -= 1
self.color_change3()
self.color_change2()
self.color_change6()
self.color_change5()
self.color_change9()
self.color_change8()
def callback7(self):
self.lvl_one_att -= 1
self.color_change4()
self.color_change5()
self.color_change7()
self.color_change8()
def callback8(self):
self.lvl_one_att -= 1
self.color_change4()
self.color_change5()
self.color_change6()
self.color_change7()
self.color_change8()
self.color_change9()
def callback9(self):
self.lvl_one_att -= 1
self.color_change5()
self.color_change6()
self.color_change9()
self.color_change8()
def color_change1(self):
self.bttn_clicks += 1
if self.bttn_clicks == 3:
self.bttn_clicks = 1
if self.bttn_clicks == 1:
self.tlbttn.configure(bg = "blue")
else:
self.tlbttn.configure(bg = "red")
def color_change2(self):
self.bttn_clicks2 += 1
if self.bttn_clicks2 == 3:
self.bttn_clicks2 = 1
if self.bttn_clicks2 == 1:
self.tmbttn.configure(bg = "blue")
else:
self.tmbttn.configure(bg = "red")
def color_change3(self):
self.bttn_clicks3 += 1
if self.bttn_clicks3 == 3:
self.bttn_clicks3 = 1
if self.bttn_clicks3 == 1:
self.trbttn.configure(bg = "blue")
else:
self.trbttn.configure(bg = "red")
def color_change4(self):
self.bttn_clicks4 += 1
if self.bttn_clicks4 == 3:
self.bttn_clicks4 = 1
if self.bttn_clicks4 == 1:
self.mlbttn.configure(bg = "blue")
else:
self.mlbttn.configure(bg = "red")
def color_change5(self):
self.bttn_clicks5 += 1
if self.bttn_clicks5 == 3:
self.bttn_clicks5 = 1
if self.bttn_clicks5 == 1:
self.mmbttn.configure(bg = "blue")
else:
self.mmbttn.configure(bg = "red")
def color_change6(self):
self.bttn_clicks6 += 1
if self.bttn_clicks6 == 3:
self.bttn_clicks6 = 1
if self.bttn_clicks6 == 1:
self.mrbttn.configure(bg = "blue")
else:
self.mrbttn.configure(bg = "red")
def color_change7(self):
self.bttn_clicks7 += 1
if self.bttn_clicks7 == 3:
self.bttn_clicks7 = 1
if self.bttn_clicks7 == 1:
self.blbttn.configure(bg = "blue")
else:
self.blbttn.configure(bg = "red")
def color_change8(self):
self.bttn_clicks8 += 1
if self.bttn_clicks8 == 3:
self.bttn_clicks8 = 1
if self.bttn_clicks8 == 1:
self.bmbttn.configure(bg = "blue")
else:
self.bmbttn.configure(bg = "red")
def color_change9(self):
self.bttn_clicks9 += 1
if self.bttn_clicks9 == 3:
self.bttn_clicks9 = 1
if self.bttn_clicks9 == 1:
self.brbttn.configure(bg = "blue")
else:
self.brbttn.configure(bg = "red")
def rules(self):
tkinter.messagebox.showinfo("Instructions", "The idea of the game, is to make sure all the boxes on the screen are the same colour. By pressing a button it will flip, all colours touching it, including diagonally. ")
def round_win(self):
self.lbl1.grid_forget()
self.rulesbttn.grid_forget()
self.tlbttn.grid_forget()
self.tmbttn.grid_forget()
self.trbttn.grid_forget()
self.mlbttn.grid_forget()
self.mmbttn.grid_forget()
self.mrbttn.grid_forget()
self.blbttn.grid_forget()
self.bmbttn.grid_forget()
self.brbttn.grid_forget()
self.win()
def win(self):
self.lbl2 = Label(self, text = "CONGRATULATIONS!", font=("Helvetica", 40))
self.lbl2.grid(row = 0, column = 0)
root = Tk()
root.title("Program")
app = Application(root)
root.mainloop()
What i can work out how to do, is somehow use a loop so that when all 9 squares are the Red that it runs the round_win() function.
im unsure where to put the loop, and how to write it (for loop, while loop, if, but, else, etc)
Thanks heaps guys for any help you may be able to provide :)
You can put the original buttons into a list:
def level_one(self):
...
self.game_buttons = []
for btn_index in range(9):
bg = "red" # change this to something based on the index
next_button = Button(self, bg = bg, width = 20, height = 10)
next_button['command'] = (lambda index=btn_index: self.callback(index))
row = index/3 + 1
column = index % 3
next_button.grid(row = row, column = column, columnspan = 1)
self.game_buttons.append(next_button)
def callback1(self, index):
button = self.game_buttons[index]
# add the appropriate code here
def color_change(self, index):
# add the appropriate code here
Also, you can change the following code:
self.bttn_clicks2 += 1
if self.bttn_clicks2 == 3:
self.bttn_clicks2 = 1
to
self.bttn_clicks2 = self.bttn_clicks2 % 3 + 1

Categories