Subclassing pyqtgraph.ParameterTree issue - python-3.x

I've been using the ParameterTree class very effectively, I like it a lot! I have a lot of parameters so I thought of subclassing ParameterTree in order to clear up some code. Unfortunately when I do this I get a weird-looking non-functional ParameterTree:
All the edit fields and comboboxes are gone
This is how I'm subclassing it
class CamParamTree(ParameterTree):
def __init__(self, *args, **kwargs):
super(ParameterTree, self).__init__(*args, **kwargs)
params = [.......]
self.p = Parameter.create(name='params', type='group', children=params)
self.setParameters(self.p, showTop=False)
and then in the main GUI I instanciate it like this:
class GUI(QtGui.QMainWindow):
def __init__(self, *args, **kwargs):
self.tree = CamParamTree()
What am I doing wrong?
Cheers

Just a simple error: you need
super(CamParamTree, self).__init__(*args, **kwargs)
instead of
super(ParameterTree, self).__init__(*args, **kwargs)

Related

How to modift the input list in TKINTER AUTOCOMPLETE to make it responsive

I have a GUI where a few fields must be completed, one of them usually has values that are repeated. These values are stored in an excel.
I would like to create an initial list out of the values of a given column and then to keep updating that column from new inputs that are stored in the same excel - they would be captured by 'surnames_list_df'.
... here it loads the DF and several other things.
surnames_list_df = list(set(df['Surname'].values))
MAIN = GUI()
MAIN.surnames_list.append(surnames_list_df) **
...
MAIN.mainloop()
Then in the GUI code:
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
...
self.surnames_list = []
...
# SURNAMES.
tk.Label(self, text='Surname:').grid(column=0, row=11, sticky='e')
self.surname_in = AutocompleteEntry(self, completevalues=self.surnames_list)
self.surname_in.grid(column=1, row=11)
I believe the problem is where I put the **. I have tried several ways to update that list inside the Class but I haven't been sucessful. Might I need to send the list as an input in the class? I haven't touched that because I am not sure how I made it work and don't want to break it now that I have made it work.
Thanks in advance.
Ok, I finally figured it out and was modifying the Class to accept attributes.
... here it loads the DF and several other things.
surnames_list_df = list(set(df['Surname'].values))
MAIN = GUI(surnames_list_df)
...
MAIN.mainloop()
Then in the GUI code:
class GUI(tk.Tk):
def __init__(self, surname_list_df, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
...
self.surnames_list = surname_list_df
...
# SURNAMES.
tk.Label(self, text='Surname:').grid(column=0, row=11, sticky='e')
self.surname_in = AutocompleteEntry(self, completevalues=self.surnames_list)
self.surname_in.grid(column=1, row=11)

Passing non-default arguments to Tk class constructor

I want to pass two Queues objects to a class the inherits Tk.tk.
main.py code:
qin = Queue()
qout = Queue()
gui = GUI(qin,qout)
gui.mainloop()
gui.py code:
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs) #if im calling tk.Tk.__init__(self) nothing is displayed to the screen so *args, **kwargs is requirement for some reason, not sure why
self.qin = args[0]
self.qout = args[1]
...
error:
gui = GUI(qin,qout)
File "/home/a/gui.py", line 20, in __init__
tk.Tk.__init__(self, *args, **kwargs)
File "/usr/lib/python3.9/tkinter/__init__.py", line 2270, in __init__
self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
TypeError: create() argument 1 must be str or None, not Queue
How to fix this error?
Thanks.
Just pop the args off of kwargs before passing kwargs to the superclass init.
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
qin = kwargs.pop("qin", None)
qout = kwargs.pop("qout", None)
tk.Tk.__init__(self, *args, **kwargs)
Or, if you don't care about the caller being able to pass in other arguments through to the superlcass, just define them as normal arguments:
class GUI(tk.Tk):
def __init__(self, qin, qout):
tk.Tk.__init__(self)

what if there is no Tk() declaration in the code

