I have a function called display_change that is in the middle of my tkinter GUI. I want the user to select a number and create the number of entry boxes that they select. I figured out how to do this with a for loop and putting each entry box into a list. However whenever I write something the same data is saved between all of the entry widgets.
I don't want to show all my code but can show the whole function that this is happening in.
import tkinter as tk
from tkinter.ttk import Frame, Button
labels = []
entries = []
class Application(Frame):
def __init__(self)
super().__init__()
self.mainFrame()
def mainFrame(self):
self.master.title("Setup")
self.pack(fill=tk.BOTH, expand=True)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
lbl = tk.Label(self, text="Follow the instructions on each page", bg="snow2")
lbl.grid(sticky=tk.W, pady=4, padx=5)
area = tk.Frame(self, bg="white")
area.grid(row=1, column=0, columnspan=3, rowspan=4,
padx=5, sticky=tk.E + tk.W + tk.S + tk.N)
# ----------Inside White Box ---------------------
lbl = tk.Label(area, text="Select the number of parts to create:")
lbl.grid(row=1, column=0)
choices = {0, 3, 4, 5, 6, 7, 8, 9, 10}
node_count = tk.IntVar()
node_count.set(0)
node_select = tk.OptionMenu(area, node_count, *choices,
command=lambda x: self.display_change(area, node_count.get()))
node_select.grid(row=1, column=2)
# -----------Outside Part-------------------------
abtn = Button(self, text="Thing 1")
abtn.grid(row=1, column=3, sticky=tk.W)
cbtn = Button(self, text="Thing 2")
cbtn.grid(row=2, column=3, pady=4, sticky=tk.W)
abtn2 = Button(self, text="Thing 3")
abtn2.grid(row=3, column=3, sticky=tk.W + tk.N)
cbtn2 = Button(self, text="Thing 4")
cbtn2.grid(row=3, column=3, pady=28, sticky=tk.W + tk.N)
hbtn = Button(self, text="Exit")
hbtn.grid(row=5, column=2, sticky=tk.W)
sbtn = Button(self, text="Save")
sbtn.grid(row=5, column=3, pady=3, sticky=tk.W)
sbtn = Button(self, text="Help")
sbtn.grid(row=5, column=0, sticky=tk.W)
def display_change(self, area, nodes):
"""Here is where the display is changed so what the user choose is correctly displayed"""
lower_label = tk.Label(area, text="Enter the value of each part")
lower_label.grid(row=2, column=0, sticky=tk.N + tk.W)
global labels, entries
for label in labels:
label.destroy()
for entry in entries:
entry.destroy()
labels = []
entries = []
# This loop creates the correct number of entry box's and labels. Each entry is stored separately
for i in range(nodes):
if nodes <= 4:
labels.append(tk.Label(area, text="Part "+str(i+1)))
labels[i].place(x=10+(120*i), y=55)
entries.append(tk.Entry(area, text="Change"))
entries[i].place(x=10 + (120 * i), y=80, width=100)
else:
labels.append(tk.Label(area, text="part " + str(i + 1)))
labels[i].place(x=10 + (120 * i), y=105)
entries.append(tk.Entry(area, text="Change"))
entries[i].place(x=10 + (120 * i), y=160, width=100)
if __name__ == "__main__":
root = tk.Tk()
"""Calculate center of screen so popup is center"""
w = 650
h = 400
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws / 2) - (w / 2)
y = (hs / 2) - (h / 2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
# This line prevents the user from changing the size of the window
root.resizable(width=False, height=False)
app = Application(root)
root.mainloop()
This is what it looks like when I type something:
All I typed was 'abcd' once but it went into all the entries
When you look at all the available config options in the documentation for tkinters Entry field text is not one of them. Most likely because textvariable is an available argument for the Entry field tkinter is seeing text as short for textvariable. So as a result what is happening is all of your Entry fields are being assigned the same text variable and when one entry changes that variable all of them update with the new string in that variable.
The correct way to write your for loop would be something like the following:
for i in range(nodes):
if nodes <= 4:
labels.append(tk.Label(area, text="Part {}".format(i+1)))
labels[i].place(x=10+(120*i), y=55)
entries.append(tk.Entry(area))
entries[i].insert(0, "Change Ip") # adds text directly to an entry field
entries[i].place(x=10 + (120 * i), y=80, width=100)
else:
labels.append(tk.Label(area, text="Node {}".format(i+1)))
labels[i].place(x=10 + (120 * i), y=105)
entries.append(tk.Entry(area)
entries[i].insert(0, "Change Ip")
entries[i].place(x=10 + (120 * i), y=160, width=100)
I don't understand it completely, but the text keyword argument is associating all of the entries with the same string variable that is then stored and simultaneously updating everything.
Instead of passing the text keyword, you can use the "insert" method of the entry after instantiation to set the text in the entry.
Tkinter doesn't have the best documentation in the world, so I'm not totally sure what's going on with the text keyword. Will keep looking into it. Here is an MVCE that does not exhibit the problematic behavior:
import tkinter as tk
from tkinter.ttk import Frame, Button
labels = []
entries = []
def display_change(self, area, nodes):
"""Here is where the display is changed so what the user choose is correctly seen"""
lower_label = tk.Label(area, text="Enter the value of each part")
lower_label.grid(row=2, column=0, sticky=tk.N + tk.W)
global labels, entries
for label in labels:
label.destroy()
for entry in entries:
entry.destroy()
labels = []
entries = []
# This loop creates the correct number of entry box's and labels. Each entry is stored separately
for i in range(nodes):
if nodes <= 4:
labels.append(tk.Label(area, text="Part "+str(i+1)))
labels[i].place(x=10+(120*i), y=55)
entries.append(tk.Entry(area))
entries[i].insert(0, "Change IP")
entries[i].place(x=10 + (120 * i), y=80, width=100)
root = tk.Tk()
display_change(None, root, 4)
root.mainloop()
The problem is because Entry widgets don't have a text option, which is why the initial value they display isn't "Change Ip". Entry widgets do have a textvariable option, which must be be set to a StringVar for you to be able retrieve the current text from it later using a var.get() call.
Below is a runnable version of your code that shows an example of how to do this in the display_change() method. An new global list has been added named textvars to hold the StringVars that go with each Entry widget. You can use entries in it to get the current text in each corresponding Entry.
import tkinter as tk
from tkinter.ttk import Frame, Button
labels = []
entries = []
textvars = []
class Application(Frame):
def __init__(self, master=None):
super().__init__(master)
self.mainFrame()
def mainFrame(self):
self.master.title("Tinc VM Setup")
self.pack(fill=tk.BOTH, expand=True)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
lbl = tk.Label(self, text="Follow the instructions on each page",
bg="snow2")
lbl.grid(sticky=tk.W, pady=4, padx=5)
area = tk.Frame(self, bg="white")
area.grid(row=1, column=0, columnspan=3, rowspan=4,
padx=5, sticky=tk.E + tk.W + tk.S + tk.N)
# ----------Inside White Box ---------------------
lbl = tk.Label(area, text="Select the number of parts to create:")
lbl.grid(row=1, column=0)
choices = {0, 3, 4, 5, 6, 7, 8, 9, 10}
node_count = tk.IntVar()
node_count.set(0)
node_select = tk.OptionMenu(area, node_count, *choices,
command=lambda x: self.display_change(area, node_count.get()))
node_select.grid(row=1, column=2)
# -----------Outside Part-------------------------
abtn = Button(self, text="Thing 1")
abtn.grid(row=1, column=3, sticky=tk.W)
cbtn = Button(self, text="Thing 2")
cbtn.grid(row=2, column=3, pady=4, sticky=tk.W)
abtn2 = Button(self, text="Thing 3")
abtn2.grid(row=3, column=3, sticky=tk.W + tk.N)
cbtn2 = Button(self, text="Thing 4")
cbtn2.grid(row=3, column=3, pady=28, sticky=tk.W + tk.N)
hbtn = Button(self, text="Exit")
hbtn.grid(row=5, column=2, sticky=tk.W)
sbtn = Button(self, text="Save")
sbtn.grid(row=5, column=3, pady=3, sticky=tk.W)
sbtn = Button(self, text="Help")
sbtn.grid(row=5, column=0, sticky=tk.W)
def display_change(self, area, nodes):
"""Here is where the display is changed so what the user choose is
correctly displayed.
"""
lower_label = tk.Label(area, text="Enter the value of each part")
lower_label.grid(row=2, column=0, sticky=tk.N + tk.W)
global labels, entries, textvars
for label in labels:
label.destroy()
for entry in entries:
entry.destroy()
labels = []
entries = []
textvars = []
# This loop creates the correct number of entry box's and labels.
# Each entry is stored separately
for i in range(nodes):
if nodes <= 4:
labels.append(tk.Label(area, text="Part "+str(i+1)))
labels[-1].place(x=10+(120*i), y=55)
textvars.append(tk.StringVar())
textvars[-1].set("Change Ip")
entries.append(tk.Entry(area, textvariable=textvars[-1]))
entries[-1].place(x=10 + (120 * i), y=80, width=100)
else:
labels.append(tk.Label(area, text="Node " + str(i + 1)))
labels[-1].place(x=10 + (120 * i), y=105)
textvars.append(tk.StringVar())
textvars[-1].set("Change Ip")
entries.append(tk.Entry(area, textvariable=textvars[-1]))
entries[-1].place(x=10 + (120 * i), y=160, width=100)
if __name__ == "__main__":
root = tk.Tk()
"""Calculate center of screen so popup is center"""
w = 650
h = 400
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws / 2) - (w / 2)
y = (hs / 2) - (h / 2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
# This line prevents the user from changing the size of the window
root.resizable(width=False, height=False)
app = Application(root)
root.mainloop()
The variable should by specified in Entry by textvariable and defined at the beginning using StringVar(), check the following code
from Tkinter import *
import ttk
root = Tk()
root.title("GUI titile")
root.geometry("200x100")
variable1 = StringVar()
variable2 = StringVar()
entry1 = Entry(root,textvariable=variable1)
entry1.pack()
entry2 = Entry(root,textvariable=variable2)
entry2.pack()
root.mainloop()
GUI output image :
NOTE: imports differ according to python version
Related
for one of my first little projects I coded a fitnesscalculator last evening. Which has 3 functionalities at the start: Calculating the 1RM, BMI and FFMI. I'm running into the problem of overlapping labels when I first calculate the 1RM and then the FFMI. I have already googled and looked for similar threads but I couldn't find an answer to my solutions as my Gui is and its functionalities are based around a combobox. Please excuse the rather messy code, but I have already tried several methods to deal with this problem
from tkinter import *
from PIL import Image, ImageTk
from tkinter import ttk
root = Tk()
root.geometry("400x400")
root.title("Fitness Calculator")
#dropdown
Options = ["1RM Calculator", "BMI Calculator", "FFMI Calculator"]
#functions
def picker(input):
global calculate_button
global bf_box
global bf_label
global result_label
global result2_label
global result3_label
calculate_button.destroy()
result_label.pack_forget()
result2_label.destroy()
result3_label.destroy()
bf_label.destroy()
bf_box.destroy()
selected = drop.get() #holt sich wert vom dropdown
####################RM CALCULATOR####################
if selected == Options[0]:
#labels
weight_label = Label(root,text="Enter your training weight here: ", padx=10, pady=10)
weight_label.grid(row=2, column=0, sticky=W)
reps_label = Label(root,text="Enter your repetitions here: ", padx=10)
reps_label.grid(row=3, column=0, sticky=W)
def calculate():
weight = int(weight_box.get())
reps = int(reps_box.get())
one_rm = round(weight*(36/(37-reps)), 2)
#Result
result_label = Label(root, text="Your 1RM is: " + str(one_rm) + " kg")
result_label.grid(row=4)
weight_box.delete(0,END)
reps_box.delete(0,END)
#Entryfields
weight_box = Entry(root)
weight_box.grid(row=2, column=1)
reps_box = Entry(root)
reps_box.grid(row=3, column=1)
#Calculate button
calculate_button = Button(root,text="Calculate",command=calculate, width=16 )
calculate_button.grid(row=4,column=1,pady=10)
####################BMI CALC####################
if selected == Options[1]:
#LABELS
weight_label = Label(root,text="Enter your weight in kg here: ", padx=10, pady=10)
weight_label.grid(row=2, column=0, sticky=W)
height_label = Label(root,text="Enter your height in cm here: ", padx=10)
height_label.grid(row=3, column=0, sticky=W)
#ENTRY BOXES
weight_box = Entry(root)
weight_box.grid(row=2, column=1)
height_box = Entry(root)
height_box.grid(row=3, column=1)
def calculate():
weight = float(weight_box.get())
height = float(height_box.get())/100
bmi = round(weight/(height**2),0)
#Result
result_label = Label(root, text="Your BMI is: " + str(bmi))
result_label.grid(row=4)
weight_box.delete(0,END)
height_box.delete(0,END)
#Calculate button
calculate_button = Button(root,text="Calculate",command=calculate, width=16 )
calculate_button.grid(row=4,column=1,pady=10)
####################FFMI####################
if selected == Options[2]:
calculate_button.destroy()
#LABELS
weight_label = Label(root,text="Enter your weight in kg here: ", padx=10,pady=5)
weight_label.grid(row=2, column=0, sticky=W)
height_label = Label(root,text="Enter your height in cm here: ", padx=10,pady=5)
height_label.grid(row=3, column=0, sticky=W)
bf_label = Label(root,text="Enter your estimated bodyfat % here: ", padx=10,pady=5)
bf_label.grid(row=4, column=0, sticky=W)
#ENTRY BOXES
weight_box = Entry(root)
weight_box.grid(row=2, column=1)
height_box = Entry(root)
height_box.grid(row=3, column=1)
bf_box = Entry(root)
bf_box.grid(row=4, column=1)
def calculate():
weight = float(weight_box.get())
height = float(height_box.get())/100
bf = float(bf_box.get())
total_bf = weight*(bf)
lean_weight = weight*(1-(bf/100))
ffmi = round((lean_weight/height**2),2)
adjusted_ffmi = ffmi + 6.1 * (1.8 - height)
#Result
result_label = Label(root, text="Lean Mass: " + str(lean_weight) + " kg")
result_label.grid(row=6, sticky=W, padx=5)
result_label2 = Label(root, text="FFMI: " + str(ffmi))
result_label2.grid(row=7, sticky=W, padx=5)
result_label3 = Label(root, text="adjusted-FFMI: " + str(adjusted_ffmi))
result_label3.grid(row=8,sticky=W, padx=5)
weight_box.delete(0,END)
height_box.delete(0,END)
bf_box.delete(0,END)
#Calculate button
calculate_button = Button(root,text="Calculate",command=calculate, width=16 )
calculate_button.grid(row=5,column=1,pady=10)
calculate_button = Button(root,text="Calculate", width=16 )
calculate_button.grid(row=4,column=1,pady=10)
calculate_button.destroy()
#Dropdownbox
drop = ttk.Combobox(root, value=Options, state="readonly")
drop.current(0)
drop.grid(row=0)
drop.bind("<<ComboboxSelected>>", picker)
result_label = Label(root,text="test")
result_label.grid(row=4)
result2_label = Label(root,text="")
result2_label.grid(row=4)
result3_label = Label(root,text="")
result3_label.grid(row=4)
bf_label = Label(root)
bf_box = Entry(root)
picker(drop.current(0))
root.mainloop()
Here a Screenshot of the problem I'm referencing to:
You keep creating a new Label with name result_label in your calculate methods.
This piles the labels on top of each other, since the result_label.destroy() does not remove them from the grid.
Instead of destroying them, keep just one instance (which you already defined global) and then configure them with the new text:
result_label.config(text="Your BMI is: " + str(bmi))
I've made a simple GUI for placing objects in RoboDK via a Python script using Tkinter.
Essentailly, the user selects an object using the btnSelect button, which then updates the entry widgets with its coordinates (x, y, z, then Euler rotation). The user can then edit the entry widgets then select the "Move object" button (or btnMove in the code) to move the object to the new position. However, when selecting an object for the second time, the entry fields cannot be edited without selecting a new object.
from tkinter.constants import DISABLED, NORMAL, CENTER, END
from typing import *
import tkinter as tk
import threading
from robolink import * # RoboDK API
from robodk import * # Robot toolbox
X_MAX = 500
X_MIN = 0
Y_MAX = 300
Y_MIN = -360
ROTZ_MAX = 180
ROTZ_MIN = -180
# Keep track of selected item
obj = None
def main():
rdk = Robolink()
window = buildGUI(rdk)
window.mainloop()
def buildGUI(rdk: Robolink) -> tk.Tk:
window = tk.Tk()
canvas = tk.Canvas(window, width=200)
canvas.grid(columnspan=3, rowspan=14)
# Set the window title (must be unique for the docking to work, try to be creative)
window_title = 'Move object window'
window.title(window_title)
title = tk.Label(window, text="Move Object", font="none 14 bold")
title.grid(columnspan=3, column=0, row=0)
# Delete the window when we close it
window.protocol("WM_DELETE_WINDOW", lambda: onClose(window))
deadspace1 = tk.Label(text="")
deadspace1.grid(columnspan=3, column=0, row=1)
selectText = tk.StringVar()
btnSelect = tk.Button(window, textvariable=selectText, height=2, width=0,
bg="#bbbbbb", fg='white', justify=CENTER)
selectText.set("Select object")
btnSelect.grid(column=1, row=2)
deadspace2 = tk.Label("")
deadspace2.grid(columnspan=3, column=0, row=3)
objName = tk.StringVar()
objLabel = tk.Label(window, textvariable=objName, font="none 12 bold")
objName.set("None Selected")
objLabel.grid(columnspan=3, column=0, row=4)
deadspace2 = tk.Label("")
deadspace2.grid(columnspan=3, column=0, row=5)
# Position options
xLabel = tk.Label(window, text="x: ", font='none 12')
xLabel.grid(column=0, row=6)
xEntry = tk.Entry(window, width=10)
xEntry.grid(columnspan=2, column=1, row=6)
yLabel = tk.Label(window, text="y: ", font='none 12')
yLabel.grid(column=0, row=7)
yEntry = tk.Entry(window, width=10)
yEntry.grid(columnspan=2, column=1, row=7)
zLabel = tk.Label(window, text="z: ", font='none 12')
zLabel.grid(column=0, row=8)
zEntry = tk.Entry(window, width=10)
zEntry.grid(columnspan=2, column=1, row=8)
# Rotation options
rxLabel = tk.Label(window, text="rx: ", font='none 12')
rxLabel.grid(column=0, row=9)
rxEntry = tk.Entry(window, width=10)
rxEntry.grid(columnspan=2, column=1, row=9)
ryLabel = tk.Label(window, text="ry: ", font='none 12')
ryLabel.grid(column=0, row=10)
ryEntry = tk.Entry(window, width=10)
ryEntry.grid(columnspan=2, column=1, row=10)
rzLabel = tk.Label(window, text="rz: ", font='none 12')
rzLabel.grid(column=0, row=11)
rzEntry = tk.Entry(window, width=10)
rzEntry.grid(columnspan=2, column=1, row=11)
entries = [xEntry, yEntry, zEntry, rzEntry, ryEntry, rxEntry]
deadspace3 = tk.Label(text="")
deadspace3.grid(columnspan=3, column=0, row=12)
btnMove = tk.Button(window, text="Move object", height=2, width=0,
bg="#bbbbbb", fg='white', justify=CENTER,
command=lambda: moveObject(entries))
btnMove.grid(column=1, row=13)
selectCallback = lambda: select_item(rdk, selectText, objName, entries)
btnSelect['command'] = selectCallback
EmbedWindow(window_title)
return window
# Close the window
def onClose(window: tk.Tk):
window.destroy()
quit(0)
def select_item(rdk: Robolink, selectText: tk.StringVar, objName: tk.Label,
entries: List[tk.Entry]):
def thread_btnSelect():
selectText.set("Waiting...")
item = rdk.ItemUserPick('Select an item', ITEM_TYPE_OBJECT)
if item.Valid():
global obj
obj = item
objName.set(item.Name())
updateObjectPosition(item, entries)
selectText.set("Select object")
# Prevent RoboDK from freezing
threading.Thread(target=thread_btnSelect).start()
def updateObjectPosition(item: Item, entries: List[tk.Entry]):
pose = item.Pose()
coords = Pose_2_KUKA(pose)
for entry, coord in zip(entries, coords):
entry.delete(0, END)
entry.insert(0, str(coord))
def moveObject(entries: tk.Entry):
global obj
if obj is None:
ShowMessage("No object selected")
return
try:
coords = getCoords(entries)
obj.setPose(KUKA_2_Pose(coords))
except Exception as err:
ShowMessage(str(err))
def getCoords(entries: List[tk.Entry]) -> list:
coords = [0] * 6
for i, entry in enumerate(entries):
coords[i] = float(entry.get())
return coords
if __name__ == "__main__":
main()
Using a tkinter.Variable such as tkinter.DoubleVar with your entries should fix this issue. You can also use tkinter.DoubleSpin for convenience.
x, y, z, rx, ry, rz = Pose_2_TxyzRxyz(item.Pose())
xVar = tk.DoubleVar(value=x)
xEntry = tk.Spinbox(window, textvariable=xVar, format="%.2f", from_=-9999999, to=9999999)
xVal = xVal.get()
I'm creating a frame which has many that are build vertically and I need a scrollbar to make them all visible. To do that I embedded my frame on a canvas.
The problem is that the widgets on the frame require more width that what the canvas provides as shown below
If I don't embed the frame on a canvas, then the widgets take the proper amount of width and are resized properly. I believe that the problem is the the canvas spans across 1 column whereas the widgets in the canvas require more than 2. I used `columnspan=2' on the canvas but the widgets on the embedded frame are still cut; they are just zoomed.
Is there a way to expand the width of the canvas according to the width they frame wants?
Here's an example code
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from PIL import ImageTk, Image
import os
# Method to make Label(Widget) invisible
def hide_frame(frame):
# This will remove the widget
frame.grid_remove()
# Method to make Label(widget) visible
def show_frame(frame, c, r):
# This will recover the widget
frame.grid(column=c, row=r)
def populate(frame):
'''Put in some fake data'''
for row in range(100):
tk.Label(frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="Blah blah blah blah blah blah blah blah %s" %row
tk.Label(frame, text=t).grid(row=row+4, column=1)
#____________________________________________________________________________________________
#This will be the main window
window = tk.Tk()
#window.geometry('1500x1200')
window.attributes('-zoomed', True)
window.title("daq")
frame_main = Frame(window)
frame_main.place(rely=0.10, relx=0.0, relwidth=1.0)
#Create a tabcontrol
tabControl = ttk.Notebook(frame_main)
tabControl.grid(column=0, row=1)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Digitizer tab
tab_Digitizer = ttk.Frame(tabControl)
tabControl.add(tab_Digitizer, text=' Digitizer ')
digitizer_tab_dummy_label = Label(tab_Digitizer, text="")
digitizer_tab_dummy_label.grid(column=0, row=0)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Channel settings
lbl_channel_registers = Label(tab_Digitizer, text="Channel registers", font='bold')
lbl_channel_registers.grid(column=0, row=3, sticky=W)
frame_channel_registers = Frame(tab_Digitizer)
frame_channel_registers.grid(column=0, row=4)
btn_hide_channel_registers = Button(tab_Digitizer, text="Hide", fg="red", command=lambda: hide_frame(frame_channel_registers) )
btn_hide_channel_registers.grid(column=1, row=3)
btn_show_channel_registers = Button(tab_Digitizer, text="Show", fg="green", command=lambda: show_frame(frame_channel_registers, 0, 4))
btn_show_channel_registers.grid(column=2, row=3)
##Channel settings - PSD
def onFrameConfigure(event):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
def handle_user_scrolling(event):
canvas.yview_scroll(int(-event.delta/abs(event.delta)), "units")
def handle_scrollbar_scrolling(event):
canvas.configure(scrollregion=canvas.bbox("all"))
lbl_PSD_channel_registers = Label(frame_channel_registers, text="DPP-PSD registers")
lbl_PSD_channel_registers.grid(column=0, row=3, padx=5, sticky=W)
btn_hide_PSD_channel_registers = Button(frame_channel_registers, text="Hide", fg="red", command=lambda: [hide_frame(canvas), hide_frame(myscrollbar)] )
btn_hide_PSD_channel_registers.grid(column=1, row=3)
btn_show_PSD_channel_registers = Button(frame_channel_registers, text="Show", fg="green", command=lambda: [show_frame(canvas, 0, 4), show_frame(myscrollbar, 1, 4)])
btn_show_PSD_channel_registers.grid(column=2, row=3)
canvas = tk.Canvas(frame_channel_registers, borderwidth=1, background="#FF0000")
frame_PSD_channel_registers = Frame(canvas, background="#0000FF")
frame_PSD_channel_registers.grid(column=0, row=0, padx=25, sticky=W)
frame_PSD_channel_registers.bind("<MouseWheel>", handle_user_scrolling)
frame_PSD_channel_registers.bind("<Configure>", handle_scrollbar_scrolling)
myscrollbar=Scrollbar(frame_channel_registers ,orient="vertical", command=canvas.yview)
#canvas.configure(yscrollcommand=myscrollbar.set)
canvas.configure(scrollregion=canvas.bbox("all"))
myscrollbar.grid(column=1, row=4, sticky=NS)
canvas.grid(column=0, row=4, columnspan=3)
#frame_PSD_channel_registers = Frame(canvas, background="#0000FF")
#frame_PSD_channel_registers.grid(column=0, row=0, padx=25, sticky=W)
#frame_PSD_channel_registers.bind("<MouseWheel>", handle_user_scrolling)
#frame_PSD_channel_registers.bind("<Configure>", handle_scrollbar_scrolling)
canvas.create_window((0, 0), window=frame_PSD_channel_registers, anchor="nw")
canvas.configure(yscrollcommand=myscrollbar.set)
###### PSD channels settings
#Short gate
def short_gate_width_selection(event):
print ("Short gate width : " + str( entry_short_gate_width.get() ) + " " + var_short_gate_width_unit.get() )
pass
lbl_short_gate_width = Label(frame_PSD_channel_registers, text="Short gate width")
lbl_short_gate_width.grid(column=0, row=0, padx=25, sticky=W)
var_short_gate_width = IntVar(frame_PSD_channel_registers)
var_short_gate_width.set("15")
entry_short_gate_width = Entry(frame_PSD_channel_registers, width=10, textvariable=var_short_gate_width, exportselection=0)
entry_short_gate_width.grid(column=1, row=0, sticky=W)
opt_short_gate_width = ["samples", "ns"]
var_short_gate_width_unit = StringVar(frame_PSD_channel_registers)
var_short_gate_width_unit.set(opt_short_gate_width[0]) # default value
short_gate_width_unit = OptionMenu(frame_PSD_channel_registers, var_short_gate_width_unit, *opt_short_gate_width, command = short_gate_width_selection)
entry_short_gate_width.bind('<Return>', short_gate_width_selection)
short_gate_width_unit.grid(column=2, row=0, sticky=W)
#Long gate
def long_gate_width_selection(event):
print ("Long gate width : " + str( entry_long_gate_width.get() ) + " " + var_long_gate_width_unit.get() )
pass
lbl_long_gate_width = Label(frame_PSD_channel_registers, text="Long gate width")
lbl_long_gate_width.grid(column=0, row=1, padx=25, sticky=W)
var_long_gate_width = IntVar(frame_PSD_channel_registers)
var_long_gate_width.set("100")
entry_long_gate_width = Entry(frame_PSD_channel_registers, width=10, textvariable=var_long_gate_width, exportselection=0)
entry_long_gate_width.grid(column=1, row=1, sticky=W)
opt_long_gate_width = ["samples", "ns"]
var_long_gate_width_unit = StringVar(frame_PSD_channel_registers)
var_long_gate_width_unit.set(opt_long_gate_width[0]) # default value
long_gate_width_unit = OptionMenu(frame_PSD_channel_registers, var_long_gate_width_unit, *opt_long_gate_width, command = long_gate_width_selection)
entry_long_gate_width.bind('<Return>', long_gate_width_selection)
long_gate_width_unit.grid(column=2, row=1, sticky=W)
#Extras word options
def extras_word_options_selection(event):
if 'Counter' in var_extras_word_options_selection.get():
extras_word_options_step_counter.grid(column=2, row=22, sticky=W)
else:
extras_word_options_step_counter.grid_remove()
print ("Extras word options : " + var_extras_word_options_selection.get() )
pass
def extras_word_options_step_counter_selection(event):
print ("Step for trigger counter : ", var_extras_word_options_step_counter.get() )
pass
lbl_extras_word_options_selection = Label(frame_PSD_channel_registers, text="Extras word options")
lbl_extras_word_options_selection.grid(column=0, row=22, padx=25, sticky=W)
opt_extras_word_options_selection = ["[31:16] = Extended Time Stamp , [15:0] = Baseline * 4",
"[31:16] = Extended Time Stamp , [15:0] = Flags",
"[31:16] = Extended Time Stamp , [15:10] = Flags, [9:0] = Fine Time Stamp",
"[31:16] = Lost Trigger Counter , [15:0] = Total Trigger Counter",
"[31:16] = Positive Zero Crossing, [15:0] = Negative Zero Crossing",
"Fixed value = 0x12345678 (debug use only)."]
var_extras_word_options_selection = StringVar(frame_PSD_channel_registers)
var_extras_word_options_selection.set(opt_extras_word_options_selection[2]) # default value
extras_word_options_selection = OptionMenu(frame_PSD_channel_registers, var_extras_word_options_selection, *opt_extras_word_options_selection, command = extras_word_options_selection)
extras_word_options_selection.grid(column=1, row=22, sticky=W)
#This keeps the window open - has to be at the end
window.mainloop()
I am trying to make a staffing calculator using GUI tkinter in python I expect to get the function calculation results once I fill all entries and click on calculate button in a new window (master) based on the entry but unfortunately I got an empty label in the new window also I am not reeving any error to fix, would you please help me?, here is my code and screen shot:
from tkinter import *
root = Tk()
root.title("Workload Staffing Calculator")
#Header
headerlab = Label(root, text="Please fill the below form and click calculate to get the required staff.").grid(row=0,columnspan=2,pady=20,padx=20)
#Inputs names
vollabel = Label(root, text="Volumes").grid(padx=0,pady=10)
ahtlabel = Label(root, text="AHT (sec.)").grid(padx=0, pady=10)
Occlabel = Label(root, text="Occupancy (%)").grid(padx=0, pady=10)
Shrinklabel = Label(root, text="Shrinkage (%)").grid(padx=0, pady=10)
weekendlabel = Label(root, text="Days Off").grid(padx=0, pady=10)
Shiftlabel = Label(root, text="Shift Duration (h)").grid(padx=0, pady=10)
#Entry inptus
volentry = Entry(root, width=10, borderwidth=3)
ahtentry = Entry(root, width=10, borderwidth=3)
occentry = Entry(root, width=10, borderwidth=3)
shrinkentry = Entry(root, width=10, borderwidth=3)
weekendentry = Entry(root, width=10, borderwidth=3)
shiftentry = Entry(root, width=10, borderwidth=3)
#shoving inputs on screen
volentry.grid(row=1, column=1, padx=20)
ahtentry.grid(row=2, column=1, padx=20)
occentry.grid(row=3, column=1, padx=20)
shrinkentry.grid(row=4, column=1, padx=20)
weekendentry.grid(row=5, column=1, padx=20)
shiftentry.grid(row=6, column=1, padx=20)
#Calculate Fuction
def calstaff() :
v = volentry.get()
a = ahtentry.get()
o = occentry.get()
s = shrinkentry.get()
w = weekendentry.get()
sh = shiftentry.get()
required = (int(v) * int(a)) / (int(sh) * 3600)
total = required * (7 / (7 - int(w))) * (1 + float(s))
newwindow = Tk()
newwindow.title("The required is: ")
result = Label(newwindow, textvariable=total).pack()
return result
#calculate button
calculate = Button(root, text="Calculate", command=calstaff)
calculate.grid(padx=20,pady=10)
root.mainloop()
It is not recommended to use Tk() more than once as it can interrupt the flow of the main loop. To create another window you should try using Toplevel()
Secondly, Instead of textvariable use text
Refer to the code below:
.
..
def calstaff() :
v = volentry.get()
a = ahtentry.get()
o = occentry.get()
s = shrinkentry.get()
w = weekendentry.get()
sh = shiftentry.get()
required = (int(v) * int(a)) / (int(sh) * 3600)
total = required * (7 / (7 - int(w))) * (1 + float(s))
newwindow = Toplevel() #TOPLEVEL() USED
newwindow.title("The required is: ")
result = Label(newwindow, text=total) #text instead of textvariable
result.pack()
newwindow.mainloop() #mainloop for newwindow
..
I am trying to make the following layout
tkinter layout
but the ID: label and the entry box are center left , and center right when then they should be next to each other , and they keep getting separated by the grid
I am also trying to use a for loop to make the number pad but im not sure how to make a new variable outside of the loops, and increment by 1 in the loop that creates the button
from tkinter import *
window = Tk()
#BOTTOM FRAME SECTION
bottomframe = Frame(window,bg="cyan", width =900, height = 100)
bottomframe.pack(fill=BOTH,side=BOTTOM)
button = Button(window,text="LOG IN")
button.pack(fill=BOTH,side=BOTTOM)
checkbutton = Checkbutton(window, text="Use pseudonym?")
checkbutton.pack(side=BOTTOM)
topframe = Frame(window,bg="red",width =900, height = 100)
topframe.pack(fill=BOTH,side=TOP)
label1 = Label(window, text="Majestic 12 Identifier")
label1.pack(side=TOP)
label2 = Label(window, text="ID")
label2.pack(side=LEFT)
label3 = Label(window,text="Enter keycode:")
label3.pack(side=TOP)
entry1 = Entry(window)
entry1.pack(side=LEFT)
#GRID SECTION
frame = Frame(window)
frame.pack(fill=BOTH,side=BOTTOM)
n = +1
for i in range(3):
Grid.rowconfigure(frame,i,weight=1)
Grid.columnconfigure(frame,i,weight=1)
for i in range(3):
b = Button(frame, text="%d" % (i+n))
for j in range(3):
b = Button(frame, text="%d" % (j+1))
b.grid(row=i, column=j,ipadx=2,ipady=2,padx=2,pady=2,sticky= W+E+N+S)
window.mainloop()
any help is welcome
Ok, I gave it a try. I played around a bit with the Frame objects. I deleted one, that was not needed. And I introduced topframe2 in order to make it possible for label2 and entry1 to be in the same row.
Watch carefully the parent of the various entries and labels. Not everything should get the window object as direct parent.
I am using expand and fill arguments - here I am basically applying what I just learned at Textbox not expanding with containing frame - TKinter and tkinter gui layout using frames and grid
from tkinter import *
window = Tk()
# BOTTOM FRAME SECTION
topframe = Frame(window, width=900, height=100)
topframe.pack(fill=BOTH, side=TOP)
label1 = Label(topframe, text="Majestic 12 Identifier")
label1.pack(side=TOP, fill=BOTH, expand=1)
topframe2 = Frame(topframe, width=900, height=100)
topframe2.pack(fill=BOTH, side=TOP)
label2 = Label(topframe2, text="ID")
label2.pack(side=LEFT)
entry1 = Entry(topframe2)
entry1.pack(side=LEFT, fill=X, expand=1)
label3 = Label(window, text="Enter keycode:")
label3.pack(side=TOP)
# GRID SECTION
frame = Frame(window)
frame.pack(fill=BOTH, side=TOP, expand=1)
n = +1
for i in range(3):
Grid.rowconfigure(frame, i, weight=1)
Grid.columnconfigure(frame, i, weight=1)
for i in range(3):
b = Button(frame, text="%d" % (i + n))
for j in range(3):
b = Button(frame, text="%d" % (j + 1))
b.grid(row=i, column=j, ipadx=2, ipady=2, padx=2, pady=2, sticky=W + E + N + S)
button = Button(window, text="LOG IN")
button.pack(fill=BOTH, side=BOTTOM)
checkbutton = Checkbutton(window, text="Use pseudonym?")
checkbutton.pack(side=BOTTOM)
if __name__ == '__main__':
window.mainloop()