Python tkinter downsizing widgets - python

I've looked at all the other questions and answers and couldn't find one that fit what I'm trying to do.
Code:
class GameWin:
def __init__(self, master):
self.master = master
self.master.title("Title")
self.main_frame = Frame(self.master, bd = 10, bg = uni_bg)
self.main_frame.grid()
self.left_frame = Frame(self.main_frame, bd = 10, bg = uni_bg)
self.left_frame.grid(column = 0, row = 0)
self.right_frame = Frame(self.main_frame, bd = 10, bg = uni_bg)
self.right_frame.grid(column = 1, row = 0)
self.right_frame.columnconfigure(0, weight = 1)
self.right_frame.rowconfigure(0, weight = 1)
self.right_frame.columnconfigure(1, weight = 1)
self.right_frame.rowconfigure(1, weight = 1)
self.web = Text(self.left_frame, font = (uni_font, 12), wrap = WORD, bg = uni_bt_bg, fg = uni_fg)
self.web.grid(column = 0, row = 0, padx = 5, pady = 5)
self.output = Text(self.left_frame, font = (uni_font, 12), wrap = WORD, bg = "black", fg = uni_fg)
self.output.grid(column = 0, row = 1, padx = 5, pady = 5, sticky = "ew")
self.output.configure(state = "disabled")
self.input = Entry(self.left_frame, font = (uni_font, 12))
self.input.grid(column = 0, row = 2, sticky = "ew")
self.input.bind('<Return>', self.submit)
self.notepad = Text(self.right_frame, font = (uni_font, 12), wrap = WORD, bg = uni_fg, fg = "black", width = 42)
self.notepad.grid(column = 0, row = 0, pady = 5, rowspan = 2)
self.sys_info = Text(self.right_frame, font = (uni_font, 12), wrap = WORD, bg = uni_bg, fg = uni_fg, width = 35, height = 11, bd = 0)
self.sys_info.tag_configure('center', justify='center')
self.sys_info.grid(column = 1, row = 0, pady = 5)
self.sys_info.insert(END, "NAME", "center")
self.sys_info.configure(state = "disabled")
self.trace = Text(self.right_frame, font = (uni_font, 12), wrap = WORD, bg = uni_bg, fg = uni_fg, width = 35, height = 11)
self.trace.grid(column = 1, row = 1, pady = 5)
self.email = Text(self.right_frame, font = (uni_font, 12), wrap = WORD, bg = uni_bt_bg, fg = uni_fg)
self.email.grid(column = 0, row = 2, pady = 5, columnspan = 2)
self.email.configure(state = "disabled")
self.respond = Entry(self.right_frame, font = (uni_font, 12))
self.respond.grid(column = 0, row = 3, columnspan = 2, sticky = "ew")
self.respond.bind('<Return>', self.do_respond)
def submit(self, event):
self.output.configure(state = "normal")
self.output.configure(state = "disabled")
pass
def do_respond(self, event):
pass
Image of current screen: https://i.imgur.com/P2B6E5y.png
First thing I'm trying to figure out is how to not explicitly state the size of the 3 text widgets in the top right. Because everyone's screen is differently sized. If I don't explicitly state the size, they expand and everything goes wacko (since the default text widget is big). I want the widgets to automatically downscale to fit within the column (the same width as the big grey bottom right text widget). Is this even possible?
Second is for the frames and widgets to fill up all the space in the window. Whether it's fullscreen (like in the pic) or a smaller window (and hopefully keep their size relative to each other). There's a lot of empty space at the edges of the window and I want to get rid of that. I've tried everything I can think of but I can't get them to fill that space.
I tried putting the top 3 widgets each in their own frame, limiting the size of the frames relative to the window size, and setting the widgets to fill that frame but it doesn't work. Code I used to try this: https://pastebin.com/3YWK9Xg2
class GameWin:
def __init__(self, master):
self.master = master
self.master.title("Hacker")
win_width = self.master.winfo_width()
win_height = self.master.winfo_height()
self.main_frame = Frame(self.master, bd = 10, bg = uni_bg)
self.main_frame.grid(sticky = "nsew")
self.left_frame = Frame(self.main_frame, bd = 10, bg = uni_bg, height = int(win_height), width = int(win_width/2))
self.left_frame.grid(column = 0, row = 0, rowspan = 3)
self.left_frame.grid_propagate(False)
self.note_frame = Frame(self.main_frame, bd = 10, bg = uni_bg, height = int(win_height/2), width = int(win_width/4))
self.note_frame.grid(column = 1, row = 0, rowspan = 2, sticky = "n")
self.note_frame.grid_propagate(False)
self.sys_frame = Frame(self.main_frame, bd = 10, bg = uni_bg, height = int(win_height/4), width = int(win_width/4))
self.sys_frame.grid(column = 2, row = 0, sticky = "n")
self.sys_frame.grid_propagate(False)
self.trace_frame = Frame(self.main_frame, bd = 10, bg = uni_bg, height = int(win_height/4), width = int(win_width/4))
self.trace_frame.grid(column = 2, row = 1, sticky = "n")
self.trace_frame.grid_propagate(False)
self.bottom_right_frame = Frame(self.main_frame, bd = 10, bg = uni_bg, height = int(win_height/2), width = int(win_width/2))
self.bottom_right_frame.grid(column = 1, row = 2, columnspan = 2)
self.bottom_right_frame.grid_propagate(False)
self.web = Text(self.left_frame, font = (uni_font, 12), wrap = WORD, bg = uni_bt_bg, fg = uni_fg)
self.web.grid(column = 0, row = 0, padx = 5, pady = 5)
self.output = Text(self.left_frame, font = (uni_font, 12), wrap = WORD, bg = "black", fg = uni_fg)
self.output.grid(column = 0, row = 1, padx = 5, pady = 5, sticky = "ew")
self.input = Entry(self.left_frame, font = (uni_font, 12))
self.input.grid(column = 0, row = 2, sticky = "ew")
self.input.bind('<Return>', self.submit)
self.notepad = Text(self.note_frame, font = (uni_font, 12), wrap = WORD, bg = uni_fg, fg = "black")
self.notepad.pack(fill = BOTH, expand = YES)
self.sys_info = Text(self.sys_frame, font = (uni_font, 12), wrap = WORD, bg = uni_bg, fg = uni_fg)
self.sys_info.tag_configure('center', justify='center')
self.sys_info.grid(sticky = "nsew")
self.sys_info.insert(END, "NAME", "center")
self.sys_info.configure(state = "disabled")
self.trace = Text(self.trace_frame, font = (uni_font, 12), wrap = WORD, bg = uni_bg, fg = uni_fg)
self.trace.grid(sticky = "nsew")
self.email = Text(self.bottom_right_frame, font = (uni_font, 12), wrap = WORD, bg = uni_bt_bg, fg = uni_fg)
self.email.grid(row = 0, pady = 5, columnspan = 2, sticky = "nsew")
self.email.configure(state = "disabled")
self.respond = Entry(self.bottom_right_frame, font = (uni_font, 12))
self.respond.grid(row = 1, columnspan = 2, sticky = "ew")
self.respond.bind('<Return>', self.do_respond)
def submit(self, event):
self.output.configure(state = "normal")
self.output.configure(state = "disabled")
def do_respond(self, event):
pass
and picture of the result: https://i.imgur.com/IVnw65x.png
Here is the full code: https://pastebin.com/Gm2ePqFH. I want it to look like it is in the first picture, without having to explicitly state the size of each text widget. And I want to get it to all stay the same size relative to the window.

