Error with python3 tkinter - python

Here is mi code from Python3.6 and Ubuntu 17.10
It is write with Atom and will be implemented on Jupyter
Notebook
from tkinter import *
from tkinter import ttk
Here start the error
class Aplicacion():
def __init__(self):
self.root = Tk()
self.root.geometry('300x200')
self.root.resizable(width = False, height = False)
self.root.configure(bg = 'red')
self.root.title('Cachonerismo')
self.nombre = StringVar()
self.respuesta = StringVar()
self.txt = ttk.Entry(self.root,textvariable = self.nombre)
self.txt.pack(side = TOP)
self.txt1 = ttk.Entry(self.root, textvariable = self.respuesta)
self.txt1.pack(side = BOTTOM)
self.btn = ttk.Button(self.root, text = 'Mostrar', command = self.saluda).pack(side = LEFT)
self.bcl = ttk.Button(self.root, text='Cerrar', command = self.root.destroy).pack(side = RIGHT)
self.root.mainloop()
def saluda(self):
self.a = self.nombre.get(self)
self.respuesta.set(a)
app = Aplicacion()
And here is the error i get
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
return self.func(*args)
File "tkinterTest.py", line 23, in saluda
self.a = self.nombre.get(self)
TypeError: get() takes 1 positional argument but 2 were given

This is the chunk of code failing:
class StringVar(Variable):
"""Value holder for strings variables."""
_default = ""
def __init__(self, master=None, value=None, name=None):
"""Construct a string variable.
MASTER can be given as master widget.
VALUE is an optional value (defaults to "")
NAME is an optional Tcl name (defaults to PY_VARnum).
If NAME matches an existing variable and VALUE is omitted
then the existing value is retained.
"""
Variable.__init__(self, master, value, name)
def get(self):
"""Return value of variable as string."""
value = self._tk.globalgetvar(self._name)
if isinstance(value, str):
return value
return str(value)
You have to "call" the class to instantiate it:
self.nombre = StringVar()
self.respuesta = StringVar()

Related

Associate idle keyboard events to widget text tkinter

