QStandardItemEditorCreator in PySide - python

I'm trying to implement Qt's Color Editor Factory Example (http://doc-snapshot.qt-project.org/4.8/itemviews-coloreditorfactory.html) in PySide.
The problem I'm facing is that QStandardItemEditorCreator class is not in PySide, or I haven't been able to find it after searching the docs for a long time. The only reference to it in the PySide documentation can be found in the following page (http://www.pyside.org/docs/pyside/PySide/QtGui/QItemEditorCreatorBase.html), the relevant part being the following:
QStandardItemEditorCreator is a convenience template class that can be used to register widgets without the need to subclass PySide.QtGui.QItemEditorCreatorBase .
Without any link to QStandardItemEditorCreator.
In short, how may I get QStandardItemEditorCreator's functionality in PySide?
Thanks.

I ended up implementing QStandardItemEditorCreator in python. Here's my implementation:
class QStandardItemEditorCreator(QItemEditorCreatorBase):
def __init__(self, cls):
super(QStandardItemEditorCreator, self).__init__()
self.propertyName = cls.staticMetaObject.userProperty().name()
self.cls = cls
def createWidget(self, parent):
return self.cls(parent)
def valuePropertyName(self):
return self.propertyName
If anyone has a better answer I'll gladly choose yours over mine.

Related

Keeping classes loosely coupled and sharing data

I've been working in python on a project where I have a GUI which I split up a bunch of the work between classes. I don't know a lot of the best practices for passing data around between classes, and I've frequently run into the issue, where I have to implement something, or change something for work, and I've resorted to making a lot of the classes objects of another class in order to give it the data I need.
Any ideas or suggests would be greatly appreciated on how to keep my classes independent for later modification and still pass the relevant data around without affecting interfaces too much?
As an example
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork(Window):
def __init__(self, parent=None):
self.parent=parent
I often find myself doing stuff like the above giving objects to class Window
or simply inheriting everything from them as in ParseMyWork
There must be better and cleaner ways of passing data around without making my classes utterly dependent on eachother, where one little change creates a cascade effect that forces me to make changes in a bunch of other classes.
Any answers to the question don't necessarily have to be in python, but it will be helpful if they are
If I'm understanding your question correctly, I would say that inheritance is not necessary in your case. Why not give ParseMyWork a function for dealing with a specific Window task?
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork():
def __init__(self, parent=None):
self.parent=parent`
def doWindowActivity(self, window):
window.doStuff
Then you can use the function like this
work_parser = ParseMyWork()
window = Window()
work_parser.doWindowActivity(window);
That way you can use your work_parse instance with any window instance.
Apologies in advance for my Python, it's been a while so if you see any rookie mistakes, do point them out.
Keep it simple.py:
def doStuff(window):
#do work here
return window
def parseStuff(stuff):
pass
really.py:
from simple import doStuff, parseStuff
def really_simple(window):
okay = doStuff(window)
return parseStuff(okay)
don't complicate the class:
from really import really_simple
really_simple(window)
imo: classes are overly complicated objects, and in a lot of cases more confusing than they need to be, plus they hold references and modify stuff, and can be difficult to decouple once they have been tied to other classes. if there isn't a clear reason why a class needs to be used, then it probably doesn't need to be used.
Classes are super powerful, so it's good you're getting started with em.
Discalimer: Haven't worked in python for a while now, so things might not be exact. The general idea still applies though.
Getting into your question now:
I would say the best way to achieve what you want is to create an instance of the first object where you will extract information from.
Now when creating a class, it's vital that you have attributes within them that you will want to be stored within it that you would like to retrieve once the class is instantiated.
For example, using your Window class example above, let's say that you have an attribute called resolution. It would look something like this:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
Now the resolution information associated with your Window class is forever part of any Window class instance. Now, the next step would be to create a get method for resolution. This should be done as follow:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
def getResoultion():
return self.resolution
Now, the reason we created this get method is because we can now set a variable to the information that is returned with it.
So let's say that you have everything associated with your Window class in its own file (let's say the file name is called Window.py). In a separate file (let's call it main.py), you can do the following:
import Window
windowInstance = Window()
windowResolution = windowInstance.getResolution()
If you print out the variable windowResolution, you should get that 40x80 printed out.
Now, as a side note, I do believe it is possible to get the information associated with an attribute with an instance of a class by simply doing something like
windowResolution = windowInstance.resolution
but that is bad practice in general. The reason, in a nutshell, is because you are now exposing attribute names of your class which you do not want to do because it makes it easy for a person outside of your code to learn the name where that information is held and change it. This can then lead to a myriad of other problems when it comes to making an overall program work. That is why it is best practice to use getters and setters. I already showed what getters are. Simply a get method for attributes. Setters, as you can probably assume, allow for one to set the information of an attribute to something else. Now you might say "Gabe, if we can create setter methods, what's the point of it if they just change it". My answer to that is to not give a setter method to all attributes. For attributes you don't mind for a person to change, give it a setter method, but for attributes you do not want any outside users to touch, simply don't create a setter method for it. Same goes with getter methods too. Users don't need to see all of the information of all attributes that makes your program work. Here's a better explanation: https://en.wikipedia.org/wiki/Mutator_method
Now, back to your example. Now let's say you have your ParseMyWork class in its own file like we did with your Window class, and let's say that ParseMyWork needs the resolution info from Window class. You can do the following :
import Window
import ParseMyWork
windowInstance = Window()
windowResolution = windowInstance.getResolution()
parseInstance = ParseMyWork(windowResolution)
This will only pass the window resolution information associated with your Window class. Hope this helps.

Drag and drop with pyqt5 (SIGNAL)

I am trying to get drag and drop (with images or files) working for my listwidget in pyqt5. I can find a lot of examples with pyqt4, but there is one part that does not work in the newer version:
In the "dropevent":
self.emit(QtCore.SIGNAL("dropped"), links)
and in the MainForm:
self.connect(self.view, QtCore.SIGNAL("dropped"), self.pictureDropped)
I read a lot of posts but can't seem to find an answer how this should be written down with pyqt5. Could anyone please help me with this?
link to the entire example:
PyQT4: Drag and drop files into QListWidget
Simple.
The signal must come first
The slot come as parameter.
You must connect only after the signal was created
You must emit only after the connection was made.
Here we go with a small example:
self.signalOwner.mySignal.connect(self.slotFunction)
In your example let's say and consider that the view owns the signal and that pictureDropped is your slot function, so:
self.view.dropped.connect(self.pictureDropped)
Remember, your signal must emit certain type(s) or nothing at all andddd your #pyqtSlot function must receive same type(s) with the function receiving the same amount of parameter that your signal emits.
I have made a post some short time ago about drag and drop with images, had many difficulties to figure it out how to accept events and how the classes behave, it's a bit deeper than only signals so, if you need here is the POST :D
Your linked example uses the old-style signal and slot syntax, whereas you need to use the new-style syntax. In PyQt4 (versions 4.5 or later), you could use either style, but PyQt5 only supports the new style.
The old-style syntax allowed custom signals to be emitted on-the-fly, but the new-style syntax demands that the signal is declared beforehand on the class:
class ListWidget(QtWidgets.QListWidget):
dropped = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
...
def dropEvent(self, event):
...
self.dropped.emit(list_of_files)
The signal connection is then made like this:
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
...
self.listWidget = ListWidget()
self.listWidget.dropped.connect(self.handleDropped)
def handleDropped(self, list_of_files):
print('dropped:', list_of_files)

How to use Gtk.Widget.set_template()

I am trying to use the Gtk.Widget.set_template() method but I am not sure how to use it without Gio.Resource. I am using python3 with gi.repository.
Let's say I have a foowidget.ui and then I would like to have a class:
class FooWidget(Gtk.Box):
Gtk.Box.__init__(self)
#set_template here with 'foowidget.ui'
self.init_template()
It is not possible right now to use set_template with python. There is an open bug for it here.
EDIT:
By now, it is possible to use templates with python. It looks like this:
from gi.repository import Gtk
#Gtk.Template(resource_path='/path/to/resource/window.ui')
class Window(Gtk.Window):
__gtype_name__ = 'Window'
button = Gtk.Template.Child()
def __init__(self, **kwargs):
super().__init__(**kwargs)
#Gtk.Template.Callback('clicked')
def on_button_clicked(self, widget):
pass
There is a package called pygi-composite-templates you can install via pip (or just copy to your project) that implements all of the necessary pieces to use composite templates using PyGObject. There is a working example project that uses Gio.Resource and and example that loads directly from a file too.
Find it on github.
Disclaimer: I'm the author of pygi-composite-templates

How to refactor those basic classes (PyQt5)

I am learning PyQt5 and I tried to create a extended widgets.
I am also learning OOP so I lack experience for this project.
My final goal is to have master widgets that can disable/enable some slave widgets.
So far I need check and radio buttons.
So I tried to create an abstract class that contains the extended behavior of the widgets (the management of the state of the slaves widgets):
class QDisablingWidget():
__metaclass__ = ABCMeta
def __init__(self):
self.slaveWidgets = []
self.slaveStateWhenMasterIsEnabled = {}
def addSlaveWidget(self, slaveWidget, isEnabledWhenMasterIsEnabled=True):
[...]
def updateSlaveStatus(self):
[...]
Then I create my extended widget classes:
class QDisablingCheckBox(QtWidgets.QCheckBox, QDisablingWidget):
def __init__(self, text=None, parent=None, isInMutexGroup=False):
super(QtWidgets.QCheckBox, self).__init__()
super(QDisablingWidget, self).__init__()
if text:
self.setText(text)
if parent:
self.setParent(parent)
self.isInMutexGroup = isInMutexGroup
# Click signal handling
self.stateChanged.connect(self.updateSlaveStatus)
class QDisablingRadioButton(QtWidgets.QRadioButton, QDisablingWidget):
def __init__(self, text=None, parent=None, isInMutexGroup=False):
super(QtWidgets.QRadioButton, self).__init__()
super(QDisablingWidget, self).__init__()
if text:
self.setText(text)
if parent:
self.setParent(parent)
self.isInMutexGroup = isInMutexGroup
# Click signal handling
self.toggled.connect(self.updateSlaveStatus)
You can already see the problem:
I need to connect my self.updateSlaveStatus to the correct signals (stateChanged and toggled) so I added it in the constructor of the derived classes.
Recently I also added the isInMutexGroup argument for some implementation reasons and I realize that I am duplicating the code in both derived classes...
It is the first time I try to use OOP "for real" (first attempt of multiple inheritance and abstract class), so even if I know I am breaking the beauty of the OOP concept, I don't know what to do to get a nice class hierarchy...
So basically, I am looking for a solution on this example. But I am also looking for guidelines, general advice, tutorials, etc. Actually anything that could help me!
Thank you for your help.
Even if I got a downvote for that question, I think some beginners could be interested by the solution I found:
I have my extension abstract class like that:
class QDisablingWidget(QtCore.QObject):
__metaclass__ = ABCMeta
def __init__(self, isInMutexGroup=False, **kwds):
[...]
Then I can derive class like that:
class QDisablingCheckBox(QtWidgets.QCheckBox, QDisablingWidget):
def __init__(self, **kwds):
super().__init__(**kwds)
# On click signal handling
self.stateChanged.connect(self.updateSlaveStatus)
and
class QDisablingRadioButton(QtWidgets.QRadioButton, QDisablingWidget):
def __init__(self, **kwds):
super().__init__(**kwds)
# On click signal handling
self.toggled.connect(self.updateSlaveStatus)
Finally, when I use the classes I need to create object like that:
disablingRadioBut = QWidgets.QDisablingRadioButton(text="My button",
parent=self,
isInMutexGroup=True)
I.e I must use keywords explicitly so that each constructors will eat the kewords the use/know.
Thanks to this approach I have maximum reusability of my extension class.
I got this solution here:
http://pyqt.sourceforge.net/Docs/PyQt5/multiinheritance.html
And more details here:
http://rhettinger.wordpress.com/2011/05/26/super-considered-super/
A very nice article!

PyQt4 - Custom widget class structure?

During regular intervals of my program, a block (of 3 stacked) widgets need to be added to a horizontal layout. Since the widgets within each block are important to eachother, I wish to encapsulate each stack as it's own widget (making the layout adding business much easier).
I'm having trouble getting PyQt4 to recognise my 'stack' as a widget.
I made the widget stack in Qt Designer (as form: widget) and converted it to a .py via
'pyuic4 DesignerFile.ui > ClassFile.py'.
Now I can't seem to add this 'stack' (parent widget of 3 child widgets) to the layout via .addWidget( Class ).
I tried constructing a super class of the stack class (because I need to add more functionality to the stack) but the instance of the class is either...
Not recognised as a widget
Invisible
defective because I've no idea on how to structure the super class.
Here's what I'm failing with at the moment (though it's about the 8th class structure I've tried):
from ClassFile import ClassCode
class Stack(ClassCode):
def __init__(self,parent= None):
QtGui.QWidget.__init__(self,parent)
Could somebody help me structure this or lead me to some good examples?
(I've mimicked the code in both the following sources but with no avail!!
http://lateral.netmanagers.com.ar/stories/27.html#what-you-need-to-follow-the-tutorial
http://zetcode.com/tutorials/pyqt4/customwidgets/ )
Thanks!
Specs:
python 2.7.2
PyQt4
Windows 7
When you compile a python module from a ui file with the default options, it will (amongst other things) generate a simple "setup" class. In outline, the setup class will look like this:
class Ui_ClassCode(object):
def setupUi(self, ClassCode):
ClassCode.setObjectName("ClassCode")
# bunch of boiler-plate ui code goes here
self.retranslateUi(ClassCode)
QtCore.QMetaObject.connectSlotsByName(ClassCode)
def retranslateUi(self, ClassCode):
pass
There are a couple of issues to notice here that are relevant to the question.
Firstly, the setup class is designed to be used as a mixin rather than as a direct subclass. It's task is to "inject" ui into a host widget that is passed to the setupUI method.
Secondly, the setup class is given an ugly, unpythonic identifier that is created by prepending "Ui_" to the objectName property that was set in Designer.
Fortunately, pyuic4 provides a way to bypass these two issues. All that's required is to use the -w option when compiling the python module from the ui file:
pyuic4 -w designerfile.ui > classfile.py
This will add a wrapper class that (1) can be easily subclassed, and (2) has the class-name that you damn well gave it in Qt Designer.
The wrapper class will look something like this:
class ClassCode(QtGui.QWidget, Ui_ClassCode):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QWidget.__init__(self, parent, f)
self.setupUi(self)
As you can see, it doesn't do anything special: you could easily replicate what it does in your own code. But, IMO, it does make the compiled modules much more intuitive to use.
For example:
from PyQt4 import QtGui, QtCore
from classfile import ClassCode
class Stack(ClassCode):
def __init__(self, parent=None):
ClassCode.__init__(self, parent)
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.stack = Stack(self)
self.setCentralWidget(self.stack)
First, it's more appropriate to call the parent __init__ with the use of super. That will ensure the method in the proper super class is invoked. Second, when using a class constructed with pyuic, you need to call self.setupUi(self) from your __init__ method. And lastly, you need to make sure and multiple inherit from both the proper Qt class and the pyuic generated class (which is really more of a mixin).
So, something like this:
from ClassFile import ClassCode
class Stack(QtGui.QWidget, ClassCode):
def __init__(self,parent= None):
super(Stack, self).__init__(parent)
self.setupUi(self)

Categories