Related
I have a problem regarding updating frames in tkinter. When I am in the Search frame, I update a file with some information, and then switch frames to the ShowSearch class. However, when the mainloop runs for the first time, it runs and initializes all the classes, so that my ShowSearch frame will display information in the file from the previous run of the program. My question is if there is a way for me to send data to the file storeSearch.txt, and then when I have called controller.show_frame(ShowSearch), my ShowSearch class will reinitialize and retrieve the data from the file storeSearch.txt and then display it. I only need help with reinitializing/updating the class since I already have written the code that retrieves the data from the file and displays it in my ShowSearch class.
import tkinter as tk
import Projekt_KTH_GUI as PK
import functools
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
container = tk.Frame(self)
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for F in (Homescreen, Menuscreen, Create, ShowUpcoming, ShowAll, OpenList, Search, Edit, ShowSearch):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(Homescreen)
def show_frame(self, container):
frame = self.frames[container]
frame.tkraise()
class Search(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
tk.Label(self, text = "Sök efter packningslista", font = ("Times new Roman", 30)).place(x = 110, y = 0)
self.objectList = PK.main()
self.search = tk.StringVar()
tk.Label(self, text = "Var god mata in ditt sökord:").place(x = 150, y = 100)
search = tk.Entry(self, textvariable = self.search, width = 40).place(x = 60, y = 120)
search_button = tk.Button(self, text = "Enter", command = self.getList).place(x = 430, y = 122.5)
menuButton = tk.Button(self, text = "Meny", command = lambda: self.controller.show_frame(Menuscreen)).place(x = 100, y = 300)
def getList(self):
searchWord = self.search.get()
objectList = self.objectList
objectList = PK.search(objectList, searchWord)
PK.filesUpdate(objectList, "storeSearch.txt")
return self.controller.show_frame(ShowSearch)
I tried to use the methods .update() and .destroy(), one line before i execute frame.tkraise(), but the .update() method doesn't do anything and when I use the .destroy() method, I get an error saying _tkinter.TclError: bad window path name ".!frame.!showsearch".
I have a question. I have this code:
import tkinter as tk
class new_f:
def __init__(self,root,num):
self.new_frame=tk.Frame(root,width=100,height=100,bg='white',bd=3,relief=tk.GROOVE)
self.new_frame.pack(side=tk.LEFT,fill=tk.X,expand=True)
self.num=num
def add_label(self,t):
self.l1=tk.Label(self.new_frame,bg='white',text=t)
self.l1.pack()
def return_instance(self):
return self.num
class Main_win:
def __init__(self,root):
self.root=root
self.bind_number=0
self.current_index=0
self.instance_list=[]
self.b1=tk.Button(self.root,text='Add Frame',command=self.add_frame_win)
self.b1.pack(side=tk.BOTTOM)
self.b2=tk.Button(self.root,text='Add text',command=self.add_text_frame)
self.b2.pack(side=tk.BOTTOM)
def return_instance_num(self,num,*args):
self.current_index=num
def add_frame_win(self):
new_in=new_f(self.root,self.bind_number)
self.instance_list.append(new_in)
new_in.new_frame.bind('<Button-1>',lambda evnt: self.return_instance_num(new_in.return_instance()))
#self.current_index=new_in.return_instance()
self.bind_number+=1
def add_text_frame(self):
instance=self.instance_list[self.current_index]
instance.add_label('Hello World')
root=tk.Tk()
ob=Main_win(root)
root.mainloop()
What I a trying to achieve is that I want to detect on which frame was the left mouse-button clicked so as to make that Frame active and add the labels to that particular Frame. However, I am stuck on how would I go about writing the code. I need a new class Because I don't know how many frames will the user need.
This is a short example of the code I will be implementing later. So my question is:
How will I go to detect which frame was picked so as to make it active to add the labels?
In this approach I have label l1 bound to Button-1
This was achieved by passing self to new_f instead of root
and binding self.l1 to Button-1
import tkinter as tk
class new_f:
def __init__(self, prog, num):
self.prog = prog
self.new_frame = tk.Frame(prog.root, width = 100, height = 100, bg = 'white', bd = 3, relief = tk.GROOVE)
self.new_frame.pack(side = tk.LEFT, fill = tk.X, expand = True)
self.num = num
def add_label(self, t):
self.l1 = tk.Label(self.new_frame, bg = 'white', text = t)
self.l1.pack()
# binding button-1 press to label
self.l1.bind("<Button-1>", lambda evnt: self.prog.return_instance_num(self.return_instance()))
def return_instance(self):
return self.num
class Main_win:
def __init__(self, root):
self.root = root
self.bind_number = 0
self.current_index = 0
self.instance_list = []
self.b1 = tk.Button(self.root, text = 'Add Frame', command = self.add_frame_win)
self.b1.pack(side = tk.BOTTOM)
self.b2 = tk.Button(self.root, text = 'Add text', command = self.add_text_frame)
self.b2.pack(side = tk.BOTTOM)
def return_instance_num(self, num, *args):
self.current_index = num
def add_frame_win(self):
# note passing self not root
new_in = new_f(self, self.bind_number)
self.instance_list.append(new_in)
new_in.new_frame.bind('<Button-1>', lambda evnt: self.return_instance_num(new_in.return_instance()))
#self.current_index = new_in.return_instance()
self.bind_number = self.bind_number + 1
def add_text_frame(self):
instance = self.instance_list[self.current_index]
instance.add_label('Hello World')
root = tk.Tk()
ob = Main_win(root)
# This necessary to prevent error if user hits 'Add text' before 'Add Frame'
ob.add_frame_win()
root.mainloop()
Here is an alternative method that uses dictionaries to store l1 and new_frame objects as keys and new_f instances as values.
This method can be used for other tkinter objects (Entry, Listbox, Text, Canvas)
import tkinter as tk
class new_f:
def __init__(self, parent):
self.parent = parent
self.frame = tk.Frame(
parent.root, width = 100, height = 100,
bg = "white", bd = 3, relief = tk.GROOVE)
self.frame.pack(
side = tk.LEFT, fill = tk.X, expand = True)
self.frame.bind("<Button-1>", parent.get_current_frame)
def add_label(self, t):
self.label = tk.Label(self.frame, bg = "white", text = t)
self.label.pack(fill = tk.BOTH, expand = True)
# bind button-1 to label, set instance_label and current to self
self.label.bind("<Button-1>", self.parent.get_current_label)
self.parent.instance_label[self.label] = self.parent.current = self
class Main_win:
instance_label = dict() # This method can be expanded for other objects
instance_frame = dict() # that you may want to create in frames
def __init__(self, root):
self.root = root
self.b1 = tk.Button(
self.root, text = "Add Frame", command = self.add_frame_win)
self.b1.pack(side = tk.BOTTOM)
self.b2 = tk.Button(
self.root, text = "Add text", command = self.add_text_frame)
self.b2.pack(side = tk.BOTTOM)
def get_current_label(self, ev):
self.current = self.instance_label[ev.widget]
def get_current_frame(self, ev):
self.current = self.instance_frame[ev.widget]
def add_frame_win(self):
# note passing self not root
self.new_in = new_f(self)
self.instance_frame[self.new_in.frame] = self.current = self.new_in
def add_text_frame(self):
# Change message with entry tool?
self.current.add_label("Hello World")
root = tk.Tk()
ob = Main_win(root)
# This necessary to prevent error if user hits 'Add text' before 'Add Frame'
ob.add_frame_win()
root.mainloop()
I'm trying to create a modular class ( for some gui buttons ).
CoreButton should consist of most methods for a common button, including tk frame.
Goal is to inheret CoreButton - and to use its frame to build rest of button's GUI - it does not appear.
any help will be appriciated
class CoreButton(ttk.Frame):
def __init__(self, master,nickname, hw_in=[], hw_out=[],ip_in='', ip_out='', sched_vector=[]):
ttk.Frame.__init__(self, master)
self.master = master
if ip_in == '': ip_in = ip_out # in case remote input is not defined
self.grid()
#####Rest of code
and class that inherits:
class ToggleBut2(CoreButton):
def __init__(self, master, hw_in=[], hw_out=[],ip_in='', ip_out='', sched_vector=[]):
CoreButton.__init__(self, master, nickname="JOHM", hw_in=hw_in, hw_out=hw_out, ip_in=ip_in, ip_out=ip_out, sched_vector=sched_vector)
self.master = master
def build_gui(self, nickname='babe', height=3, width=13):
self.button = tk.Checkbutton(self, text=nickname, variable=self.but_var, indicatoron=0, height=height, width=width, command=self.sf_button_press)
self.button.grid(row=0, column=0)
I don't know what you try to do but I would do something like this
I don't use self.grid() inside class, so outside class I can use tb1.pack() or tb1.grid() depends on which layout manager I use in window.
In __init__ I execute self.build_gui() so I don't have to do it manually, but now all classes have to create self.build_gui() without arguments.
I add Label only for test - to display "selected"/"not selected". You don't need it.
import tkinter as tk
from tkinter import ttk
class CoreButton(ttk.Frame):
def __init__(self, master, nickname, hw_in=None, hw_out=None, ip_in=None, ip_out=None, sched_vector=None):
ttk.Frame.__init__(self, master)
self.nickname = nickname
self.hw_in = hw_in
if self.hw_in is None:
self.hw_in = []
#self.hw_in = hw_in or []
self.hw_out = hw_out
if self.hw_out is None:
self.hw_out = []
#self.hw_out = hw_out or []
self.ip_out = ip_out
self.ip_in = ip_in
if self.ip_in is None:
self.ip_in = self.ip_out # in case remote input is not defined
#self.ip_in = hw_in or self.ip_out
self.sched_vector = sched_vector
if sched_vector is None:
sched_vector = []
#self.sched_vector = sched_vector or []
self.build_gui() # <--- to build it automatically
def build_gui(self):
# you will overide it in child widgets
raise NotImplementedError('You have to override method build_gui()')
class ToggleBut2(CoreButton):
def __init__(self, master, hw_in=None, hw_out=None, ip_in=None, ip_out=None, sched_vector=None, height=3, width=13):
self.height = height
self.width = width
# `self.but_var` is used in `build_gui` so it has to be created before `__init__` which executes `build_gui`
# or create it directly in `build_gui`
#self.but_var = tk.StringVar()
CoreButton.__init__(self, master, "JOHM", hw_in, hw_out, ip_in, ip_out, sched_vector)
def build_gui(self, nickname='babe'):
self.but_var = tk.IntVar()
self.button = tk.Checkbutton(self, text=self.nickname, variable=self.but_var, indicatoron=0, height=self.height, width=self.width, command=self.sf_button_press)
self.button.grid(row=0, column=0)
self.label = tk.Label(self, text='[not selected]')
self.label.grid(row=1, column=0)
def sf_button_press(self):
print(self.but_var.get())
if self.but_var.get() == 0:
self.label['text'] = '[ not selected ]'
else:
self.label['text'] = '[ selected ]'
# --- main ---
root = tk.Tk()
tb1 = ToggleBut2(root, height=1, width=10)
tb1.pack()
tb2 = ToggleBut2(root, height=3, width=30)
tb2.pack()
tb2 = ToggleBut2(root, height=5, width=50)
tb2.pack()
root.mainloop()
i have some problems with tkinter,i have two scrollbars,the first one isn't fitting with the entire frame,is taking the subframe(f5),and it's a problem,i have tried to make a new frame and change the existing ones,but all that i get is garbage,i will apreciate any help with the scrollbar issue.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#spyder
from Tkinter import *
import tkFileDialog
def curdir():
cdir = tkFileDialog.askdirectory(parent=finestra, initialdir="/home")
v.set(cdir)
#MAIN
finestra = Tk()
finestra.title("Creacio de fitxer comprimit")
f=Frame(finestra)
f.pack(side=TOP)
b=Button(f,text='Escollir directori treball',command=curdir)
b.pack(side=LEFT,anchor=W)
v=StringVar()
v.set("/home")
e1=Entry(f,width=35,textvariable=v)
e1.pack(side=LEFT)
l1=Label(f,text="Fitxers a incorporar al fitxer tar:")
l1.pack(side=TOP,anchor=N,padx=120)
f1=Frame(finestra)
f1.pack(side=TOP,anchor=NW)
l2=Label(f1,text="Llista:")
l2.pack(side=LEFT)
br=Button(f1,text='Reomplir')
br.pack(side=LEFT)
bo=Button(f1,text='Ocultar no seleccionats')
bo.pack(side=LEFT)
bos=Button(f1,text='Ocultar seleccionats')
bos.pack(side=LEFT)
Label(f1,text="\t\tCompresió").pack(side=LEFT)
rb1=Radiobutton(f1,text="cap").pack(side=LEFT)
rb2=Radiobutton(f1,text="gzip",value="gzip").pack(side=LEFT)
rb3=Radiobutton(f1,text="bzip2",value="bzip2").pack(side=LEFT)
rb4=Radiobutton(f1,text="xz",value="xz").pack(side=LEFT)
f2=Frame(finestra)
f2.pack(side=LEFT,anchor=W,pady=0)
scrollbar = Scrollbar(f2)
scrollbar.pack(side=RIGHT,fill="y",expand=False)
listbox = Listbox(f2, bd=0, yscrollcommand=scrollbar.set,width=55)
listbox.pack(side=TOP,anchor=W,fill="both",expand=True)
scrollbar.config(command=listbox.yview)
f3=Frame(finestra)
f3.pack(side=LEFT)
Label(f3,text="Tots:").pack(side=TOP,anchor=W)
tots=Button(f3,text=">>>").pack(side=TOP)
Label(f3,text="Als seleccionats:").pack(side=TOP)
af=Button(f3,text="-->").pack(side=TOP)
qt=Button(f3,text="<--").pack(side=TOP)
Label(f3,text="Tots:").pack(side=TOP,anchor=W)
cap=Button(f3,text="<<<").pack(side=TOP)
f4=Frame(finestra)
f4.pack(side=TOP)
scrollbar = Scrollbar(f4)
scrollbar.pack(side=RIGHT, fill=Y)
listbox = Listbox(f4, bd=0, yscrollcommand=scrollbar.set,width=35)
listbox.pack(side=LEFT,padx=5)
scrollbar.config(command=listbox.yview)
f6=Frame(finestra)
f6.pack(side=TOP,anchor=W,padx=20)
Button(f6,text="Crea").pack(side=LEFT)
Label(f6,text="fitxer tar:").pack(side=LEFT)
f5=Frame(f2)
f5.pack(side=BOTTOM,anchor=W)
Button(f5,text="Sortir").pack(side=BOTTOM,anchor=S)
mainloop()
Presenting such an example will not get you many replies. The one-letter variables and the unstructured approach make the program as good as unreadable. I really recommend that in the future you use a more structured approach. Classes are so easy to use in Python, you should take the time to practice a little.
I've never programmed in Tkinter (I used pygtk), and was interested, so I rewrote part of the program. Though probably not perfect, I think the (incomplete) code below is near what you need, and you can probably complete the rest...
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# tk.py
#
from Tkinter import *
import tkFileDialog
import pdb
def curdir():
cdir = tkFileDialog.askdirectory(parent=finestra, initialdir="/home")
v.set(cdir)
class EscollirDireccion(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
b = Button(self, text='Escollir directori treball', command=curdir)
b.pack(side = LEFT)
v = StringVar()
v.set("/home")
e = Entry(self, width = 35, textvariable = v)
e.pack(side = LEFT)
class Llista(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
l = Label(self, text = "Llista:")
l.pack(side = LEFT)
br = Button(self, text = 'Reomplir')
br.pack(side = LEFT)
bo = Button(self, text = 'Ocultar no seleccionats')
bo.pack(side = LEFT)
bos = Button(self, text = 'Ocultar seleccionats')
bos.pack(side = LEFT)
class SortirButtonBox(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
b = Button(self, text = "Sortir")
b.pack(side = LEFT)
Label(self, text = "").pack(side = LEFT, expand = True)
class ListBoxWithScrollbar(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
self.scrollbar = Scrollbar(self)
self.scrollbar.pack(side = RIGHT, fill = Y)
self.listbox = Listbox(self, bd = 0,
yscrollcommand = self.scrollbar.set,
width=55)
self.listbox.pack(side = RIGHT)
class LeftPanel(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
EscollirDireccion(self).pack()
Llista(self).pack()
ListBoxWithScrollbar(self).pack()
SortirButtonBox(self).pack(fill = X)
class TransferButtons(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
widgets = [(Label(self, text = "Tots"), None),
(Button(self, text = ">>>"), None),
(Label(self, text = "Als seleccionats"), None),
(Button(self, text = "->"), None),
(Button(self, text = "<-"), None),
(Label(self, text = "Tots"), None),
(Button(self, text = "<<<"), None)]
widgets.reverse()
for wdg in widgets:
wdg[0].pack(side = BOTTOM);
class RightPanel(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
tb = TransferButtons(self).pack(side = LEFT)
self.listbox = ListBoxWithScrollbar(self)
self.listbox.pack(side = LEFT)
class MainWindow(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
self.pack()
parent.title("Creacio de fitxer comprimit")
lp = LeftPanel(self)
lp.pack(side = LEFT)
rp = RightPanel(self)
rp.pack(side = LEFT)
def main():
tk = Tk()
mw = MainWindow(parent = tk)
mw.mainloop()
tk.destroy()
return 0
if __name__ == '__main__':
main()
Thanks to #jedwards for lending a hand with a packing problem...
I am writing a programm in which I am trying to open a n number of windows. My code is:
from tkinter import *
from tkinter import ttk
class Main_window(ttk.Frame):
"""A program"""
def __init__(self, master):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""Creates all the objects in the window"""
self.min_lbl = ttk.Label(self, text = "1").grid(row = 0, column = 0,
sticky = W)
self.max_lbl = ttk.Label(self, text = "100").grid(row = 0, column = 2,
sticky = W)
spinval = IntVar()
self.scale = ttk.Scale(self, orient = HORIZONTAL,
length = 200,
from_ = 1, to = 100,
variable = spinval,
command=self.accept_whole_number_only)
self.scale.grid(row = 0,column = 1,sticky = W)
self.spinbox = Spinbox(self, from_ = 1, to = 100,
textvariable = spinval,
command = self.update,
width = 10)
self.spinbox.grid(row = 0,column =3,sticky = W)
self.go_bttn = ttk.Button(self, text = "Go",
command = self.create_windows
).grid(row = 1, column = 1, sticky = W)
def accept_whole_number_only(self, e=None):
"""Makes the numbers from the scale whole"""
value = self.scale.get()
if int(value) != value:
self.scale.set(round(value))
def update(self):
"""Updates the scale and spinbox"""
self.scale.set(self.spinbox.get())
def create_windows(self):
"""This function will create all the new windows"""
value = self.scale.get()
window_num = value
negative_window_num = 1
while window_num != 0:
root = Tk()
root.title("This is Window "+str(window_num)[:-2]+" of "+str(value)[:-2])
root.geometry("350x200")
app = Window_creator(root)
root.mainloop()
window_num -= 1
class Window_creator(ttk.Frame):
"""makes child windows"""
def __init__(self, master):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""creates all the widgets in the window"""
def main():
"""Loops the window"""
root = Tk()
root.title("Programm")
root.geometry("350x200")
app = Main_window(root)
root.mainloop()
main()
What I want this code to do is I want to be able to set the spinbox or scale to number n and then when I click the Button i want n numbers of child windows to appear. I tried this with a while loop but it doesn't quite work like I want it to by creating a new window just after the I closed the prevoius window. You also have to close the main window first for it to work (I am going to make the button close the window automatically later). Any Ideas on how I could make this work?
Call child = Toplevel(), instead of root = Tk().
Also, you can not call mainloop more than once (since there should be only one event loop).
from tkinter import *
from tkinter import ttk
class Main_window(ttk.Frame):
"""A program"""
def __init__(self, master):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""Creates all the objects in the window"""
self.min_lbl = ttk.Label(self, text = "1").grid(row = 0, column = 0,
sticky = W)
self.max_lbl = ttk.Label(self, text = "100").grid(row = 0, column = 2,
sticky = W)
spinval = IntVar()
self.scale = ttk.Scale(self, orient = HORIZONTAL,
length = 200,
from_ = 1, to = 100,
variable = spinval,
command=self.accept_whole_number_only)
self.scale.grid(row = 0,column = 1,sticky = W)
self.spinbox = Spinbox(self, from_ = 1, to = 100,
textvariable = spinval,
command = self.update,
width = 10)
self.spinbox.grid(row = 0,column =3,sticky = W)
self.go_bttn = ttk.Button(self, text = "Go",
command = self.create_windows
).grid(row = 1, column = 1, sticky = W)
def accept_whole_number_only(self, e=None):
"""Makes the numbers from the scale whole"""
value = self.scale.get()
if int(value) != value:
self.scale.set(round(value))
def update(self):
"""Updates the scale and spinbox"""
self.scale.set(self.spinbox.get())
def create_windows(self):
"""This function will create all the new windows"""
value = self.scale.get()
window_num = value
negative_window_num = 1
for n in range(int(window_num)):
child = Toplevel()
child.title("This is Window "+str(window_num)[:-2]+" of "+str(value)[:-2])
child.geometry("350x200")
app = Window_creator(child)
class Window_creator(ttk.Frame):
"""makes child windows"""
def __init__(self, master):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""creates all the widgets in the window"""
def main():
"""Loops the window"""
root = Tk()
root.title("Programm")
root.geometry("350x200")
app = Main_window(root)
root.mainloop()
main()