Good day, guys. I've got a problem with switching between frames in tkinter. I'm trying to make a clock app with time, stopwatch, timer and alarm. If I click on the first frame it's working, but if I select the second frame it's breaks. The previous frame just don't open because the second frame refreshing too fast (lbl.after). Can you help me with switching between frames?
from tkinter import *
from tkmacosx import *
from time import strftime
root = Tk()
root.title('Time')
root.geometry('500x500')
root.resizable(False, False)
counter = -1
running = False
def time_frame():
string = strftime("%H:%M:%S %A %d %Y")
frame_time = Frame(root, width = 480, height = 410, bg = 'gray70')
frame_time.place(x = 10, y = 80)
lbl1 = Label(frame_time, text = list, width = 32, height = 10, font = ('Arial', 25))
lbl1.place(x = 10, y = 80)
lbl1.config(text=string)
lbl1.after(1000, time_frame)
def stopwatch_frame():
frame_stopwatch = Frame(root, width = 480, height = 410, bg = 'gray70')
frame_stopwatch.place(x = 10, y = 80)
lbl2 = Label(frame_stopwatch, text = '0', width = 25, height = 5, font = ('Arial', 25))
lbl2.place(x = 10, y = 80)
start_button = Button(frame_stopwatch, width = 80, height = 40, text = 'Start')
start_button.place(x = 10, y = 240)
stop_button = Button(frame_stopwatch, width = 80, height = 40, text = 'Stop')
stop_button.place(x = 100, y = 240)
reset_button = Button(frame_stopwatch, width = 80, height = 40, text = 'Reset')
reset_button.place(x = 190, y = 240)
lbl2.after(1, stopwatch_frame)
frame_top = Frame(root, width = 500, height = 70, bg = 'gray64')
frame_top.place(x = 0, y = 0)
time_btn = Button(frame_top, text = 'Time', width = 50, height = 50, command = time_frame)
time_btn.place(x = 10, y = 10)
stopwatch_btn = Button(frame_top, text = 'Stopwatch', width = 50, height = 50, font = ('Arial', 9), command = stopwatch_frame)
stopwatch_btn.place(x = 80, y = 10)
timer_btn = Button(frame_top, text = 'Timer', width = 50, height = 50)
timer_btn.place(x = 150, y = 10)
alarm_btn = Button(frame_top, text = 'Alarm', width = 50, height = 50)
alarm_btn.place(x = 220, y = 10)
root.mainloop()
Here is a simplified example of a clock and stop watch class.
import tkinter as tk
from tkmacosx import *
from time import strftime, process_time
class timer:
delaya = None
delayb = None
def __init__( self ):
self.root = tk.Tk()
self.root.title('Time')
self.buttona = tk.Button( self.root, text = 'clock', width = 40, command = self.setclock )
self.buttonb = tk.Button( self.root, text = 'watch', width = 40, command = self.setwatch )
self.buttona.grid( row=0, column=0, sticky='ew' )
self.buttonb.grid( row=0, column=1, sticky='ew' )
self.root.update_idletasks()
self.root.resizable( False, False )
def clock( self ):
self.root.after_cancel( self.delaya )
self.delaya = None
self.buttona[ 'text' ] = strftime("%H:%M:%S %A %d %Y")
self.delaya = self.root.after( 1000, self.clock )
def watch( self ):
self.root.after_cancel( self.delayb )
self.delayb = None
self.buttonb[ 'text' ] = f'{process_time():0.5f}'
self.delayb = self.root.after( 1, self.watch )
def setclock( self ):
if self.delaya == None:
self.delaya = self.root.after( 1000, self.clock )
else:
self.root.after_cancel( self.delaya )
self.delaya = None
self.buttona[ 'text' ] = 'clock'
def setwatch( self ):
if self.delayb == None:
self.delayb = self.root.after( 1, self.watch )
else:
self.root.after_cancel( self.delayb )
self.delayb = None
self.buttonb[ 'text' ] = 'watch'
if __name__ == '__main__':
device = timer( )
tk.mainloop()
Related
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()
I have written a first attempt at a tkinter countdown app and I'm struggling with the stop and reset buttons as well as parts of the interface design.
My stop button does nothing at all whereas my reset button resets the values, but then continues the countdown immediately. I suspect it's because I have set self.running to True in the init method and that my app loops through those lines again and again. How do I prevent that from happening?
The other issue is that my width argument in all of my entry fields gets seemingly ignored. How can I assign the same width to all three fields?
Thanks for your help.
from tkinter import *
import time
from tkinter import messagebox
class Application(Frame):
def __init__(self,master):
super(Application,self).__init__(master)
self.place()
self.widgets()
self.running = True
def widgets(self):
self.hour = StringVar()
self.hour.set("00")
# Why is the width ignored?
self.hour_entry = Entry(width = 7, font=("Calibri",14,""), textvariable = self.hour)
self.hour_entry.place(x = 10, y = 10)
self.minute = StringVar()
self.minute.set("00")
self.minute_entry = Entry(width = 7, font=("Calibri",14,""), textvariable = self.minute)
self.minute_entry.place(x = 30, y = 10)
self.second = StringVar()
self.second.set("00")
self.seconds_entry = Entry(width = 7, font=("Calibri",14,""), textvariable = self.second)
self.seconds_entry.place(x = 50, y = 10)
self.start_btn = Button(text = "Start", command=self.clock)
self.start_btn.place(x = 30, y = 100)
self.stop_btn = Button(text = "Stop", command=self.stop)
self.stop_btn.place(x = 70, y = 100)
self.reset_btn = Button(text = "Reset", command=self.reset)
self.reset_btn.place(x = 110, y = 100)
def clock(self):
if self.running == True:
self.time_total = int(self.hour_entry.get())*3600 + int(self.minute_entry.get())*60 + int(self.seconds_entry.get())
while self.time_total > -1:
# returns 3600/60 = 60 with 0 left: so that's 60 min, 0 seconds
self.mins, self.secs = divmod(self.time_total,60)
self.hours = 0
if self.mins > 60:
self.hours, self.mins = divmod(self.mins, 60)
self.hour.set("{0:02d}".format(self.hours))
self.minute.set("{0:02d}".format(self.mins))
self.second.set("{0:02d}".format(self.secs))
self.time_total -= 1
root.update()
time.sleep(1)
if self.time_total == 0:
messagebox.showinfo("Time Countdown", "Time's up!")
def start(self):
self.running = True
self.clock()
def stop(self):
self.running = False
def reset(self):
self.running = False
self.hour.set("00")
self.minute.set("00")
self.second.set("00")
if __name__ == '__main__':
root = Tk()
app = Application(root)
mainloop()
For the timer, use the after method instead of sleep.
The entry widths are being used, but the place method puts one entry on top of another.
Also - Call the start method from the button click to reset the running flag.
Try this code:
from tkinter import *
import time
from tkinter import messagebox
class Application(Frame):
def __init__(self,master):
super(Application,self).__init__(master)
self.place()
self.widgets()
self.running = False
def widgets(self):
self.hour = StringVar()
self.hour.set("00")
# Why is the width ignored?
self.hour_entry = Entry(width = 4, font=("Calibri",14,""), textvariable = self.hour)
self.hour_entry.place(x = 10, y = 10)
self.minute = StringVar()
self.minute.set("00")
self.minute_entry = Entry(width = 4, font=("Calibri",14,""), textvariable = self.minute)
self.minute_entry.place(x = 60, y = 10)
self.second = StringVar()
self.second.set("00")
self.seconds_entry = Entry(width = 4, font=("Calibri",14,""), textvariable = self.second)
self.seconds_entry.place(x = 110, y = 10)
self.start_btn = Button(text = "Start", command=self.start)
self.start_btn.place(x = 30, y = 100)
self.stop_btn = Button(text = "Stop", command=self.stop)
self.stop_btn.place(x = 70, y = 100)
self.reset_btn = Button(text = "Reset", command=self.reset)
self.reset_btn.place(x = 110, y = 100)
def clock(self):
if self.running == True:
# returns 3600/60 = 60 with 0 left: so that's 60 min, 0 seconds
self.mins, self.secs = divmod(self.time_total,60)
self.hours = 0
if self.mins > 60:
self.hours, self.mins = divmod(self.mins, 60)
self.hour.set("{0:02d}".format(self.hours))
self.minute.set("{0:02d}".format(self.mins))
self.second.set("{0:02d}".format(self.secs))
root.update()
#time.sleep(1)
root.after(1000, self.clock) # wait 1 second, re-call clock
if self.time_total == 0:
self.running = False
messagebox.showinfo("Time Countdown", "Time's up!")
self.time_total -= 1
def start(self):
self.time_total = int(self.hour_entry.get())*3600 + int(self.minute_entry.get())*60 + int(self.seconds_entry.get())
self.running = True
self.clock()
def stop(self):
self.running = False
def reset(self):
self.running = False
self.hour.set("00")
self.minute.set("00")
self.second.set("00")
if __name__ == '__main__':
root = Tk()
app = Application(root)
mainloop()
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.
from tkinter import *
from PIL import Image, ImageTk
import time
schermata = Tk()
screen_width = schermata.winfo_screenwidth()
screen_height = schermata.winfo_screenheight()
indice = 0
schermata.iconbitmap("immagini\icona.ico")
screen_resolution = str(screen_width)+'x'+str(screen_height)
large_font = ('Verdana',30)
schermata.geometry(screen_resolution)
schermata.title("Jovan's RPG")
class GUI(Frame):
def __init__(self, master):
super(GUI, self).__init__(master)
self.pack()
self.bg()
self.immagine()
self.testo()
self.statistiche()
self.inserimenti()
def bg(self):
load = Image.open("immagini\\background.png")
render = ImageTk.PhotoImage(load)
img = Label(schermata, image = render)
img.image = render
img.pack()
def immagine(self):
load = Image.open("immagini\\dn.png")
render = ImageTk.PhotoImage(load)
img = Label(schermata, image = render)
img.image = render
img.place( x = 10, y = 10 )
def testo(self):
self.testo = Text(schermata, width = 110, height = 35, border = 5, bg = "black", fg ="white")
self.testo.place( x = 400, y = 20 )
def statistiche(self):
self.stats = Text(schermata, width = 40, height = 10, border = 5, bg = "black", fg ="white")
self.stats.place( x = 10, y = (screen_height - 200))
def inserisci(self):
fraseInserita = self.inserimento.get()
scrivere(fraseInserita)
self.inserimento.delete('0', END)
def inserimenti(self):
self.inserimento = Entry(schermata,font=large_font, width = 25, border = 5, bg = "black", fg ="white")
self.inserimento.place( x = 400, y = (screen_height - 100))
self.bottone = Button(schermata, width = 30, height = 3, border = 5, text = "Inserisci", command = self.inserisci)
self.bottone.place( x = (screen_width - 300), y = (screen_height - 100))
g = GUI(schermata)
def scrivere(scrittura):
g.testo.insert('1.0', scrittura)
def cancellaTesti():
g.testo.delete('0',END)
def wait(secondi):
time.sleep(secondi)
Levels class
from GUI import *
g = GUI(schermata)
class Livelli():
def __init__(self): pass
def cicloLivelli(self):
self.presentazione()
def presentazione(self):
scrivere("Salve avventuriero, qual e' il tuo nome?")
Main
from GUI import *
a = GUI(schermata)
l = Livelli()
if __name__ == "__main__":
a.mainloop()
l.cicloLivelli()
As you see i called the function back[(scrivere)], but the interpreter won't let the string appear in the Text widget. I've just posted the class of the GUI and the class of the "levels" that i'm looking forward to use for creating, of course, my levels for the game i'm creating. I'm searching for an answer and can't find it, hope you guys can help.
The get something on the screen you need to include self.config(width=700, heigh=800) (width and height totally arbitrary :)!) before self.pack() in class GUI and change all schermata into self (as you have defined the instance of GUI as the master frame).
I made the program put something on screen with the version below and I had to define some variables like screen_height, screen_width just so to prove the concept.
I also defined the method scrivere. Anyway it is rendering something so hopefully you can proceed. Good luck.
import tkinter as tk
class GUI(tk.Frame):
def __init__(self):
super(GUI, self).__init__()
self.config(width=700, height=500)
self.pack()
# self.bg()
# self.immagine()
self.testo()
self.statistiche()
self.inserimenti()
def bg(self):
load = Image.open("immagini\\background.png")
render = ImageTk.PhotoImage(load)
img = Label(self, image = render)
img.image = render
img.pack()
def immagine(self):
load = Image.open("immagini\\dn.png")
render = ImageTk.PhotoImage(load)
img = Label(self, image = render)
img.image = render
img.place( x = 10, y = 10 )
def testo(self):
self.testo = tk.Text(self, width = 110, height = 35, border = 5, bg = "black", fg ="white")
self.testo.place( x = 400, y = 20 )
def statistiche(self):
screen_height = 400
self.stats = tk.Text(self, width = 40, height = 10, border = 5, bg = "black", fg ="white")
self.stats.place( x = 10, y = (screen_height - 200))
def inserisci(self):
fraseInserita = self.inserimento.get()
self.scrivere(fraseInserita)
self.inserimento.delete('0', 'end')
def inserimenti(self):
large_font = ('calibri', 12)
screen_height = 400
screen_width = 600
self.inserimento = tk.Entry(self,font=large_font, width = 25, border = 5, bg = "black", fg ="white")
self.inserimento.place( x = 400, y = (screen_height - 100))
self.bottone = tk.Button(self, width = 30, height = 3, border = 5, text = "Inserisci", command = self.inserisci)
self.bottone.place( x = (screen_width - 300), y = (screen_height - 100))
def scrivere(self, frase):
print(' you need to define this function when button is pressed')
class Livelli():
def __init__(self):
pass
def cicloLivelli(self):
self.presentazione()
def presentazione(self):
print("Salve avventuriero, qual e' il tuo nome?")
if __name__ == "__main__":
a = GUI()
l = Livelli()
l.cicloLivelli()
a.mainloop()
Here's the code so far:
# -*- coding: utf-8 -*-
from Tkinter import *
#Creates game window
master = Tk()
master.geometry("640x480")
master.resizable(width = False, height = False)
master.title("YeeHaw Poker")
#Divides window into subsections
menuFrame = Frame(master, bg = "black", height = 60)
menuFrame.pack(fill = X, side = TOP)
tableFrame = Frame(master, highlightbackground = "black", highlightthickness = 4)
tableFrame.pack(fill = BOTH, expand = True)
optionsFrame = Frame(master, bg = "black", height = 100)
optionsFrame.pack(fill = X, side = BOTTOM)
#Draws poker table decorations
tableDecorations = Canvas(tableFrame, bg = "#771427", highlightthickness = 0)
tableDecorations.pack(fill = BOTH, expand = True)
#Renders window thus far so that dimensions can be found
master.update()
tWidth = tableDecorations.winfo_width()
tHeight = tableDecorations.winfo_height()
#Main edge
gap = 10
tableDecorations.create_rectangle(gap, gap, tWidth - gap, tHeight - gap, fill ="#277714", width = 4)
#Table outline
gap = 30
tableDecorations.create_rectangle(gap, gap, tWidth - gap, tHeight - gap, outline = "#35a31b", width = 2)
#Card outline coordinates
cardNum = 5
cardSize = 20
cardHeight = cardSize * 3.5
cardWidth = cardSize * 2.5
cardSpace = 10
cardTop = tHeight / 4
cardLeft = (tWidth - (cardNum * (cardWidth + cardSpace))) / 2
cardY1 = cardTop + cardHeight
cardY2 = cardTop
cardX1 = [0 for i in range(0, cardNum)]
cardX2 = [0 for i in range(0, cardNum)]
suit = [0 for i in range(0, cardNum)]
for i in range(0, cardNum):
cardX1[i] = cardLeft + (i * (cardWidth + cardSpace))
cardX2[i] = cardX1[i] + cardWidth
suit[i] = Label(tableDecorations, text = "", bg = "white", font = (None, 50))
suit[i].place(x = 5000, y = 5000)
#Draws specified card in specified place
def drawCard(pos, type, pip):
if type == "empty":
tableDecorations.create_rectangle(cardX1[pos], cardY1, cardX2[pos], cardY2, outline = "#35a31b", width = 2)
suit[pos].pack_forget()
else:
tableDecorations.create_rectangle(cardX1[pos], cardY1, cardX2[pos], cardY2, fill = "white", outline = "grey", width = 1)
if type == "diamond":
suit[pos].config(text = "♦", fg = "red")
elif type == "heart":
suit[pos].config(text = "♥", fg = "red")
elif type == "spade":
suit[pos].config(text = "♠", fg = "black")
elif type == "club":
suit[pos].config(text = "♣", fg = "black")
suit[pos].pack()
#Creates new table
def newTable():
for i in range(0, cardNum):
drawCard(i, "diamond", 0)
newTable()
master.mainloop()
However this doesn't move the labels with the diamonds in at all, as shown here:
It's infuriating...
I'm wanting the diamond to appear on each individual card, but clearly that's not happening here...
Any ideas?