how to show/hide widget in tkinter without moving other widget - python

I'm using grid_remove() and grid() command to hide/show the widget but the result is the other widget is move out of the original position.
How to hide/show the widget without moving widget
Example:
from tkinter import *
from tkinter import ttk
GUI = Tk()
GUI.title("myTest")
GUI.geometry("700x700")
Nameget = StringVar()
Priceget = StringVar()
Quantityget = StringVar()
Unitget = StringVar()
Partnumget = StringVar()
L_Partnum = ttk.Label(GUI, text = 'Part number')
L_Partnum.grid(row = 0, column = 0)
L_namme = ttk.Label(GUI, text = 'Name')
L_namme.grid(row = 0, column = 1)
L_quan = ttk.Label(GUI, text = 'Quantity')
L_quan.grid(row = 1, column = 2)
L_quan.grid_remove()
L_price = ttk.Label(GUI, text = 'Price')
L_price.grid(row = 3, column = 3)
E_partnum = ttk.Entry(GUI, textvariable = Partnumget)
E_partnum.grid(row = 1, column = 0)
E_namme = ttk.Entry(GUI,textvariable = Nameget)
E_namme.grid(row = 1, column = 1)
E_unit = ttk.Entry(GUI,textvariable = Unitget)
E_quan = ttk.Entry(GUI,textvariable = Quantityget)
E_quan.grid(row = 2, column = 2)
E_quan.grid_remove()
E_price = ttk.Entry(GUI,textvariable = Priceget)
E_price.grid(row = 4, column = 3)
I_check_vat = IntVar()
def d_check_vat_1():
E_partnum.focus()
if I_check_vat.get() == 1:
L_quan.grid()
E_quan.grid()
elif I_check_vat.get() == 0:
L_quan.grid_remove()
E_quan.grid_remove()
C_CHECK_VAT = ttk.Checkbutton(GUI, text="click here to see the result", variable=I_check_vat, command=d_check_vat_1)
C_CHECK_VAT.grid(row = 5, column = 0)
GUI.mainloop()
Before clicking:
After clicking:
image with the expected output:

The problem is grid() does not take up empty space by default, it gives the last empty row/col to the widget(if previous rows before it are empty).
So what you can do is, set minimum space for your column and row so that those space will remain empty, so change your function to:
def d_check_vat_1():
E_partnum.focus()
if I_check_vat.get():
L_quan.grid(row=2, column=2)
E_quan.grid(row=3, column=2)
width = E_quan.winfo_reqwidth() # Get widget width
height = L_quan.winfo_reqheight() # Get widget height
GUI.rowconfigure(2,minsize=height) # Now apply the values
GUI.rowconfigure(3,minsize=height)
GUI.columnconfigure(2,minsize=width)
else:
L_quan.grid_remove()
E_quan.grid_remove()
Now its dynamic as well, it takes the width of widget and applies that as the minsize of that row so that row will have that empty space.

Related

Tkinter Python: Inability to Configure 'readonly' mode with Entry Widgets

