Goal : dynamically create label and button (represents a task) and when I click this button it should destroy the label and button.
Problem : Unable to access buttons individually
Here is my code :
class Gui:
# constructor
def __init__(self, root):
self.root = root
self.root.title("TASKS")
self.root.geometry("300x700")
self.root.resizable(width=False, height=False)
self.clock = Label(self.root, fg="blue")
self.clock.grid(row = 0,column = 0,padx = 80,pady = 40)
self.update_clock()
self.new_button = Button(self.root, text="New",command = self.newwindow).grid(row = 0, column =1)
self.r =0
# clock
def update_clock(self):
now = strftime("%H:%M:%S")
self.clock.configure(text=now)
self.clock.after(1000, self.update_clock)
# label creator
def label(self, txt):
self.l = Label(self.root, text=txt, fg="red",pady =15)
self.l.grid(row = self.r, column =0)
# button creator
def donebutton(self):
self.b = Button(self.root, text="Done",command = lambda : self.del_task())
self.b.grid(row = self.r,column = 1)
# create a task
def task(self,txt):
self.r +=1
self.label(txt)
self.donebutton()
# delete task
def del_task(self):
self.l.destroy()
self.b.destroy()
# display gui method
def display(self):
self.root.mainloop()
# new window
def newwindow(self):
self.newwindow = Toplevel(self.root)
self.newwindow.title("NEW TASK")
self.newwindow.geometry("300x200")
self.newwindow.resizable(width=False, height=False)
Label(self.newwindow,text="Task").grid()
self.t1 = Text(self.newwindow,height = 2,width = 36)
self.t2 = Text(self.newwindow,height = 2,width = 10)
self.t1.grid()
Label(self.newwindow, text="Time").grid()
self.t2.grid()
self.c_b=Button(self.newwindow,text = "CREATE",command = lambda : self.task(self.t1.get("1.0",END)))
self.c_b.grid()
if __name__ == '__main__':
a = Gui(Tk())
a.display()
Requesting help with the code and I do not mind changing the whole code.
You keep overwriting the button. You said you don't care if the code is written completely different so, I changed a bunch.
Windows, Clock and Tasks are separated into classes
no targetable references to windows or buttons are held
the command for the "New Button" creates the NewTasks window
the command for the "Done Button" destroys its parent
the command for the "Create Button" creates a Task in the main window
a scrollable frame was added so tasks can never vertically overflow the main window
start, pause, done and remove Buttons were included
a scrollable output panel was included
ability to reposition tasks in the display is included
task labels can be clicked to show their content in the output panel
start, pause and done report to the output, and done includes elapsed time
once a task is started it cannot be removed
a task can only be "done" if it is running
a modicum of widget/grid formatting was applied to stop the display from jumping around as tasks were created/removed
I got bored and built your app ... probably.
from tkinter import Tk, Button, Label, Toplevel, Text, Frame, Canvas, Scrollbar
from time import strftime, time
class Task(Frame):
def __init__(self, master, text, output, move, **kwargs):
Frame.__init__(self, master, **kwargs)
self.grid_columnconfigure(0, weight=1)
self.stored = []
self.starttime = 0
self.send_output= output
self.lbl = Label(self, text=text, height=1, anchor='nw', fg='blue', font='calibri 14')
self.lbl.grid(row=0, column=0, sticky='nswe')
self.lbl.bind('<1>', self.output)
font = 'consolas 10 bold'
self.b1 = Button(self, font=font, text=chr(9654), command=self.start)
self.b2 = Button(self, font=font, text=chr(10073)+chr(10073), state='disabled', command=self.pause)
self.b3 = Button(self, font=font, text=chr(10006), state='disabled', command=self.done)
self.b4 = Button(self, font=font, text=chr(9866), command=self.destroy)
self.b5 = Button(self, font=font, text=chr(9650), command=lambda: move(self, -1))
self.b6 = Button(self, font=font, text=chr(9660), command=lambda: move(self, 1))
self.b1.grid(row=0, column=1) #start
self.b2.grid(row=0, column=2) #pause
self.b3.grid(row=0, column=3) #done
self.b4.grid(row=0, column=4) #remove
self.b5.grid(row=0, column=5) #move up
self.b6.grid(row=0, column=6) #move down
def start(self):
self.b1['state'] = 'disabled'
self.b2['state'] = 'normal'
self.b3['state'] = 'normal'
self.b4['state'] = 'disabled'
self.starttime = time()
self.send_output(f"{self.lbl['text']}", f"{strftime('%I:%M:%S')} STARTED: ")
def pause(self):
self.b1['state'] = 'normal'
self.b2['state'] = 'disabled'
self.b3['state'] = 'disabled'
self.stored.append(time() - self.starttime)
self.send_output(f"{self.lbl['text']}", f"{strftime('%I:%M:%S')} PAUSED: ")
def done(self):
self.stored.append(time() - self.starttime)
t = sum(self.stored)
self.send_output(f"{self.lbl['text']}\telapsed time: {self.etime(t)}\n", f"{strftime('%I:%M:%S')} FINISHED: ")
self.destroy()
def etime(self, s):
h = int(s//3600)
s -= 3600*h
m = int(s//60)
s -= 60*m
return f'{h:02}:{m:02}:{int(s):02}'
def output(self, event):
self.send_output(self.lbl['text'], 'Task: ')
class NewTasks(Toplevel):
WIDTH = 416
HEIGHT = 50
def __init__(self, master, slave, output, move, **kwargs):
Toplevel.__init__(self, master, **kwargs)
self.title("New Task")
self.geometry(f'{NewTasks.WIDTH}x{NewTasks.HEIGHT}')
self.resizable(width=False, height=False)
Label(self, text="Task").grid(row=0, column=0)
txt = Text(self, height=2, width=36, font='consolas 12')
txt.grid(row=0, column=1)
Button(self, text="CREATE", command=lambda: self.create(slave, output, move, txt)).grid(row=0, column=2, sticky='e', padx=4, pady=12)
def create(self, target, output, move, txt):
t = Task(target.frame, txt.get("1.0",'end'), output, move)
t.grid(column=0, sticky='nswe')
target.update(t)
class ScrollFrame(Canvas):
def __init__(self, master, **kwargs):
Canvas.__init__(self, master, **kwargs)
vsb = Scrollbar(self, orient='vertical', command=self.yview)
vsb.pack(side='right', fill='y')
self.configure(yscrollcommand=vsb.set)
self.frame = Frame(self, height=0)
self.frame.grid_columnconfigure(0, weight=1)
self.frame.bind('<Configure>', lambda e:self.configure(scrollregion=self.bbox("all")))
self.create_window((0,0), width=App.WIDTH-20, window=self.frame, anchor="nw")
self.movelist = []
def update(self, target):
self.movelist.append(target)
def move_item(self, elem, dir=1):
c = self.frame.winfo_children()
i = self.movelist.index(elem)
if i+dir in range(0, len(self.movelist)):
e = self.movelist.pop(i)
self.movelist.insert(i+dir, e)
for n in range(len(self.movelist)):
while n < len(self.movelist) and self.movelist[n] not in c:
self.movelist.pop(n)
if n < len(self.movelist):
self.movelist[n].grid(row=n, column=0, sticky='nswe')
continue
break
class Clock(Label):
def __init__(self, master, **kwargs):
Label.__init__(self, master, **kwargs)
self.update()
def update(self):
self['text'] = strftime('%I:%M:%S')
self.after(1000, self.update)
class App(Tk):
WIDTH = 600
HEIGHT = 447
def __init__(self, **kwargs):
Tk.__init__(self, **kwargs)
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
Clock(self, fg="blue", font='calibri 18').grid(row=0, column=0, ipady=10, sticky='nswe')
sf = ScrollFrame(self, highlightthickness=0)
sf.grid(row=1, column=0, columnspan=3, sticky='nswe')
command = lambda: NewTasks(self, sf, self.output, sf.move_item)
Button(self, text="New", font='calibri 12', command=command).grid(row=0, column=1, columnspan=2)
self.out = Text(self, height=8, font="calibri 14")
self.out.grid(row=2, column=0, columnspan=2)
self.out.tag_configure("bold", font="calibri 12 bold")
vsb = Scrollbar(self, orient='vertical', command=self.out.yview)
vsb.grid(row=2, column=2, sticky='ns')
self.out.configure(yscrollcommand=vsb.set)
def output(self, text, btext=''):
self.out.insert('end', btext, 'bold')
self.out.insert('end', text)
if __name__ == '__main__':
app = App()
app.title("Task Scheduler")
app.geometry(f'{App.WIDTH}x{App.HEIGHT}')
app.resizable(width=False, height=False)
app.mainloop()
Related
Okay, so I am been learning python for 2 weeks and implementing TkInter now, I am trying to make an project where the user can set an Alarm and when the alarm rings the user will hit stop then the program will ask the user some random math questions, I been messing around and got everything up to the Math problem to work, I have a lot of placeholders in place and I am stuck with getting the answer of x and y to return to an INT, I have it made where it will show what x+y will equal and what the user enter but when I run the while loop my program just freezes. I assume its because the answer returns as a Label and that's not an INT, so all my issues are in my Math Class and have been trying for 3 days and cant figure it out. Please anything will be helpful, I tried using the .get method but that also gives me errors.
import tkinter as tk
import time
import datetime
from tkinter import *
from winsound import PlaySound, SND_FILENAME, SND_LOOP, SND_ASYNC
import random
class WakeUpApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side='top', fill='both', expand='true',)
container.grid_rowconfigure(0, minsize=400, weight=1)
container.grid_columnconfigure(0, minsize=250, weight=2)
self.frames = {}
for F in (Alarm, Chooser, Difficulty, Math):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame(Alarm)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
present = datetime.datetime.now()
now = present.strftime("%H:%M:%S")
class Alarm(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
Alarm.hour = tk.StringVar()
Alarm.min = tk.StringVar()
Alarm.sec = tk.StringVar()
hour_a = tk.Entry(self, text=Alarm.hour, width=4).place(x=50, y=50)
min_a = tk.Entry(self, text=Alarm.min, width=4).place(x=70, y=50)
sec_a = tk.Entry(self, text=Alarm.sec, width=4).place(x=90, y=50)
current_time = tk.Label(self, text=f'Current Time: {now}').place(x=0, y=30)
set_time = tk.Label(self, text='Set Time').place(x=0, y=50)
'''
VERY IMPORTANT -- THIS CODE STARTS THE ALARM
setalarm = tk.Button(self, text='Set Alarm', command=lambda: wake())
setalarm.place(x=90, y=90)
'''
setalarm = tk.Button(self, text='Set Alarm', command=lambda: controller.show_frame(Chooser))
setalarm.place(x=90, y=90)
def wake():
alarm_time = f'{Alarm.hour.get()}:{Alarm.min.get()}:{Alarm.sec.get()}'
alarm_clock(alarm_time)
def play_sound(self,):
PlaySound('Sound.wav', SND_FILENAME|SND_LOOP|SND_ASYNC)
def stop_sound(self):
PlaySound(None, SND_FILENAME)
def alarm_clock(alarm_time):
while True:
time.sleep(1)
present = datetime.datetime.now()
now = present.strftime("%H:%M:%S")
print(now)
if now == alarm_time:
break
if now == alarm_time:
play_sound(self)
testbutton = Button(self, text='pls work', command=lambda: stop_sound(self))
testbutton.pack()
class Chooser(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='Please Choose Your Wake Up Game')
label.pack(pady=50, padx=50)
math = tk.Button(self, text='Math Game',
height=5, width=15,
command=lambda: controller.show_frame(Difficulty))
math.place(x=125, y=75)
guesser = tk.Button(self, text='Guessing Game',
height=5, width=15,
command=lambda: controller.show_frame(Alarm))
guesser.place(x=125, y=175)
class Difficulty(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='Please Choose Your Difficulty for the Questions')
label.pack(pady=50, padx=50)
level1 = tk.Button(self, text='Level 1 \n ie: 12+17',
height=5, width=15,
command=lambda: controller.show_frame(Math))
level1.place(x=125, y=75)
level2 = tk.Button(self, text='Level 2 \n ie: 12*9',
height=5, width=15,
command=lambda: controller.show_frame(Alarm))
level2.place(x=125, y=175)
level3 = tk.Button(self, text='Level 3 \n ie: 6*7+21',
height=5, width=15,
command=lambda: controller.show_frame(Alarm))
level3.place(x=125, y=275)
class Math(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
x = tk.IntVar()
y = tk.IntVar()
z = tk.IntVar()
ab = tk.IntVar()
x = random.randint(1, 10)
y = random.randint(1, 10)
xy = int(x + y)
problem = tk.Label(self, text=f'{x} + {y}').place(x=0, y=30)
goal = tk.Label(self, text=xy).place(x=0, y=90)
solution = tk.Entry(self, text=z).place(x=0, y=50)
new = tk.Entry(self, text=ab).place(x=0, y=70)
def answer2(self):
py_guess = tk.Label(self, text=ab.get()).place(x=125, y=120)
button2 = tk.Button(self, text='GIVE ME Z PLS', command=lambda: answer())
button2.pack()
button2 = tk.Button(self, text='The Problem', command=lambda: answer2(self))
button2.pack()
def answer():
user_guess = tk.Label(self, text=z.get()).place(x=125, y=100)
level1(user_guess)
def level1(user_guess):
keepGoing = True
while keepGoing:
if (z == xy):
good = tk.Label(self, text='good job').pack()
keepGoing = False
else:
bad = tk.Label(self, text='nope go again').pack()
string_solution = solution.get()
int_solution = int(string_solution)
app = WakeUpApp()
app.mainloop()
So my problem is that I want to create multiple entry fields like over 30, but every time I reformat it using .pack or .grid it keeps throwing off the formatting. is there a way to fit nearly 30 entry boxes on one window without using anything like SQLite? As we can see from this code, we have 4 fields, how would you go on with shrinking the boxes to put in more entry fields like over 30.
Secondly, I want to output all the typed data entry fields to the Listbox is there a way to add a table column to the list box to show a breakdown of each entry field.
The third is it possible to move the Listbox to another tab on the same window to show all entry fields that were typed in, if so how would you do so.
Here is my current code so far
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from datetime import *
# Import Packages
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import *
import tkinter.filedialog
from tkcalendar import Calendar, DateEntry
from tkinter import messagebox
from tkintertable import TableCanvas, TableModel
from tkinter import ttk
# Database
#import sqlite3
import csv
window = Tk()
window.title("TESTTEST")
window.geometry("750x450")
window.config(background='black')
#style = ttk.Style(window)
#style.configure('lefttab.TNotebook', tabposition='wn',)
# TAB LAYOUT
#tab_control = ttk.Notebook(window,style='righttab.TNotebook')
#tab1 = ttk.Frame(tab_control)
#tab2 = ttk.Frame(tab_control)
#tab3 = ttk.Frame(tab_control)
#tab4 = ttk.Frame(tab_control)
#tab5 = ttk.Frame(tab_control)
#tab6 = ttk.Frame(tab_control)
# ADD TABS TO NOTEBOOK
#tab_control.add(tab1, text=f'{"Home":^20s}')
#tab_control.add(tab2, text=f'{"View":^20s}')
#tab_control.add(tab3, text=f'{"Search":^20s}')
#tab_control.add(tab4, text=f'{"Edit":^20s}')
#tab_control.add(tab5, text=f'{"Export":^20s}')
#tab_control.add(tab6, text=f'{"About ":^20s}')
#label1 = Label(tab1, text= 'Python RPA APP',padx=1, pady=1)
#label1.grid(column=0, row=0)
#label2 = Label(tab2, text= 'View',padx=5, pady=5)
#label2.grid(column=0, row=0)
#label3 = Label(tab3, text= 'Search',padx=5, pady=5)
#label3.grid(column=0, row=0)
#label4 = Label(tab4, text= 'Edit/Update',padx=5, pady=5)
#label4.grid(column=0, row=0)
#label5 = Label(tab5, text= 'Export',padx=5, pady=5)
#label5.grid(column=0, row=0)
#label6 = Label(tab6, text= 'About',padx=5, pady=5)
#label6.grid(column=0, row=0)
#tab_control.pack(expand=1, fill='both')
class Main(ttk.Frame):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.punches_list = []
self.ent1 = tk.StringVar()
self.ent2 = tk.StringVar()
self.ent3 = tk.StringVar()
self.ent4 = tk.StringVar()
self.init_ui()
def init_ui(self):
f = ttk.Frame()
# ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW)
## ttk.Label(f, text = "Entry1").pack(side=LEFT, padx=5, pady=5, anchor=NW)
## self.txTest = ttk.Entry(f,textvariable=self.ent).pack(fill=X, padx=5, expand=True, anchor=NW)
# ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW)
# self.txTest1 = ttk.Entry(f, textvariable=self.ent2).pack(side=TOP, anchor=NW)
ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW, fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest1 = ttk.Entry(f, textvariable=self.ent1).pack(side=TOP, anchor=NW, fill=tk.BOTH, pady=5, padx=5, expand=0)
ttk.Label(f, text = "Entry2").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest2 = ttk.Entry(f, textvariable=self.ent2).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
ttk.Label(f, text = "Entry3").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest3 = ttk.Entry(f, textvariable=self.ent3).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
#tkinter.Label(window, text = "Username").grid(row = 0) #'username' is placed on position 00 (row - 0 and column - 0)
#tkinter.Entry(window).grid(row = 0, column = 1) # first input-field is placed on position 01 (row - 0 and column - 1)
ttk.Label(f, text = "Entry4").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest4 = ttk.Entry(f, textvariable=self.ent4).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.lstItems = self.get_listbox(f, 140,140).pack(anchor=N)
w = ttk.Frame()
ttk.Button(w, text="Add",command=self.add_In).pack(side=TOP, anchor=NE)
ttk.Button(w, text="Clear", command=self.clear_Out).pack(side=TOP, anchor=NE)
ttk.Button(w, text="Close", command=self.on_close).pack(side=TOP, anchor=NE)
#f.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
#w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
f.pack(side=tk.LEFT, fill=tk.BOTH, pady=5, padx=5, expand=1)
w.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
def add_In(self,):
#s = "IN {0:>30} {1}".format(str(datetime.now()), self.ent.get())
s = self.ent1.get()
self.set_list(s)
s = self.ent2.get()
self.set_list(s)
s = self.ent3.get()
self.set_list(s)
s = self.ent4.get()
self.set_list(s)
self.ent1.set('')
self.ent2.set('')
self.ent3.set('')
self.ent4.set('')
def clear_Out(self):
#s = "OUT {0:>29} {1}".format(str(datetime.now()), self.ent1.get())
#field_name.set('')
self.ent1.set('')
self.ent2.set('')
self.ent3.set('')
self.ent4.set('')
#self.set_list(s)
def set_list(self,s):
self.punches_list.append(s)
self.lstItems.delete(0, tk.END)
for i in self.punches_list:
self.lstItems.insert(tk.END, i)
def on_set(self):
self.check.set(1)
def on_close(self):
#self.destroy()
self.parent.on_exit()
def get_listbox(self, container, height=750, width=600):
sb = tk.Scrollbar(container,orient=tk.VERTICAL)
w = tk.Listbox(container,
relief=tk.GROOVE,
selectmode=tk.BROWSE,
height=height,
width=width,
background = 'white',
font='TkFixedFont',
yscrollcommand=sb.set,)
sb.config(command=w.yview)
w.pack(side=tk.LEFT,fill=tk.BOTH, expand =1)
sb.pack(fill=tk.Y, expand=1)
return w
class App(tk.Tk):
"""Start here"""
def __init__(self):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_exit)
self.set_style()
self.set_title()
Main(self,)
def set_style(self):
self.style = ttk.Style()
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
self.style.theme_use("vista") #change to your liking :)
def set_title(self):
s = "{0}".format('Employee Time-Clock')
self.title(s)
self.destroy()
def on_exit(self):
window.destroy()
#self.destroy()
#sys.exit()
#"""Close all"""
#if messagebox.askokcancel( self.title(), "Do you want to quit?", parent=self):
# self.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()
Your code is a giant mess, brah ;D. What I gather from your question is that you need some kind of table. What I gather from your code is the table should have cells comprised of Label and Entry. You also want an interface to create entries. Below is an example of all of that. I don't really see anything to explain. It's just a bunch of Frame, Label, Entry and Button. The only real action is in Table. All that action is, is mathematically figuring out where to put the next Item. This is all really basic stuff.
import tkinter as tk
from tkinter import ttk
#the entire bottom row of the app.
#has a dependency on self.master.table ~ not good OOP
class EntryManager(tk.Frame):
def __init__(self, master, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.grid_columnconfigure(5, weight=1)
font='Helvetica 10 bold'
tk.Label(self, text='Label', font=font, width=5).grid(row=0, column=0, padx=2)
lbl = tk.Entry(self, width=10, font=font)
lbl.grid(row=0, column=1, padx=2)
tk.Label(self, text='Entry', font=font, width=5).grid(row=0, column=2, padx=2)
ent = tk.Entry(self, width=25, font=font)
ent.grid(row=0, column=3, padx=2)
tk.Button(self, text='add', font=font, command=lambda: self.master.table.addItem(lbl.get(), ent.get())).grid(row=0, column=4, padx=2, sticky='w')
tk.Label(self, text='rows', font=font, width=4).grid(row=0, column=5, padx=2, sticky='e')
r = tk.Entry(self, width=4, font=font)
r.insert('end', self.master.table.rows)
r.grid(row=0, column=6, padx=2)
tk.Label(self, text='cols', font=font, width=4).grid(row=0, column=7, padx=2)
c = tk.Entry(self, width=4, font=font)
c.insert('end', self.master.table.cols)
c.grid(row=0, column=8, padx=2)
tk.Button(self, text='set', font=font, command=lambda: self.master.table.setDims(r.get(), c.get())).grid(row=0, column=9, padx=2, sticky='e')
#generic scrollable frame
class ScrollFrame(tk.Frame):
def __init__(self, master, row=0, column=0, scrollspeed=.02, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.grid(row=row, column=column, sticky='nswe')
self.scrollspeed = scrollspeed
self.canvas = tk.Canvas(self, highlightthickness=0)
self.canvas.grid(column=0, row=0, sticky='nswe')
self.v_scroll = tk.Scrollbar(self, orient='vertical', command=self.canvas.yview)
self.v_scroll.grid(row=0, column=1, sticky='ns')
self.canvas.configure(yscrollcommand=self.v_scroll.set)
self.canvas.bind_all('<MouseWheel>', self.on_mousewheel)
self.frame = tk.Frame(self.canvas, height=0)
self.frame.grid_columnconfigure(0, weight=1)
self.frame.bind('<Configure>', lambda e:self.canvas.configure(scrollregion=self.canvas.bbox("all")))
self.canvas.create_window((0,0), window=self.frame, anchor="nw")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
def on_mousewheel(self, event):
self.canvas.yview_moveto(self.v_scroll.get()[0]+((-event.delta/abs(event.delta))*self.scrollspeed))
#a table cell
class Item(tk.Frame):
#property
def value(self):
return self.__value.get()
#value.setter
def value(self, text):
self.__value.set(text)
def __init__(self, master, text, value, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
tk.Label(self, text=text, width=10, font='none 8 bold').grid(row=0, column=0, pady=5, padx=5)
self.__value = tk.StringVar(value=value)
tk.Entry(self, textvariable=self.__value, width=25).grid(row=0, column=1, pady=5, padx=5)
#the table
class Table(ScrollFrame):
def __init__(self, master, rows=15, cols=3, **kwargs):
ScrollFrame.__init__(self, master, **kwargs)
self.entries = []
self.rows = rows
self.cols = cols
def addItem(self, text, value):
if len(self.entries) < self.rows*self.cols:
self.entries.append(Item(self.frame, text, value))
self.entries[-1].grid(row=(len(self.entries)-1)%self.rows, column=(len(self.entries)-1)//self.rows)
def getItem(self, row, column):
return self.entries[self.rows*column+row].value
def setDims(self, rows, cols):
if rows.isnumeric():
self.rows = int(rows)
if cols.isnumeric():
self.cols = int(cols)
for ent in self.entries:
ent.grid_forget()
for i, ent in enumerate(self.entries):
if i < self.rows*self.cols:
ent.grid(row=i%self.rows, column=i//self.rows)
class App(tk.Tk):
WIDTH, HEIGHT, TITLE = 770, 465, 'Application'
def __init__(self):
tk.Tk.__init__(self)
ttk.Style().theme_use("vista")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.table = Table(self, rows=20, cols=3)
self.table.grid(row=0, column=0, sticky='nswe')
EntryManager(self).grid(row=1, column=0, sticky='nswe', ipady=5)
#junk for testing
for i in range(12):
self.table.addItem(f'entry_{i}', f'data {i}')
if __name__ == '__main__':
app = App()
app.config(background='black')
app.title(App.TITLE)
app.geometry(f'{App.WIDTH}x{App.HEIGHT}')
#app.resizable(width=False, height=False)
app.mainloop()
Might as well dump the table keys in the table and see what happens. The sizes and alignments of things could use some work.
I created a window with tkinter for my programm but I want it to resize itself when the user resizes the window. Right now when I increase or decrease the size of the window the widgets stay at the same position and don't in-/decrease in size.
Here is my code:
import tkinter as tk
class Graphicaluserinterface(tk.Frame):
def __init__(self,master=None):
super().__init__(master)
self.grid()
self.check1 = tk.IntVar()
self.fileopenname1 = tk.StringVar()
self.entrystring = tk.IntVar()
self.menubar = tk.Menu(self)
self.create_widgets()
def create_widgets(self):
self.filemenu=tk.Menu(self.menubar,tearoff=0)
self.menubar.add_cascade(label="File",menu=self.filemenu)
self.filemenu.add_command(label="Exit",command = root.destroy)
self.helpmenu=tk.Menu(self.menubar,tearoff=0)
self.programmstart = tk.Button(self, text = "Start Program")
self.programmstart.grid(row=10,column=8,sticky = "W")
self.checkbutton1 = tk.Checkbutton(self, text = "Drehzahl und Drehmoment",variable=self.check1,onvalue=1,offvalue=0)
self.checkbutton1.grid(row=0,column=0,columnspan=3,sticky = "W")
self.leer1 = tk.Label(self,text=" ") #erzeugt leere Zelle, sonst ist startbutton links
self.leer1.grid(row=0,column=3,columnspan=5)
self.leer2 = tk.Label(self,text=" ")
self.leer2.grid(row=5,column=8,rowspan=2)
self.leer3 = tk.Label(self,text=" ")
self.leer3.grid(row=9,column=9)
self.inputpathdisplay = tk.Label(self,textvariable=self.fileopenname1,bg="white",width=60)
self.inputpathdisplay.grid(row=1,column=8,columnspan=3,sticky = "W")
self.inputpathdisplaylabel = tk.Label(self,text="Inputfile")
self.inputpathdisplaylabel.grid(row=0,column=8,columnspan=3)
root = tk.Tk()
app = Graphicaluserinterface(master=root)
app.master.title("Programm")
app.master.minsize(800,300)
root.config(menu=app.menubar)
app.mainloop()
You need to configure the weight on your grid's rows and columns. The following is a refactored version of your code that should act a little more as you were hoping. Please continue development from this code:
#! /usr/bin/env python3
import tkinter
from tkinter.constants import *
class GraphicalUserInterface(tkinter.Frame):
#classmethod
def main(cls):
root = tkinter.Tk()
root.title('Program')
root.minsize(560, 105)
gui = cls(root)
gui.grid(row=0, column=0, sticky=NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root['menu'] = gui.menubar
cls.create_toplevel(root, 'First Toplevel')
root.mainloop()
#staticmethod
def create_toplevel(root, window_title):
window = tkinter.Toplevel(root)
window.title(window_title)
window.minsize(560, 105)
def __init__(self, master=None):
super().__init__(master)
self.check_value = tkinter.BooleanVar()
self.filename = tkinter.StringVar()
self.menubar = tkinter.Menu(self)
self.file_menu = tkinter.Menu(self.menubar, tearoff=FALSE)
self.help_menu = tkinter.Menu(self.menubar, tearoff=FALSE)
self.program_start = tkinter.Button(
self, text='Start Program',
command=lambda: self.create_toplevel(self.master, 'Another Window')
)
self.check_button = tkinter.Checkbutton(
self, text='Speed & Torque', variable=self.check_value,
onvalue=True, offvalue=False
)
self.input_path_display = tkinter.Label(
self, textvariable=self.filename, bg='white', width=60
)
self.input_path_display_label = tkinter.Label(self, text='Input File')
self.create_widgets()
def create_widgets(self):
self.menubar.add_cascade(label='File', menu=self.file_menu)
self.file_menu.add_command(label='Exit', command=self.master.destroy)
pad = dict(padx=5, pady=5)
self.check_button.grid(row=0, column=0, **pad)
self.input_path_display_label.grid(row=0, column=1, sticky=EW, **pad)
self.input_path_display.grid(row=1, column=1, sticky=NSEW, **pad)
self.program_start.grid(row=2, column=1, sticky=EW, **pad)
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(1, weight=1)
if __name__ == '__main__':
GraphicalUserInterface.main()
i try to learn Object Oriendet with Tkinter.
i make a Button Class and try using this but i cant change it's state
this my class
class Buton():
def __init__(self, konum=None, text=None, command=None, cursor="hand2", state="normal", width=None,
row=None, column=None, sticky=None):
print("SELF: ", type(self), self)
self.konum = konum
self.text = text
self.command = command
self.cursor = cursor
self.state = state
self.width = width
self.row = row
self.column = column
self.sticky = sticky
self.buton_bas()
def buton_bas(self):
self.buton = Button(self.konum, text=self.text, state=self.state, command=self.command)
self.buton.grid(row=self.row, column=self.column, padx=2, pady=5)
def state_change(self, new_state):
self.['state'] = new_statew
My def and button
def print():
global label
label = Label(pencere, text=entry.get(), fg="lightgray", bg=darkbg, font=("Times 10"))
label.grid(row=3, column=0, columnspan=2, padx=2, pady=5, )
Buton.state_change(buton1, "disable")
buton1 = Buton(konum=pencere, text="Print", command=print, row=2, column=0)
When i push Print button, it print the text from entry. its ok but i cant change button's state. i take this: TypeError: 'Buton' object does not support item assignment
i try ;
self.state = new_state
but dont work.. what is wrong?
thanks for help from now
Your code contains a lot of errors. I have fixed them. You need to use <button>["state"] = state. Try:
from tkinter import *
root = Tk()
class Buton():
def __init__(self, konum=None, text=None, command=None, cursor="hand2", state="normal", width=None,
row=None, column=None, sticky=None):
#print("SELF: ", type(self), self)
self.konum = konum
self.text = text
self.command = command
self.cursor = cursor
self.state = state
self.width = width
self.row = row
self.column = column
self.sticky = sticky
self.buton_bas()
def buton_bas(self):
self.buton = Button(self.konum, text=self.text, state=self.state, command=self.command)
self.buton.grid(row=self.row, column=self.column, padx=2, pady=5)
def state_change(self, new_state):
self.buton['state'] = new_state
def print():
global label
label = Label(root, text="You can change text", fg="lightgray", bg="grey", font=("Times 10"))
label.grid(row=3, column=0, columnspan=2, padx=2, pady=5, )
Buton.state_change(buton1, "disable")
buton1 = Buton(konum=root, text="Print", command=print, row=2, column=0)
So I've got a custom widget that inherits from frame and contains a canvas and a scrollbar, and a custom widget that also inherits from frame that I want to dynamically add to the canvas, resizing the scrollregion as necessary. Here's my code:
class MessageItem(Frame):
"""A message to be contained inside a scrollableContainer"""
def __init__(self, message, **kwds):
Frame.__init__(self, **kwds)
self.text = Label(self, text = message)
self.text.grid(column = 0, row = 0, sticky = N+S+E+W)
class scrollableContainer(Frame):
"""A scrollable container that can contain a number of messages"""
def initContents(self):
"""Initializes a scrollbar, and a canvas that will contain all the items"""
#the canvas that will contain all our items
self.canv = Canvas(self)
self.canv.grid(column = 0, row = 0, sticky = N+S+W)
#force Tkinter to draw the canvas
self.canv.update_idletasks()
#use the values from the canvas being drawn to determine the size of the scroll region
#note that currently, since the canvas contains nothing, the scroll region will be the same as
#the size of the canvas
geometry = self.canv.winfo_geometry()
xsize, ysize, xpos, ypos = parse_geometry_string(geometry)
self.canv['scrollregion'] = (0, 0, xsize, ysize)
#the scrollbar for that canvas
self.vscroll = Scrollbar(self, orient = VERTICAL, command = self.canv.yview )
self.vscroll.grid(column = 1, row = 0, sticky = N+S+E)
self.canv["yscrollcommand"] = self.vscroll.set
def __init__(self, **kwds):
Frame.__init__(self, **kwds)
#initialize the widget's contents
self.grid(sticky = N+S+E+W)
self.pack()
self.initContents()
#initialize the list of contents so we can append to it
self.contents = []
def addMessage(self, message):
#Add the message to the list of contents
self.contents.append(MessageItem(message))
#Add the message to the grid
self.contents[(len(self.contents) - 1)].grid(column = 0, row = (len(self.contents) - 1))
#set the new scrollable region for the canvas
scrollregionlist = self.canv['scrollregion'].split()
oldRegion = int(scrollregionlist[3])
newRegion = oldRegion + parse_geometry_string(self.contents[
(len(self.contents) - 1)].winfo_geometry())[3]
self.canv['scrollregion'] = (int(scrollregionlist[0]), int(scrollregionlist[1]),
int(scrollregionlist[2]), newRegion)
The problem I'm experiencing is that self.canv['scrollregion'] appears to disappear outside of init. In the addMessage method, in the line:
scrollregionlist = self.canv['scrollregion'].split()
The scrollregion property on self.canv returns an empty string, which I can verify by putting a
print self.canv['scrollregion']
immediately before that line
You sure a Text widget wouldn't suffice here?
anyway,
from Tkinter import *
class MessageItem(Frame):
"""A message to be contained inside a scrollableContainer"""
def __init__(self, master, message, **kwds):
Frame.__init__(self, master, **kwds)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.text = Label(self, text=message, anchor='w', bg='gold')
self.text.grid(row=0, column=0, sticky='nsew')
class scrollableContainer(Frame):
"""A scrollable container that can contain a number of messages"""
def __init__(self, master, **kwargs):
Frame.__init__(self, master, **kwargs) #holds canvas & scrollbars
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.canv = Canvas(self, bd=0, highlightthickness=0)
self.hScroll = Scrollbar(self, orient='horizontal',
command=self.canv.xview)
self.hScroll.grid(row=1, column=0, sticky='we')
self.vScroll = Scrollbar(self, orient='vertical',
command=self.canv.yview)
self.vScroll.grid(row=0, column=1, sticky='ns')
self.canv.grid(row=0, column=0, sticky='nsew')
self.canv.configure(xscrollcommand=self.hScroll.set,
yscrollcommand=self.vScroll.set)
self.frm = Frame(self.canv, bd=2, bg='green') #holds messages
self.frm.grid_columnconfigure(0, weight=1)
self.canv.create_window(0, 0, window=self.frm, anchor='nw', tags='inner')
self.messages = []
for i in range(20):
m = MessageItem(self.frm, 'Something Profound', bd=2, bg='black')
m.grid(row=i, column=0, sticky='nsew', padx=2, pady=2)
self.messages.append(m)
self.update_layout()
self.canv.bind('<Configure>', self.on_configure)
def update_layout(self):
self.frm.update_idletasks()
self.canv.configure(scrollregion=self.canv.bbox('all'))
self.canv.yview('moveto','1.0')
self.size = self.frm.grid_size()
def on_configure(self, event):
w,h = event.width, event.height
natural = self.frm.winfo_reqwidth()
self.canv.itemconfigure('inner', width= w if w>natural else natural)
self.canv.configure(scrollregion=self.canv.bbox('all'))
def add_message(self, message):
m = MessageItem(self.frm, message, bd=2, bg='red')
m.grid(row=self.size[1], column=0, padx=2, pady=2, sticky='we')
self.messages.append(m)
self.update_layout()
root = Tk()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
sc = scrollableContainer(root, bd=2, bg='black')
sc.grid(row=0, column=0, sticky='nsew')
def new_message():
test = 'Something Profane'
sc.add_message(test)
b = Button(root, text='New Message', command=new_message)
b.grid(row=1, column=0, sticky='we')
root.mainloop()