I am trying to create my own python code editor. For that I tried to use the tkcode module. Tkcode partially covers my needs (colors in the text for example), but it does not have the keyboard events that Idle has (automatic indentation when pressing enter, when pressing tab puts 4 spaces, etc). Some of them I can try to recreate, but automatic indentation is difficult. Is there any way to associate the Idle events to my code editor using the idlelib without creating another window (since I am making a notebook)? I went through the source code of Idle and couldn't find the way.
I know that this site is not to ask for recommendations, but if you recommend a better module to create a text widget that allows me to create this editor, it would be great too.
This is the code I have made:
from tkcode import CodeEditor
from tkinter import ttk
import tkinter as tk
import re
class CodeEditor(CodeEditor):
def __init__(Self, *args, **kargs):
super().__init__(*args, **kargs)
Self.bind("<Return>", Self.enter)
def get_current_line(Self):
return Self.get("insert linestart", "insert lineend")
def enter(Self, event):
for index, char in enumerate(Self.get_current_line()):
if(char != " "):
break
else:
index += 1
Self.insert("insert", "\n")
Self.insert("insert", " "*index)
return "break"
class FileHandler:
def __init__(Self, progs_path, filetabs):
Self.files = {}
Self.progs_path = progs_path
Self.filetabs = filetabs
def askopen(Self):
v = tk.Toplevel()
v.transient()
v.resizable(0, 0)
prog = ttk.Entry(v)
prog.pack(padx=10, pady=10)
prog.bind("<Return>", lambda Event:(Self.open(prog.get()), v.destroy()))
def open(Self, prog):
progfile = str(prog)[0]
progfile = f"prog{progfile}00A{progfile}99.py"
if(progfile in Self.files):
text = Self.files[progfile][prog]
else:
functions = {}
name = None
with open(f"{Self.progs_path}/{progfile}") as file:
for line in file:
match = re.match("(def|class) prog(\w+)", line)
if(match):
name = match[2]
functions[name] = line
if(line.startswith(" ") and name):
functions[name] += line
Self.files[progfile] = functions
text = functions[prog]
frame = ttk.Frame(Self.filetabs)
code_editor = CodeEditor(frame, language="python", highlighter="mariana", font="TkFixedFont", autofocus=True, padx=10, pady=10)
code_editor.pack(fill="both", expand=True)
code_editor.content = text
Self.filetabs.add(frame, text="prog"+prog)
v = tk.Tk()
filetabs = ttk.Notebook()
fh = FileHandler(".", filetabs)
menubar = tk.Menu(tearoff=0)
file = tk.Menu(tearoff=0)
menubar.add_cascade(label="Archivo", menu=file)
file.add_command(label="Abrir prog", command=fh.askopen)
v["menu"] = menubar
filetabs.pack(fill="both", expand=True)
fh.open("833")
In the end I was able to fix it. I was able to recreate almost all but one of the functions. For the last one, I made an impersonator class for idlelib.editor.EditorWindow to be able to do the automatic indentation, in addition to adding two new functions to the tkcode.CodeEditor.
However, I find this solution to be very unstable. Any better answer is still appreciated c:
This is the code:
from tkcode import CodeEditor
from tkinter import ttk
from idlelib.editor import EditorWindow
import tkinter as tk
import re
class FakeEditorWindow(EditorWindow):
def __init__(Self, text):
Self.text = text
Self.indentwidth = 4
Self.tabwidth = 4
Self.prompt_last_line = ''
Self.num_context_lines = 50, 500, 5000000
Self.usetabs = False
def is_char_in_string(Self, text_index):
return 1
class CodeEditor(CodeEditor):
def __init__(Self, *args, **kargs):
super().__init__(*args, **kargs)
Self.fake_editor_window = FakeEditorWindow(Self)
Self.bind("<Tab>", Self.tab)
Self.bind("<Control-Shift_L>", Self.dedent)
Self.bind("<BackSpace>", Self.backspace)
Self.bind("<Home>", Self.inicio)
Self.bind("<Return>", Self.enter)
def undo_block_start(Self):
pass
def undo_block_stop(Self):
pass
def get_current_line(Self):
return Self.get("insert linestart", "insert lineend")
def selection_get(Self):
if(Self.tag_ranges("sel")):
return Self.get("sel.first", "sel.last")
else:
return ""
def get_selection_zone(Self):
return (map(int, Self.index('sel.first').split(".", 1)),
map(int, Self.index('sel.last').split(".", 1)))
def tab(Self, event):
selection = Self.selection_get()
if(selection):
(startline, startcolumn), (endline, endcolumn) = Self.get_selection_zone()
if(startcolumn == 0):
for line in range(startline, endline+1):
Self.insert(f"{line}.0", " "*4)
Self.tag_add("sel", f"{startline}.0", "sel.last")
Self.mark_set("insert", f"{endline+1}.0")
else:
Self.insert("insert", " "*4)
return "break"
def dedent(Self, event):
if(Self.tag_ranges("sel")):
(startline, startcolumn), (endline, endcolumn) = Self.get_selection_zone()
if(startcolumn == 0):
for line in range(startline, endline+1):
if(Self.get(f"{line}.0", f"{line}.4") == " "*4):
Self.delete(f"{line}.0", f"{line}.4")
def backspace(Self, event):
if(not Self.tag_ranges("sel") and Self.get("insert linestart", "insert").isspace()):
cursor_line, cursor_col = map(int, Self.index("insert").split(".", 1))
Self.delete(f"{cursor_line}.{cursor_col-4}", "insert")
return "break"
def inicio(Self, event):
cursor_line, cursor_column = map(int, Self.index('insert').split(".", 1))
if(not Self.get("insert linestart", f"{cursor_line}.{cursor_column}").isspace()):
for i in range(cursor_column, -1, -1):
if(Self.get("insert linestart", f"{cursor_line}.{i}").isspace()):
Self.mark_set("insert", f"{cursor_line}.{i}")
return "break"
def enter(Self, event):
return EditorWindow.newline_and_indent_event(Self.fake_editor_window, event)
class FileHandler:
def __init__(Self, progs_path, filetabs):
Self.files = {}
Self.progs_path = progs_path
Self.filetabs = filetabs
def askopen(Self):
v = tk.Toplevel()
v.transient()
v.resizable(0, 0)
prog = ttk.Entry(v)
prog.pack(padx=10, pady=10)
prog.bind("<Return>", lambda Event:(Self.open(prog.get()), v.destroy()))
def open(Self, prog):
progfile = str(prog)[0]
progfile = f"prog{progfile}00A{progfile}99.py"
if(progfile in Self.files):
text = Self.files[progfile][prog]
else:
functions = {}
name = None
with open(f"{Self.progs_path}/{progfile}") as file:
for line in file:
match = re.match("(def|class) prog(\w+)", line)
if(match):
name = match[2]
functions[name] = line
if(line.startswith(" ") and name):
functions[name] += line
Self.files[progfile] = functions
text = functions[prog]
frame = ttk.Frame(Self.filetabs)
code_editor = CodeEditor(frame, language="python", highlighter="mariana", font="TkFixedFont", autofocus=True, padx=10, pady=10)
code_editor.pack(fill="both", expand=True)
code_editor.content = text
Self.filetabs.add(frame, text="prog"+prog)
v = tk.Tk()
filetabs = ttk.Notebook()
fh = FileHandler(".", filetabs)
menubar = tk.Menu(tearoff=0)
file = tk.Menu(tearoff=0)
menubar.add_cascade(label="Archivo", menu=file)
file.add_command(label="Abrir prog", command=fh.askopen)
v["menu"] = menubar
filetabs.pack(fill="both", expand=True)
fh.open("833")