Hello stackoverflow community,
I'm working on a project where I am attempting to configure tkinter entry widgets as 'readonly' to prevent the user of the GUI from being able to write or modify the contents of the entry fields. When I set the 'state' attribute to 'readonly' using the code provided below, it 'grays out' the entry field as opposed to merely preventing the user from changing the fields' content. This is shown in the top-left entry field in the image below. Are there recommendations on how to fix this?
# Render canvas to contain tabular results from character table with scrollbars for GUI functionality
self.character_records_canvas = tkinter.Canvas(self.options_main_frame, width = 1150, height = 800)
# Define properties of scrollbars to render on frame
self.scrollbar_vertical = tkinter.Scrollbar(self.options_main_frame, orient = tkinter.VERTICAL, command = self.character_records_canvas.yview)
self.scrollbar_horizontal = tkinter.Scrollbar(self.options_main_frame, orient = tkinter.HORIZONTAL, command = self.character_records_canvas.xview)
# Pack widget objects into main frame
self.scrollbar_horizontal.pack(side = tkinter.BOTTOM, fill = tkinter.X)
self.scrollbar_vertical.pack(side = tkinter.RIGHT, fill = tkinter.Y)
self.character_records_canvas.pack(side = tkinter.LEFT, fill = tkinter.BOTH, expand = 1)
# Configure canvas to communicate with scrollbars
self.character_records_canvas.configure(yscrollcommand=self.scrollbar_vertical.set)
self.character_records_canvas.configure(xscrollcommand=self.scrollbar_horizontal.set)
# Bind box around canvas to enable scrollbar functionality
self.character_records_canvas.bind('<Configure>', lambda e : self.character_records_canvas.configure(scrollregion = self.character_records_canvas.bbox("all")))
# Render child frame in canvas to display tabular results
self.character_records_frame = tkinter.Frame(self.character_records_canvas)
self.character_records_frame.pack(side = tkinter.LEFT, fill = tkinter.BOTH, expand = 1)
# Configure the child frame to communicate with the canvas
self.character_records_canvas.create_window((0,0), window = self.character_records_frame, anchor = "nw")
self.character_records_canvas.configure(scrollregion = self.character_records_canvas.bbox("all"))
# Return list of results from character database table
query = "USE tictactoe_office_db;"
self.db_obj.execute_query(query)
query = """
SELECT * FROM `character`;
"""
character_results_list = self.db_obj.read_query(query)
# Render table column headers on frame
self.character_id_header = tkinter.Entry(self.character_records_frame, state = 'readonly')
self.first_name_header = tkinter.Entry(self.character_records_frame)
self.last_name_header = tkinter.Entry(self.character_records_frame)
self.branch_name_header = tkinter.Entry(self.character_records_frame)
self.game_wins_header = tkinter.Entry(self.character_records_frame)
self.game_losses_header = tkinter.Entry(self.character_records_frame)
self.match_wins_header = tkinter.Entry(self.character_records_frame)
self.match_ties_header = tkinter.Entry(self.character_records_frame)
self.match_losses_header = tkinter.Entry(self.character_records_frame)
self.match_total_header = tkinter.Entry(self.character_records_frame)
self.character_id_header.grid(row = 3, column = 0, sticky = "w")
self.first_name_header.grid(row = 3, column = 1, sticky = "w")
self.last_name_header.grid(row = 3, column = 2, sticky = "w")
self.branch_name_header.grid(row = 3, column = 3, sticky = "w")
self.game_wins_header.grid(row = 3, column = 4, sticky = "w")
self.game_losses_header.grid(row = 3, column = 5, sticky = "w")
self.match_wins_header.grid(row = 3, column = 6, sticky = "w")
self.match_ties_header.grid(row = 3, column = 7, sticky = "w")
self.match_losses_header.grid(row = 3, column = 8, sticky = "w")
self.match_total_header.grid(row = 3, column = 9, sticky = "w")
self.character_id_header.insert(0, "character_id")
self.first_name_header.insert(0, "first_name")
self.last_name_header.insert(0, "last_name")
self.branch_name_header.insert(0, "branch_name")
self.game_wins_header.insert(0, "game_wins")
self.game_losses_header.insert(0, "game_losses")
self.match_wins_header.insert(0, "match_wins")
self.match_ties_header.insert(0, "match_ties")
self.match_losses_header.insert(0, "match_losses")
self.match_total_header.insert(0, "match_total")
# Render tabular results on child frame
for i in range(0, len(character_results_list)):
for j in range(0,len(character_results_list[0])):
self.entry = tkinter.Entry(self.character_records_frame)
self.entry.grid(row = i + 4, column = j, sticky = "w")
self.entry.insert(tkinter.END, str(character_results_list[i][j]))
# Render column header border labels
for i in range(0, 10):
self.character_records_menu_label_2 = tkinter.Entry(self.character_records_frame)
self.character_records_menu_label_2.grid(row = 2, column = i, sticky = "n")
self.character_records_menu_label_2.insert(0, "-----------------------------------")
# Render "back" buttons
self.options_back_button_1 = tkinter.Button(self.character_records_frame, text = "BACK", width = 10, command = self.destroy_character_records_canvas)
self.options_back_button_1.grid(row = 47, column = 9)
self.options_back_button_2 = tkinter.Button(self.character_records_frame, text = "BACK", width = 10, command = self.destroy_character_records_canvas)
self.options_back_button_2.grid(row = 47, column = 0)