If you want widgets to shrink down to the size of the column, the strategy that has worked best for me is to make the widget very small and then use the layout manager (pack, place, or grid) make them bigger to fit. You can either make the widget 1x1 if that's truly a minimum size you will accept, or you can set it to what you think the absolute minimum should be (for example, 4 lines of 20 characters, 20 lines of 10 characters, etc).
So, start by making those widgets as small as possible.
Next, make sure you use the sticky attribute so that the widgets grow to fill their allotted space. You also need to make sure you use the sticky attribute for self.right_frame so that it fills its space too.
Finally, make sure that you call rowconfigure and columnconfigure to set a positive weight on any widget that has children managed by grid. You aren't doing that for self.master, nor are you doing it for self.left_frame and self.right_frame
As a rule of thumb, if you're only putting one or two widgets in a frame and you want those widgets to fill the frame, it's much better to use pack than grid, simply because you don't have to remember to give the rows and columns weights.
For example, you can use pack to manage the left and right frames. You can probably use pack to put GameWin inside of its master, too.
Also, don't try to solve all of your layout problems at once. In your case, I would tackle the problem like this:
Start with just your mainframe and get it so that it fills the containing window. Make sure you manually resize the window to watch it grow and shrink.
Next, add your left and right frames. Make sure they grow and shrink to fit mainframe.
Next, focus on just the widgets in the left frame. Add them, and make sure they shrink and fit.
Then, focus on the right frame. Add them, and make sure they shrink and fit.
Finally, a word of advice. Group your calls to grid together. As your code is written now, you need to fix a whole bunch of lines scattered over the entire file. With some reorganization, almost all of the lines of code you need to change will be in one block of code.
For example, instead of this:
self.web = Text(...)
self.web.grid(...)
self.output = Text(...)
self.output.grid(...)
self.input = Text(...)
self.input.grid(...)
self.notepad = Text(...)
self.notepad.grid(...)
Do this:
self.web = Text(...)
self.output = Text(...)
self.input = Text(...)
self.notepad = Text(...)
self.web.grid(...)
self.output.grid(...)
self.input.grid(...)
self.notepad.grid(...)
With that, at a glance you can answer the question "how are my widgets defined?", and "how are my widgets laid out". With the way you have it now, those questions are very difficult to answer.