tkinter Listbox error when used as class object

I want to create a class of Listbox object so that it can be used anywhere it is needed but it throws TypeError error, here is my code:
import tkinter as tk
class cls_list(tk.Listbox):
def __init__(self, master, callfrom):
tk.Listbox.__init__(self, master, callfrom)
callfrom.bind("<KeyRelease>", self.show_list)
def show_list(self, event):
x = callfrom.winfo_x()
y = callfrom.winfo_y()
h = callfrom.winfo_height()
self.place(x = x, y = y+h)
self.insert('end',*('Banana','Orange','Apple','Mango'))
if __name__ == '__main__':
root = tk.Tk()
ent = tk.Entry(root, font = (None, 20))
lst = cls_list(root, ent)
ent.pack()
root.mainloop()
Can someone correct me what I am doing wrong?
Here is complete Exception occurred:
File "/home/waheed/env_pinpoint/lib/python3.9/site-packages/test_listbox.py", line 5, in __init__
tk.Listbox.__init__(self, master, callfrom)
File "/usr/lib/python3.9/tkinter/__init__.py", line 3162, in __init__
Widget.__init__(self, master, 'listbox', cnf, kw)
File "/usr/lib/python3.9/tkinter/__init__.py", line 2566, in __init__
BaseWidget._setup(self, master, cnf)
File "/usr/lib/python3.9/tkinter/__init__.py", line 2537, in _setup
if 'name' in cnf:
File "/usr/lib/python3.9/tkinter/__init__.py", line 1652, in cget
return self.tk.call(self._w, 'cget', '-' + key)
TypeError: can only concatenate str (not "int") to str
This is what I have achieved so far.
import tkinter as tk
if __name__ == '__main__':
root = tk.Tk()
root.geometry('400x400')
ent = tk.Entry(root, font = (None, 20))
lst = tk.Listbox(root, font = (None, 20))
ent.pack()
ent.focus_set()
def hide_list(event):
index = int(lst.curselection()[0])
val = lst.get(index)
ent.delete(0,'end')
ent.insert(0,val)
lst.place_forget()
def show_list(event):
ent.update_idletasks()
x = ent.winfo_x()
y = ent.winfo_y()
h = ent.winfo_height()
lst.place(x = x, y = y+h)
items = ['Banana','Orange','Apple','Mango']
searchkey = ent.get()
lst.delete(0, "end")
for item in items:
if searchkey.lower() in item.lower():
lst.insert("end", item)
n = lst.size()
if n < 15:
lst.config(height = 0)
else:
lst.config(height = 15)
ent.bind("<KeyRelease>", show_list)
lst.bind("<<ListboxSelect>>", hide_list)
root.mainloop()
And now I want to make it an object (separate class) for using in multiple scripts.
I hope now I have explained my question properly.
The specific error you're asking about is caused because you're passing callfrom here: tk.Listbox.__init__(self, master, callfrom).
The listbox widget doesn't know what to do with callfrom, it expects the second positional argument to be a dictionary.
The proper way to initialize the class is without callfrom. You will need to save callfrom as an instance attribute if you need to use it outside of the __init__.
def __init__(self, master, callfrom):
tk.Listbox.__init__(self, master)
self.callfrom = callfrom
...
def show_list(self, event):
x = self.callfrom.winfo_x()
y = self.callfrom.winfo_y()
h = self.callfrom.winfo_height()
...

Tkinter custom entry widget exception

