This is a GUI I’ve been writing for a script I already have working. What I’m struggling with here is retrieving the information in the textboxes.
Under the definition generate I am able to pop a name off of listx but I am unable to grab the local variable entry from any of the instances of the new_title_box class.
from Tkinter import *
import ttk
boxvar=""
folder=""
listx=[]
count = 1
myrow = 1
class new_title_box:
def __init__(self,name):
global myrow, count, listx
self.entry = StringVar()
self.name = name
self.name = ttk.Entry(mainframe,width=45,textvariable=self.entry)
self.name.grid(column=1,row=myrow+1,sticky=(N,W))
listx.append(name)
print(listx) ## For debugging to insure that it is working correctly, if it gives output it, this part works
myrow = myrow + 1
count=count+1
def make_new(*args):
new_title_box('box'+str(count))
def generate(*args):
global listx, boxvar
while len(listx) > 0:
boxvar=listx.pop(0)
print(boxvar) ## For debugging to insure that it is working correctly, if it gives output it, this part works
folder = boxvar.entry.get() ## Not working here
print(folder) ## For debugging to insure that it is working correctly, if it gives output it, this part works
root = Tk()
root.title("File Maker")
mainframe = ttk.Frame(root, padding = "50 50 50 50")
mainframe.grid(column = 0,row = 0,sticky = (N, W, E, S))
mainframe.columnconfigure(0,weight=1)
mainframe.columnconfigure(0,weight=1)
add_entry = ttk.Button(mainframe,width=20, text = "add entry", command=make_new)
add_entry.grid(column=2,row=2,sticky=(N,W))
add_entry = ttk.Button(mainframe,width=20, text = "make files", command=generate)
add_entry.grid(column=2,row=3,sticky=(N,W))
root.mainloop()
Here's the traceback I'm getting:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter_init_.py", line 1442, in call
return self.func(*args)
File "C:\python\SampAqTkinter.py", line 28, in generate
folder = boxvar.entry ## Not working here
AttributeError: 'str' object has no attribute 'entry'
There are two things that need to be changed to fix the problem you describe:
In the new_title_box.__init__() method change: listx.append(name) to listx.append(self.name)
In the generate() function, change: folder = boxvar.entry.get() to folder = boxvar.get().
You are appending a string to listx, use self.name instead of the local string name
Related
I have a program that puts the contents of a dictionary in a Tkinter Listbox, but I'm having trouble deleting it from the Listbox and the dictionary.
from tkinter import *
import ast
f = open("orders.txt", "r")
contents = f.read()
f.close()
things = ast.literal_eval(contents)
secondthing = [things, "test"]
root = Tk()
f = Frame(root).pack()
l = Listbox(root)
b = Button(root, text = "delete selection", command = lambda: delete(l))
b.pack()
l.pack()
for i, j in things.items():
oneitem = i + " " + j
l.insert(END, oneitem)
def delete(listbox):
global things
# Delete from Listbox
selection = l.curselection()
l.delete(selection[0])
# Delete from list that provided it
evaluater = l.get(selection[0])
value = eval(evaluater)
ind = things.index(value)
del(things[ind])
print(things)
root.mainloop()
When I try to delete something it gives me:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/tkinter/__init__.py", line 1883, in __call__
return self.func(*args)
File "/Users/mimmo/black_market/aaa.py", line 12, in <lambda>
b = Button(root, text = "delete selection", command = lambda: delete(l))
File "/Users/mimmo/black_market/aaa.py", line 28, in delete
value = eval(evaluater)
File "<string>", line 1
ohhh ohhhhh
^
SyntaxError: unexpected EOF while parsing
Can someone help me because I can delete it from the Listbox, I just have an error when deleting it from the dictionary.
The contents of orders.txt:
{"ayyy" : "ayyyyyy", "ohhh" : "ohhhhh"}
First of all, I would recommend using json or pickle to store contents of the dictionary - it's the most common practice. I don't really understand what do you want to do so I wrote a function which deletes an element from listbox and things by it's index.
An error you are getting is caused by eval function which tries to intepret your listbox item as python code. Of course, it's getting syntax error.
# Deletes element from listbox and thigs by it's index
def delete(listbox, index: int):
global things
item = listbox.get(index)
key = item.split()[0]
del things[key]
listbox.delete(index)
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).
I'm writing a Tkinter with gspread app. I believe the connections to the spreadsheets are made properly because i can read data off it. I'm using python 2.7.15 and gspread 0.6.2. I get the error. If i leave out the 'RAW' argument at the end of the function call, I no longer get any errors, but nothing gets written to the spreadsheet.
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1550, in __call__
return self.func(*args)
File "app.py", line 22, in clicked
sheet.insert_row(insertRow,index,'RAW')
TypeError: insert_row() takes at most 3 arguments (4 given)
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from Tkinter import *
scope = ["https://spreadsheets.google.com/feeds",'https://www.googleapis.com/auth/spreadsheets',"https://www.googleapis.com/auth/drive.file","https://www.googleapis.com/auth/drive"]
creds = ServiceAccountCredentials.from_json_keyfile_name("client_secret.json", scope)
client = gspread.authorize(creds)
sheet = client.open("This").sheet1 # Open the spreadhseet
#data = sheet.get_all_records() # Get a list of all records
#row = sheet.row_values(3) # Get a specific row
#col = sheet.col_values(3) # Get a specific column
#cell = sheet.cell(1,2).value # Get the value of a specific cell
def clicked():
index = sheet.row_count
index+=1
insertRow = [nametxt.get(),placetxt.get(), phonetxt.get()]
sheet.insert_row(insertRow,index,'RAW')
window = Tk()
window.title("Registration application")
window.geometry('700x700')
namelbl = Label(window, text="Name",font=("Ubuntu",20))
placelbl = Label(window, text="Place", font=("Ubuntu",20))
phonelbl = Label(window,text="Phone No", font=("Ubuntu",20))
placetxt = Entry(window,width = 20)
nametxt = Entry(window,width=20)
phonetxt = Entry(window,width = 20)
namelbl.grid(column=1, row=1,)
nametxt.grid(column=2, row=1)
placelbl.grid(column=1, row=2)
placetxt.grid(column=2,row=2)
phonelbl.grid(column =1, row=3)
phonetxt.grid(column = 2,row=3)
button = Button(window, text="submit",command=clicked)
button.grid(column=2, row=5)
window.mainloop()
#sheet.update_cell(2,2, "CHANGED") # Update one cell
You're using an old version of gspread. In the version you're using the definition of insert_row looks like this:
def insert_row(self, values, index=1):
Notice how it takes only three arguments: self (automatically passed when called on an instance), along with values and index. It doesn't accept any other parameters. You need to remove the RAW argument for your code to work with this version of the library.
I'm working with Tkinter and I'm trying to create an attribute called wordlist for a main object that belongs to the Main1 class.
This is the Main1 class:
class Main1(Instructions):
def __init__(self, master, wordlist):
super(Main1,self).__init__(master)
self.wordlist = self.readwords()
self.textbox.insert(0.0,self.wordlist)
def create_wdgts(self):
mainlbl = Label(self,text="Tänk på ett ord!")
mainlbl.grid(row=0,column=2)
self.textbox = Text(self, width = 50, height = 5, wrap = WORD)
self.textbox.grid(column=2,row=1)
self.backbttn = Button(self,text="Tillbaka")
self.backbttn["command"] = self.back
self.backbttn.grid(column=5,row=0)
self.pointentry = Entry(self)
self.pointentry.grid(column=2, row=2)
self.pointlbl = Label(self,text = "Poäng:")
self.pointlbl.grid(column = 1, row= 2)
self.pointbttn = Button(self, text="skicka poäng")
self.pointbttn.grid(row= 2, column = 3)
self.pointbttn["command"]= self.pointhndlr()
self.crrctlbl = Label(self, text = "Rätt ord:")
self.crrctlbl.grid(column = 1, row = 3)
self.crrctentry = Entry(self)
self.crrctentry.grid(column = 2, row= 3)
self.crrctbttn = Button(self, text="skicka rätt ord")
self.crrctbttn.grid(row= 3, column = 3)
self.yesbttn = Button(self, text="Ja")
self.yesbttn.grid(row = 4, column=4)
self.nobttn = Button(self, text = "Nej")
self.nobttn.grid(row=4, column=5)
def readwords(self):
"""Returns list with all words in words.txt"""
file = codecs.open("words.txt","r","utf8")
wordlist = []
for word in file:
wordlist.append(word.strip())
return wordlist
def guess(self):
self.guesstemp = random.choice(wordlist)
self.textbox.insert(0.0,"Ange poäng för ordet '"+guesstemp+"': ")
def pointhndlr(self):
pointtemp = self.pointentry.get()
self.pointentry.delete(0)
self.wordlist = remvwords(self.wordlist,self.guesstemp,self.pointtemp,self.guesslist,self.pointlist)
I hope I don't need to post more of the program as this is already a lot of code. Anyway, I get an error message saying that my Main1 object has no wordlist attribute. Why? I created it in the init method!
Grateful for all help.
Sahand
EDIT: The error is traced back to the last line, where I try to change the value of self.wordlist.
The error message is:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/tkinter/__init__.py", line 1475, in __call__
return self.func(*args)
File "/Users/SahandZarrinkoub/Documents/graphics.py", line 294, in main1
main1.guess()
File "/Users/SahandZarrinkoub/Documents/graphics.py", line 364, in guess
self.textbox.insert(0.0,"Ange poäng för ordet '"+guesstemp+"': ")
NameError: global name 'guesstemp' is not defined
The reason here is that this:
super(Main1,self).__init__(master)
will in turn call this:
def create_wdgts(self):
which will in turn do this:
self.pointbttn["command"]= self.pointhndlr()
This does not assign the function self.pointhndlr to self.pointbttn["command"], instead it calls self.pointhndlr, and assigns the result to self.pointbttn["command"].
The solution: remove the parenthesis:
self.pointbttn["command"]= self.pointhndlr
The way you call super.init is wrong.
You used:
super(Main1,self).__init__(master)
You should use:
super(Main1,self).__init__(self, master)
The way you called it, the object you are creating is not initialized as an Instructions instance. Instead, the master object gets re-initialized or re-cast as an Instructions instance.
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