Make an Entry When a Checkbox is Unchecked in Tkinter

I have a check button that is checked by default. If the user unchecks it, a label and an entry should appear. I tried to do so by using the key binding method; however, it has a drawback which is that if the user checks the checkbox again, the new label and entry won't disappear. How do I solve that problem?
checkButtonVar = IntVar(value = 1)
checkButtonIsChnaceDefault = Checkbutton(root, variable = checkButtonVar)
labelIsChanceDefault = Label(root, text="Make chance = 0.9?")
labelIsChanceDefault.grid(row=3, column = 0, sticky = 'w')
checkButtonIsChnaceDefault.grid(row = 3, column = 1)
def checkCheckButton(event):
labelChance = Label(root, text = "Enter chance of winning")
labelChance.grid( row = 3, column = 2)
global entryChance
entryChance = Entry(root, borderwidth = 3)
entryChance.grid(row = 3, column = 3)
checkButtonIsChnaceDefault.bind('<Button-1>', checkCheckButton)
Here's a screenshot of the program to make things clear.
You don't need to bind the Check-button. Use command option. And setting offvalue and onvalue can control the appearance.
See the tkinter.Checkbutton
checkButtonVar = IntVar()
checkButtonIsChnaceDefault = Checkbutton(root, variable = checkButtonVar,offvvalue=0,onvalue=1,command=checkCheckButton)
...
checkButtonIsChnaceDefault.grid(row = 3, column = 1)
#==== Define the widgets here.
labelChance = Label(root, text = "Enter chance of winning")
entryChance = Entry(root, borderwidth = 3)
def checkCheckButton():
if checkButtonVar.get()==0:
labelChance.grid( row = 3, column = 2)
entryChance.grid(row = 3, column = 3)
else:
labelChance.grid_forget()
entryChance.grid_forget()

how to format 2 check buttons in same row and column python

I have created two check buttons and I want them both in row 5 and column 1. But I want the 'YES' check button to be formatted on the left side and the 'NO' check button to be on the right.
I have used sticky but it will not work. I also tried changing the width of the check buttons but this did not work either.
Do you have any suggestions?
Thank you!
self.yes_checkbtn = Checkbutton(self.entry_frame, width = 20, variable = checkbutton1,
anchor = W, text = "YES")
self.no_checkbtn = Checkbutton(self.entry_frame, width = 20, variable = checkbutton2,
anchor = E, text = "NO")
self.yes_checkbtn.grid(row = 5, column = 1, sticky = W)
self.no_checkbtn.grid(row = 5, column = 1, sticky = E)
Outcome:
I dont have enough points yet to show the image without a link - sorry
Put both check buttons under another new frame, then you can grid this new frame to column 1 of row 5, also change option width of Checkbutton to a small number, like 5.
Example code
from tkinter import *
root = Tk()
entry_frame = Frame(root)
entry_frame.grid(row=0, column=0)
for i in range(4):
for j in range(2):
label = Label(entry_frame, text=f'Row {i} Column {j}')
label.grid(row=i, column=j)
frame = Frame(entry_frame)
frame.grid(row=4, column=1)
checkbutton1 = BooleanVar()
checkbutton2 = BooleanVar()
yes_checkbtn = Checkbutton(frame, width = 5, variable = checkbutton1,
anchor = W, text = "YES", bg='green')
no_checkbtn = Checkbutton(frame, width = 5, variable = checkbutton2,
anchor = E, text = "NO", bg='blue')
yes_checkbtn.grid(row = 0, column = 1, sticky = W)
no_checkbtn.grid(row = 0, column = 2, sticky = W)
root.mainloop()