I'm trying to create a custom Tkinter Entry widget that will convert lowercase characters to uppercase before the characters are inserted into the widget. I know there are solutions that bind key release events to a widget with a function to get the widget text and then convert to uppercase and reinsert the text. But those solutions display the lowercase character before the conversion occurs, which I prefer not to do.
I'm trying to use a custom Entry widget based on code shared by Bryan Oakley - Tkinter adding line number to text widget
This code works great for a custom Text widget and I have used it in other applications.
Now I'm trying to use the same approach to create a custom Entry widget. Here is sample code that incorporates both a custom Text widget and custom Entry widget:
from tkinter import *
class CustomText(Text):
def __init__(self, *args, **kwargs):
Text.__init__(self, *args, **kwargs)
self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)
def _proxy(self, *args):
if args[0] == "insert" and args[1] == "insert":
args =('insert', 'insert', args[2].upper())
cmd = (self._orig,) + args
result = self.tk.call(cmd)
return result
class CustomEntry(Entry):
def __init__(self, *args, **kwargs):
Entry.__init__(self, *args, **kwargs)
self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)
def _proxy(self, *args):
if args[0] == "insert" and args[1] == "insert":
args =('insert', 'insert', args[2].upper())
cmd = (self._orig,) + args
result = self.tk.call(cmd)
return result
def get_text():
print("TEXT widget text = ", mytext.get("1.0", "end"))
print("ENTRY widget text = " ,entryvar.get())
root = Tk()
entryvar = StringVar()
root.geometry("300x300")
myframe = Frame(root, width = 300, height = 300)
Label(myframe, text="TEXT WIDGET").pack(side = TOP)
myframe.pack(side = TOP)
mytext = CustomText(myframe, width = 30, height=1, wrap="none")
mytext.pack(side = TOP)
Label(myframe, text="ENTRY WIDGET").pack(side = TOP)
myentry = CustomEntry(myframe, textvariable=entryvar, width = 30)
myentry.pack(side = TOP)
Button(myframe, text="Get Entry Widget Text", command=get_text).pack(side=TOP)
root.mainloop()
The solutions works for the CustomText widget. As you can see the characters are converted before insertion and the result is as if the user is entering the characters with the shift key pressed.
But I get an exception when entering data into the CustomEntry widget I get the following exception form the result = self.tk.call(cmd):
Traceback (most recent call last):
File "C:/Users/rhkea/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/custom_entry_box.py", line 57, in <module>
root.mainloop()
File "C:\Users\rhkea\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1283, in mainloop
self.tk.mainloop(n)
File "C:/Users/rhkea/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/custom_entry_box.py", line 34, in _proxy
result = self.tk.call(cmd)
_tkinter.TclError: selection isn't in widget .!frame.!customentry
Any ideas on why this might be happening?
After playing around with the code, I have found out that after inserting text in the entry, the method index sel.first is called. But there is no selection so an error is raised "selection isn't in widget .!frame.!customentry". I don't know how this is handled in a regular Entry but you can catch this error:
class CustomEntry(Entry):
def __init__(self, *args, **kwargs):
Entry.__init__(self, *args, **kwargs)
self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)
def _proxy(self, *args):
if args[0] == "insert" and args[1] == "insert":
args = ('insert', 'insert', args[2].upper())
cmd = (self._orig,) + args
try:
return self.tk.call(cmd)
except TclError as e:
if args[0] == 'index' and args[1] == 'sel.first':
pass
else:
raise TclError(str(e))
Otherwise, you can use an altogether different method to change the case of the inserted text: use a trace on the textvariable of the entry.
class CustomEntry(Entry):
def __init__(self, *args, **kwargs):
Entry.__init__(self, *args, **kwargs)
self._var = StringVar(self)
self.configure(textvariable=self._var)
self._var.trace_add('write', self._uppercase)
def _uppercase(self, *args):
self._var.set(self._var.get().upper())
With self._var.trace_add('write', self._uppercase), the method _uppercase() is called each time the content of the StringVar changes.

python AttributeError: NoneType has no attribute

