Tkinter Scrollbar taking more space than expected - python

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...

Related

tkinter.place() not working and window still blank

I have a problem with tkinter.place, why it is not working?
class KafeDaun(tk.Frame):
def __init__(self, master = None):
super().__init__(master)
self.master.title("Kafe Daun-Daun Pacilkom v2.0 🌿")
self.master.geometry("500x300")
self.master.configure(bg="grey")
self.create_widgets()
self.pack()
def create_widgets(self):
self.btn_buat_pesanan = tk.Button(self, text = "Buat Pesanan", width = 20)
self.btn_buat_pesanan.place(x = 250, y = 100)
self.btn_meja = tk.Button(self, text = "Selesai Gunakan Meja", width = 20)
I still get this blank Frame even though already use tkinter.place on btn_buat_pesanan
I expect it to have a button on the exact location, like when using tkinter.pack() or tkinter.grid(). Do you have any suggestion
... ... ... ... ..
Try this.
You have to pack the frame like this self.pack(fill="both", expand=True). Because the place did not change the parent size, that's why it didn't visible
import tkinter as tk
class KafeDaun(tk.Frame):
def __init__(self, master = None):
super().__init__(master)
self.master.title("Kafe Daun-Daun Pacilkom v2.0 🌿")
self.master.geometry("500x300")
self.master.configure(bg="grey")
self.create_widgets()
self.pack(fill="both", expand=True)
def create_widgets(self):
self.btn_buat_pesanan = tk.Button(self, text = "Buat Pesanan", width = 20)
self.btn_buat_pesanan.place(x = 250, y = 100)
self.btn_meja = tk.Button(self, text = "Selesai Gunakan Meja", width = 20)
app =tk.Tk()
s = KafeDaun(app)
app.mainloop()
Or you can set the width and height of the frame. super().__init__(master, width=<width>, height=<height>)

How can I detect which on which frame was a Button Clicked in Tkinter?

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()

Python - Inheritance from a Tk class

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()

Duplicating values in text file

I am using a text file to store values for a tkinter combobox. If the user enters a value not in the file, I want it added. Everything works fine, but if the user selects an existing value, it also is added again to the list. I believe it is because I am returning stripped values and comparing against values with '\n'. Any help on how to correct this is greatly appreciated.
from tkinter import *
from tkinter import ttk
regionList = open('regions1.txt','r')
root = Tk()
root.configure()
varRegions = StringVar(root, value='')
class MainWindow(Frame):
def __init__(self,master = None):
Frame.__init__(self,master)
self.master = master
self.grid()
self.create_widgets()
def create_widgets(self):
"""Create Window Layout"""
Boxfont = ('Arial', 12, 'bold')
self.blank = Label(self,text='').grid(row=2,column=0)
self.label = Label(self, font=Boxfont, text="Regions").grid(row=3,column=1)
self.regcombo = ttk.Combobox(self, font = Boxfont, width = 16, textvariable = varRegions)
self.regcombo.bind("<Return>", self.regcombo_onEnter)
self.regcombo.bind('<<ComboboxSelected>>',self.regcombo_onEnter)
self.regcombo['values'] = regionList.readlines()
self.regcombo.grid(row=3, column=2,sticky = W)
self.blank = Label(self,text='').grid(row=4,column=0)
def regcombo_onEnter(self,event):
varRegions.set(varRegions.get().lower().strip())
mytext = varRegions.get().strip()
vals = self.regcombo.cget('values')
self.regcombo.select_range(0,END)
print(mytext)
if not vals:
self.regcombo.configure(values = (mytext,))
elif mytext not in vals:
with open('regions1.txt','a') as f:
f.write('\n'+ mytext)
self.regcombo.configure(values = vals + (mytext,))
f.close
return 'break'
app = MainWindow(root)
root.mainloop()

Tkinter does not show one frame

I am trying to make a GUI for my program but I have changed my code a lot and I saw that GUI misses one frame but it was fine before.
Could anyone help me and tell why a frame with a button does not appear on the bottom?
Whole "button_part" object does not appear.
from tkinter import *
import tkinter as tk
import os
import glob
BOUNDS = ["Last week", "Last 2 weeks", "Last 3 weeks"]
class settings_part:
path_to_copy = 0
def __init__(self, master, update_func):
path_to_copy = StringVar()
settings_frame = Frame(master, background="")
settings_frame.pack(side=TOP, fill=X)
date_bound = StringVar()
date_bound.set(BOUNDS[1])
date_option = OptionMenu(settings_frame, date_bound, *BOUNDS, command=update_func)
date_option.config(background="#732c30")
date_option.config(foreground="white")
date_option.config(bd=0)
date_option.pack(side=LEFT, padx=5, pady=5)
path_to_copy.set("~/Python/usun")
box_with_path = Entry(settings_frame, textvariable=path_to_copy)
box_with_path.pack(side=RIGHT, padx=5, pady=5)
# s = path_to_copy.get()
class songs_part:
def __init__(self, master, root):
self.songs_frame = Frame(master)
self.update_songs(root.list_of_songs)
self.songs_frame.pack()
def update_songs(self, l):
for song in l:
c = Checkbutton(self.songs_frame, text=song[0], variable=song[1])
c.pack()
class button_part:
def __init__(self, master, copyFunc):
self.button_frame = Frame(master)
btn_image = PhotoImage(file="copybtn.png")
self.copy_button = Button(self.button_frame, command=copyFunc, text="Copy",
image=btn_image, highlightthickness=0, bd=0, activebackground="#732c30")
self.copy_button.pack()
class App:
def __init__(self):
root = Tk()
root.title("Copying songs")
root.geometry("500x500")
root.option_add("*Font", "Calibra")
back_image = PhotoImage(file="back.png")
self.window = Label(root, image=back_image)
self.window.pack(fill="both", expand="yes")
self.list_of_songs = list()
self.make_list_of_songs()
self.set_part = settings_part(self.window, self.update_list)
self.son_part = songs_part(self.window, self)
self.but_part = button_part(self.window, self.copy_songs)
root.mainloop()
def make_list_of_songs(self):
owd = os.getcwd()
os.chdir("/home/stanek/Music/usun")
for file in glob.glob("*.mp3"):
self.list_of_songs.append([file, tk.IntVar()])
os.chdir(owd)
def copy_songs(self):
for s in self.list_of_songs:
print(s)
def update_list(self, arg):
print("updating list with songs from " + arg)
self.son_part = songs_part(self.window, self)
if __name__ == '__main__':
App()
You never pack the button frame.

Categories