Getting/Setting Tkinter Variables in a Controller/View Architecture -- Attribute Error - python

This question is directed at anyone who is familiar with the "psudeo-mvc" code and questions related to Bryan Oakley's Tkinter UI example here -- Unfortunately I do not have reputation enough to simply comment on an existing question.
I have read all the links off of the original question, and still cannot figure out what is wrong with my code. The only difference that I see is that I put my different "view" classes HomeWindow, OutfileWindow, TestWindow in separate python files, and am therefore importing them into the controller so it can see them -- obviously I am missing something... So the question is:
In two of my view classes HomeWindow and OutfileWindow I am trying to both get and set values in the shared_data dictionary. Why am I getting AttributeError on the shared_data variable?
Here is the relevant controller code:
import Tkinter as T
import HomeWindow
import OutfileWindow
import TestWindow
## This class inherits from Tkinter.Tk class.
class Controller(T.Tk):
## constructor for our PSSE Plotting Application
def __init__(self, *args, **kwargs):
T.Tk.__init__(self, *args, **kwargs)
T.Tk.title(self, "My Application")
self.configure(background = COLOR_WINDOW)
## Build a container frame within the root TK window that will hold all other widgets.
containerFrame = T.Frame(self)
containerFrame.configure(bg=COLOR_FRAME)
containerFrame.grid(row=0,column=0,sticky='nsew')
containerFrame.grid_rowconfigure(0, weight=1)
containerFrame.grid_columnconfigure(0, weight=1)
## build a dictionary of windows (tk frames) hashed by each frame's __name__ variable
windows = ( HomeWindow.HomeWindow,
OutfileWindow.OutfileWindow,
TestWindow.TestWindow )
## list of Frame Class __name__ variables which will act as keys
self.windowKeys = []
## dictionary Frame Class Objects
self.windowDictionary = {}
for frameClass in windows:
windowKey = frameClass.__name__
self.windowKeys.append(windowKey)
window = frameClass(parent=containerFrame, controller=self)
self.windowDictionary[windowKey] = window
window.grid(row=0, column=0, sticky="nsew")
## Call up the main window.
self.show_window("HomeWindow")
## ---------------------------------------------------------------------------
## dictionary of data that is accessible to all classes via the controller
self.shared_data = {
# file management
"cwd" : T.StringVar(),
"cwdSet" : T.BooleanVar(),
"allOutfiles" : [],
"selectedOutfiles" : [],
"allCsvfiles" : [],
"selectedCsvfiles" : [],
# data managment
"allChannels" : [],
"selectedChannels" : [],
"allColumns" : [],
"selectedColumns" : [],
# plot(s) management
"plot_titles" : [],
"xlabels" : [],
"ylabels" : [],
# Room for more....
"test" : "Hello World"
}
def show_window(self, windowKey):
window = self.windowDict[windowKey]
window.tkraise()
window.refresh()
And here is where I get errors when I try to access/use the values contained within shared_data:
class HomeWindow(T.Frame):
def __init__(self, parent, controller):
T.Frame.__init__(self,parent)
self.controller = controller
print self.controller.shared_data["test"]
And Again Here:
class OutfileWindow(T.Frame):
def __init__(self, parent, controller):
T.Frame.__init__(self,parent)
self.controller = controller
self.controller.shared_data["cwd"].set("Specify a directory...")
self.controller.shared_data["cwdSet"].set(False)
Here is the error for the first instance: (the second is the same error and variable)
> python27 Controller.py
Traceback (most recent call last):
File "Controller.py", line 211, in <module>
main()
File "Controller.py", line 199, in main
PlottingApplication = Controller()
File "Controller.py", line 71, in __init__
window = frameClass(parent=containerFrame, controller=self)
File "C:\Users\user\Documents\004_MyTools\005_Plotter\HomeWindow.py", line 37, in __init__
print self.controller.shared_data["test"]
File "C:\Program Files (x86)\Python27\lib\lib-tk\Tkinter.py", line 1903, in __getattr__
return getattr(self.tk, attr)
AttributeError: shared_data

Related

Tkinter Progressbar: ValueError: could not convert string to float: ''

