I can't output my variable as a label in Tkinter - python

I would like to put a variable in a Tkinter label that prints out the value of the variable 'x'.
I tried to follow the example from the Tkinter documentation but it still seems to give me a trace error 'in second_click lblx2.place(window)'
x = max(numbers)
y = min(numbers)
z = sum(numbers)
a = float(z / len(numbers))
var_x = StringVar()
var_x.set(x)
lblx2 = Label(window, textvariable=var_x, font=('Arial Bold', 15), bg='blue', fg='red')
lblx2.place(window)
I expect it to just place the number on my window like regular text but it does not print anything.
The full error:
Exception in Tkinter callback
Traceback (most recent call last):
File "REDACTED", line 1705, in __call__ return self.func(*args)
File "REDACTED", line 49, in <lambda> btn['command'] = (lambda: second_click())
File "REDACTED", line 102, in second_click lblx2.place(window)
File "REDACTED", line 2188, in place_configure
File "REDACTED", line 1320, in _options cnf = _cnfmerge(cnf)
File "REDACTED", line 104, in _cnfmerge for c in _flatten(cnfs):
TypeError: object of type 'Tk' has no len()
When I remove (window) from place, it stops giving the errors but still does not put the number on the window

I believe the error is that window is not a suitable parameter for a Label object. Instead, it is used to change the location of the element. You could either
turn it into this: lblx2.place(x=whatever,y=whatever) (note: replace whatever with the location)
or
Remove the whole line of code entirely as it's unnecessary

Don't see a problem. Please provide a full example, not just pieces of code one cannot simply run. Here is mine, that DOESN'T reproduce the issue, and it really doesn't get much simpler than this:
from tkinter import *
from random import random
x = random()
root = Tk()
var_x = StringVar()
var_x.set(x)
Label(root, textvariable=var_x).pack()
root.mainloop()

Related

error when changing a Tkinter button command method

Code:
from tkinter import *
#screen 1
scr1 = Tk()
scr1.configure(bg='#2e3033')
canvas = []
teamCommentsButton = []
#update Vissuals
def updateTeams():
for x in range(6):
onClick = lambda : comments(x+10)
canvas[x].itemconfig(teamCommentsButton[x], command = onClick)
def comments (team):
print(team)
comments = Toplevel(scr1)
for x in range(6):
canvas.append(Canvas(scr1, width = 840, height = 326, bg='#2e3033', highlightthickness=1, highlightbackground='#2e3033'))
teamCommentsButton.append(Button(canvas[x], text='☰', command = lambda : comments(x), width = 2, height = 1))
teamCommentsButton[x].place(x = 20, y = 20)
canvas[x].grid(column = 0 if x < 3 else 1, row = (x if x < 3 else x - 3))
scr1.title('Pit TV - Match')
updateTeams()
scr1.mainloop()
Error:
Traceback (most recent call last):
File "c:\Users\user\Documents\Team 1710\Code\GKC2022\test.py", line 26, in <module>
updateTeams()
File "c:\Users\user\Documents\Team 1710\Code\GKC2022\test.py", line 13, in updateTeams
canvas[x].itemconfig(teamCommentsButton[x], command = onClick)
File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 2903, in itemconfigure
return self._configure(('itemconfigure', tagOrId), cnf, kw)
File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1636, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid boolean operator in tag search expression
I want to be able to change the parameter of a command in a Tkinter button but I get this error when I try to do it. I have tried changing the parameter to a constant onClick = lambda : comments(10) and I have tried directly putting the method call as the command command = comments(x+10) but both give me the same error
on top of that when I remove the call to updateTeams() the code runs without errors but prints 5 no matter which button I click. I would expect that it prints a range from 0-5 depending on the button I click because the parameter I set for each button is dependent on x.
here is what the window looks like when I remove updateTeams() window
You have two problems in your Code:
Problem 1
The buttons are not items of the canvases.
You have to treat the button like a regular tkinter widget and use configure:
teamCommentsButton[x].configure(command=onClick)
If you want the button to actually be inside the canvas you have to add it to another frame and add that frame as an item to the window using:
canvas[x].create_window((20, 20), window=buttonFrame)
Problem 2
In Python lambda functions created in loops will execute the same function. That means your lambdas in updateTeams() will always use x = 15. This can be avoided by using an own function for creating lambdas:
def create_lambda(x):
return lambda: comments(x + 10)

"can only concatenate str (not "int") to str" when zipping list of strings and list of objects

