Re: [PyQt] simpler 'connect' function
On Wednesday 16 January 2008 09:21:40 Aaron Digulla wrote: As for making the API simpler, I'd opt for button.connectClicked(self.buttonWasClicked) Wouldn't it be nicer if the signals where attributes of your object, so that you could write button.clicked.connect(self.onButtonClicked) (and likewise for disconnect). This is basically what C# uses, although there the += and -= operators are used for connect and disconnect respectively. To connect one would get: button.clicked += self.onButtonClicked I've adopted this notation in my Python programs because I think it's the most visually appealing. -- -- Ewald ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
On 2008-01-17, Ewald de Wit wrote: On Wednesday 16 January 2008 09:21:40 Aaron Digulla wrote: As for making the API simpler, I'd opt for button.connectClicked(self.buttonWasClicked) Wouldn't it be nicer if the signals where attributes of your object, so that you could write button.clicked.connect(self.onButtonClicked) (and likewise for disconnect). That seems like a nice syntax to me. Qt Jambi (Qt bindings for Java) uses a similar (but not quite as nice) syntax: button.clicked.connect(this, buttonClicked()); This is basically what C# uses, although there the += and -= operators are used for connect and disconnect respectively. To connect one would get: button.clicked += self.onButtonClicked I'm not at all keen on this though. I've adopted this notation in my Python programs because I think it's the most visually appealing. -- -- Ewald ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt -- Mark Summerfield, Qtrac Ltd., www.qtrac.eu ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
Quoting Ewald de Wit [EMAIL PROTECTED]: On Wednesday 16 January 2008 09:21:40 Aaron Digulla wrote: As for making the API simpler, I'd opt for button.connectClicked(self.buttonWasClicked) Wouldn't it be nicer if the signals where attributes of your object, so that you could write button.clicked.connect(self.onButtonClicked) That's one way to look at it. In C++, a signal is much more close to a method, though. Taking a step back, what happens behind the scenes is: connect(sender, signal, receiver, slot) i.e. connect is a global / static function. It just happens to work only with classes derived from QObject, so it has been implemented as a member method but actually, it just connects two QObjects. So the syntax most closely resembling what is actually going on would be: connect(button.clicked, self.onButtonClicked) For this to work, clicked must be implemented as a method of QPushButton, for example, so that connect() can pick the sender object from the call. As a convenience (since clicked() is now a full-blown method), this would work, too: button.clicked(self.onButtonClicked) Since signals are actually declared in the C++ class headers, I think there is no possibility to have clashes between method and signal names. Unfortunately, this again introduces ambiguities because of argument overloading which must be solved by mapping argument types to the method name, probably manually. Regards, -- Aaron Optimizer Digulla a.k.a. Philmann Dark It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits. http://www.pdark.de/ ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
RE: [PyQt] simpler 'connect' function
Ewald de Wit Wouldn't it be nicer if the signals where attributes of your object, so that you could write button.clicked.connect(self.onButtonClicked) Is there a clean way to handle signals with the same name that take different arguments? Here's an idea I can think of for QComboBox. combo.activated[int].connect(callback1) combo.activated[QString].connect(callback2) This sort of matches the syntax the clr library is using to bind to dotnet generic functions. This could still lead to ambiguities where a signal argument used variations on the same type (reference vs pointer vs const). Another thing to keep in mind is defining new slots on custom classes. Declaring them statically on the class would be a closer match to what C++ Qt does, but a departure from existing Pyqt code. class MyObject(QObject): forgotten = QtCore.SLOT() remembered = QtCore.SLOT([QString]) perhaps = QtCore.SLOT_shortCircuit() Interesting ideas. But I don't really have problems with the existing connect function. If we could just get rid of the SIGNAL requirement and pass a string argument it would get a whole lot nicer. ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
RE: [PyQt] simpler 'connect' function
Aaron Digulla: I've wasted several hours searching for typos so far, so I can't live with the current state and making this area even more volatile will only increase the chance that I'll give up on PyQt and create a fork. At minimum I'm talking about the simplification of a single argument to an existing function. You are talking about entirely new attributes that leave no room for expansion and bring new ambiguities. I've been using Pyqt for several years the way it is. I don't feel it's broken and fork-worthy as you do. I do see room for improvements, and don't need drastic changes. Remember: If everyone in the world would develop software the way you do, you'd be unemployed. I'm not sure how to interpret this. I hope to keep using Pyqt for a long time. ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
Peter Shinners schrieb: But I don't really have problems with the existing connect function. If we could just get rid of the SIGNAL requirement and pass a string argument it would get a whole lot nicer. I've wasted several hours searching for typos so far, so I can't live with the current state and making this area even more volatile will only increase the chance that I'll give up on PyQt and create a fork. Remember: If everyone in the world would develop software the way you do, you'd be unemployed. Regards, -- Aaron Optimizer Digulla a.k.a. Philmann Dark It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits. http://darkviews.blogspot.com/ http://www.pdark.de/ ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
Peter Shinners schrieb: Remember: If everyone in the world would develop software the way you do, you'd be unemployed. I'm not sure how to interpret this. I hope to keep using Pyqt for a long time. I'm trying to make you understand that your way of developing software works for *you* but not for *me*. I'm a very fast developer but that means I quickly get frustrated when I can't track down bugs fast. I wrote a little app with around 8000 lines of code in the past two weeks, say 40h all in all, in my spare time. Of that, I spent 4 hours hunting a connect() bug and 8 hours because of the setModel() bug I reported in another thread. With tiny, compatible changes in the API, I could have used that time on real work and I'd have, say, 3000 additional lines of code instead of a weekend wasted. So that means, usually, I can code a huge amount of functionality in a very short time but for these two weak spots (connect and GC), I'm losing a lot of time and I see that a lot of other beginners have the same problem. In the past two weeks, many people have complained about the connect API and most don't like the current string literals. Therefore, I'm trying to argue to make some changes to make PyQt more bullet proof for beginners. If I get the feeling that no one listens to my arguments, then I'll do what I have to do to scratch my itch: I'll fork the project. Regards, -- Aaron Optimizer Digulla a.k.a. Philmann Dark It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits. http://darkviews.blogspot.com/ http://www.pdark.de/ ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
On Thursday 17 January 2008 18:27:19 Peter Shinners wrote: button.clicked.connect(self.onButtonClicked) Is there a clean way to handle signals with the same name that take different arguments? Here's an idea I can think of for QComboBox. combo.activated[int].connect(callback1) combo.activated[QString].connect(callback2) A simpler way would be to just give the signal objects a different name, like activatedInt and activatedString. It's the easiest way to uniquely specify which signal you mean. Btw, it would also be convenient to have an emit method on the signal object, like for example combo.activatedInt.emit(1) combo.activatedString.emit('Pizza') canvas.mouseMoved.emit(dx, dy) If __call__ is used instead of emit, then the syntax becomes even shorter: canvas.mouseMoved(dx, dy) And once there is a signal object, other methods become possible as well. For example a slots() method that returns a list of all connected slots. One could then do lazy evaluation like if self.heavyJobFinished.slots(): result = self.doHeavyJob() self.heavyJobFinished.emit(result) This example skips doing the heavy job if there is no one listening for the result. Just some ideas. -- -- Ewald ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
On Thursday 17 January 2008, Ewald de Wit wrote: On Thursday 17 January 2008 18:27:19 Peter Shinners wrote: button.clicked.connect(self.onButtonClicked) Is there a clean way to handle signals with the same name that take different arguments? Here's an idea I can think of for QComboBox. combo.activated[int].connect(callback1) combo.activated[QString].connect(callback2) The problem with this approach is that you can't represent all C++ argument types with Python types. A simpler way would be to just give the signal objects a different name, like activatedInt and activatedString. It's the easiest way to uniquely specify which signal you mean. The problem with this is that things can get clunky - focusChangedQWidgetPtrQWidgetPtr for example. Those that don't like strings because they can't be type checked are wrong. They can be type checked against Qt signals (see QMetaObject::indexOfSignal()). The problem is that they can't be distinguished from Python signals which are not pre-defined. My prefered option at the moment is just not to support Python signals in any new approach - short-circuit signals would have to be used instead (which don't have parentheses and are therefore easy to distinguish from Qt signals). Phil ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
RE: [PyQt] simpler 'connect' function
Quoting Peter Shinners [EMAIL PROTECTED]: That's why I'm against string literals in an API. If that API doesn't even offer any checks to string literals, that's even worse. I'd be against using constants to define the signals. What type of value is going to match things like const QString? How can Pyqt possibly check that the given callback accepts the type of arguments requested? You're missing my point: I try to reduce the amount of typos. If all signals in Qt were predefined constants in PyQt, then a typo would result in attribute not found exceptions when they are defined instead of volatile doesn't work bugs when they are used for the first time. I'm not trying to fix signals defined by other frameworks which extend Qt nor ones written by PyQt developers. If they want to waste their time hunting typos, I'm cool with that. Everyone has the right to make their lives as miserable as they want. As for making the API simpler, I'd opt for button.connectClicked(self.buttonWasClicked) I think that would be the most simple API possible which still a) doesn't introduce ambiguity (you can't omit the connect), b) contains the two objects to connect, c) makes sure which one sends and which one receives in the right/intuitive way (i.e. in the way most of the people think), d) allows to catch typos, e) allows to check argument types, f) allows to use auto-completion and g) is backward compatible. Your proposed change doesn't fit d) to g). If you still think it's a good idea, you can always try to implement it (just do QPushButton.connect = ...) and after a while, you'll see how it's bad. Regards, -- Aaron Optimizer Digulla a.k.a. Philmann Dark It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits. http://www.pdark.de/ ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
Just jumping in on the thread here,not replying to anyone in particular. I modified (polite word for hacked up) an example program written by Troy Melhase for PyKDE3, and what he had done was kind of interesting, I thought: sigClicked = SIGNAL (clicked ()) class MainWindow (KMainWindow): def __init__ (self, parent): ... self.connect (self.button, sigClicked, self.buttonClicked) The program uses 15-20 signals, all defined and referenced as above. It'd seem like it would be possible to have PyQt/PyKDE automatically do the SIGNAL definitions (as predefined constants, for example SIG_CLICKED) and then just reference them as in the connect statement above. I don't know if any checking could be performed to validate that 'self.button' really emits a 'sigClicked' or 'clicked ()' signal. I also don't know if I'd really advocate this or if I'd do it this way again, but it was a nice way to organize the program and still keeps things readable - just thought I'd throw it out as one alternative. Jim ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
RE: [PyQt] simpler 'connect' function
Pete Shinners: Creating a method or constant for each type of signal does solve d and f, but comes at a cost. 1) Adds new methods or symbols that are not a part of Qt. 2) Breaks non-qt widgets that have custom signals. 3) Ambiguity for overloaded signals like QComboBox's activated. There is no cost to enhancing connect to work as a method, other than remembering there is another calling style. Also do not forget the creating of signals in Python. The usefulness of Pyqt's short circuited signals would require a tricky framework to work the same as the predefined signals inside Qt. ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
RE: [PyQt] simpler 'connect' function
Quoting Peter Shinners [EMAIL PROTECTED]: No, but a few ideas have been thrown around on the list in the past couple of days. Your suggestion is nice and concise - the dropping of SIGNAL() was briefly discussed during developed of PyQt4. Allowing string arguments for the signal/slot name would be a good improvement. Hopefully the change can be made for connect and emit. I'd still vote for connect to be a method on QObject instances. Since the first argument to connect must always be a QObject instance (?), it would cut down on the awkwardness. Sorry, I can't follow you here. 1) signal and slot already take string arguments. This discussion is to get rid of them. 2) connect is already a method of QObject. Since you have to connect two objects, you must always pass the second one as a parameter to the first.connect() call. Currently, my favorite is: self.connect(other.CLICKED, ) because that avoids typos and folds the first and second argument of the connect call into one argument. I'm just curious how you can split other.CLICKED into other and other.__class__.CLICKED in connect without losing compatibility with old code. self.connectClicked(other, ...) would be more simple but it's a brain twister: clicked doesn't belong to self but to other. other.connectClicked(self.otherWasClicked) might be the way to go. Regards, -- Aaron Optimizer Digulla a.k.a. Philmann Dark It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits. http://www.pdark.de/ ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
Peter Shinners schrieb: Aaron Digulla: Sorry, I can't follow you here. 1) signal and slot already take string arguments. This discussion is to get rid of them. I get TypeError: argument 2 of QObject.connect() has an invalid type when I try to pass a string to connect. Is this a change coming for 4.4? QObject.connect(other, clicked(), self.onOtherClicked) # Would be better No, you still have to wrap the string in a call to QtCore.SIGNAL() but that's still a string to me: No type checking, no way to know if your signal is really connected to anything and whether it will fire or not. That's why I'm against string literals in an API. If that API doesn't even offer any checks to string literals, that's even worse. 2) connect is already a method of QObject. Since you have to connect two objects, you must always pass the second one as a parameter to the first.connect() call. Currently, my favorite is: self.connect(other.CLICKED, ) It is currently similar to a static method of QObject. I'd prefer and instance method on all QObjects. The problem I have with the above syntax is that seem to work well when connecting to functions. More generally useful would be. other.connect(clicked(), self.onOtherClicked) # Would be best Hopefully either of these can be added in addition to the current. QObject.connect(other, SIGNAL(clicked()), self.onOtherClicked) # Connect in 4.3 The actual call is QObject.connect(other, SIGNAL(clicked()), self, self.onOtherClicked) i.e. it connects other, SIGNAL(clicked()) to self, self.onOtherClicked (because the fourth parameter could be a method of a third Python object). As I said before, I'd like an API which avoid the code duplication and the error prone string literals. In my own code, I predefine all signals I want to use. In Python, this is actually pretty simple. Just put this code in an __init__.py file of your module: --- __init__.py --- from PyQt4.QtCore import SIGNAL, QAbstractTableModel, QAbstractItemModel, QModelIndex from PyQt4.QtGui import QTextEdit, QLineEdit, QItemSelectionModel, QPushButton, \ QAction # Define constants for many signals QAbstractItemModel.DATA_CHANGED_SIGNAL = SIGNAL('dataChanged(QModelIndex,QModelIndex)') QAbstractItemModel.COLUMNS_ABOUT_TO_BE_INSERTED_SIGNAL = SIGNAL('columnsAboutToBeInserted(QModelIndex,int,int)') QAbstractItemModel.COLUMNS_INSERTED_SIGNAL = SIGNAL('columnsInserted(QModelIndex,int,int)') QAbstractItemModel.COLUMNS_ABOUT_TO_BE_REMOVED_SIGNAL = SIGNAL('columnsAboutToBeRemoved(QModelIndex,int,int)') QAbstractItemModel.COLUMNS_REMOVED_SIGNAL = SIGNAL('columnsRemoved(QModelIndex,int,int)') QAbstractItemModel.ROWS_ABOUT_TO_BE_INSERTED_SIGNAL = SIGNAL('rowsAboutToBeInserted(QModelIndex,int,int)') QAbstractItemModel.ROWS_INSERTED_SIGNAL = SIGNAL('rowsInserted(QModelIndex,int,int)') QAbstractItemModel.ROWS_ABOUT_TO_BE_REMOVED_SIGNAL = SIGNAL('rowsAboutToBeRemoved(QModelIndex,int,int)') QAbstractItemModel.ROWS_REMOVED_SIGNAL = SIGNAL('rowsRemoved(QModelIndex,int,int)') QAbstractTableModel.DATA_CHANGED_SIGNAL = SIGNAL('dataChanged(QModelIndex,QModelIndex)') QAction.TRIGGERED = SIGNAL(triggered()) QItemSelectionModel.SELECTION_CHANGED = SIGNAL('selectionChanged(QItemSelection,QItemSelection)') QLineEdit.TEXT_EDITED = SIGNAL('textEdited(QString)') QModelIndex.__str__ = lambda self: 'QModelIndex valid=%s row=%d column=%d' % (self.isValid(), self.row(), self.column()) QPushButton.CLICKED = SIGNAL('clicked()') --- __init__.py --- Now, you can do this anywhere: self.connect(closeButton, QPushButton.CLICKED, self.accept) (because the init file is loaded *once* when your module is accessed from *anywhere* for the *first* time). Regards, -- Aaron Optimizer Digulla a.k.a. Philmann Dark It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits. http://darkviews.blogspot.com/ http://www.pdark.de/ ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
RE: [PyQt] simpler 'connect' function
Aaron Digulla: No, you still have to wrap the string in a call to QtCore.SIGNAL() but that's still a string to me: No type checking, no way to know if your signal is really connected to anything and whether it will fire or not. That's why I'm against string literals in an API. If that API doesn't even offer any checks to string literals, that's even worse. I'd be against using constants to define the signals. What type of value is going to match things like const QString? How can Pyqt possibly check that the given callback accepts the type of arguments requested? The type of safety you are asking for is not possible, regardless of the signal argument type. Python could help with some introspection, but a predefined constant does not help any more than a string literal. The actual call is QObject.connect(other, SIGNAL(clicked()), self, self.onOtherClicked) i.e. it connects other, SIGNAL(clicked()) to self, self.onOtherClicked (because the fourth parameter could be a method of a third Python object). I assume this type of call is only given as a placeholder to match the C++ syntax. Pyqt takes a single callable as the slot, the fourth paramater is optional and unnecessary. Still hoping to see other.connect(clicked(), onOtherClicked) other.emit(clicked()) ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
[PyQt] simpler 'connect' function
I'm sure this has come up, but as I write my Pyqt code, I keep noticing that the QObject.connect call feels like a wart. Is there already a pyqt shortcut for a call like this? QtCore.QObject.connect(myButton, QtCore.SIGNAL(clicked()), onClicked) The closer I could be to something like the following, the better. myButton.connect(clicked(), onClicked) Are there any shortcuts for wiring signals and slots I haven't noticed? ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
I'm not sure how accepted that approach is, but I personally really didn't like having to say QtGui and QtCore all the time, so I from ... import *-ed those. This makes a connect a couple words shorter and a lot less hideous. On Jan 10, 2008 6:26 PM, Peter Shinners [EMAIL PROTECTED] wrote: I'm sure this has come up, but as I write my Pyqt code, I keep noticing that the QObject.connect call feels like a wart. Is there already a pyqt shortcut for a call like this? QtCore.QObject.connect(myButton, QtCore.SIGNAL(clicked()), onClicked) The closer I could be to something like the following, the better. myButton.connect(clicked(), onClicked) Are there any shortcuts for wiring signals and slots I haven't noticed? ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Re: [PyQt] simpler 'connect' function
On Thursday 10 January 2008, Peter Shinners wrote: I'm sure this has come up, but as I write my Pyqt code, I keep noticing that the QObject.connect call feels like a wart. Is there already a pyqt shortcut for a call like this? QtCore.QObject.connect(myButton, QtCore.SIGNAL(clicked()), onClicked) The closer I could be to something like the following, the better. myButton.connect(clicked(), onClicked) Are there any shortcuts for wiring signals and slots I haven't noticed? No, but a few ideas have been thrown around on the list in the past couple of days. Your suggestion is nice and concise - the dropping of SIGNAL() was briefly discussed during developed of PyQt4. One sublety of your suggestion is that self provides the emitter object whereas the short form of the Qt connect uses this to provide the slot object. I don't know if that would be counter-intuitive. I'd like people to continue to throw out suggestions and see if any sort of concensus appears. The existing method for making connections will be retained no matter what. Phil ___ PyQt mailing listPyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt