Active Topics

 


Reply
Thread Tools
pelago's Avatar
Posts: 2,121 | Thanked: 1,540 times | Joined on Mar 2008 @ Oxford, UK
#11
Originally Posted by attila77 View Post
Avoid things like MainWindow.ledArray[r].append(QtGui.QPushButton())
Hi, I'm not the OP but I'm trying to learn PyQt. Do you mean that
Code:
tempPushButton = QtGui.QPushButton()
MainWindow.ledArray[r].append(tempPushButton)
is the thing to do? Is there a reference as to why the first form is incorrect?
 
Posts: 3,319 | Thanked: 5,610 times | Joined on Aug 2008 @ Finland
#12
Originally Posted by pelago View Post
Hi, I'm not the OP but I'm trying to learn PyQt. Do you mean that
Code:
tempPushButton = QtGui.QPushButton()
MainWindow.ledArray[r].append(tempPushButton)
is the thing to do? Is there a reference as to why the first form is incorrect?
It's not incorrect, just might cause trouble on particular combination of methods and classes AFAIK the problem stems from two sources - from the way Python garbage collection works and from the problem that it does not necessarily know about object pointer ownership transfers than happen on Qt's level. Can't find anything descriptive on google right now, so you'll have to take my word for it Or remember this and when your first segfault appears, try the suggested change above and then ponder why it fixes the problem
__________________
Blogging about mobile linux - The Penguin Moves!
Maintainer of PyQt (see introduction and docs), AppWatch, QuickBrownFox, etc
 
mikec's Avatar
Posts: 1,366 | Thanked: 1,185 times | Joined on Jan 2006
#13
Originally Posted by attila77 View Post
Great stuff ! Two notes, though (not as discouragement, just as advices):

Avoid things like MainWindow.ledArray[r].append(QtGui.QPushButton())

The problem is that Python handles Qt object lifetimes/references differently than C++ and this (calling a constructor as a parameter for another function) can cause all sorts of nastiness if you're not careful. I know it's uglier to allocate a local variable for this, but you'll understand when you meet the first segfaults

The other note is python style - when dealing arrays it's recommended to use the 'in' operator. Faster, IMHO prettier and less error-prone than index based stuff. So, something like:

Code:
# c-ish
for r in range(8): 
            for c in range(16):
                self.ledArray[r][c].setChecked(self.ledState)

# pythonic
for row in self.ledArray: 
            for led in row:
                led.setChecked(self.ledState)
See ?

The Pythonic way rocks, so much easier when you know how
__________________
N900_Email_Options Wiki Page
 
Posts: 402 | Thanked: 229 times | Joined on Nov 2009 @ Missouri, USA
#14
I assume list comprehensions aren't used to keep things simple/terse?
__________________
aspidites | blog | aspidites@inbox.com
 
mikec's Avatar
Posts: 1,366 | Thanked: 1,185 times | Joined on Jan 2006
#15
Originally Posted by pelago View Post
Hi, I'm not the OP but I'm trying to learn PyQt. Do you mean that
Code:
tempPushButton = QtGui.QPushButton()
MainWindow.ledArray[r].append(tempPushButton)
is the thing to do? Is there a reference as to why the first form is incorrect?
Just tried this, and it does not work. you end up appending the same pushbutton into the array, rather than an instance of the qpushbutton. This has got me curious
__________________
N900_Email_Options Wiki Page
 
Posts: 3,319 | Thanked: 5,610 times | Joined on Aug 2008 @ Finland
#16
Originally Posted by mikec View Post
Just tried this, and it does not work. you end up appending the same pushbutton into the array, rather than an instance of the qpushbutton. This has got me curious
That's what I get when I don't post a full example just a hint. In python, all those objects are addressed by reference. If I understand correctly what you did, in C terms - you are appending the tempPushbutton *pointer address* to the list, not it's values, so whenever you change it, you changed all the values

I can already hear the question - but then I need to create an array and append all of them... yuck, that's no better than the original ! But before I address that valid concern, let's let's dig a little deeper into the topic of Python-style garbage collection. Take a look at this:

Code:
// C++
col = new QColor();
col = new QColor();

# Python
col = QtGui.QColor()
col = QtGui.QColor()
If you think the two are equivalent, you're wrong The point is that in case of C++, the first created object is still there after the second line, even though it is no longer directly addressable. In Python, however, the events of the second line mean the object will be garbage collected as there are no references left to it ! Now, to curve back to the original problem, we can solve this by increasing the reference count by hierarchical means, by specifying an explicit parent object.

This also explains why you don't get a segfault in your original example - by calling the layout's addWidget before the QPushButton you created a reference that prevents garbage collection. Without this, if you came back to it after the original QPushButton pointer went out of scope (or the reference disappeared for whatever ownership reason), you would get a big fat segfault because (unlike in C++) the underlying object is no longer there. So the alternative solution to local variables (which are ugly if you have many objects) is to specify parents in the constructor, creating the necessary reference to avoid garbage collection (i.e. mylist.append(QPushButton(parent))).

Usually you create enough references inadvertently (like here with addWidget, or QObject voodoo that happens behind the scenes) for garbage collection/ownership not to mess you up, but sooner or later, especially in applications with multiple intertwined classes, you *will* run into segfaults or weirdness because of this. Seems we got into deep water here, but the idea is not to get surprised when you meet your first segfaults and know where to look for trouble spots
__________________
Blogging about mobile linux - The Penguin Moves!
Maintainer of PyQt (see introduction and docs), AppWatch, QuickBrownFox, etc
 

The Following 2 Users Say Thank You to attila77 For This Useful Post:
Posts: 3,319 | Thanked: 5,610 times | Joined on Aug 2008 @ Finland
#17
Originally Posted by aspidites View Post
I assume list comprehensions aren't used to keep things simple/terse?
Yes, the whole thing could have been written as a one-liner with list comprehension, but that is a bit scary (and sounds backwards) for many python newbies. First things first

EDIT: just for the sake of completeness:
Code:
[[led.setChecked(self.ledState) for led in row] for row in self.ledArray]
__________________
Blogging about mobile linux - The Penguin Moves!
Maintainer of PyQt (see introduction and docs), AppWatch, QuickBrownFox, etc

Last edited by attila77; 2010-03-13 at 11:12.
 

The Following 2 Users Say Thank You to attila77 For This Useful Post:
Reply


 
Forum Jump


All times are GMT. The time now is 19:16.