So I came across a Python3 tkinter GUI code snippet and it doesn't have anything like root = Tk() but IT RUNS! I read this and it is really helpful. But my question is, if the tk window and interpreter is initiated when I create my first widget, how can I add more widgets to the root without specifying it? aka. What should I do when I want to add more widgets to the same program / same window, since I don't have a variable like root to store the root window object?
By the way, there was a controller class like this:
class Controller(tk.Tk):
def __init__ (self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
parentObj = tk.Frame(self)
self.allFrames = {}
...
Does it mean that the parentObj frame is the windows / outmost layer of frame in this app? How do I understand this class definition here? What is tk.Tk.__init__(self, *args, **kwargs) here for?
Controller is a subclass of tk.Tk. Controller is identical to tk.Tk but with enhancements. Thus, doing something=Controller(...) serves the same purpose as something=tk.Tk().
What should I do when I want to add more widgets to the same program / same window,
Use self as the parent if inside the class, use the instance of the class if outside.
class Controller(tk.Tk):
def __init__ (self, *args, **kwargs):
...
self.some_widget = tk.Label(self, ...)
... and ...
root = Controller()
some_other_widget = tk.Label(root, ...)
Does it mean that the parentObj frame is the windows / outmost layer of frame in this app?
No. The outmost "layer" is the instance of Controller. That is the root window. parentObj lives inside that window.
What is tk.Tk.__init__(self, *args, **kwargs) here for?
This is just the standard python way for a subclass to initialize its parent class.

Spurious arguments to __new__ when using metaclass

I am trying to learn about metaclasses in python 3.7 and have the following code
class Foo(type):
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
return super().__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
return super().__call__(cls, *args, **kwargs)
class Bar(metaclass=Foo):
def __new__(cls, *args, **kwargs):
print(cls)
print(args)
print(kwargs)
return super().__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
return super().__init__(*args, **kwargs)
b = Bar()
When I run it I get the output
<class '__main__.Bar'>
(<class '__main__.Bar'>,)
{}
and the error
File "meta/main.py", line 91, in __new__
return super().__new__(cls, *args, **kwargs)
TypeError: object.__new__() takes no arguments
where the line correpondse to the __new__ call in Bar
I can't work out why the second <class '__main__.Bar'> is being passed in. If I change Bar to not use the Foo metaclass (i.e. change class Bar(metaclass=Foo): to class Bar:) I get
<class '__main__.Bar'>
()
{}
and no errors (as I would expect). Thanks for any help
You are passing in an extra argument on calls:
def __call__(cls, *args, **kwargs):
return super().__call__(cls, *args, **kwargs)
__call__ is not an implicit static method, drop that cls argument:
def __call__(cls, *args, **kwargs):
return super().__call__(*args, **kwargs)

Memoized objects still have their __init__() invoked?

So I am creating a memoized class, and have been observing a strange behavior.
Here's the snippet of the code:
class SomeClass(object):
_Memoized = {}
def __new__(cls, id: str, *args, **kwargs):
if id not in cls._Memoized:
print('New Instance')
cls._Memoized[id] = super(SomeClass, cls).__new__(cls, *args, **kwargs)
else:
print('Existing Instance')
return cls._Memoized[id]
def __init__(self, id: str):
print('Running init')
self.id = id
def test():
w1 = SomeClass(id='w1')
wx = SomeClass(id='w1')
print(id(w1), id(wx), id(w1) == id(wx))
test()
Running the above code results in:
New Instance
Running init
Existing Instance
Running init <===-------------------???
140008534476784 140008534476784 True
My questions: During the second invocation of SomeClass(), why does it execute the __init__ constructor? Wasn't the __init__ constructor only invoked on instantiating? Is there a way to prevent the __init__ from being invoked?
The purpose of __new__ is to create a new instance, which is why Python calls __init__ on it. You might instead override __call__ on a metaclass to avoid creating a new instance.
class MemoMeta(type):
def __init__(self, name, bases, namespace):
super().__init__(name, bases, namespace)
self.cache = {}
def __call__(self, id_, *args, **kwargs):
if id_ not in self.cache:
print('New Instance')
self.cache[id_] = super().__call__(id_, *args, **kwargs)
else:
print('Existing Instance')
return self.cache[id_]
class SomeClass(metaclass=MemoMeta):
def __init__(self, id_, *args, **kwargs):
print('Running init')
self.id = id_
def test():
w1 = SomeClass(id_='w1')
wx = SomeClass(id_='w1')
print(id(w1), id(wx), id(w1) == id(wx))
test()

Resources