In my program snippet I create a python window with 2 fields and 3 buttons. The left two buttons should perform some action but instead an error is thrown:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib64/python3.4/tkinter/__init__.py", line 1538, in __call__
return self.func(*args)
File ".../GuiFile.py", line 11, in <lambda>
self.F[2] = ButtonClass().make_button(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))
File ".../ClassFile.py", line 11, in doButtonAction1
print(gf.StartGui.F[0].textField.get("1.0","end-1c"))
AttributeError: 'NoneType' object has no attribute 'textField'
Why is dict item F[0] (created in line 9 of GuiFile.py) not recognized as Text() class with the attribute textField (defined in line 43 of GuiFile.py)?
MainProgramFile.py
#!/usr/bin/env python3
import sys
import ClassFile
import GuiFile as gf
if __name__== '__main__':
gf.StartGui().mainloop()
GuiFile.py
import sys
from tkinter import *
import ClassFile as cf
class StartGui(Frame):
F = {}
def __init__(self,parent=None):
Frame.__init__(self, parent)
self.F[0] = FieldTextClass().make_field(labeltext="Label of field 1", fieldtext="veld 1", fieldheight=90)
self.F[1] = FieldTextClass().make_field(labeltext="Label of field 2", fieldtext="veld 2")
self.F[2] = ButtonClass().make_button(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))
self.F[3] = ButtonClass().make_button(stacked="left", buttontext= "Exchange button", buttoncommand = lambda: cf.mainButtons.doButtonSwitchValues(self))
self.F[4] = ButtonClass().make_button(stacked="right",buttontext= "Quit button",buttoncommand = lambda: cf.mainButtons.doButtonQuit(self))
self.pack(expand=True, fill=BOTH, anchor="nw", side=LEFT)
#for i in range(self.F.__len__()): print(self.F[i].__class__,self.F[i].objectType)
class ButtonClass (Frame, Button):
objectType = "button"
def make_button(self, parent=None, stacked="horizontal", buttontext="Button", buttonwidth=120, buttonheight=32, buttoncommand=""):
self.buttonwidth=buttonwidth
self.buttonheight=buttonheight
self.buttontext=buttontext
self.buttoncommand=buttoncommand
if stacked=="vertical":
BUTTONSTACK = TOP
elif stacked=="right":
BUTTONSTACK = RIGHT
elif stacked=="horizontal" or stacked=="left":
BUTTONSTACK = LEFT
else:
BUTTONSTACK = LEFT
self.top = Frame(parent, height=self.buttonheight, width=self.buttonwidth)
self.top.pack_propagate(False)
self.top.pack(side=BUTTONSTACK)
button = Button(self.top, text=self.buttontext, command=self.buttoncommand,height=self.buttonheight, width=self.buttonwidth)
button.pack(fill=BOTH)
class FieldTextClass(Frame,Text,Label):
textField = None
objectType = "inputField"
def make_field(self, parent=None, labeltext="Empty", fieldtext="Empty", fieldwidth=600, fieldheight=20, labelwidth=120, labelheight=20):
self.fieldheight=fieldheight
self.fieldwidth=fieldwidth
self.fieldtext=fieldtext
self.labeltext=labeltext
self.labelheight=labelheight
self.labelwidth=labelwidth
self.top = Frame(parent)
#create the label, whith the text shifted left/top in a separate Frame
labelFrame = Frame(self.top, height = self.labelheight,width=self.labelwidth)
label = Label(labelFrame, text=self.labeltext, fg="black", anchor="nw")
label.pack(expand=True, fill=BOTH, anchor="nw", side=LEFT)
labelFrame.pack_propagate(False)
labelFrame.pack(side=LEFT, anchor="nw")
#create the text field, packed in a separate Frame
fieldFrame = Frame(self.top, height = self.fieldheight,width=self.fieldwidth)
self.textField = Text(fieldFrame, fg="black",bg="white")
self.textField.insert(INSERT,self.fieldtext)
self.textField.pack(expand=True, fill=BOTH, side=LEFT)
fieldFrame.pack_propagate(False)
fieldFrame.pack(side=LEFT)
self.top.pack(side=TOP)
ClassFile.py
import sys
from tkinter import *
import GuiFile as gf
class mainButtons():
def doButtonQuit(self):
print("Quitting test via ClassFile")
self.quit()
def doButtonAction1(self):
print(gf.StartGui.F[0].textField.get("1.0","end-1c"))
print(gf.StartGui.F[1].textField.get("1.0","end-1c"))
gf.StartGui.F[0].textField.delete("1.0","end")
gf.StartGui.F[0].textField.insert(INSERT, "New text")
def doButtonSwitchValues(self):
tmp0=gf.StartGui.F[0].textField.get("1.0","end-1c")
tmp1=gf.StartGui.F[1].textField.get("1.0","end-1c")
gf.StartGui.F[0].textField.delete("1.0","end")
gf.StartGui.F[0].textField.insert(INSERT, tmp1)
gf.StartGui.F[1].textField.delete("1.0","end")
gf.StartGui.F[1].textField.insert(INSERT, tmp0)
When you do ButtonClass().make_button() (or FieldTextClass.make_field()) , python will return the value of the function, not the instance of the class. The function returns None, so the dictionary elements are None.
The way you're using the custom classes is very strange. Instead of creating special functions, put that code in an __init__, and use the class like you would any other class.
For example:
class ButtonClass (Frame):
def __init__(self, parent=None, stacked="horizontal",
buttontext="Button", buttonwidth=120, buttonheight=32,
buttoncommand=""):
Frame.__init__(self, parent)
self.buttonwidth=buttonwidth
...
...
self.F[2] = ButtonClass(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))
Note: when doing it this way, you don't have to create a separate frame inside __init__ (ie: self.top), since self is itself already a Frame.