Related

How to scrolldown a textbox using scrollbar widget tkinter

Application: Building a notes application (as an intro to GUI development in Python) which includes feature of a scrollbar to scroll through a textbox
Problem: I can't actually seem to scroll down through the textbox. I don't seem to get the grayed rectangle which lets me control the scrollbar and scroll up/down through the textbox
#importing necessary packages
from tkinter import *
from tkinter import font
from tkinter import ttk
#set up main window
root = Tk()
root.title("Notes")
root.geometry("400x650")
#functions
#functions to change all widget button's backgrounds when user hovers over it and leaves it
def enter_button(e):
e.widget.config(background = "#D4D4D4")
#SystemButtonFace is default colour
def leave_button(e):
e.widget.config(background = "SystemButtonFace")
#clear text in text-box
def clear():
#delete all text from text_box
text_box.delete(1.0,END)
def bold_it():
#create font
try:
bold_font = font.Font(text_box, text_box.cget("font"))
bold_font.configure(weight = "bold")
#creating tag called "bold" which bolds textll upon condition
text_box.tag_configure("bold", font = bold_font)
#creating a bold tag which highlights first character
bold_tag = text_box.tag_names("sel.first")
#condition for checking to see if tag is applied or not
#in the first highlighted character
#if tag is applied, remove the bold from first-highlighted text
#- last highlighted text
#"bold" needs to be matched in the tag
if "bold" in bold_tag:
text_box.tag_remove("bold","sel.first","sel.last")
else:
text_box.tag_add("bold","sel.first", "sel.last")
except TclError:
pass
def italics_it():
try:
#create a font
italics_font = font.Font(text_box, text_box.cget("font"))
italics_font.configure(slant = "italic")
#create a tag called "italic"
text_box.tag_configure("italics", font = italics_font)
italics_tag = text_box.tag_names("sel.first")
#condition to see whether tag has been applies or not
if "italics" in italics_tag:
text_box.tag_remove("italics", "sel.first","sel.last")
else:
text_box.tag_add("italics", "sel.first", "sel.last")
except TclError:
pass
#frames
top_frame = LabelFrame(root, padx = 30, pady = 10)
button_frame = LabelFrame(root, padx = 30, pady = 10)
text_frame = LabelFrame(root, padx = 10, pady = 10)
bottom_frame = LabelFrame(root, borderwidth = 0, highlightthickness = 5)
top_frame.grid(row = 0 , column = 0)
button_frame.grid(row = 1, column = 0, pady = 10)
text_frame.grid(row = 2, column = 0, pady = 1)
bottom_frame.grid(row = 3, column = 0, pady = 3)
#labels, textboxes, buttons
#top_frame content
Notes_label = Label(top_frame, text = "Notes", fg = "black", font = 1, padx = 141)
Notes_label.grid(row = 0 , column = 0)
save_button = Button(top_frame, text = "save")
#padx increases distance between buttons
#button_frame content
#bold button
#the ideal is that if u press ctrl + b, the bold_button is pressed by itself
#rn, it's gonna be a highlight technique
bold_button = Button(button_frame, text = "B", padx = 4, pady = 2, command = bold_it)
bold_button.grid(row = 0, column = 0)
#italicsize button
italics_button = Button(button_frame, text = "I", padx = 4, pady = 2, command = italics_it)
italics_button.grid(row = 0, column = 2, padx = 15)
#text_box frame button
text_box = Text(text_frame, width = 45, height = 27)
text_box.grid(row = 0, column = 0)
#text_box frame content
main_scrollbar = ttk.Scrollbar(text_frame, orient = "vertical", command = text_box.yview)
main_scrollbar.grid(row = 0, column = 1)
text_box["yscrollcommand"] = main_scrollbar.set
clear_button = Button(bottom_frame, text = "clear", padx = 2, pady = 2, command = clear)
clear_button.grid(row = 0, column = 0, padx = 15, pady = 10)
save_button = Button(bottom_frame, text = "save note", padx = 2, pady = 2)
save_button.grid(row = 0, column =1, padx = 15, pady = 10)
#binding all buttons for changing colours when user hovers over it and leaves it
bold_button.bind("<Enter>", enter_button)
bold_button.bind("<Leave>", leave_button)
italics_button.bind("<Enter>", enter_button)
italics_button.bind("<Leave>", leave_button)
clear_button.bind("<Enter>", enter_button)
clear_button.bind("<Leave>", leave_button)
save_button.bind("<Enter>", enter_button)
save_button.bind("<Leave>", leave_button)
# main program loop
root.mainloop()
here's an image of the problem image of problem
I would also be very grateful if one could explain the concept of scrollbar.set and like yview and why they are both needed for the scrollbar to work. Tutorials and videos don't seem to explain the concept, but just implement it
In line 145. You're missing sticky
main_scrollbar.grid(row = 0, column = 1, sticky=NS)
Output:

