Multiple commands to a button in tkinter - python

I'm a car park admittance thingy for college. Basically what is does when it's run, a window comes up, asks the user to enter make, model, colour, and reg plate. Then it saves this data to a list, array or whatever. The user presses a button to enter their car into the car park, and also to see what cars are currently in the car park. When I press admit vehicle, I need the data to be saved to this list/array/tree, and also for a integer variable to decrease by one. Here's the relevant code. There is more, but this is the relevant bits.
# Admit Button
btn_admit = ttk.Button(bottom_frame)
btn_admit.config(text='Admit Vehicle')
btn_admit.bind('<Button-1>', self.admit) # I need this to reduce the variable as well
...
def admit(self, event):
self.useful_msg.set("Vehicle Admitted") # This is only here to show a message currently it does nothing else
This is the 'spaces available' variable:
self.num_spaces = IntVar(mid_frame)
self.num_spaces.set = 0
lbl_num_spaces = Label(mid_frame)
lbl_num_spaces.config(textvariable=self.num_spaces, bg='yellow')
Finally, this is the code for the window that shows the tree of cars that are in the car park (with some example cars hard-coded for now):
class ShowCarsGui:
def __init__(self, master):
self.master = master
self.master.geometry('1200x600+100+100')
# Frames
top_frame = tk.Frame(self.master)
tree_container = tk.Frame(self.master)
bottom_bar = tk.Frame(self.master)
# Widgets:
# Logo
carpark_icon = tk.PhotoImage(file='car.gif')
lbl_carpark_icon = tk.Label(top_frame)
lbl_carpark_icon.config(image=carpark_icon)
lbl_carpark_icon.image = carpark_icon
# Header
lbl_header = tk.Label(top_frame)
lbl_header.config(text="Vehicles in car park", font='helvetica 32 bold')
# Tree(ttk)
self.tree = ttk.Treeview(tree_container)
self.tree["columns"] = ("Make", "Model", "Colour", "Registration")
self.tree["height"] = 10
self.tree["show"] = 'headings' # Gets rid of default first column
vsb = ttk.Scrollbar(tree_container)
vsb.configure(orient='vertical', command=self.tree.yview)
hsb = ttk.Scrollbar(tree_container)
hsb.configure(orient='horizontal', command=self.tree.xview)
self.tree.configure(yscroll=vsb.set, xscroll=hsb.set)
self.tree_populate()
# Button
quit_button = tk.Button(bottom_bar)
quit_button.config(text='Quit', width=25)
quit_button.bind('<Button-1>', self.close_window)
# Positioning frames
top_frame.grid_rowconfigure(0, minsize=150) # Make row 150 pixels high
top_frame.grid(row=0)
tree_container.grid(row=1)
bottom_bar.grid(row=2)
# Top
lbl_carpark_icon.grid(row=0, column=0, padx=10, sticky='w')
lbl_header.grid(row=0, column=1, padx=20)
# Middle
self.tree.grid(column=0, row=0, sticky='nsew')
vsb.grid(column=1, row=0, sticky='ns')
hsb.grid(column=0, row=1, sticky='ew')
# Bottom
quit_button.grid(row=0, column=0)
def close_window(self, event):
self.master.destroy()
def tree_populate(self):
# Eventually this needs to come from car park object
tree_columns = ("Make", "Model", "Colour", "Registration")
tree_data = [
("Ford", "Ka", "Blue", "FD54 2WE"),
("Vauxhall", "Corsa", "Green", "KJ61 9YH"),
("VW", "Polo", "Silver", "AA54 9TQ"),
("Nissan", "Qashqai", "Red", "YRE 456W"),
("Toyota", "Starlet", "Gold", "J234 WYE"),
]
for col in tree_columns:
self.tree.heading(col, text=col, anchor='w')
for country_data in tree_data:
self.tree.insert("", 0, values=country_data)
Finally here is the code for the entire program:
import tkinter as tk
from tkinter import *
from tkinter import ttk
class CarParkGui:
def __init__(self, master):
self.master = master
self.master.configure(bg='light cyan')
self.master.title("Collyer's Car Park")
self.master.option_add('*Font', 'Georgia 12') # Font for all widgets
self.master.option_add('*Font', 'helvetica 20 bold')
self.master.option_add('*Background', 'light cyan') # background of all widgets
self.master.geometry('1200x500+100+100') # w,h,x,y (top left corner)
self.top() # Build top bar
self.middle() # Define middle frame
self.bottom() # Define Bottom Frame
def top(self):
# Frame for top section
top_frame = Frame(self.master)
# Logo
carpark_icon = PhotoImage(file='car.gif')
lbl_carpark_icon = Label(top_frame) # Instance of tkinter label (parent is frame)
lbl_carpark_icon.config(image=carpark_icon)
lbl_carpark_icon.image = carpark_icon # Have to have this as well as previous one
# Header
lbl_header = Label(top_frame)
lbl_header.config(text='Admit Vehicle', font='helvetica 32 bold')
# Grid positioning for top frame
top_frame.grid_rowconfigure(0, minsize=150) # Make row 150 pixels high
top_frame.grid(row=0)
# Within Frame
lbl_carpark_icon.grid(row=0, column=0, padx=10)
lbl_header.grid(row=0, column=1, padx=20)
def middle(self):
# Frame to contain other widgets
mid_frame = Frame(self.master)
# Label - Car Make
lbl_make = Label(mid_frame)
lbl_make.config(text='Make') # Presentation
# Label - Car Model
lbl_model = Label(mid_frame)
lbl_model.config(text='Model')
# Label - Colour
lbl_colour = Label(mid_frame)
lbl_colour.config(text='Colour')
# Label - Registration
lbl_reg = Label(mid_frame)
lbl_reg.config(text='Registration')
# Label - Spaces
lbl_spc = Label(mid_frame)
lbl_spc.config(text='Spaces')
# Text Entry - Make
self.make = StringVar(mid_frame)
txt_make = Entry(mid_frame)
txt_make.config(textvariable=self.make, width=20)
# Text Entry - Model
self.model = StringVar(mid_frame)
txt_model = Entry(mid_frame)
txt_model.config(textvariable=self.model, width=20)
# Text Entry - Colour
self.colour = StringVar(mid_frame)
txt_colour = Entry(mid_frame)
txt_colour.config(textvariable=self.colour, width=20)
# Text Entry - Registration
self.reg = StringVar(mid_frame)
txt_reg = Entry(mid_frame)
txt_reg.config(textvariable=self.reg, width=20)
# Label for number of space available (WILL BE UPDATED)
self.num_spaces = IntVar(mid_frame)
self.num_spaces.set = 0
lbl_num_spaces = Label(mid_frame)
lbl_num_spaces.config(textvariable=self.num_spaces, bg='yellow')
# Display
mid_frame.grid_columnconfigure(0, minsize=100) # Make row 150 pixels high
mid_frame.grid(row=1, sticky='w')
# Row 0
lbl_make.grid(row=1, column=0)
txt_make.grid(row=1, column=1)
lbl_spc.grid(row=1, column=2)
lbl_num_spaces.grid(row=1, column=3, sticky='w')
# Row 1
lbl_model.grid(row=2, column=0)
txt_model.grid(row=2, column=1, padx='10')
# Row 2
lbl_colour.grid(row=3, column=0)
txt_colour.grid(row=3, column=1, padx='10')
# Row 3
lbl_reg.grid(row=4, column=0)
txt_reg.grid(row=4, column=1, padx='10')
def bottom(self):
# Frame for bottom section
bottom_frame = Frame(self.master)
# Grid reference for bottom frame
bottom_frame.grid(row=2)
# Guidance message (WILL BE UPDATED)
self.useful_msg = StringVar(bottom_frame)
self.useful_msg.set("Enter your vehicle details")
self.lbl_msg = Label(bottom_frame) # Use self so we can change config at
self.lbl_msg.config(textvariable=self.useful_msg, fg='red', width=20)
# Admit Button
btn_admit = ttk.Button(bottom_frame)
btn_admit.config(text='Admit Vehicle')
btn_admit.bind('<Button-1>', self.admit)
# Show Vehicles Button
btn_show = ttk.Button(bottom_frame)
btn_show.config(text='Show Vehicles In Car Park')
btn_show.bind('<Button-1>', self.show)
# Within bottom_frame
# row 0
self.lbl_msg.grid(row=0, column=0)
# row 1
btn_admit.grid(row=1, column=0, sticky='e')
btn_show.grid(row=1, column=1, sticky='e')
def admit(self, event):
self.useful_msg.set("Vehicle Admitted")
def show(self, event):
self.new_window = Toplevel(self.master)
self.app = ShowCarsGui(self.new_window)
___ This is where ShowCarsGui() is ____
def main():
root = Tk()
CarParkGui(root)
root.mainloop()
main()