I currently have a problem where I just do not know how to solve it.
In the controller I run a measurement, in the view I want to implement a progressbar.
To implement the progressbar in the view with the help of a StepValue, so how many steps per second, I need two values from the controller.
In the constructor in the controller I instantiate two StringVars, which are empty at the beginning. In the measurement, with the help of a method from the DeviceLibary, the method is to be called, which returns the times and these are to update the StringVars with the help of the set method.
In the view, the step value should be calculated from this, but apparently the StringVars are not updated.
class Controller():
def __init__(self):
super().__init__()
self.paramset = Paramset() #get parameters
self.get_test_done_time = tkinter.StringVar()
self.get_sample_period = tkinter.StringVar()
def measure_data(self, port):
try:
self.dev = Device(port) #Device is a libary
except Exception:
messagebox.showerror("Error", "No COM-Port")
return None
try:
self.dev.set_curr_range(self.paramset.curr_range[0].get())
self.dev.set_sample_rate(float(self.paramset.sampleRate[0].get()))
t, volt, curr = self.dev.run_test("cyclic", display='pbar',
filename=self.paramset.textdata[0].get())
self.get_test_done_time.set(self.dev.get_test_done_time())
self.get_sample_period.set(self.dev.get_sample_period())
self.dev.stop_test()
self.dev.close()
def start_test(self, port):
self.worker = threading.Thread(target=self.measure_data, args=(port,))
self.worker.start()
Class View:
def __init__(self):
self.controller = Controller()
self.percentLabel = Label(textvariable=self.percent)
self.progress_frame = ttk.Frame(self)
self.pb = ttk.Progressbar(self.progress_frame, orient=tk.HORIZONTAL, length=200)
self.pb.pack()
self.progress_frame.grid(row=len(vars(self.controller.paramset)) - 6, column=0)
self.start_button = ttk.Button(self.buttonframe, text="Start Test", command=lambda: self.start_measurement(self.portVar.get()) or self.start_progress_bar()) #start measurement = start_test in controller
def progress(self):
if self.variable.get() == "Cyclo":
if self.controller.worker.is_alive():
self.stepValue = float(self.controller.get_test_done_time.get())/ float(self.controller.get_sample_period.get())
while self.pb["value"] < 100:
self.pb['value'] += self.stepValue
self.percentLabel['text'] = self.update_progress_label()
time.sleep(1.2)
self.update_idletasks()
if self.pb["value"] == 100:
self.pb["value"] = 0
self.percentLabel['text'] = "Current Progress: 0.0%"
self.pb.stop()
self.update_idletasks()
def start_progress_bar(self):
self.progress_worker = threading.Thread(target = lambda:self.progress())
self.progress_worker.start()
Error:
Exception in thread Thread-2 (<lambda>):
Traceback (most recent call last):
File "C:\Users\xxx\AppData\Local\Programs\Python\Python310\lib\threading.py", line 1009, in _bootstrap_inner
self.run()
File "C:\Users\xxx\AppData\Local\Programs\Python\Python310\lib\threading.py", line 946, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\xxx\xxx\xxx\xxx\View.py", line 265, in <lambda>
self.progress_worker = threading.Thread(target = lambda:self.progress())
File "C:\Users\xxx\xxx\xxx\xxx\xxx\View.py", line 252, in progress
self.stepValue = float(self.controller.get_test_done_time.get())/ float(self.controller.get_sample_period.get())
ValueError: could not convert string to float: ''

kivy: KeyError: (3385,) in widget.py

When trying to exectue following code (edited version from the kivy-designer, stands under the MIT license):
def __init__(self, **kwargs):
self._buttons = {}
super(PlaygroundSizeView, self).__init__(**kwargs)
for title, values in self.default_sizes:
grid = StackLayout(orientation="lr-tb", size_hint=(1, None))
def sort_sizes(item):
return item[1][1] * item[1][0]
values = sorted(values, key=sort_sizes, reverse=True)
for name, size in values:
btn = ToggleButton(text='', markup=True, size_hint=(0.25, 0.25))
btntext = ('%s\n[color=777777][size=%d]%dx%d[/size][/color]' %
(name, btn.font_size * 0.8, size[0], size[1]))
btn.text = btntext
btn.bind(on_press=partial(self.set_size, size))
grid.add_widget(btn)
self._buttons[name] = btn
item = AccordionItem(title=title)
_sv = ScrollView(do_scroll_x=False)
_sv.add_widget(grid)
item.add_widget(_sv)
self.accordion.add_widget(item)
self.accordion.select(self.accordion.children[-1])
self.update_buttons()
I get following Error 7 times in a row with different numbers before the program stops:
Exception ignored in: functools.partial(, 3385)
Traceback (most recent call last):
File "E:\Programme(x86)\Python\Kivy Virtual Environment\lib\site-packages\kivy\uix\widget.py", line 239, in _widget_destructor
KeyError: (3385,)
It only appeared after I edited the code and added ScrollView at #1. I think it might be that python is trying to garbage collect ScrollView but is somehow unable to.
Linue 239 of widget.py is the del line of following function:
def _widget_destructor(uid, r):
# Internal method called when a widget is deleted from memory. the only
# thing we remember about it is its uid. Clear all the associated callbacks
# created in kv language.
del _widget_destructors[uid]
Builder.unbind_widget(uid)
Thanks a lot in advance!
That line #1 has a typo in add_widget.
Are you sure that add_widget returns the parent widget?
I suggest you make a ScrollView first, then add the grid, then add the item to accordion.

Python timed subprocess.Popen