I get this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Hunter\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "c:\Users\Hunter\Documents\Programming\Python Scripts\Scripts\spoolClient\menuScript.py", line 46, in <lambda>
updateJsonButton = Button(preferences, text="Save Preferences", command=lambda: updateJson())
File "c:\Users\Hunter\Documents\Programming\Python Scripts\Scripts\spoolClient\menuScript.py", line 17, in updateJson
for i, j in zip(entryNames, entry):
File "C:\Users\Hunter\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1643, in cget
return self.tk.call(self._w, 'cget', '-' + key)
TypeError: can only concatenate str (not "int") to str
When trying to run my script:
from tkinter import *
from tkinter.ttk import *
from tkinter import messagebox
from tkinter import filedialog
import qrMaker
import qrReader
import json
settings = {}
#define vars
preferencesSkippedRows = [1, 3, 5, 7, 9, 11]
def openPreferences():
def updateJson():
print("here")
for i, j in zip(entryNames, entry):
print("loopdie")
value = str(j.get())
settings[i]=value
settingsjson = json.dumps(settings)
print(settingsjson)
f = open("preferences.json","w")
f.write(settingsjson)
f.close()
preferences = Tk()
preferences.title("Preferences")
preferences.iconbitmap(qrMaker.getCurrentPath()+'icon.ico')
preferences.geometry('400x600')
topText = Label(preferences, width=30, text="Filament Spool Client Preferences")
cameraText = Label(preferences, width=30, text="Select Camera Instance:")
cameraEntry = Combobox(preferences, width=30, values=qrReader.getCameras())
qrWidthText = Label(preferences, width=30, text="QR Output Width (in.)")
qrWidthEntry = Entry(preferences, width=30)
qrHeightText = Label(preferences, width=30, text="QR Output Height (in.)")
qrHeightEntry = Entry(preferences, width=30)
text = [cameraText, qrWidthText, qrHeightText]
entry = [cameraEntry, qrWidthEntry, qrHeightEntry]
entryNames = ['cameraEntry', 'qrWidthEntry', 'qrHeightEntry']
updateJsonButton = Button(preferences, text="Save Preferences", command=lambda: updateJson())
for i in preferencesSkippedRows:
preferences.grid_rowconfigure(i, minsize=10)
topText.grid(column = 0, row = 0)
row=2
for text, entry in zip(text, entry):
text.grid(column = 0, row = row)
entry.grid(column = 1, row = row)
row+=2
updateJsonButton.grid(column=1, row=row+2)
preferences.mainloop()
openPreferences() #I call script.openPreferences() in my main program but I left this here for debugging purposes
I can see from the error message that the error occurs somewhere in the line that my zip function occurs, but I have no idea what causes this. Oddly enough, this error goes away if instead of setting updateJson equal to the command value of my Tkinter button state, I set updateJson, which calls the function right as the button object is initialized. I also know what the error is saying, I just don't know where an integer is coming from, and how I can fix this issue. Any help would be appreciated.
Update: I've just found that the actual zipping of the two lists is not the problem, but when I introduce the for loop, the same error occurs.
Answering to close out this thread, answer from "user2357112 supports Monica".
The issue in this script is that for text, entry in zip(text, entry) literally uses "entry" in the for loop, and is executed after the button instance is created, meaning that if updateJson is called during the button object initialization, then there will be no error thrown as entry is still defined as a list. However, after for text, entry in zip(text, entry) executes at startup, entry is now defined as the last object in the list entry, no longer the list entry itself. When the user presses the button and updateJson is called, an error is thrown as entry is not a list anymore(I'm not 100% sure on the error part).

Class object has no attribute tk?

I am fairly new to python and with the help of tutorials I am trying to create a calculator but got stuck due to an error which I am unable to correct which occurs when I press a number button
from tkinter import *
root=Tk()
root.title("Yuvi's CAl")
global char
class cal():
def __init__(self):
self.string= StringVar()
root=Tk()
root.title("Yuvi's CAl")
self.string=StringVar
enter=Entry(root,textvariable=self.string)
enter.grid(row=0,column=0,columnspan=6)
values=["1","2","3","4","5","+","6","7","=","8","9","c"]
row=1
col=0
i=0
for txt in values:
if i==3:
row=3
col=0
if i==6:
row=4
col=0
if i==9:
row=5
col=0
if txt=="+":
but=Button(root,text=txt)
but.grid(row=row,column=col)
elif txt=="=":
but=Button(root,text=txt,command=lambda:self.equals)
but.grid(row=row,column=col)
elif txt=="c":
but=Button(root,text=txt,command=lambda:self.clr)
but.grid(row=row,column=col)
else:
but=Button(root,text=txt,command=lambda txt=txt:self.add(txt))
but.grid(row=row,column=col)
col+=1
i+=1
def add(self,char):
meet=self.string.get(self)
self.string.set((str(meet)) + (str(char)))
def equals(self):
result=eval(self.string.get())
self.string.set(result)
def clr(self):
self.string.set("")
ent=cal()
root.mainloop()
and this being the error when I press a number button
Traceback (most recent call last):
File "/usr/lib/python3.4/tkinter/__init__.py", line 1541, in __call__
return self.func(*args)
File "/home/yuvi/Documents/LiClipse Workspace/GUI/src/Misiio_calcuator.py", line 40, in <lambda>
but=Button(root,text=txt,command=lambda txt=txt:self.add(txt))
File "/home/yuvi/Documents/LiClipse Workspace/GUI/src/Misiio_calcuator.py", line 46, in add
meet=self.string.get(self)
File "/usr/lib/python3.4/tkinter/__init__.py", line 339, in get
value = self._tk.globalgetvar(self._name)
AttributeError: 'cal' object has no attribute '_tk'
Do rectify if any mistakes
Thank you in advance
There are several issues with your code first you should remove hiding your global vars within your __init__ as it creates two windows and only running mainloop for one of them. In addition you overwrite self.string with the StringVar class object after first creating an instance of it. So your __init__ could look like so
...
def __init__(self):
self.string=StringVar()
enter=Entry(root,textvariable=self.string)
enter.grid(row=0,column=0,columnspan=6)
values=["1","2","3","4","5","+","6","7","=","8","9","c"]
row=1
col=0
i=0
...
then in your add you don't have to pass self to self.string.get, that is it should look like
...
def add(self,char):
meet=self.string.get()
self.string.set((str(meet)) + (str(char)))
...
Those changes fixes your exception but I guess there are still other logical mistakes in the calculator, however that's not what the question is about and fixing them wouldn't help you learning python.

Using the lambda function in 'command = ' from Tkinter.

This is a very easy code to understand things :
Main :
import pdb
#pdb.set_trace()
import sys
import csv
sys.version_info
if sys.version_info[0] < 3:
from Tkinter import *
else:
from tkinter import *
from Untitled import *
main_window =Tk()
main_window.title("Welcome")
label = Label(main_window, text="Enter your current weight")
label.pack()
Current_Weight=StringVar()
Current_Weight.set("0.0")
entree1 = Entry(main_window,textvariable=Current_Weight,width=30)
entree1.pack()
bouton1 = Button(main_window, text="Enter", command= lambda evt,Current_Weight,entree1: get(evt,Current_Weight,entree1))
bouton1.pack()
and in another file Untitled i have the "get" function :
def get (event,loot, entree):
loot=float(entree.get())
print(loot)
When i run the main i receive the following error :
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/idlelib/run.py", line 121, in main
seq, request = rpc.request_queue.get(block=True, timeout=0.05)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/queue.py", line 175, in get
raise Empty
queue.Empty
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/tkinter/init.py", line 1533, in call
return self.func(*args)
TypeError: () missing 3 required positional arguments: 'evt', 'Current_Weight', and 'entree1'
How can i solve that ?
I thought the lambda function allows us to uses some args in a event-dependant function.
The command lambda does not take any arguments at all; furthermore there is no evt that you can catch. A lambda can refer to variables outside it; this is called a closure. Thus your button code should be:
bouton1 = Button(main_window, text="Enter",
command = lambda: get(Current_Weight, entree1))
And your get should say:
def get(loot, entree):
loot = float(entree.get())
print(loot)
Actually, you just need the Entry object entree1 as the lamda pass-in argument. Either statement below would work.
bouton1 = Button(main_window, text="Enter", command=lambda x = entree1: get(x))
bouton1 = Button(main_window, text="Enter", command=lambda : get(entree1))
with the function get defined as
def get(entree):
print(float(entree.get()))

Python and tkinter: NameError: global name 'roomChange' is not defined

I'm receiving the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
return self.func(*args)
File "D:\COMPUTER SCIENCE\Seating Plan\SeatingPlan TEST.py", line 205, in displayText
if roomChange.get().strip() == "":
NameError: global name 'roomChange' is not defined
When attempting to run the following code:
from tkinter import *
import tkinter.messagebox
def displayText():
""" Display the Entry text value. """
global roomChange
if roomChange.get().strip() == "":
tkinter.messagebox.showerror("Invalid Value", "Please enter a valid classroom name.")
else:
tkinter.messagebox.showinfo("Temporary Window", "Text value = " + roomChange.get().strip())
def roomChanger():
chrm = Tk()
chrm.title("Change Room")
chrm.wm_iconbitmap('./Includes/icon.ico')
chrm["padx"] = 40
chrm["pady"] = 20
# Create a text frame to hold the text Label and the Entry widget
textFrame = Frame(chrm)
#Create a Label in textFrame
roomChangeLabel = Label(textFrame)
roomChangeLabel["text"] = "Enter name of classroom: "
roomChangeLabel.pack(side=LEFT)
# Create an Entry Widget in textFrame
roomChange = Entry(textFrame)
roomChange["width"] = 50
roomChange.pack(side=LEFT)
textFrame.pack()
roomChangeButton = Button(chrm, text="Submit", command=displayText)
roomChangeButton.pack()
chrm.mainloop()
testButton = Button(window, text='Change Room', command=roomChanger)
testButton.place(x = 825, y = 360)
Can anyone suggest a solution to my problem?
Thanks
In roomChanger() you assign to roomChange:
roomChange = Entry(textFrame)
so you need to mark that name as a global inside that function too. Add a global roomChange statement in that function.
displayText() on the other hand, never tries to assign to roomChange and the global statement in that function can safely be removed.
I had the same problem.
Here was my solution:
from tkinter import *
from tkinter import messagebox
Some sort of namespace glitch. That second line shouldn't be necessary. Technically from a syntax perspective import * implies import messagebox too because it's part of it all.
Use those two lines, take away import tkinter.messagebox

Categories

Resources