I am using python 3.7 and tkinter.
I want to display text information which is periodically updated and I want to display it in a table format where each cell is of fixed width. Without going into too many specifics, I am using grid geometry manager. Unfortunately, the text is not displaying in the cells, and I don't know why.
I understand the construct of my "table"-like GUI is not as simple as it could be. I want to be able to easily hide/show rows, so I have given each row its own frame making it easy to show/hide any row. (I have also used a grid layout within each row as well, thinking that this will be the easiest way to eventually force the geometry manager to give me uniform/non-changing cell widths.)
My first problem is that no text is displaying in my labels in the "table".
I have verified via print('label text = ', label.cget("textvariable")), that the correct textvariable was in fact assigned to the label.
I have read many posts regarding "tkinter label text not showing" and nothing has helped.
Thank you for any insights. Here is the code:
driverList = ['bob','fred','ethel']
tracks = ['daytona', 'charlotte', 'atlanta', 'darlington','lasvegas','watkins','talladega']
dynamicAllDriverFlagReportDict = {'bob': ['bob','i','','RevDn','','','',''],
'fred': ['fred','In-Up','','','','RevUp','Ham',''],
'ethel': ['ethel','','RevDn','','','In-Dn','Sht','']
}
global driverFrameDict
driverFrameDict= dict()
# Set up the GUI
window = tk.Tk()
myDataFrame = tk.Frame(master=window)
myDataFrame.pack()
btnFrame= tk.Frame(master=window, bg="gray")
btnFrame.pack(side="bottom")
for driverIndex in range(len(driverList)):
myOneStockFrame = tk.Frame(master=myDataFrame, height=25, width=800)
for tfIndex in range(len(tracks)+1):
oneTFFrame = tk.Frame(master=myOneStockFrame,relief=tk.RAISED, borderwidth=1)#, height=25)#, width=8)
if tfIndex == 0:
label = tk.Label(master=oneTFFrame,text=driverList[driverIndex])#, height=15, width=8)
else:
print('driverIndex=', driverIndex, '; tfIndex=', tfIndex, 'dynamicAllDriverFlagReportDict=', dynamicAllDriverFlagReportDict[driverList[driverIndex]][tfIndex])
label = tk.Label(master=oneTFFrame,textvariable=dynamicAllDriverFlagReportDict[driverList[driverIndex]][tfIndex])#,height=20)#, width=8)
print('label text = ', label.cget("textvariable"))
label.pack()#padx=5,pady=5)
#label.pack_propagate(0)
oneTFFrame.grid(row=0,column=tfIndex)#, sticky= "nswe", padx=0, pady=0)
#oneTFFrame.grid_propagate(0)
myOneStockFrame.grid(row=driverIndex,column=0)#, sticky= "nswe", padx=0, pady=0)
#myOneStockFrame.grid_propagate(0)
driverFrameDict[driverList[driverIndex]] = myOneStockFrame
#print('driverFrameDict['+driverList[driverIndex]+'] = ', myOneStockFrame)
window.mainloop()
Here is the output:
Thank you.
textvariable has to be set to an instance of one of the special tkinter variables (StringVar, etc). You're passing a string, which causes a new internal variable to be created with a name that matches the string.
Related
I'm attempting to create a simple point of sale system where when a button is pressed, its quantity and price are added up and eventually a total is shown (haven't gotten to this bit yet)
I've decided to also incorporate a clear button which will clear the frame in which the clicked items and their prices + quantities are shown however I'm having some problems with clearing the frame and still being able to click buttons afterwards.
This is the code I have for the Item button:
def AddButton():
global item_num #calls global variable
item_num += 1
item_text = "Chips 2.00"+" "+str(item_num) #concatonates text & variable
item1.config(text=item_text) #updates label text - doesn't add multiple
item1.pack()
addButton = Button(itemFrame, text="Chips", width=10, height=10, command=AddButton)
addButton.grid(row=1, column=1)
item1 = Label(receiptFrame)
and I began by trying to use .destroy like this:
def clearClick(): #blank function for clear button
receiptFrame.destroy()
however, since this completely deletes the frame, I'm then not able to re-input more items after it's been cleared
I also tried re-creating the frame:
def clearClick(): #blank function for clear button
receiptFrame.destroy()
receiptFrame = Frame(root, width=600, height=500, bd=5, relief="ridge")
receiptFrame.grid(row=1, column=3, columnspan=2)
but this still doesn't work
Is there a way to clear the contents of a frame without deleting the frame itself or does .destroy have to be used?
fr.winfo_children() returns the list of widgets inside the frame:
root = tk.Tk()
fr = tk.Frame()
lb = tk.Label(fr)
lb.grid()
print(fr.winfo_children())
for child in fr.winfo_children():
child.destroy()
print(fr.winfo_children()) # Now empty
Apologies if this was answered before but I cannot find anything out there with these specifics.
I'm finishing a query tool for the team I'm working with where they can choose the fields to query a database and a search a string (along with other options).
The result is being sent to a Tkinter TreeView widget (found this to be the best approach in terms of events control and visualization).
I have a main issue which is to constrain the size of the Treeview to a certain width, no matter how many fields the user chooses. Since the complete GUI is non scalable I want the Treeview to have a max size.
I have tried to include the width when defining the columns, but it seems to bypass that.
The Treeview is a child of a LabelFrame and the positioning is defined with grid.
Here a code sample of what I'm doing to set the TreeView (since this is a company application I have to be careful with disclosing some field names):
CoreQuery.groupResults = LabelFrame(CoreQuery.root, text="Query Result", padx=5, pady=5, height=470,width=960)
CoreQuery.tree = ttk.Treeview(CoreQuery.groupResults, selectmode='browse')
CoreQuery.tree.bind("<Double-1>", CoreQuery.OnTreeDoubleClick)
CoreQuery.scrollbar_horizontal = ttk.Scrollbar(CoreQuery.root, orient='horizontal', command=CoreQuery.tree.xview)
CoreQuery.scrollbar_vertical = ttk.Scrollbar(CoreQuery.root, orient='vertical', command=CoreQuery.tree.yview)
CoreQuery.tree.config(height=18, xscrollcommand=CoreQuery.scrollbar_horizontal.set, yscrollcommand=CoreQuery.scrollbar_vertical.set)
CoreQuery.tree.grid(row=0, sticky="w")
CoreQuery.scrollbar_horizontal.grid(row=1,column=0, sticky='ns')
CoreQuery.scrollbar_vertical.grid(row=0, column=2, sticky='ew')
CoreQuery.scrollbar_horizontal.configure(command=CoreQuery.tree.xview)
CoreQuery.scrollbar_vertical.configure(command=CoreQuery.tree.yview)
CoreQuery.tree.configure(yscroll=CoreQuery.scrollbar_vertical, xscroll=CoreQuery.scrollbar_horizontal)
The Following is the method that receives the SQL query result and places the data in the TreeView:
def ScreenPrintResults(header,rows):
columns=len(header)
minColumnsize=math.ceil(965/columns)
#Clear Treeview
CoreQuery.tree.delete(*CoreQuery.tree.get_children())
for values in rows:
values[0] = str(values[0]).replace(".0", "")
if (values[0].isdigit()):
values[0] = int(values[0])
auxCount=0
CoreQuery.tree['columns']=header
for value in header:
CoreQuery.tree.heading(value, text=str(value))
CoreQuery.tree.column(value, stretch=tk.NO)
for items in rows:
if auxCount==0:
CoreQuery.tree.column('#0', width=30, stretch=tk.NO)
else:
CoreQuery.tree.column(value, width=minColumnsize)
CoreQuery.tree.insert('',tk.END,auxCount+1,text=str(auxCount+1),
values=list(items))
auxCount=auxCount+1
CoreQuery.updateMessage.config(foreground="Black", font="Verdana 10 bold")
CoreQuery.message.set("...")
Is there any kind of limitation I can add the width of the TreeView so that it does not go beyond a certain width?
Or do I need to split the available width to the number of columns I get from the query?
I honestly don't care if all the information is on screen, hence I placed the scrollbars.
Here is a screenshots of the issue:
Thanks for the help!
EDIT: Changed the For loop code and added more clarifying screenshots of the issue
The example below demonstrate how to set width for the columns the minwith and maxwidth which takes integers. Also you can set height of the row using the rowheight attribute for your text to display well in the tree.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
tree = ttk.Treeview(root, column=("col1","col2"), show="headings")
style = ttk.Style(root)
style.configure('my.Treeview', rowheight=50)
tree.configure(style='my.Treeview')
tree.heading("#0", text="COMPANY NAME")
tree.heading("#1", text="DEPARTMENT")
tree.heading("#2", text="BRANCH")
tree.column("#0", stretch=tk.NO, minwidth=100, width=000)
tree.column("#1", stretch=tk.NO, minwidth=100, width=400)
tree.column("#2", stretch=tk.NO, minwidth=100, width=400)
tree.insert("", tk.END, values=("Am using python version 3.6.1 \n on windows machine ", "This an example Tkinter Treeview in Python, which is from \nttk class make"))
tree.insert("", tk.END, values=("This an example Tkinter Treeview in Python, which is from \nttk class make sure #import ttk\n also from tkinter import *", "Apologies if this was answered before but I cannot find "))
tree.pack()
root.mainloop()
In my code I have a spin box that the user uses to select the number of teams they want, then in a separate frame columns are created to match the number of teams they chose, and when they use the spin box to change this value it also changes the number of columns
frame=Frame(root)
frame.pack(anchor=CENTER)
Label(frame,text='Team selection').grid(row=0,column=0,columnspan=5)
NumTeams=StringVar()
Spinbox(frame,values=(1,2,3,4,5),textvariable=NumTeams).grid(row=2,column=0,columnspan=5)
frame2=Frame(root)
frame2.pack()
for i in range(int(NumTeams.get())):
Label(frame2,text=str(i)).grid(row=0,column=i)
frame2.update()
The above code is an attempt at achieving this, does anyone know a way that this can be done?
You can use the command argument to specify a method to be run whenever your spinbox changes values. I'm not entirely sure what type of columns you mean, but hopefully you can work with this.
from Tkinter import *
def on_spin():
num_teams.set("New text")
root = Tk()
frame = Frame(root)
frame.pack(anchor=CENTER)
frame2 = Frame(root)
frame2.pack()
num_teams = StringVar()
label = Label(frame2, textvariable=num_teams)
label.pack()
spin = Spinbox(frame, from_=1, to=5, command=on_spin)
spin.pack()
root.mainloop()
I have written the following code:
from Tkinter import *
root = Tk()
root.title("Power Method")
labeltext1 = StringVar()
labeltext2 = StringVar()
labeltext1.set('Parameters') # Set start value
labeltext2.set('Epsilon')
label1 = Label (root, textvariable = labeltext1, height = 4)
label1.pack()
Entry(root, textvariable = labeltext1). pack()
label2 = Label (root, textvariable = labeltext2)
label2.pack()
Entry(root, textvariable = labeltext2). pack()
checkBox1 = Checkbutton(root, text = "NumPy")
checkBox1.pack()
checkBox2 = Checkbutton(root, text = "Not NumPy")
checkBox2.pack()
Button(root, text = "Exit").pack(side = RIGHT)
Button(root, text = "Compute").pack(side = RIGHT)
root.mainloop()
This code, when run, creates a window that contains Parameters, Epsilon as two places that you could enter value and NumPy and Not NumPy as checkboxes and finally a compute and exit button.
I am trying to format the code, in a way that Parameters and Epsilon appear on the left of the window, Numpy and Not Numpy infront of them on the right and Compute and Exit stay in their current positions.
Any help regarding the formatting would be appreciated.
Alright you need to google .grid() and .pack() and .place() for tkinter to learn more about what each is good for. For your case you could use any of them, but .grid() is probably the best and easiest for you to use.
To do this you must change .pack() to .grid() everywhere you have it, then you should use the row and column options to put your widgets where you want them. E.G.
label1.grid(row = 1, column = 1)
label2.grid(row = 1, column = 2)
this will put label2 on the right side of label1. The way .grid() works is that the columns are as wide as the largest (widest) widget in that column, same applies for rows.
if you need anything else just ask, but please do look at the documentations as Bryan said.
Here is the below code and I am having issues surrounding retrieving input from multiple values. I have been working on this issue for some time now without any suggest. I do appreciate the insight; however, I am at wits end. If someone could please provide a fix to my code I would be ever so grateful.
#!C:/Python27/python.exe
from Tkinter import *
import ImageTk, Image
root = Tk()
root.title('HADOUKEN!')
def retrieve_input(text,chkvar,v):
textarea_result = text.get()
checkbox_result = chkvar.get()
radiobutton_result = v.get()
root.destroy()
text = Text(root, height=16, width=40)
scroll = Scrollbar(root, command=text.yview)
text.configure(yscrollcommand=scroll.set)
text.grid(sticky=E)
scroll.grid(row=0,column=1,sticky='ns')
text.focus()
chkvar = IntVar()
chkvar.set(0)
c = Checkbutton(root, text="CaseIt", variable=chkvar)
c.grid(row=1,column=0,sticky=W)
v = ""
radio1 = Radiobutton(root, text="Src", variable=v, value=1)
radio1.grid(row=1,column=0)
radio1.focus()
radio2 = Radiobutton(root, text="Dst", variable=v, value=2)
radio2.grid(row=2,column=0)
b1 = Button(root, text="Submit", command=lambda: retrieve_input(text,chkvar,v))
b1.grid(row=1, column=2)
img = ImageTk.PhotoImage(Image.open("Hadoken.gif"))
panel = Label(root, image = img)
panel.grid(row=0, column=2)
root.mainloop()
print textarea_result
print checkbox_result
print radiobutton_result
You have several problems in your code, though most of them produce errors that should be self-explanatory. My suggestion is to start over with just a single widget, and get the logic working for that to reduce the number of things that could go wrong. Once you have that working, you can then add one widget at a time as you learn how to use that widget.
That being said, here are the most obvious errors that I spotted:
The first problem is that you are incorrectly calling the get method of a text widget. This method is documented to take two arguments -- a starting index and an ending index. Since tkinter always adds a trailing newline, you want to get everything from the start ("1.0"), to the end minus one character ("end-1c"). Thus, you should be getting the value in the text widget like this:
textarea_result = text.get("1.0", "end-1c")
The second problem is that retrieve_input seems to assume that v is a StringVar or IntVa since you are calling a get method on it. Given that you are using that variable with a radiobutton, that's what it should be. However, you created it as a normal variable, which of course doesn't have a get method. You should declare it as one of the special tkinter variables:
...
v = StringVar()
radio1 = Radiobutton(root, text="Src", variable=v, value=1)
...
The third problem is, retrieve_input is setting local variables. If you want to set the value of global variables (which I assume, since you are later trying to access them after the widget is destroyed), then you need to declare them as global:
def retrieve_input(text,chkvar,v):
global textarea_result, checkbox_result, radiobutton_result
...