I can't figure out this Tkinter error

I'm using Python's Tkinter to create a GUI for a project i'm working on.
When I try to run part of the code though, I get this error:
Traceback (most recent call last):
File "calculator.py", line 59, in <module>
app = Application()
File "calculator.py", line 28, in __init__
self.create_widgets()
File "calculator.py", line 45, in create_widgets
self.special_chars.create_button(char, self.add_char_event(special_characters[char]))
File "calculator.py", line 20, in create_button
self.button_list += Button(self, text = txt, command = fcn)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/
lib-tk/Tkinter.py", line 1206, in cget
TypeError: cannot concatenate 'str' and 'int' objects
The problem is that I can't find the file that the error message references; my python2.7/lib-tk folder only contains complied versions (.pyo and .pyc) of Tkinter.
Is there a way to figure out what's going wrong?
Here's the source of calculator.py
from Tkinter import *
from exp import full_eval
from maths import special_characters
class special_char_frame(LabelFrame):
def __init__(self, master = None, text = 'Special Characters'):
LabelFrame.__init__(self, master)
self.grid()
self.button_list = []
def create_button(self, txt, fcn):
self.button_list += Button(self, text = txt, command = fcn)
self.button_list[-1].grid(row = 0)
class Application(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
## equation entry pane
self.text_entry = Entry(self, width = 100)
self.text_entry.grid(row = 0, column = 0)
self.text_entry.bind('<KeyPress-Return>', self.calculate)
## result pane
self.result = StringVar()
self.result_label = Label(self, textvariable = self.result, wraplength = 815, justify = LEFT)
self.result_label.grid(row = 1, column = 0, columnspan = 2, sticky = W)
self.result.set('')
## calculate button
self.calc_button = Button(self, text = 'Calculate', command = self.calculate)
self.calc_button.grid(row = 0, column = 1)
## special character button pane
self.special_chars = special_char_frame(self)
for char in special_characters:
self.special_chars.create_button(char, self.add_char_event(special_characters[char]))
self.special_chars.grid(column = 0, columnspan = 2, row = 2)
def calculate(self, event = None):
try:
self.result.set(full_eval(self.text_entry.get()))
except Exception as error:
raise
#self.result.set(str(error))
self.text_entry.select_range(0, END)
def add_char_event(self, char):
def add_char(self = self, event = None):
self.text_entry.insert(INSERT, char)
return add_char
app = Application()
app.master.title('Calculator')
app.mainloop()
full_eval is a function for evaluating mathematical expressions.
special_characters is a dict containing special characters and their explanations. For now it's just special_characters = {'imaginary unit' : u'\u2148'}
Ok, so I missed this the first time, but the issue is actually that you are trying to add a Button to a list:
self.button_list += Button(self, text = txt, command = fcn)
If you simply wrap the Button in brackets, the error goes away (which makes sense because you are supposed to be able to add two lists):
self.button_list += [Button(self, text = txt, command = fcn)]
ORIGINAL ATTEMPT
My guess:
special_characters is a dictionary. It has key-value mappings where the values are ints. Then, when used in self.text_entry.insert(INSERT, char), text_entry is trying to insert an int into a str and causing the above error. The simple solution: wrap char with str in add_char.
def add_char_event(self, char):
def add_char(self = self, event = None):
self.text_entry.insert(INSERT, str(char))
return add_char
Your other option is to wrap str around the special_characters lookup:
for char in special_characters:
self.special_chars.create_button(char,
self.add_char_event(str(special_characters[char])))

Categories

Resources