Why does my python program cut off a good section of my tkinter output?

I'm programming a simple application to help with tracking combat information for dnd using python and tkinter. I started with the input page and it worked fine, but when I started to use tabs to allow the user to access a help page, strangely it cut off about half of the original output, the only thing I changed is using ttk and my_frame 1 instead of root. I've tried changing .place to .grid and it worked to some degree, although instead it displayed the buttons in strange positions in front of the rest of the outputs. Then I tried adding blank lines on the help tag, this did work but it seems quite ineffective and time consuming. I can guess from this there's no space but the geometry was set to 500x500 which should be plenty. So I'm trying to figure out what's going wrong. Thanks for reading!
(Also it isn't quite complete yet hence why the next page function does something random)
This is the code:
import tkinter as tk
from tkinter import ttk
#Starting up tkinter
root = tk.Tk()
root.title("Dungeons and dragons combat manager")
root.geometry("500x500")
root.configure(background = "White")
#Initialise the arrays
player_details = []
overall_data = []
#help page
my_notebook = ttk.Notebook(root)
my_notebook.pack(pady = 15)
my_frame1 = tk.Frame(my_notebook, width = "500", height = "500")
my_frame1.grid(row = 0, column = 0, columnspan = 2, padx = 40, pady = 5)
my_frame2 = tk.Frame(my_notebook, width = 500, height = 500)
my_notebook.add(my_frame1, text = "Main")
my_notebook.add(my_frame2, text = "Help")
line1 = tk.Label(my_frame2, text = "Hello, welcome to the help page!", font = ('Times New Roman', 12)).grid(row = 0, column = 0, sticky = 'W')
line2 = tk.Label(my_frame2, text = "Most of the instructions will be given during application use", font = ('Times New Roman', 12)).grid(row = 1, column = 0, sticky = 'W')
line3 = tk.Label(my_frame2, text = "Please ensure all numerical inputs are given in integers", font = ('Times New Roman', 12)).grid(row = 2, column = 0, sticky = 'W')
line4 = tk.Label(my_frame2, text = "If any mistakes are made please press the restart button", font = ('Times New Roman', 12)).grid(row = 3, column = 0, sticky = 'W')
line5 = tk.Label(my_frame2, text = "Once the order is displayed initiative cannot be changed", font = ('Times New Roman', 12)).grid(row = 4, column = 0, sticky = 'W')
line6 = tk.Label(my_frame2, text = "However, health can be edited at any time", font = ('Times New Roman', 12)).grid(row = 5, column = 0, sticky = 'W')
line7 = tk.Label(my_frame2, text = "Good luck with your encounter!", font = ('Times New Roman', 12)).grid(row = 6, column = 0, sticky = 'W')
#main section
tk.Label(my_frame1, text = "Player details form", font = ('Times New Roman', 16)).grid(row = 0, column = 0, padx = 25, pady = 5)
#function definitions
def submit():
player_details = []
player_details.append(name.get())
player_details.append(health.get())
player_details.append(ac.get())
player_details.append(initiative.get())
overall_data.append(player_details)
print(str(overall_data))
player_num = tk.Label(root, text = "Inputting for Player :" + str(len(overall_data)+1), fg = 'White', bg = "Black")
player_num.place(x = 30, y = 210, width = 240, height = 25)
def clear():
name.delete(0, 'end')
health.delete(0, 'end')
ac.delete(0, 'end')
initiative.delete(0, 'end')
name.focus_set()
def next_page():
print("chicken")
#display
player_data = ['Name: ','Health: ','Armour Class: ','initiative: ']
labels = range(4)
for i in range(4):
bg_colour = "Black"
l = tk.Label(my_frame1,
text = player_data[i],
fg='White',
bg=bg_colour)
l.place(x = 20, y = 60 + i*30, width=120, height=25)
name = tk.Entry(my_frame1,width = 15,fg = "Black",bg = "White")
name.place(x = 150, y = 60, width = 120, height=25)
health = tk.Entry(my_frame1, width = 15,fg = "Black",bg = "White")
health.place(x = 150, y = 90, width = 120, height=25)
ac = tk.Entry(my_frame1, width = 15,fg = "Black",bg = "White")
ac.place(x = 150, y = 120, width = 120, height=25)
initiative = tk.Entry(my_frame1, width = 15,fg = "Black",bg = "White")
initiative.place(x = 150, y = 150, width = 120, height=25)
submit_button = tk.Button(my_frame1, text = "Submit", command = submit)
submit_button.place(x = 30, y = 180, width = 100, height = 25)
clear_button = tk.Button(my_frame1, text = "Clear", command = clear)
clear_button.place(x = 160, y = 180, width = 100, height = 25)
player_num = tk.Label(my_frame1, text = "Inputting for Player : 1", fg = 'White', bg = "Black")
player_num.place(x = 30, y = 210, width = 240, height = 25)
next_button = tk.Button(my_frame1, text = "Next", command = next_page)
next_button.place(x = 30, y = 240, width = 100, height = 25)
'''
It is because you haven't made the notebook large enough, and haven't requested that it expand to fill the available space. You're relying on the default size of the notebook, and you're putting more things in than will fit. Plus, you're using place instead of pack inside the notebook, and place won't cause the containing window to grow or shrink. This is one of the disadvantages to using place as a general purpose layout mechanism.
The easy solution is to use the options that pack supports, such as fill and expand, though without knowing what your full UI should look like it's hard to say if that's the correct solution or not.
my_notebook.pack(fill="both", expand=True)
Another solution would be to stop using place. If you use grid and/or pack, then the notebook will resize to fit its contents.

why is the layout all messed up if i expand the window, python tkinter

i want it to expand the size accordingly if the window is expanded, so far i use the grid.row/column configure to make its weight =1 but it will be all messed up it i expand the window.
import time
import tkinter as tk
#Initialise the window
clock = tk.Tk()
clock.title('Easy CLock')
clock.configure(bg='#121212')
clock.columnconfigure(0, weight = 1)
clock.rowconfigure(0, weight = 1)
border_effects = {
"flat": tk.FLAT,
"sunken": tk.SUNKEN,
"raised": tk.RAISED,
"groove": tk.GROOVE,
"ridge": tk.RIDGE,
}
#Logo will be under the main parent
logo = tk.PhotoImage(file = r'C:\Users\User\VSC\Alarm\Logo1.png')
logo_size = logo.subsample(5)
#Time and Date function
def time_date():
# current time
current_time = time.strftime('%H:%M:%S')
current_date = time.strftime(r'%m/%d/%Y')
clock.after(200, time_date)
#Displays the time
c_time = tk.Label(f_time, text = current_time, fg='white', bg='#121212', font=('Verdana', 30))
c_date = tk.Label(f_time, text = current_date, font=('Verdana', 10), fg='white', bg='#121212')
c_time.grid(column=0, row=0)
c_date.grid(column=0, row=1)
#alarm button command
def alarm_func():
#Alarm label
c_clicked = tk.Label(f_alarm, text='Alarm Interface', fg='white', bg='#121212')
c_clicked.grid(column=0, row=1, sticky = 'N')
def recall_frame(event):
if event == f_alarm:
event.grid_forget()
f_time.grid(column=0, row =1, columnspan = 4, sticky = 'N')
elif event == f_time:
event.grid_forget()
f_alarm.grid(column=0, row=1, columnspan = 4, rowspan = 2)
def back_func():
pass
#Creating Frames
f_time = tk.Frame(clock) #Clock Button
f_alarm = tk.Frame(clock) #Alarm Buttton
#configure the frames
f_time.configure(bg = '#121212')
f_alarm.configure(bg = '#121212')
#Setting label in the frame
f_lbl = tk.Label(clock, text= ' Simplistic Clock', image = logo_size, font=('Verdana', 30), fg='white', bg='#121212', compound = tk.LEFT)
time_but = tk.Button(clock, text='Clock', command= lambda :[time_date(), recall_frame(f_alarm)], bg='#f39c12', width = 15, relief = border_effects['ridge'])
alarm_but = tk.Button(clock, text = 'Alarm', command = lambda :[alarm_func(), recall_frame(f_time)], bg='#f39c12', width = 15, relief = border_effects['ridge'])
quit_but = tk.Button(clock, text='Exit', command = clock.quit, bg='#f39c12', width = 15, relief = border_effects['ridge'])
back_but = tk.Button(clock, text = 'Back To Home', command = back_func, bg='#f39c12', width = 15, relief = border_effects['ridge'])
f_lbl.config(borderwidth = 4, relief = border_effects['sunken'])
f_lbl.grid_columnconfigure(0, weight = 1)
#Putting it on the frames
f_lbl.grid(column = 0, row = 0, columnspan = 4, sticky = 'N')
time_but.grid(column = 0, row = 3)
alarm_but.grid(column = 1, row = 3)
back_but.grid(column = 2, row = 3)
quit_but.grid(column = 3, row = 3)
clock.mainloop()
also, why does the border in the f_lbl, simplistic clock not fully extended through out all 4 column since i put columnspan = 4 , and weight = 1 , should't it expand fully through all 4 columns?

Adding frame over lable on python

I want to create frame over the label and been trying lots of code but it is not working out. Also trying to make checkbutton to left side of the screen with no frame. Can anyone help me? Thank you
I got far as this
But I want to make it look like this with the frame
show_status = Label(dashboard, bd = 5, text = 'Even', fg = 'black',
font = ('Arial', 70), width = 8)
def update_dashboard():
three_buttons = Label(dashboard, relief = 'groove')
Alpha_button = Checkbutton(three_buttons, text = 'Alpha',
variable = alpa_1,
command = update_dashboard)
Beta_button = Checkbutton(three_buttons, text = 'Beta',
variable = beta_2,
command = update_dashboard)
Gamma_button = Checkbutton(three_buttons, text = 'Gamma',
variable = gemma_3,
command = update_dashboard)
Alpha_button.grid(row = 1, column = 0, sticky = 'w')
Beta_button.grid(row = 1, column = 2, sticky = 'w')
Gamma_button.grid(row = 1, column = 4, sticky = 'w')
margin = 5 # pixels
show_status.grid(padx = margin, pady = margin, row = 1,
column = 1, columnspan = 2,)
three_buttons.grid(row = 4, column = 2, sticky = W)
dashboard.mainloop()
You can use a Frame or a Canvas and draw the rest of the widgets on it. Let us use the Frame by relying on the grid layout manager.
To have that effect you are looking for, you simply need to span the label over the 3 columns of the check button widgets using the option the columnspan option.
Full program
Here is a simple solution using the object oriented concepts:
'''
Created on May 8, 2016
#author: Billal Begueradj
'''
import Tkinter as Tk
class Begueradj(Tk.Frame):
'''
Dislay a Label spanning over 3 columns of checkbuttons
'''
def __init__(self, parent):
'''Inititialize the GUI
'''
Tk.Frame.__init__(self, parent)
self.parent=parent
self.initialize_user_interface()
def initialize_user_interface(self):
"""Draw the GUI
"""
self.parent.title("Billal BEGUERADJ")
self.parent.grid_rowconfigure(0,weight=1)
self.parent.grid_columnconfigure(0,weight=1)
self.parent.config(background="lavender")
# Create a Frame on which other elements will be attached to
self.frame = Tk.Frame(self.parent, width = 500, height = 207)
self.frame.pack(fill=Tk.X, padx=5, pady=5)
# Create the checkbuttons and position them on the second row of the grid
self.alpha_button = Tk.Checkbutton(self.frame, text = 'Alpha', font = ('Arial', 20))
self.alpha_button.grid(row = 1, column = 0)
self.beta_button = Tk.Checkbutton(self.frame, text = 'Beta', font = ('Arial', 20))
self.beta_button.grid(row = 1, column = 1)
self.gamma_button = Tk.Checkbutton(self.frame, text = 'Gamma', font = ('Arial', 20))
self.gamma_button.grid(row = 1, column = 2)
# Create the Label widget on the first row of the grid and span it over the 3 checbbuttons above
self.label = Tk.Label(self.frame, text = 'Even', bd = 5, fg = 'black', font = ('Arial', 70), width = 8, relief = 'groove')
self.label.grid(row = 0, columnspan = 3)
# Main method
def main():
root=Tk.Tk()
d=Begueradj(root)
root.mainloop()
# Main program
if __name__=="__main__":
main()
Demo
Here is a screenshot of the running program:

Iterating via loops to make multiple widgets and make the below code better

I'm pretty new to Python and have written my first ever program with a GUI and have been reading a lot about code to loop your way into creating multiple widgets but haven't seen a solution for my code below.
I have written a program that simulates a tennis match and have created a GUI for the program which consists of GUI in the form as a Livescoreboard.
For the scoreboard I have createad a lot of labels that will contain the different scores and the players names etc like a real tennis scoreboard and I've also made a few buttons.
My code below is the two methods in which I create and update all the widgets in the GUI. Looking at it, from a novice perspective, it doesn't seem to be the best way of writing this code.
Have been searching and trying to come up with something else than this but haven't found any.
Is there a way to this better or is it fine the way it is?
# Creates the widgets in the GUI.
def create_widgets(self):
# Images
photo = tk.PhotoImage(file = 'Federer.gif')
label = tk.Label(self, image = photo)
label.image = photo
label.place(relwidth = 1, relheight = 1)
img = tk.PhotoImage(file = 'Rolex.gif')
rolex_label = tk.Label(self, image = img)
rolex_label.image = img
rolex_label.grid(row = 0, column = 3, columnspan = 2)
# Creates and sets some StringVar()
self.set_1_player_1 = tk.StringVar()
self.set_1_player_2 = tk.StringVar()
self.set_2_player_1 = tk.StringVar()
self.set_2_player_2 = tk.StringVar()
self.set_3_player_1 = tk.StringVar()
self.set_3_player_2 = tk.StringVar()
self.spelare_1 = tk.StringVar()
self.spelare_2 = tk.StringVar()
self.sets_player_1 = tk.StringVar()
self.sets_player_2 = tk.StringVar()
self.games_player_1 = tk.StringVar()
self.games_player_2 = tk.StringVar()
self.points_player_1 = tk.StringVar()
self.points_player_2 = tk.StringVar()
self.show_score_by = tk.StringVar()
self.spelare_1.set(self.prepared_match.get_player_1().get_name())
self.spelare_2.set(self.prepared_match.get_player_2().get_name())
self.sets_player_1.set('0')
self.sets_player_2.set('0')
self.games_player_1.set('0')
self.games_player_2.set('0')
self.points_player_1.set('0')
self.points_player_2.set('0')
self.show_score_by.set(None)
# The labels
tk.Label(self, font = "Purisa 8 bold", text = 'Set 1', height = 2, width = 6, relief = tk.RAISED).grid(row = 0, column = 0)
tk.Label(self, font = "Purisa 8 bold", text = 'Set 2', height = 2, width = 6, relief = tk.RAISED).grid(row = 0, column = 1)
tk.Label(self, font = "Purisa 8 bold", text = 'Set 3', height = 2, width = 6, relief = tk.RAISED).grid(row = 0, column = 2)
tk.Label(self, font = "Purisa 8 bold", text = 'SETS', height = 2, width = 6, relief = tk.RAISED).grid(row = 0, column = 5)
tk.Label(self, font = "Purisa 8 bold", text = 'GAMES', height = 2, width = 6, relief = tk.RAISED).grid(row = 0, column = 6)
tk.Label(self, font = "Purisa 8 bold", text = 'POINTS', height = 2, width = 15, relief = tk.RAISED).grid(row = 0, column = 7)
tk.Label(self, textvariable = self.set_1_player_1, height = 2, width = 6, relief = tk.RAISED).grid(row = 1, column = 0)
tk.Label(self, textvariable = self.set_2_player_1, height = 2, width = 6, relief = tk.RAISED).grid(row = 1, column = 1)
tk.Label(self, textvariable = self.set_3_player_1, height = 2, width = 6, relief = tk.RAISED).grid(row = 1, column = 2)
self.name_player_1 = tk.Label(self, textvariable = self.spelare_1, height = 2, width = 18, relief = tk.RAISED)
self.name_player_1.grid(row = 1, column = 3, columnspan = 2)
tk.Label(self, textvariable = self.sets_player_1, height = 2, width = 6, relief = tk.RAISED).grid(row = 1, column = 5)
tk.Label(self, textvariable = self.games_player_1, height = 2, width = 6, relief = tk.RAISED).grid(row = 1, column = 6)
tk.Label(self, textvariable = self.points_player_1, height = 2, width = 15, relief = tk.RAISED).grid(row = 1, column = 7)
tk.Label(self, textvariable = self.set_1_player_2, height = 2, width = 6, relief = tk.RAISED).grid(row = 2, column = 0)
tk.Label(self, textvariable = self.set_2_player_2, height = 2, width = 6, relief = tk.RAISED).grid(row = 2, column = 1)
tk.Label(self, textvariable = self.set_3_player_2, height = 2, width = 6, relief = tk.RAISED).grid(row = 2, column = 2)
self.name_player_2 = tk.Label(self, textvariable = self.spelare_2, height = 2, width = 18, relief = tk.RAISED)
self.name_player_2.grid(row = 2, column = 3, columnspan = 2)
tk.Label(self, textvariable = self.sets_player_2, height = 2, width = 6, relief = tk.RAISED).grid(row = 2, column = 5)
tk.Label(self, textvariable = self.games_player_2, height = 2, width = 6, relief = tk.RAISED).grid(row = 2, column = 6)
tk.Label(self, textvariable = self.points_player_2, height = 2, width = 15, relief = tk.RAISED).grid(row = 2, column = 7)
tk.Label(self, font = "Purisa 8 bold", text = 'Show score by: ', height = 2, width = 15).grid(row = 0, column = 8, padx = 50)
# The buttons
self.play_button = tk.Button(self, bd = 5, text = 'Play', command = self.play, height = 2, width = 10, relief = tk.RIDGE)
self.play_button.grid(pady = 10, row = 3, column = 3, columnspan = 2)
self.quit_button = tk.Button(self, bd = 3, text = 'Quit', command = self.quit, height = 1, width = 5, relief = tk.RIDGE)
self.quit_button.grid(row = 5, column = 3, columnspan = 2, pady = 5)
self.restart_button = tk.Button(self, bd = 4, text = 'Restart', command = self.restart, height = 1, width = 7, relief = tk.RIDGE)
self.restart_button.grid(row = 4, column = 3, columnspan = 2, pady = 5)
self.pause_button = tk.Button(self, text = 'Pause', command = self.pause, height = 1, width = 5, relief = tk.RIDGE)
self.pause_button.grid(row = 3, column = 8, sticky = tk.S)
tk.Radiobutton(self, command = self.show_score, text = 'Point', variable = self.show_score_by, value = 'Point', height = 1, width = 10).grid(row = 1, column = 8, padx = 50, sticky = tk.S)
tk.Radiobutton(self, command = self.show_score, text = 'Game', variable = self.show_score_by, value = 'Game', height = 1, width = 10).grid(row = 2, column = 8, padx = 50)
tk.Radiobutton(self, command = self.show_score, text = 'Set', variable = self.show_score_by, value = 'Set', height = 1, width = 10).grid(row = 3, column = 8, padx = 50, sticky = tk.N)
# Updates the widgets in the frame.
def update_widgets(self):
self.sets_player_1.set(self.prepared_match.get_sets()[0])
self.sets_player_2.set(self.prepared_match.get_sets()[1])
if self.prepared_match.show_score_by in ['Point', 'Game', None]:
self.games_player_1.set(self.prepared_match.get_games()[0])
self.games_player_2.set(self.prepared_match.get_games()[1])
if self.prepared_match.show_score_by == 'Point':
self.points_player_1.set(self.prepared_match.get_real_score()[0])
self.points_player_2.set(self.prepared_match.get_real_score()[1])
elif self.prepared_match.show_score_by == 'Game':
self.points_player_1.set('0')
self.points_player_2.set('0')
elif self.prepared_match.show_score_by == 'Set':
self.points_player_1.set('0')
self.points_player_2.set('0')
self.games_player_1.set('0')
self.games_player_2.set('0')
self.set_1_player_1.set(self.prepared_match.get_previous_sets()[0][0])
self.set_1_player_2.set(self.prepared_match.get_previous_sets()[0][1])
self.set_2_player_1.set(self.prepared_match.get_previous_sets()[1][0])
self.set_2_player_2.set(self.prepared_match.get_previous_sets()[1][1])
self.set_3_player_1.set(self.prepared_match.get_previous_sets()[2][0])
self.set_3_player_2.set(self.prepared_match.get_previous_sets()[2][1])
if self.prepared_match.match_is_ended():
if self.prepared_match.get_sets()[0] == 2:
self.name_player_1.config(fg = 'red')
else:
self.name_player_2.config(fg = 'red')
self.update()
You can make use of setattr (and as you made a class, the __ setattr __ method). You can refactor a lot of your code but you'll find hereunder optimizations your initialization code :
You can create a method like :
def create_scoreboard(self, n_players, n_sets):
""" Create attributes set_X_player_Y """
for player in range(1, n_players+1):
for set in range(1, n_sets+1):
self.__setattr__(
"set_%d_player_%d" % (set, player),
tk.StringVar()
)
for attribute in ['sets', 'games', 'points']:
self.__setattr__(
"%s_player_%d" % (attribute, player),
tk.StringVar(value='0')
)
Then you can loop over players, sets, etc.
However, the best approach would be to create player objects to store their scores. You can try to isolate objects using a "natural" approach and creating a scoreboard object, players, gamepads (for your buttons), etc.

Categories

Resources