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()
Related
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()
When the "view" button is pressed, it should trigger the function solution(i) such that label should be displayed in the new window. The problem is that the window opens and the previous label is packed but the label which gets it's text from "i" does not gets packed, Is there any issue in passing the parameter.
Any help is appreciated.
root = Tk()
root.config(background = "#303939")
root.state('zoomed')
def pre():
with open("DoubtSolution.txt","r+") as f:
dousol = f.read()
dousol_lst = dousol.split("`")
k = 0
window = Tk()
window.config(background = "#303939")
window.state('zoomed')
predoubt = Label(window,
text="Previous Doubts",
fg="Cyan",
bg="#303939",
font="Helvetica 50 bold"
).grid(row=0, column=1)
def solution(text):
print(text)
window1 = Tk()
window1.config(background="#303939")
window1.state('zoomed')
sol = Label(window1,
text=text[:text.find("~")],
font=font.Font(size=20),
bg="#303939",
fg="Cyan")
sol.pack()
window1.mainloop()
for i in dousol_lst:
if i[-5:] == admno:
doubt = Label(window, text=i[i.find("]]")+2:i.find("}}}}")], font=font.Font(size=20), bg="#303939",
fg="Cyan")
doubt.grid(row=2+k, column=1, pady=10)
view = Button(
master=window,
text="View", font=font.Font(size=15, family="Helvetica"),
activebackground="White",
bg="Teal",
bd=0.8,
fg="White",
command = lambda k = k:solution(i)
)
view.grid(row=2+k, column=2, padx=20)
k=k+1
window.mainloop()
previous = Button(
master=root,
text="Previous Doubts", font="Helvetica 22 bold",
activebackground="White",
bg="Teal",
bd=0.8,
fg="White",
command = pre
).grid(row=4, column=3, padx=20)
root.mainloop()
I am trying to clear the items on the window without closing the root window just the items visible.While everything is deleted Some of the labels are still left.I created a button "close" to remove the items.My code is as below;
from tkinter import*
root = Tk()
root.geometry("480x480")
# Node
myLabel1 = Label(root, text=f'Node')
myLabel1.grid(row=0, column=0)
rows = [] # show the input entry boxes
for i in range(6):
# name
entry = Entry(root, width=5, bd=5)
entry.grid(row=2+i, column=0)
# x
myLabel2 = Label(root, text=f'x{i}')
myLabel2.grid(row=2+i, column=1)
entry_x = Entry(root, width=5, bd=5)
entry_x.grid(row=2+i, column=2)
# y
myLabel3 = Label(root, text=f'y{i}')
myLabel3.grid(row=2+i, column=3)
entry_y = Entry(root, width=5, bd=5)
entry_y.grid(row=2+i, column=4)
# save current input row
rows.append((entry, entry_x, entry_y))
def close():
for name,ex,ey in rows:
name.destroy()
ex.destroy()
ey.destroy()
myLabel3.destroy()
myLabel2.destroy()
myLabel1.destroy()
myButton_close.destroy()
myButton_close = Button(root, text="close",padx = 10,pady = 10, command=close)
myButton_close.grid(row=8, column=6)
root.mainloop()
where could i be going wrong?
Create a Frame to hold the widgets and then you can destroy the frame to clear the window:
from tkinter import *
root = Tk()
root.geometry("480x480")
frame = Frame(root)
frame.pack(fill=BOTH, expand=1)
# Node
myLabel1 = Label(frame, text=f'Node')
myLabel1.grid(row=0, column=0)
rows = [] # store the input entry boxes
for i in range(6):
# name
entry = Entry(frame, width=5, bd=5)
entry.grid(row=2+i, column=0)
# x
myLabel2 = Label(frame, text=f'x{i}')
myLabel2.grid(row=2+i, column=1)
entry_x = Entry(frame, width=5, bd=5)
entry_x.grid(row=2+i, column=2)
# y
myLabel3 = Label(frame, text=f'y{i}')
myLabel3.grid(row=2+i, column=3)
entry_y = Entry(frame, width=5, bd=5)
entry_y.grid(row=2+i, column=4)
# save current input row
rows.append((entry, entry_x, entry_y))
def close():
frame.destroy()
myButton_close = Button(frame, text="close", padx=10, pady=10, command=close)
myButton_close.grid(row=8, column=6)
root.mainloop()
Grouping widgets into a frame make it easier to clear certain part of the window.
You create the labels in a loop but you are not saving any reference to the labels except for the last myLabel2/3. However you can ask a widget about its children, and then destroy them all:
def close():
for widget in root.winfo_children():
widget.destroy()
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
I am trying to get the input of what page number the user wants. They should type in a number, and click the submit button. To test it, I just want to print whatever they typed and then close the window. I've been following: http://effbot.org/tkinterbook/entry.htm as a guide, but I am stumped.
Why does
print(temp)
not print out a number to console?
right now it prints out:
<bound method IntVar.get of <tkinter.IntVar object at 0x000001FBC85353C8>>
I've cleaned up the code a little bit:
import sys
from file import *
from page import *
from view import View
import tkinter as tk
from tkinter import *
class ViewGui:
def __init__(self):
#Included in the class, but unrelated to the question:
self._file = File("yankee.txt", 25)
self.pages = self._file.paginate()
self.initial_list = self.pages[0].readpage(self._file.fo)
self.initial_string = ''.join(self.initial_list)
# Create root
self.root = Tk()
self.root.wm_title("yankee.txt - page 1")
# Create frame for buttons
self.bframe = Frame(self.root)
self.bframe.pack(side=BOTTOM, fill=X)
self.tbutton = tk.Button(self.bframe, text="Top", command=lambda a="top": self.clicks(a)).pack(side=LEFT, expand=1, fill=X)
self.bbutton = tk.Button(self.bframe, text="Bottom", command=lambda a="bottom": self.clicks(a)).pack(side=LEFT, expand=1, fill=X)
self.ubutton = tk.Button(self.bframe, text="Up", command=lambda a="up": self.clicks(a)).pack(side=LEFT, expand=1, fill=X)
self.dbutton = tk.Button(self.bframe, text="Down", command=lambda a="down": self.clicks(a)).pack(side=LEFT, expand=1, fill=X)
self.pbutton = tk.Button(self.bframe, text="Page", command=lambda a="page": self.pageclicks()).pack(side=LEFT, expand=1, fill=X)
self.qbutton = tk.Button(self.bframe, text="Quit", command=quit).pack(side=LEFT, expand=1, fill=X)
# Create and pack Text
self.T = Text(self.root, height=35, width=60, wrap=NONE)
self.T.pack(side=TOP, fill=X)
# Create and pack Scrollbar
self.S = Scrollbar(self.root, orient=HORIZONTAL, command=self.T.xview)
self.S.pack(side=BOTTOM, fill=X)
# Attach Text to Scrollbar
self.T.insert('1.0', self.initial_string)
self.T.config(xscrollcommand=self.S.set, state=DISABLED)
self.S.config(command=self.T.xview)
def pageclicks(self):
print("pageClicks is getting called at least...")
pop = Tk()
pop.wm_title("Page Number")
pop.label = Label(pop, text="Enter a Page Number:", width=35)
pop.label.pack(side=TOP)
pop.entrytext = IntVar()
Entry(pop, textvariable=pop.entrytext).pack()
pop.submitbuttontext = StringVar()
Button(pop, text="Submit", command=lambda a=pop: self.submitted(a)).pack(side=LEFT, pady=5, padx=40)
pop.cancelbuttontext = StringVar()
Button(pop, text="Cancel", command=pop.destroy).pack(side=LEFT, pady=5, padx=40)
def submitted(self, a):
print('submitted is getting called')
temp = (a.entrytext.get)
print(temp)
def clicks(self, a):
print("you clicked clicks with the " + a)
self.root.wm_title(self._file.filename + " - Page " + self._file.buttonHandler(a))
if __name__ == "__main__":
vg = ViewGui()
vg.root.mainloop()
When you create a new window you should not use Tk(), you must use tk.Toplevel()
Must change:
pop = Tk()
to
pop = tk.Toplevel()
You should also use get(), not just get. Must change:
temp = (a.entrytext.get)
to
temp = a.entrytext.get()
Code:
def pageclicks(self):
print("pageClicks is getting called at least...")
pop = tk.Toplevel()
pop.wm_title("Page Number")
pop.label = Label(pop, text="Enter a Page Number:", width=35)
pop.label.pack(side=TOP)
pop.entrytext = IntVar()
Entry(pop, textvariable=pop.entrytext).pack()
pop.submitbuttontext = StringVar()
Button(pop, text="Submit", command=lambda a=pop: self.submitted(a)).pack(side=LEFT, pady=5, padx=40)
pop.cancelbuttontext = StringVar()
Button(pop, text="Cancel", command=pop.destroy).pack(side=LEFT, pady=5, padx=40)
def submitted(self, a):
print('submitted is getting called')
temp = a.entrytext.get()
print(temp)
Made changes to these two methods and now it is working.
def pageclicks(self):
print("pageClicks is getting called at least...")
pop = Tk()
pop.wm_title("Page Number")
pop.label = Label(pop, text="Enter a Page Number:", width=35)
pop.label.pack(side=TOP)
pop._entry = Entry(pop)
pop._entry.pack()
pop._entry.focus_set()
Button(pop, text="Submit", command=lambda a=pop: self.submitted(a)).pack(side=LEFT, pady=5, padx=40)
Button(pop, text="Cancel", command=pop.destroy).pack(side=LEFT, pady=5, padx=40)
def submitted(self, _pop):
temp = _pop._entry.get()
print(temp)
_pop.destroy()