I have the following code which gets data from a webscrape.
I only just learnt how to use the
subprocess.Popen
and i am trying to ouse my initiative along with other answers to similar questions on how to use the
subprocess.Popen
to execute the script below to get the webscrape data into my insert field updated every 30 seconds or so. But it is not working. Please could you point me in the right direction?
import xlrd
import subprocess
from Tkinter import *
import urllib2
from ttk import *
import Tkinter as tk
class Application(Frame):
"""GUI to display results of 'equity get'"""
def __init__(self, master):
"""initialise the Frame"""
Frame.__init__(self,master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""Create button, text and entry Widget"""
"""what it is i.e. label"""
url = "https://......."
request= urllib2.Request(url)
handle = urllib2.urlopen(request)
content = handle.read()
splitted_page = content.split("<.......">", 1);
splitted_page = splitted_page24[1].split("</.......>", 1)
self.data = Label(self, text ="Data")
self.data1 = Entry(self, width = 10)
self.data1.insert(0,splitted_page[0])
self.data.grid(column = 1, row = 1)
self.data1.grid(column = 2, row = 1)
self.data1.grid(column = 3, row = 1)
a = 0
while a < 10:
a += 1
time.sleep(15)
while True:
out = subprocess.Popen(["C:\Users\.....\Desktop\Py\python.exe","C:\Users\.....\Desktop\..\Python27\.....\tester.py"])
app = Application(root)
root.title("reload test")
root.geometry("700x300")
root.mainloop()
the error i get is
error no 22: invalid syntax referring to the script between the
(["C:\Users\.....\Desktop\Py\python.exe","C:\Users\.....\Desktop\..\Python27\.....\tester.py"])
then multiple command line windows open displaying the same error and i have to shut down the computer to stop it!
i amended the reference to my file with the 'r' prefix as follows:
([r"C:\Users\.....\Desktop\..\Python27\.....\tester.py"])
but removed the python.exe call as it just calling up the command line window. Now, i receive the following error message:
Traceback (most recent call last):
File "C:\Users\....\Desktop\Py\Python27\.....\tester.py", line 46, in <module>
app = Application(root)
File "C:\Users\......\Desktop\Py\Python27\.....\tester.py", line 18, in __init__
self.create_widgets()
File "C:\Users\.....\Desktop\Py\Python27\......\tester.py", line 44, in create_widgets
out = subprocess.Popen([r"C:\Users\Isaac\Desktop\Py\Python27\.....\tester.py"])
File "C:\Users\.....\Desktop\Py\lib\subprocess.py", line 672, in __init__
errread, errwrite)
File "C:\Users\.....\Desktop\Py\lib\subprocess.py", line 882, in _execute_child
startupinfo)
WindowsError: [Error 193] %1 is not a valid Win32 application
Python uses backslash to quote characters, like \n = newline and \t = tab.
Use an r prefix to make a raw string literal, like a Windows file path:
out = subprocess.Popen([r"C:\Users\.....\Desktop\Py\python.exe", r"C:\Users\.....\Desktop\..\Python27\.....\tester.py"])

Class Variable Retrieval in Python

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

Placing a Button in UltimateListCtrl using wxPython

I'm new to Pythong and I have been trying to get a button within UltimateListCtrl. I still can't figure out what I'm doing wrong. Here is my code:
try:
from agw import ultimatelistctrl as ULC
except ImportError: # if it's not there locally, try the wxPython lib.
from wx.lib.agw import ultimatelistctrl as ULC
self.table = ULC.UltimateListCtrl(self, -1, agwStyle=ULC.ULC_REPORT|
ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)
self.table.InsertColumn(0, "Name")
self.table.InsertColumn(1, "Size")
self.table.InsertColumn(2, "Download")
for i in range(0, len(masterlist)):
pos = self.table.InsertStringItem(i,str(masterlist[i]['name']))
self.table.SetStringItem(pos, 1,str(masterlist[i]['size']))
button = wx.Button(self, id=i, label="Download")
self.table.SetItemWindow(pos, col=2, wnd=button, expand=True)
masterlist is a list of download items.
I get this traceback:
Traceback (most recent call last):
File "E:\TestApp.py", line 67, in Display
self.table.SetItemWindow(pos, col=5, wnd=button, expand=True)
File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\lib\agw\ultimatelistctrl.py", line 12961, in SetItemWindow
return self._mainWin.SetItemWindow(item, wnd, expand)
File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\lib\agw\ultimatelistctrl.py", line 9021, in SetItemWindow
item.SetWindow(wnd, expand)
File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\lib\agw\ultimatelistctrl.py", line 1863, in SetWindow
mainWin = listCtrl._mainWin
AttributeError: 'MainWindow' object has no attribute '_mainWin'
button's parent should be your ULC i.e self.table
So change this line:
button = wx.Button(self, id=wx.ID_ANY, label="Download")
to this:
button = wx.Button(self.table, id=wx.ID_ANY, label="Download")
Update in response to comment:
For some reason it doesn't seem to be possible to delete all items in a ULC with the
DeleteAllItems() method if any of the items contain widgets so instead use DeleteItem().
def emptyList(self)
itemCount = self.list.GetItemCount()
for item in xrange(itemCount):
self.list.DeleteItem(0)

Categories

Resources