AttributeError: 'Vocabulary' object has no attribute 'listBox' - python

I am creating Vocabulary, a GUI program to manage unknown words. I am getting:
/usr/bin/python3.5 /home/cali/PycharmProjects/Vocabulary/Vocabulary.py
Exception in Tkinter callback Traceback (most recent call last):
File "/usr/lib/python3.5/tkinter/init.py", line 1553, in call
return self.func(*args) File "/home/cali/PycharmProjects/Vocabulary/Vocabulary.py", line 86, in
add_item
self.listBox.insert(END, self.get_word()) AttributeError: 'Vocabulary' object has no attribute 'listBox'
Process finished with exit code 0
... when I try to add an item to the listbox.
Here is what I have done:
#!/usr/bin/env python
# Vocabulary.py
# GUI program to manage unknown words
from tkinter import *
class Word:
def __init__(self, wordorphrase, explanation, translation, example):
self.wordorphrase = wordorphrase
self.explanation = explanation
self.translation = translation
self.example = example
class Vocabulary(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.master = master
self.master.resizable(width = False, height = False)
self.master.title("Vocabulary")
self.create_widgets()
def create_widgets(self):
lblWordsOrPhrases = Label(self.master, text = 'Words or Phrases:')
lblWordsOrPhrases.grid(row = 0, column = 0)
lblWordOrPhrase = Label(self.master, text = 'Word or phrase:')
lblWordOrPhrase.grid(row = 0, column = 1, sticky = W)
listBox = Listbox(self.master,
height = 34,
width = 30)
listBox.grid(row = 1, column = 0, rowspan = 7)
txt_WordOrPhrase = Text(self.master,
height = 1,
width = 40)
txt_WordOrPhrase.grid(row = 1, column = 1, sticky = N)
lblExplanation = Label(self.master, text = 'Explanation:')
lblExplanation.grid(row = 2, column = 1, sticky = W)
txt_Explanation = Text(self.master,
height = 10,
width = 40)
txt_Explanation.grid(row = 3, column = 1, sticky = N)
lblTranslation = Label(self.master, text = 'Translation:')
lblTranslation.grid(row = 4, column = 1, sticky = W)
txt_Explanation = Text(self.master,
height = 10,
width = 40)
txt_Explanation.grid(row = 5, column = 1, sticky = N)
lblExamples = Label(self.master, text = 'Example(s):')
lblExamples.grid(row = 6, column = 1, sticky = W)
txt_Explanation = Text(self.master,
height = 10,
width = 40)
txt_Explanation.grid(row = 7, column = 1, sticky = S)
btn_Add = Button(self.master,
text = 'Add',
command = self.add_item)
btn_Add.grid(row = 8, column = 0, sticky = W)
def get_word(self):
return self.txt_WordOrPhrase.get('1.0', '1.0 lineend')
def get_explanation(self):
return self.txt_Explanation.get('1.0', '1.0 lineend')
def get_translation(self):
return self.txt_Translation.get('1.0', '1.0 lineend')
def get_example(self):
return self.txt_Example.get('1.0', '1.0 lineend')
def add_item(self):
self.listBox.insert(END, self.get_word())
def main():
root = Tk()
Vocabulary(root)
root.mainloop()
if __name__ == '__main__':
main()
I'm using Python 3.5.

You listbox is a variable local to create_widgets since it is not set with self. In order to make the variable available instance-wide, you need to contain it in self.
Change the line in create_widgets to self.listBox = Listbox(self.master, height = 34, width = 30) and change every reference to listBox to self.listBox in order to apply this change.
You might want to defined self.listBox in __init__(), as it might help keep track of instance variables.

Related

OOP and Tkinter - how to create widgets

I'm trying to create my own Frame in tkinter but I have some problems with OOP. Below is my code.
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import *
class Listbox(tk.Listbox):
def __init__(self, master, addValues = False, values = None, *args, **kwargs):
tk.Listbox.__init__(self, master, *args, **kwargs)
# Tooltip
self.lListOver = [-1, None, None]
self.bind('<Motion>', lambda e: self.f_coord(e, l = self))
self.bind('<Leave>', self.f_resetnListOver)
if addValues:
for value in values:
self.insert(END, value)
def f_coord(self, e, l):
xEnrPos, yEnrPos = e.x, e.y
idxOver = l.nearest(yEnrPos)
lListCom = l.get(0, END)
tLast = l.bbox(len(lListCom) - 1)
if tLast is not None:
yDownLast = tLast[1] + tLast[3]
if yEnrPos > yDownLast:
if self.lListOver[1] is not None:
self.f_resetnListOver(None)
return None
if idxOver != self.lListOver[0]:
sX, sY = str(l.winfo_pointerx() + 15), str(l.winfo_pointery() + 15)
if self.lListOver[1] is not None: self.lListOver[1].destroy()
self.lListOver[1] = tk.Toplevel(l.master)
self.lListOver[1].wm_geometry("+" + sX + "+" + sY)
self.lListOver[1].wm_overrideredirect(True)
tk.Label(self.lListOver[1], text = lListCom[idxOver], bg = "#217346", bd = 1, justify = tk.LEFT).pack(padx = 2, pady = 2)
self.lListOver[0] = idxOver
return None
def f_resetnListOver(self, *d):
if self.lListOver[1] is None: return None
self.lListOver[0] = -1
self.lListOver[1].destroy()
self.lListOver[1] = None
self.lListOver[2] = None
return None
class ListboxFrame(ttk.Frame):
def __init__(self, master, labelText, *args, **kwargs):
ttk.Frame.__init__(self, master)
# Listbox
ttk.Label(self, text = labelText).grid(row = 0, column = 0, columnspan = 3)
self.listbox = Listbox(self, height = 5, *args, **kwargs)
self.listbox.grid(row = 1, column = 0, columnspan = 3, padx = 2, pady = 2)
# Entry
self.entry = ttk.Entry(self)
self.entry.grid(row = 2, column = 0, padx = 2, pady = 2)
# Buttons
self.addButton = ttk.Button(self, text = "Add", width = 4, command = self.Add)
self.addButton.grid(row = 2, column = 1, padx = 1, pady = 1)
self.deleteButton = ttk.Button(self, text = "Delete", width = 6, command = self.Delete)
self.deleteButton.grid(row = 2, column = 2, padx = 1, pady = 1)
def Add(self):
if self.entry.get() == "": return
self.listbox.insert(END, self.entry.get())
self.entry.delete(0, END)
def Delete(self):
for index in reversed(self.listbox.curselection()):
self.listbox.delete(index)
# listbox.config(height = listbox.size())
root = tk.Tk()
frame = ListboxFrame(root, "Listbox", addValues = True, values = ["Name", "Surname"], height = 10)
frame.pack()
root.mainloop()
What I'm trying to do here is to set the default height of my listbox in Frame to 5
self.listbox = Listbox(self, height = 5, *args, **kwargs)
but then when I want to create an instance of this Frame, I would like to pass another value of height
frame = ListboxFrame(root, "Listbox", addValues = True, values = ["Name", "Surname"], height = 10)
Here I'm also passing addValues and values arguments of my Listbox class. Unfortunately my code doesn't work and I got the error:
33
34 root = tk.Tk()
---> 35 frame = ListboxFrame(root, "Listbox", addValues = True, values = ["Name", "Surname"], height = 10)
36 frame.pack()
37 root.mainloop()
<ipython-input-135-115c7d7ebda4> in __init__(self, master, labelText, *args, **kwargs)
5 # Listbox
6 ttk.Label(self, text = labelText).grid(row = 0, column = 0, columnspan = 3)
----> 7 self.listbox = Listbox(self, height = 5, *args, **kwargs)
8 self.listbox.grid(row = 1, column = 0, columnspan = 3, padx = 2, pady = 2)
9
TypeError: type object got multiple values for keyword argument 'height'
I'm pretty new in OOP and Tkinter hence I hope you will be able to help me with this code to make it work.

Calling a class method in another class - Tkinter

I am using Tkinter in Python 3 to create a converter between hex, binary and denary - while creating my own methods for conversions instead of using the built in methods.
I've completed the denary to binary conversion through the use of my 'highestPowerOf2' method in the DenToBin class. I want to use this method in my HexToBin class, but whenever I try to, an additional blank window pops up and I receive - AttributeError: 'NoneType' object has no attribute 'title' - error.
How would I run 'highestPowerOf2' in the HexToBin class?
(also sorry for any poor programming practise)
Code:
from tkinter import *
from functools import partial
class Menu(Frame):
def __init__(self, master= None): # initialise Menu
Frame.__init__(self, master) # initialise Frame
self.master = master # what does this do
self.createWindow()
def createWindow(self):
self.pack(fill = BOTH, expand = 1)
denToBin = Button(self, text = 'Denary to Binary', command = lambda: self.changeWindow(DenToBin))
denToBin.pack(fill = X, padx = 10, pady = 10)
hexToBin = Button(self, text = 'Hex to Binary', command = lambda: self.changeWindow(HexToBin))
hexToBin.pack(fill = X, padx = 10, pady = 10)
def changeWindow(self, object):
root.withdraw()
currentFrame = object(root)
class DenToBin(Toplevel):
def __init__(self, master = None):
Toplevel.__init__(self, master)
self.master = master
self.Window()
self.denary = 0
def Window(self):
# print(self.denary) -- Why is this not recognised?????????
self.master.title('Unit Converter: Denary to Binary')
instructionDen = Label(self, text = 'Denary Value: ')
instructionDen.grid(row = 1, column = 0, padx = 10)
instructionBin = Label(self, text = 'Binary Value: ')
instructionBin.grid(row = 2, column = 0, padx = 10)
self.denaryEntry = Entry(self)
self.denaryEntry.grid(row = 1, column = 2, padx = 10, pady = 5)
convertButton = Button(self, text = 'Convert!', command = lambda: self.highestPowerOf2(10)) # as an example
convertButton.grid(row = 3, column = 1)
# finds highest power of 2 that is less than denary number - helps self.convert()
def highestPowerOf2(self,number):
print('I find the highest power of 2 that fits into the number given.')
class HexToBin(Toplevel):
def __init__(self, master = None):
Toplevel.__init__(self, master)
self.master = master
self.Window()
self.denary = 0
def Window(self):
self.master.title('Unit Converter: Hexadecimal to Binary')
instructionHex = Label(self, text = 'Hexadecimal Value: ')
instructionHex.grid(row = 1, column = 0, padx = 10)
instructionBin = Label(self, text = 'Binary Value: ')
instructionBin.grid(row = 2, column = 0, padx = 10)
self.hexadecimalEntry = Entry(self)
self.hexadecimalEntry.grid(row = 1, column = 2, padx = 10, pady = 5)
convertButton = Button(self, text = 'Convert!', command = self.convert)
convertButton.grid(row = 3, column = 1)
def convert(self):
# I need to call the 'highestPowerOf2' method here.
pass
root = Tk()
unitConverter = Menu(root) # root is master
root.mainloop()

Can't pickle _tkinter.tkapp objects

The problem in that I can't pickle the text in entry fields. I try to make it in the 'record' function.
Error: can't pickle _tkinter.tkapp objects
I want to save data in the file and then read it.
Interface:
#program to record and store your sports results
import shelve
from tkinter import *
class Application(Frame):
'''GUI application ере displays menu for the programm'''
def __init__(self, master):
'''Initialize Frame'''
super(Application, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
''' Create widgets to get story information and to display story. '''
self.fileDat = 'data'
# label date
Label(self,
text = "date:"
).grid(row = 0, column = 0, columnspan = 2, sticky = W)
# field date
self.date_ent = Entry(self)
self.date_ent.grid(row = 1, column = 1, sticky = W)
# label №
Label(self,
text = "№:"
).grid(row = 0, column = 3, columnspan = 2, sticky = W)
# field №
self.number_ent = Entry(self)
self.number_ent.grid(row = 1, column = 4, sticky = W)
# label km
Label(self,
text = "km:"
).grid(row = 2, column = 0, columnspan = 2, sticky = W)
# field km
self.km_ent = Entry(self)
self.km_ent.grid(row = 3, column = 1, sticky = W)
# label time
Label(self,
text = "time:"
).grid(row = 3, column = 0, columnspan = 2, sticky = W)
# field time
self.time_ent = Entry(self)
self.time_ent.grid(row = 4, column = 1, sticky = W)
# record button
Button(self,
text = "record training",
command = self.record
).grid(row = 5, column = 0, sticky = W)
# show training button
Button(self,
text = "show trining",
command = self.tngDisplay
).grid(row = 5, column = 3, sticky = W)
self.tngField = Text(self, width = 75, height = 10, wrap = WORD)
self.tngField.grid(row = 6, column = 0, columnspan = 4)
def listRecord( self):
date = self.date_ent.get()
km = self.km_ent.get()
time = self.time_ent.get()
tng = [date,km, time]
return tng
def record (self):
tngList = self.listRecord
tngNumber = self.number_ent.get()
datFile = shelve.open(self.fileDat)
datFile[tngNumber] = tngList
#datFile['1'] = tngList
datFile.sync()
datFile.close()
def tngDisplay (self):
tng = ''
self.tngField.delete(0.0, END)
#i=0
datFile = shelve.open(self.fileDat)
for key, item in datFile.items():
tng = str(key) + ': ' + str(item)
# display trainings
self.tngField.insert(0.0, tng)
#i+=1
root = Tk()
root.title('RunForest')
app = Application(root)
root.mainloop()

Creating an auto incrementing loop within a function in python

I'm trying to set up a loop that keeps track of a number of ordernums as well as assign a nw ordernum to each new order in increasing value.
Here's the full code:
*This is the fixed code using Klaus D. 's advice
import tkinter
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from itertools import count
class ImprintPlusApp:
def __init__(self, master):
self.counter = count(1)
master.title("Imprint Plus Manager")
self.frame_header = ttk.Frame(master)
self.frame_header.pack()
ttk.Label(self.frame_header, text = "Bienvenidos a Imprint Plus Manager")
self.frame_crearorden = ttk.Frame(master)
self.frame_crearorden.pack()
ttk.Label(self.frame_crearorden, text = "Nombre").grid(row = 0, column = 0, padx = 5)
ttk.Label(self.frame_crearorden, text = "Email").grid(row = 2, column = 0, padx = 5)
ttk.Label(self.frame_crearorden, text = "Numero Cel/Tel").grid(row = 4, column = 0, padx = 5)
ttk.Label(self.frame_crearorden, text = "Información Adicional").grid(row = 6, column = 0, padx = 5)
self.entry_name = ttk.Entry(self.frame_crearorden, width = 24)
self.entry_email = ttk.Entry(self.frame_crearorden, width = 24)
self.entry_numtc = ttk.Entry(self.frame_crearorden, width = 24)
self.entry_addinf = Text(self.frame_crearorden, width = 50, height = 10)
self.entry_name.grid(row = 0, column = 1, padx = 5)
self.entry_email.grid(row = 2, column = 1, padx = 5)
self.entry_numtc.grid(row = 4, column = 1, padx = 5)
self.entry_addinf.grid(row = 7, column = 0, columnspan = 2, padx = 5)
ttk.Button(self.frame_crearorden, text = "Submit", command = self.submit).grid(row = 8, column = 1,columnspan = 1, padx = 5)
ttk.Button(self.frame_crearorden, text = "Clear", command = self.clear).grid(row = 8, columnspan = 1, padx = 5)
def submit(self):
result = next(self.counter)
orderResult = str(result)
print ("Nombre: {}".format(self.entry_name.get()))
print ("Email: {}".format(self.entry_email.get()))
print ("Num Cel/Tel: {}".format(self.entry_numtc.get()))
print ("Información Adicional: {}".format(self.entry_addinf.get(1.0, "end")))
self.clear()
messagebox.showinfo(title = "Orden #"+ orderResult, message = "Orden Guardada")
def clear(self):
self.entry_name.delete(0, "end")
self.entry_email.delete(0, "end")
self.entry_numtc.delete(0, "end")
self.entry_addinf.delete(1.0, "end")
def main():
root = Tk()
app = ImprintPlusApp(root)
root.mainloop()
if __name__ == '__main__':
main()
You can use itertools.count() for that. It creates a generator, that just returns one number after the other, when you call it's next() method:
from itertools import count
counter = count(1)
for row in rows:
row_id = counter.next()
In this example on every iteration through the rows you will get an other value for row_id, starting from the given argument (which was 1): 1, 2, 3, …
Generators an also be used in for loops directly:
for number in count(1):
print(number)
This will fastly print a list of numbers.
In you class it would be a good idea to create the counter in __init__() and call next() when needed:
def __init__(self, master):
self.counter = count(1)
…(more code)…
def submit(self):
my_id = self.counter.next()
…(more code)…

create a mathematis matrix with python

Well, I've looked a lot in the web before asking, so here's the thing.
I'm not really experienced in Python and I need to develop this Matrix Generator. Yes, it is a mathematics matrix. I'm using Tkinter and Python 3.3.
First i ask the Number of Rows and Columns and then I fill each field and the code transforms it in a notepad for other programs to read.
I used the grid method so i'm having trouble with large scale matrices. The thing is I need to apply a scrollbar. I have read that I can use frame and a friend of mine showed me a scrollbar he made using frames. Can you help me? ;D
Every time I refer to linhas is the same as rows and colunas is the same as columns.
import tkinter
class DropDown:
def __init__(self):
self._list_window = tkinter.Tk();
self._row_var = tkinter.StringVar(self._list_window)
self._col_var = tkinter.StringVar(self._list_window)
self._row_var.set(0)
self._col_var.set(0)
self._rows = None
self._columns = None
self._row_label = tkinter.Label(
master = self._list_window,
text = 'Number of rows: ')
self._row_label.grid(
row = 0, column = 0, padx = 5, pady = 5,
sticky = tkinter.NE)
self._row_entry = tkinter.Entry(self._list_window, width=1)
self._row_entry.grid(
row = 0, column = 1, padx = 5, pady = 5,
sticky = tkinter.EW)
self._column_label = tkinter.Label(
master = self._list_window,
text = 'Number of columns: ')
self._column_label.grid(
row = 1, column = 0, padx = 5, pady = 5,
sticky = tkinter.NE)
self._column_entry = tkinter.Entry(self._list_window)
self._column_entry.grid(
row = 1, column = 1, padx = 5, pady = 5,
sticky = tkinter.EW)
self._list_window.columnconfigure(1, weight = 1)
self._OK_button = tkinter.Button(
master = self._list_window, text = "OK",
command = self.get_dimensions)
self._OK_button.grid(
row = 2, column = 0, columnspan = 2,
padx = 5, pady = 5)
def get_dimensions(self):
self._rows = self._row_entry.get()
self._columns = self._column_entry.get()
self._list_window.destroy()
def show(self):
self._list_window.mainloop()
if self._rows != None and self._columns != None:
return (int(self._rows), int(self._columns))
else:
return (None, None)
class matrix:
def __init__(self, linhas, colunas):
self.linhas=linhas
self.colunas=colunas
self.mwindow=tkinter.Tk()
self.vars = [[] for x in range(self.linhas) ]
for i in range(self.linhas):
for j in range(self.colunas):
v=tkinter.StringVar()
self.vars[i].append(v)
entry = tkinter.Entry(master = self.mwindow, textvariable = self.vars[i][j])
entry.grid(row = i, column = j, padx = 10, pady = 10)
self.botOK=tkinter.Button(master=self.mwindow, text="OK", command=self.OK)
self.botOK.grid(row=self.linhas+1, column=(self.colunas//2)-1, columnspan=2, padx=5, pady=5)
def Start(self):
self.mwindow.mainloop()
return self.lista
def OK(self):
self.lista = []
for i in range(self.linhas):
for j in range(self.colunas):
self.lista.append(self.vars[i][j].get())
self.mwindow.destroy()
dimensoes= DropDown().show()
#print (dimensoes)
if dimensoes[0]<dimensoes[1]:
diag=dimensoes[0]
else:
diag=dimensoes[1]
matriz=matrix(dimensoes[0], dimensoes[1]).Start()
with (open("notepadmatrix.txt", "w")) as arquivo:
arquivo.write(str(dimensoes[0]*dimensoes[1])+"\n")
arquivo.write(str(dimensoes[0])+"\n")
arquivo.write(str(dimensoes[1])+"\n")
arquivo.write(str(diag)+"\n")
for i in matriz:
arquivo.write(i+"\n")
arquivo.write("fim")
and here goes the code he gave me to the scroll bar.
class Earnings():
def __init__(self, Ticker, EPS, Time):
self._root_window = tkinter.Tk()
self.canvas = tkinter.Canvas(master = self._root_window, background = '#8989E0')
self.canvas.config(scrollregion=[0,0,600,10000])
self.frame = tkinter.Frame(master = self.canvas)
self.scrollbar = tkinter.Scrollbar(master = self._root_window, orient = tkinter.VERTICAL)
self.frame.pack(side = tkinter.LEFT, fill = tkinter.BOTH, expand = tkinter.TRUE)
self.canvas.create_window((0,0), window=self.frame, anchor=tkinter.NW)
self.scrollbar.pack(side = tkinter.RIGHT, fill = tkinter.BOTH, expand = tkinter.TRUE)
self.canvas.pack(side = tkinter.TOP, fill = tkinter.BOTH, expand = tkinter.TRUE)
self.scrollbar.config(command = self.canvas.yview)
self.canvas.config(yscrollcommand = self.scrollbar.set)
self.ticker = Ticker
self.EPS = EPS
self.time = Time
for i in range(len(self.ticker)):
self.TickerButton = tkinter.Button(
master = self.frame,
text = self.ticker[i],
command = lambda i=i: self.search_ticker(self.ticker[i]))
self.TickerButton.grid(row = i+1, column = 0, padx = 10, pady = 10,
sticky = tkinter.W)
self.EPSLabel = tkinter.Label(
master = self.frame,
text = self.EPS[i])
self.EPSLabel.grid(row = i+1, column = 1, padx = 10, pady = 10,
sticky = tkinter.W)
self.TimeLabel = tkinter.Label(
master = self.frame,
text = self.time[i])
self.TimeLabel.grid(row = i+1, column = 2, padx = 10, pady = 10,
sticky = tkinter.W)
TkInter is long in the tooth, I'd use Kivy Grid layout instead:
http://kivy.org/docs/api-kivy.uix.gridlayout.html?highlight=grid

Categories