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)
Related
Code runs but when I try to write something there is a notification in therminal:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\", line 1883, in __call__
return self.func(*args)
File "c:/Users\", line 11, in getting_Text
if text[0] == 'a' :
File "C:\Users", line 1643, in cget
return self.tk.call(self._w, 'cget', '-' + key)
TypeError: can only concatenate str (not "int") to str
And also: Do I have to put all alphabet to all characerts like
if user[0]== "a"
if user[0]== "b"
etc
and do I have to do it to like thousands of characters like [0] then [1]... [100]
import tkinter as tk
#making main window
root = tk.Tk()
root.title("Encryptor")
root.geometry("600x300")
#getting text
def getting_Text():
user = text.get("1.0",'end-1c')
#I print it just to know if the programme work
print (user)
if text[0] == "a":
result.insert(tk.END, ';', 'big')
if text[0] == "b":
result.insert(tk.END, "%", "big")
#etc.
#UX of the window
prawy_margines = tk.Frame(root)
prawy_margines.pack (side=tk.RIGHT, expand =tk.YES , fill=tk.BOTH)
left_margin = tk.Frame(root)
left_margin.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH)
#after clicking button function getting_text() is used
button = tk.Button( root , text = "Encrypt", activebackground = "#FFFFFF", command=getting_Text)
button.pack( side = tk.TOP )
text=tk.Text(root, width=36, height=15 )
text.pack(side= tk.LEFT)
result= tk.Text(root, width=36, height=15 )
result.pack(side=tk.RIGHT)
root.mainloop()
What you could do to seperate a string into single letters is just get everything in your text widget. Then get the length of the string and then creata a loop which uses the first element of the string and put it somewhere you want to save the letters, then remove it from the string and end the loop.
Since it will loop as often as the length of the string you can always just use the first letter of the string and remove it until the string is empty and the loop will end because the length you set for the loop to run ends the loop.
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 want to use Tkinter to write a code where the user can enter a number N. Depending on this number N the program automatically (i dont want to use any buttons) creates N-Entry rows.
My solution works partially:
from tkinter import *
root = Tk()
Label(root, text = "Enter Number of columns").grid(row = 0, column = 0)
N = IntVar()
e_N = Entry(root, textvariable = N).grid(row = 0, column = 1)
# Put trace callbacks on the Entry IntVar
def create_rows(name, index, mode):
rows = N.get()
for i in range(rows):
Entry(root).grid(row = i + 1, column = 0)
N.trace('w', create_rows)
# Setting the vars will trigger the trace
N.set(2)
mainloop()
When you run the code for the first time, it works fine. If you delete the number two and enter a new number, new lines are automatically created. However, an error message is displayed :
Exception in Tkinter callback
Traceback (most recent call last):
File "/home/anaconda3/lib/python3.7/tkinter/__init__.py", line 508, in get
return self._tk.getint(value)
_tkinter.TclError: expected integer but got ""
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/anaconda3/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "<ipython-input-97-2da00b5c0b50>", line 12, in create_rows
rows = N.get()
File "/home/anaconda3/lib/python3.7/tkinter/__init__.py", line 510, in get
return int(self._tk.getdouble(value))
_tkinter.TclError: expected floating-point number but got ""
This error is repeated as soon as the old number is deleted and a new one is entered.
Does someone know what is wrong and how to fix it?
Also as an extra: Only new lines can be created, i.e. if you first enter 5 and then 3, the last two lines are not deleted.
Edited code:
from tkinter import *
root = Tk()
Label(root, text = "Enter Number of columns").grid(row = 0, column = 0)
N = IntVar()
e_N = Entry(root, textvariable = N).grid(row = 0, column = 1)
# Put trace callbacks on the Entry IntVar
def create_rows(name, index, mode):
try:
rows = N.get()
except _tkinter.TclError:
""
for i in range(rows):
Entry(root).grid(row = i + 1, column = 0)
N.trace('w', create_rows)
# Setting the vars will trigger the trace
N.set(2)
mainloop()
Putting a trace on the value of N means it calls create_rows whenever it changes, including just after you deleted the original number, but before you type the new one. You could put N.get() inside a try/except, and only add new lines if the contents of the number entry are a valid integer. This will handle the deleted case when the value is an empty string, and also if someone types a non-number into the entry.
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.
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