To do "two things with one button", the correct solution is to create a function that does these "two things", and then associate that function with the button.
btn_admit = ttk.Button(bottom_frame)
btn.configure(command=self.admit)
def admit(self):
self.num_spaces.set(self.num_spaces.get()-1)
self.useful_msg.set("Vehicle Admitted")
Note: the above example uses the command attribute rather than a binding. Using the command attribute is preferable because it has built-in support for keyboard traversal. And, of course, you can do as much or as little as you want in admit -- you aren't limited to one or two things.

Related

How can I "reset" the size of a Window on Tkinter when using Notebook?

I know this has been asked before but none of the solutions that I've seen so far seem to work.
So here's the exact case: I'm building an app that has 3 different tabs (using ttk.Notebook).
The initial contents of the 3 tabs is different: the second is the smallest and the third is he biggest.
Now here comes the issue (I'm using grid, btw): when I change from the first to the second, there is an extra empty space (because the content of the first Tab is a little bigger than the one of the second, and the same happens when I go from the third to the second/first, so after using the third tab and changing to another one, the size stays as if I still was in the third.
I add some of the code that I'm using, but since I'm not sure what is going wrong, I'll let you ask for whatever extra code you might need to help me find the solution.
# Tk modules
import tkinter as tk
from tkinter import ttk
# # define main()
def main():
app = App()
MainWindow(app)
app.mainloop()
# Frame for data input
class RegisterChooseType(ttk.Frame):
def __init__(self, container):
# Inheritance
super().__init__(container)
self.container = container
# Var for selection
self.selected_value = tk.IntVar()
# Options
self.options = {"padx": 10, "pady": 10}
# Doc types
self.doc_types = ("Incoming Bill", "Outgoing Bill", "Contract", "Other")
# Labels
self.barcode_label = ttk.Label(self, text="Barcode:").grid(
row=0, column=0, sticky="EW", **self.options
)
self.doc_type_label = ttk.Label(self, text="Document type:").grid(
row=0, column=2, sticky=tk.W, **self.options
)
# Entries
self.barcode_entry = ttk.Entry(self)
self.barcode_entry.grid(row=0, column=1, sticky="EW", **self.options)
self.grid()
def submit(self):
self.current_dict["func"](self, self.current_frame)
class DeleteTab(ttk.Frame):
def __init__(self, container):
# Inheritance
super().__init__(container)
# self.columnconfigure(0, weight=1)
# self.columnconfigure(1, weight=1)
self.options = {"padx": 10, "pady": 10}
## Type Barcode
# Label
self.barcode_label = ttk.Label(self, text="Barcode:").grid(
row=0, column=0, sticky="EW", **self.options
)
# Entries
self.barcode_entry = ttk.Entry(self)
self.barcode_entry.grid(row=0, column=1, sticky="EW", **self.options)
# self.pack(fill="x")
self.grid(sticky="W")
class ViewTab(ttk.Frame):
def __init__(self, container):
# Inheritance
super().__init__(container)
self.container = container
self.options = {"padx": 10, "pady": 10}
# Doc types
self.doc_types = ("Incoming Bill", "Outgoing Bill", "Contract", "Other")
## Type Barcode
# Labels
# Barcode
self.barcode_label = ttk.Label(self, text="Barcode:")
self.barcode_label.grid(row=0, column=0, sticky="EW", **self.options)
# Document type
self.doc_type_label = ttk.Label(self, text="Document Type:")
self.doc_type_label.grid(row=0, column=2, sticky="EW", **self.options)
# Entries
# Barcode
self.barcode_entry = ttk.Entry(self)
self.barcode_entry.grid(row=0, column=1, sticky="EW", **self.options)
# Document type
self.doc_type_comb = ttk.Combobox(self)
self.doc_type_comb["state"] = "readonly" # Doesn't allow new entries
self.doc_type_comb["values"] = self.doc_types
self.doc_type_comb.grid(
row=0, column=3, columnspan=3, sticky=tk.EW, **self.options
)
## View Button
self.viewSubmitButton = ttk.Button(
self, text="View", command=lambda: print("View")
)
self.viewSubmitButton.grid(
column=4,
row=self.grid_size()[0],
sticky="EW",
**self.options,
)
# New LabelFrame
self.deliver_view_LabelFrame = ttk.LabelFrame(self)
self.deliver_view_LabelFrame["text"] = "View Document"
self.deliver_view_LabelFrame.grid(
row=1,
columnspan=self.grid_size()[0],
column=0,
sticky="ew",
padx=10,
pady=10,
)
# Inside LabelFrame
##TreeView
self.dataDisplay = ttk.Treeview(self.deliver_view_LabelFrame, show="")
self.dataDisplay.pack(fill="x", **self.options)
self.grid(sticky="ews")
# Create window
class MainWindow:
def __init__(self, container):
self.container = container
## Create Parent
self.tab_parent = ttk.Notebook()
self.tab_parent.enable_traversal()
# Create tab frames
self.tab_register = ttk.Frame(self.tab_parent)
self.tab_view = ttk.Frame(self.tab_parent)
self.tab_delete = ttk.Frame(self.tab_parent)
# Adding the tabs to the main object (self.tab_parent)
self.tab_parent.add(self.tab_register, text="Register Documents")
self.tab_parent.add(self.tab_delete, text="Delete Documents")
self.tab_parent.add(self.tab_view, text="View Documents")
# Create empt variables
self.current_tab = None
self.last_tab = None
# Focus on barcode
# self.register.barcode_entry.focus()
self.tab_parent.bind("<<NotebookTabChanged>>", self.on_tab_change)
# Pack notebook
# self.tab_parent.pack(expand=True, fill="x", side="left")
self.tab_parent.grid(sticky="e")
## Triggers when changing tabs
def on_tab_change(self, event):
if self.current_tab != None:
self.current_tab.destroy()
# Get the current tab name
selected = event.widget.tab("current")["text"]
# Create frame depending on Tab chosen
if selected == "Register Documents":
self.current_tab = RegisterChooseType(self.tab_register)
self.clean_tabs()
self.last_tab = self.current_tab
elif selected == "Delete Documents":
self.current_tab = DeleteTab(self.tab_delete)
self.clean_tabs()
self.last_tab = self.current_tab
elif selected == "View Documents":
self.current_tab = ViewTab(self.tab_view)
self.clean_tabs()
self.last_tab = self.current_tab
self.current_tab.barcode_entry.focus()
def clean_tabs(self):
if self.last_tab != None:
# for widget in self.last_tab.winfo_children():
# # for widget in self.last_tab.grid_slaves():
# widget.destroy()
self.last_tab.destroy()
# ## INTERESTING
# self.last_tab.blank = ttk.Label(self.last_tab, text="1")
# self.last_tab.blank.grid()
# print(self.last_tab.grid_slaves()[0].cget("text"))
# self.container.geometry("1x1")
self.tab_parent.update()
# self.container.update()
# self.container.geometry("")
# self.container.update()
# Creatig App
class App(tk.Tk):
def __init__(self):
super().__init__()
self.geometry("")
self.title("iMPETU Document Handling v.0.1.0a")
self.resizable(0, 0)
if __name__ == "__main__":
main()
I tried deleting one by one the widgets of the current tab before changing to another one, also doing the same AFTER changing to the new tab (that's why I have 2 variables for current and last tab), I also tried leaving an empty tag (supposedly 0 pixels) but that would push all the contents down.
I tried withdraw, deiconify just out of curiosity, I also tried using self.container.update() to update the main window, also tried changing the geometry to "1x1" in the clean_tabs function and then changing again to "" at the end of the on_tab_change and see if that would maybe force it to resize but none of that worked.
You can resize all the frames (parents of instances of RegisterChooseType, DeleteTab and ViewTab) to size 1x1 at the beginning of clean_tabs():
def clean_tabs(self):
for tab in self.tab_parent.tabs():
# tab is the name of the frame
# so get the widget using .nametowidget()
# then call .config(width=1, height=1) to resize the frame to size 1x1
self.tab_parent.nametowidget(tab).config(width=1, height=1)
...

Tkinter issue when removing text fields

i am working on a GUI in Tkinter, and i have encountered a wierd issue that i have been struggling to solve.
The goal is to remove and add users from the interface. When a user is added, it is displayed, and when deleted the user should disappear from the GUI.
This is where my issue begins. When only adding and removing one user, everything works fine.
However when two or more users are added, the removal process fails. The removal works as expected on the first try, but when trying to remove any more, the interface does not update. The users get removed from the list as should, but the GUI never updates. Here is my code
#anden slet klik virker ikke
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.entries = -1
self.people = []
self.names = []
self.id = []
self.tlf = []
self.frames = []
self.master = master
self.pack()
self.create_widgets()
#Create the first two rows of the application
def create_widgets(self):
# Row 0: Input boxes
self.inputName = tk.Entry(self, bd=4)
self.inputName.grid(row=0, column=0)
self.inputID = tk.Entry(self, bd=4)
self.inputID.grid(row=0, column=1)
self.inputTLF = tk.Entry(self, bd=4)
self.inputTLF.grid(row=0, column=2)
# Row 0: "Add" button
self.addButton = tk.Button(self, text="Add", command=self.AddMember)
self.addButton.grid(row=0, column=3)
# Row 1: Labels
tk.Label(self, text = "Navn", borderwidth = 4).grid(row=1, column=0)
tk.Label(self, text="ID", borderwidth=4).grid(row=1, column=1)
tk.Label(self, text="Tlf", borderwidth=4).grid(row=1, column=2, ipadx=30)
tk.Label(self, text=" ", borderwidth=4).grid(row=1, column=3)
# What the "add" button does
def AddMember(self):
self.people.append([self.inputName.get(), self.inputID.get(), self.inputTLF.get()]) #Add textbox-text to list
self.entries += 1
self.updateMembers()
def updateMembers(self): # Display new member
# This is declared to make sure that self.entries is assigned by value, and not by index
entry = self.entries
# Add the new name from 'people' to the list of name entries, and display
self.names.append(tk.Label(self, text=self.people[entry][0], borderwidth=4))
self.names[entry].grid(row=entry + 2, column=0)
# -//- but with ids
self.id.append(tk.Label(self, text=self.people[entry][1], borderwidth=4))
self.id[entry].grid(row=entry + 2, column=1)
# -//- but with phone numbers
self.tlf.append(tk.Label(self, text=self.people[entry][2], borderwidth=4))
self.tlf[entry].grid(row=entry + 2, column=2)
# Create a frame to but multiple buttons in one grid-cell
self.frames.append(tk.Frame(self))
self.frames[entry].grid(row=entry + 2, column=3)
#Create such buttons
removeButton = tk.Button(self.frames[entry], text="X", command=lambda: self.remove(entry))
msgButton = tk.Button(self.frames[entry], text="SMS", command=lambda: self.sendSMS(entry))
callButton = tk.Button(self.frames[entry], text="Ring", command=lambda: self.makeCall(entry))
#Display such buttons
removeButton.pack(side='top')
callButton.pack(side = 'right')
msgButton.pack(side='left')
def sendSMS(self, sender_id):
print("SMSMSMSM")
def makeCall(self, sender_id):
print("RINGRINGRING")
def remove(self, sender_id):
print("")
print(self.entries)
self.people.pop(sender_id) # Remove from the "People" list
if self.entries >= 0:
# Un-display the lowest entry
self.tlf[self.entries].destroy()
self.frames[self.entries].destroy()
self.id[self.entries].destroy()
self.names[self.entries].destroy()
for i in range(self.entries): # RE-display all current entries (deleted one excluded)
tk.Label(self, text=self.people[i][0], borderwidth=4).grid(row=i + 2, column=0)
tk.Label(self, text=self.people[i][1], borderwidth=4).grid(row=i + 2, column=1)
tk.Label(self, text=self.people[i][2], borderwidth=4).grid(row=i + 2, column=2)
# Remove deleted user's info in the display lists.
self.names.pop(sender_id)
self.id.pop(sender_id)
self.tlf.pop(sender_id)
self.frames.pop(sender_id)
self.entries -= 1 # Decrement size of people
print(self.entries)
#Actually start the program
root = tk.Tk()
app = Application(master=root)
app.mainloop()
I have been troubleshooting this for hours on end, and have not managed to solve this, so any help is appreciated :D

Newbie problem with using tkinter checkbutton in a class

Running python 3.8 in PyCharm
I'm trying to create a class to allow creation of a tkinter checkbutton (and eventually other widgets) that will hold all the formatting and definition for the widget. I would like to be able to test the state of the checkbutton and act on it in a callback. But like many others, my checkbutton variable seems to always be 0. I'm fairly sure its a garbage collection issue, but I can't figure a way around it. Note the second set of parameters in the class definition specify the location of the label to display the checkbutton variable state. At the moment, the callback is just to display the variable state in a label.
Acknowledgement:
I modified code from Burhard Meier's book "Python GUI Programming Cookbook" for this. The code related to the class is mine, the rest is from Burkhard Meier.
'''
This is a modification of code by Burhard A. Meier
in "Python GUI Programming Cookbook"
Created on Apr 30, 2019
#author: Burkhard A. Meier
'''
#======================
# imports
#======================
import tkinter as tk
from tkinter import ttk
# Create instance
win = tk.Tk()
# Add a title
win.title("GUI Test Box")
# Modify adding a Label
a_label = ttk.Label(win, text="Testing TK Widgets")
a_label.grid(column=0, row=0)
# Modified Button Click Function
def click_me():
action.configure(text='Hello ' + name.get() + ' ' +
number_chosen.get())
#Define the Checkbutton Class
class ChkBut(): #lable, xloc, yloc, xlab, ylab
def __init__(self, lable, xloc, yloc, xlab, ylab): # , xloc, yloc, text="default", variable = v, onvalue='Set', offvalue='NotSet'):
v = tk.IntVar()
self.v = v
self.lable = lable
self.xloc = xloc
self.yloc = yloc
self.xlab = xlab
self.ylab = ylab
c = tk.Checkbutton(
win,
text= self.lable,
variable=self.v,
command=self.cb(self.v, xlab,ylab))
c.grid(column=xloc, row=yloc, sticky = tk.W)
c.deselect()
def cb (self, c, xlab, ylab):
if c.get()==1:
c_label = ttk.Label(win, text="Set")
c_label.grid(column=xlab, row=ylab)
elif c.get()==0:
c_label = ttk.Label(win, text="NotSet")
c_label.grid(column=xlab, row=ylab)
else:
c_label = ttk.Label(win, text=c.v.get())
c_label.grid(column=xlab, row=ylab)
# Changing the Label
ttk.Label(win, text="Enter a name:").grid(column=0, row=0)
# Adding a Textbox Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(win, width=12, textvariable=name)
name_entered.grid(column=0, row=1)
# Adding a Button
action = ttk.Button(win, text="Click Me!", command=click_me)
action.grid(column=2, row=1)
# Creating three checkbuttons
ttk.Label(win, text="Choose a number:").grid(column=1, row=0)
number = tk.StringVar()
number_chosen = ttk.Combobox(win, width=12, textvariable=number, state='readonly')
number_chosen['values'] = (1, 2, 4, 42, 100)
number_chosen.grid(column=1, row=1)
number_chosen.current(0)
check1 = ChkBut("Button 1", 0, 4, 0, 5)
chVarUn = tk.IntVar()
check2 = tk.Checkbutton(win, text="UnChecked", variable=chVarUn)
check2.deselect()
check2.chVarUn = 0
check2.grid(column=1, row=4, sticky=tk.W)
chVarEn = tk.IntVar()
check3 = tk.Checkbutton(win, text="Enabled", variable=chVarEn)
check3.select()
check3.chVarEn = 0
check3.grid(column=2, row=4, sticky=tk.W)
name_entered.focus() # Place cursor into name Entry
#======================
# Start GUI
#======================
win.mainloop()

Python tkinter - scrollbar of canvas cuts off frame content

I am currently writing a simple logbook application for my sailing holidays. Therefore I wanted to create a small gui for entering data in lines for the logbook.
I am using grid layout with frames and canvas for the main frame, to show a scroll bar, when there are to many lines.
Everything is looking fine, until the command
self.canvasCenter.configure(scrollregion=self.canvasCenter.bbox("all"))
is called. If I comment this line out, the canvas is using the full frame. If this line is active - the canvas is using only 50% of the available screen and date is cut off.
I tried to strip down the code to the necessary things (not using any additional files, configs, classes, etc.). So that it is executable stand alone:
#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
import sys
if sys.version_info.major == 2:
# We are using Python 2.x
import Tkinter as tk
elif sys.version_info.major == 3:
# We are using Python 3.x
import tkinter as tk
#from lib import logBookData
#from config import *
#Titel of the application shown in title bar
appTitle = "My APP"
#Layout geometry (size of the window)
lWidth = 768
lHeight = 900
layoutGeometry = '900x768'
#Colours for foreground and background for labels and entry fields
#headerBG = "Light Blue"
headerBG = "white"
labelBG = "white"
labelFG = "black"
#Number of columns (keep in Sync with headers and width list below!)
cNumber = 14
#Column width for number of columns defined above
cWidth = [5,7,5,5,5,5,5,5,5,5,5,5,5,10]
cHeaders = ["C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "C11", "C12", "C13", "C14" ]
class logBookGUI(tk.Tk):
def __init__(self,parent):
tk.Tk.__init__(self,parent)
self.parent = parent
self.lineCount = 0
self.initialize()
def initialize(self):
#create a masterframe
self.masterFrame = tk.Frame(self, bg=headerBG, bd=4, relief="groove") #, width = lWidth, height = lHeight)
self.masterFrame.grid(sticky=tk.NSEW)
self.masterFrame.columnconfigure(cNumber, weight=1)
#create Headerframe for Standard Info
self.headerFrame = tk.Frame(self.masterFrame, bg=headerBG, bd=2, relief="groove")
self.headerFrame.grid(row=0, column=0, sticky=tk.NSEW)
self.headerFrame.columnconfigure(cNumber, weight=1)
#Label Bootsname
boatNameLabel = tk.Label(self.headerFrame, text="Bootsname", anchor="w", fg=labelFG,bg=labelBG)
boatNameLabel.grid(column=0, row=0, sticky=tk.NSEW)
#Field Bootsname
self.boatName = tk.StringVar()
self.boatNameEntry = tk.Entry(self.headerFrame,textvariable=self.boatName, width = cWidth[0])
self.boatNameEntry.grid(column=1,row=0, sticky=tk.NSEW)
self.boatName.set(u"Solva")
for i in xrange(cNumber-2):
button = tk.Button(self.headerFrame,text=u"T %s" %i, command=self.OnButtonClick)
button.grid(column=i,row=0, sticky=tk.NSEW)
button = tk.Button(self.headerFrame,text=u"TEST", command=self.OnButtonClick)
button.grid(column=cNumber-2,row=0, sticky=tk.NSEW)
button = tk.Button(self.headerFrame,text=u"Neue Zeile", command=self.newLineClick)
button.grid(column=cNumber-1,row=1, sticky=tk.NSEW)
#create center frame
self.centerFrame = tk.Frame(self.masterFrame, bg=headerBG, bd=2, relief="groove")
self.centerFrame.grid(row=1, column=0, sticky=tk.NSEW)
self.centerFrame.columnconfigure(cNumber, weight=1)
#create a canvas for center frame
self.canvasCenter = tk.Canvas(self.centerFrame)
self.canvasCenter.grid(row=0, column=0, sticky=tk.NSEW)
self.canvasCenter.columnconfigure(cNumber, weight=1)
# Create a vertical scrollbar linked to the canvas.
vsbar = tk.Scrollbar(self.centerFrame, orient=tk.VERTICAL, command=self.canvasCenter.yview)
vsbar.grid(row=0, column=cNumber, sticky=tk.NSEW)
self.canvasCenter.configure(yscrollcommand=vsbar.set)
# Create a frame on the canvas to contain the content.
self.contentFrame = tk.Frame(self.canvasCenter, bg="Red", bd=2, relief="groove")
self.contentFrame.grid(row=0, column=0, sticky=tk.NSEW)
self.contentFrame.columnconfigure(cNumber, weight=1)
column = 0
for header in cHeaders:
label = tk.Label(self.contentFrame, text=header, anchor="w", fg=labelFG,bg=labelBG,borderwidth=2,relief="groove", width = cWidth[column])
label.grid(column = column, row=1, sticky="EW")
column += 1
self.addLine()
# Create canvas window to hold the centerframe.
self.canvasCenter.create_window((0,0), window=self.contentFrame, anchor=tk.NW)
# Update buttons frames idle tasks to let tkinter calculate buttons sizes
self.contentFrame.update_idletasks()
self.canvasCenter.configure(scrollregion=self.canvasCenter.bbox("all"))
self.grid_columnconfigure(cNumber,weight=1)
self.resizable(True,False)
self.update()
self.geometry("%sx%s" % (lHeight, lWidth))
def newLineClick(self):
self.addLine()
def OnButtonClick(self):
pass
def OnPressEnter(self,event):
pass
def addLine(self):
tkLine = []
try:
for i in xrange(cNumber):
self.entryVar = tk.StringVar()
self.entry = tk.Entry(self.contentFrame,textvariable=self.entryVar,width=cWidth[i])
self.entry.grid(column=i, row = self.lineCount + 3, sticky='EW')
tkLine.append(self.entryVar)
self.canvasCenter.configure(scrollregion=self.canvasCenter.bbox("all"))
except IndexError:
print ("Error in config file. Number of columns and given columns do not match - check file config.py")
sys.exit()
self.update()
self.lineCount += 1
if __name__ == "__main__":
app = logBookGUI(None)
app.title(appTitle)
app.mainloop()
Could someone give me an advice how to use scrollregion, so that the whole size of the frame is used?
Many thanks,
Gernot

Tkinter blank window

I found this introductory tutorial online, but when I run it, I get just a blank window. Any idea what's going wrong?
# A more complex example showing the use of classes in GUI programming
from tkinter import *
class GUIExample:
def __init__(self, master):
self.master = master # for showInfo()
# Create frame to hold widgets
frame = Frame(master)
# Create label for header
self.headLbl = Label(frame, text="Widget Demo Program", relief=RIDGE)
self.headLbl.pack(side=TOP, fill=X)
# Dummy frame for border
spacerFrame = Frame(frame, borderwidth=10)
# Create frame to hold center part of the form
centerFrame = Frame(spacerFrame)
leftColumn = Frame(centerFrame, relief=GROOVE, borderwidth=10)
rightColumn = Frame(centerFrame, relief=GROOVE, borderwidth=10)
# Some colorful widgets
self.colorLabel = Label(rightColumn, text="Select a color")
self.colorLabel.pack(expand=YES, fill=X)
entryText = StringVar(master)
entryText.set("Select a color")
self.colorEntry = Entry(rightColumn, textvariable=entryText)
self.colorEntry.pack(expand=YES, fill=X)
# Create some radio buttons
self.radioBtns = []
self.radioVal = StringVar(master)
btnList = ("black", "red", "green", "blue", "white", "yellow")
for color in btnList:
self.radioBtns.append(Radiobutton(leftColumn, text=color, value=color, \
indicatoron=TRUE, variable=self.radioVal, command=self.updateColor))
else:
if (len(btnList) > 0):
self.radioVal.set(btnList[0])
self.updateColor()
for btn in self.radioBtns:
btn.pack(anchor=W)
# Make the frames visible
leftColumn.pack(side=LEFT, expand=YES, fill=Y)
rightColumn.pack(side=LEFT, expand=YES, fill=BOTH)
centerFrame.pack(side=TOP, expand=YES, fill=BOTH)
# Create an indicator checkbutton
self.indicVal = BooleanVar(master)
self.indicVal.set(TRUE)
self.updateIndic()
Checkbutton(spacerFrame, text="Show indicator", command=self.updateIndic, \
variable=self.indicVal).pack(side=TOP, fill=X)
# Create the Info button
Button(spacerFrame, text="Info", command=self.showInfo).pack(side=TOP, fill=X)
# Create the Quit button
Button(spacerFrame, text="Quit", command=self.quit).pack(side=TOP, fill=X)
def quit(self):
import sys
sys.exit()
def updateColor(self):
self.colorLabel.configure(fg=self.radioVal.get())
self.colorEntry.configure(fg=self.radioVal.get())
def updateIndic(self):
for btn in self.radioBtns:
btn.configure(indicatoron=self.indicVal.get())
def updateColorPrev(self):
if (self.colorprevVal.get()):
for btn in self.radioBtns:
color = btn.cget("text")
btn.configure(fg=color)
else:
for btn in self.radioBtns:
btn.configure(fg="black")
def showInfo(self):
toplevel = Toplevel(self.master, bg="white")
toplevel.transient = self.master
toplevel.title("Program info")
Label(toplevel, text="A simple Tkinter demo", fg="navy", bg="white").pack(pady=20)
Label(toplevel, text="Written by Bruno Dufour", bg = "white").pack()
Label(toplevel, text="http://www.cs.mcgill.ca/ Ėƒbdufou1/", bg="white").pack()
Button(toplevel, text="Close", command=toplevel.withdraw).pack(pady=30)
root = Tk()
ex = GUIExample(root)
root.title("A simple widget demo")
root.mainloop()
They forgot
frame.pack()
and
spacerFrame.pack()
I didn't test rest of code.
EDIT: BTW: In place of
def quit(self):
import sys
sys.exit()
I would use something more natural - and less drastic
def quit(self):
self.master.destroy()

Categories