How to display output of print() in GUI python

I am new in creating GUI. I am doing it in Python with Tkinter. In my program I calculate following characteristics
def my_myfunction():
my code ...
print("Centroid:", centroid_x, centroid_y)
print("Area:", area)
print("Angle:", angle)
I would like to ask for any help/tips how to display those values in GUI window or how to save them in .txt file so that I can call them in my GUI
Thanks in advance
Tkinter is easy and an easy way to do a GUI, but sometimes it can be frustrating. But you should have read the docs before.
However, you can do in this way.
from tkinter import *
yourData = "My text here"
root = Tk()
frame = Frame(root, width=100, height=100)
frame.pack()
lab = Label(frame,text=yourData)
lab.pack()
root.mainloop()
There are several ways to display the results of any operation in tkiner.
You can use Label, Entry, Text, or even pop up messages boxes. There are some other options but these will probably be what you are looking for.
Take a look at the below example.
I have a simple adding program that will take 2 numbers and add them together. It will display the results in each kind of field you can use as an output in tkinter.
import tkinter as tk
from tkinter import messagebox
class App(tk.Frame):
def __init__(self, master):
self.master = master
lbl1 = tk.Label(self.master, text = "Enter 2 numbers to be added \ntogether and click submit")
lbl1.grid(row = 0, column = 0, columnspan = 3)
self.entry1 = tk.Entry(self.master, width = 5)
self.entry1.grid(row = 1, column = 0)
self.lbl2 = tk.Label(self.master, text = "+")
self.lbl2.grid(row = 1, column = 1)
self.entry2 = tk.Entry(self.master, width = 5)
self.entry2.grid(row = 1, column = 2)
btn1 = tk.Button(self.master, text = "Submit", command = self.add_numbers)
btn1.grid(row = 2, column = 1)
self.lbl3 = tk.Label(self.master, text = "Sum = ")
self.lbl3.grid(row = 3, column = 1)
self.entry3 = tk.Entry(self.master, width = 10)
self.entry3.grid(row = 4, column = 1)
self.text1 = tk.Text(self.master, height = 1, width = 10)
self.text1.grid(row = 5, column = 1)
def add_numbers(self):
x = self.entry1.get()
y = self.entry2.get()
if x != "" and y != "":
sumxy = int(x) + int(y)
self.lbl3.config(text = "Sum = {}".format(sumxy))
self.entry3.delete(0, "end")
self.entry3.insert(0, sumxy)
self.text1.delete(1.0, "end")
self.text1.insert(1.0, sumxy)
messagebox.showinfo("Sum of {} and {}".format(x,y),
"Sum of {} and {} = {}".format(x, y, sumxy))
if __name__ == "__main__":
root = tk.Tk()
myapp = App(root)
root.mainloop()

Laying out Labels properly in Tkinter

I have the following code:
from Tkinter import *
master = Tk()
center(master, 300, 200)
#Label(text = 'Clients').grid(row = 0, column = 1)
lb = Listbox(master, selectmode = BROWSE)
sb = Scrollbar(master)
sb.grid(row = 0, column = 0, sticky =NS, rowspan = 1)
lb.grid(row = 0, column = 1)
sb['command'] = lb.yview
lb['yscrollcommand'] = sb.set
Label(master, text = "AAAAA").grid(row = 0, column = 2)
Label(master, text = "BBBBB").grid(row = 1, column = 3)
mainloop()
Which creates this window:
I know I can use sticky = N to make AAAAA cling to the top of the cell and be at the top of the window.
But my question is: How do I make it so that I can put multiple labels next to my listbox widget in a sort of grid of their own? Can I use .grid for this? Or do I have to use .place?
Or am I going about this entirely wrong?

Categories