<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">That didn't change things for me.<br>
<br>
... which is good.  For my test, I require a long-running task that<br>
locks the GUI.  Both QPixmap *save* and QImage *save* seem to fill the<br>
bill.<br>
<br>
I changed QMessageBox to *exec_* from *show* and fired it from the<br>
*started* signal of the thread per your example, which seems to be a<br>
straightforward approach, but that couldn't manage to display anything<br>
unless the thread paused with a *sleep* first.<br></blockquote><div><br></div><div>I *think* that it depends on "where" (as in "which thread") the task occurs.</div><div>The issue with QPixmap.save() comes from the fact that, being it not thread</div><div>safe, it would lock the main loop.<br>So, I suppose that your "threaded" function might not be actually thread</div><div>safe with Qt's main loop. I think that a good way to find out if it is is to check</div><div>if the GUI actually responds after the QThread.sleep (in the code you gave,</div><div>it means testing if the button responds to mouse events while saving).<br>In my tests, using QPixmap.save it didn't: the "Ok" button didn't react until</div><div>the saving was completed. If that's the case, you might need to do some</div><div>kind of introspection about what your function actually does. Keep in mind</div><div>that even some "declared" thread safe functions might lock the GUI, even</div><div>if run from a separated QThread.</div><div>Unfortunately I'm not such an expert about threading, and I cannot give</div><div>you a fair and complete answer about that. Sorry.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Returning to your kind reply....<br>
<br>
> - You don't need to return every function if the returned value is<br>
> not required, as Python implicitly returns None if no explicit<br>
> return exists<br>
<br>
Hah!  You're not the first to be bugged by this habit of mine. </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">[...] </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">When I'm writing my own classes, I'll usually make the *set* methods </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">return *self*, for example.<br></blockquote><div><br></div><div>Well, as I wrote, "you don't need": nobody says you couldn't try :-)<br>As long as you're "comfortable" with your code, do what you want with it.<br>I'm just saying it because, when analyzing somebody else's code, people</div><div>could be annoyed about unnecessary lines. It's just not about "duh, who</div><div>cares", but possibly something like "I'm eager to help you, but, please,</div><div>don't bugger me with unnecessary code that only distracts me from</div><div>actually helping you and finally just ignore it".<br>When I'm asking out for help I usually spend a *lot* of time making my</div><div>code as much as "standard" as possible: it's something that can take</div><div>a *long* time to be achieved, but I know that it's also something that</div><div>would dramatically increase the possibility of somebody helping me: if </div><div>somebody see my code and can understand it on the fly, he/she might</div><div>be able to answer me instantly, or, at least, better consider to take some</div><div>of his/her time to do so.</div><div>I've seen plenty of "custom-styled-code" in both questions and answers</div><div>that people would just ignore because they were just too hard to read,</div><div>even for the most "meaningless" reason (such as variable namings not</div><div>following PEP or framework standards like using capitalized names for</div><div>variables or class/instance properties; believe me, that's just confusing,</div><div>no matter what you do with your own code).</div><div>The result is pretty simple: even if I spend an hour to write a more</div><div>readable question, I know that I'm increasing the possibility of someone</div><div>answering me (and it goes the same with answers too). The alternative</div><div>is that I don't care about it, losing the even slight possibility of a single </div><div>person being able or eager to help me, leaving me without any answer</div><div>at all.</div><div>And, at the same time and maybe even more important, leaving</div><div>somebody else, with the same kind of doubt, without an helpful answer.</div><div><br></div><div>Everybody has his/her habits, that's no harm in that. But when you're<br></div><div>asking a question or giving an answer, you cannot expect that</div><div>everybody follows your own standards, no matter how they fit you.</div><div><br></div><div>[end of my uncalled rant; sorry, but I really think that it's important,</div><div>and I know I'm not the only one :-) ]</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">> - Avoid using object names that already are existing properties or<br>
> methods (like self.thread)<br>
<br>
Oh, heck!<br>
<br>
I remember, writing Pascal, where it was fairly common to prefix<br>
labels to indicate their type: x-strings, i-integers, f-functions, and<br>
xxx-methods, where xxx was the abbreviated name of the class.  This<br>
had the virtue of avoiding tracking-over implementor's names during<br>
subclassing and having your own tracked-over in turn.  In Python, it's<br>
much more chic to rely on implicit typing, and best practice is to<br>
avoid such prefixing, and I get into trouble.<br></blockquote><div><br></div><div>Well, Python has its ups and downs.</div><div>The dynamic typing and its property/attribute are a bless as they're</div><div>some kind of a disgrace.</div><div>[Un]fortunately, the properties and function/methods of Qt are quite</div><div>standardized, but I can understand that there can be some "mishap"</div><div>here and there, because they are *a lot* and sometimes you might just</div><div>forget about them. Just yesterday I finally found out that I had a bug</div><div>with a calendar function because I was using a function named</div><div>"moveEvent" (which made sense, as it was necessary to "move" the</div><div>start date of a calendar event), until I remembered that "moveEvent"</div><div>is a standard QWidget protected function.<br><br>Sometimes I even don't care about them myself, as long as I'm sure</div><div>that I don't need them, but I try to avoid that practice (especially in</div><div>shared code). As a rule of thumb, just really think when you're naming</div><div>functions, methods, properties or attributes.<br>From time to time you'll get it wrong anyway, but that's just part of the</div><div>process :-)</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">> - You can connect the finished signal directly to the close (or,<br>
> better, accept) slot of the popup and delete the thread itelf:<br>[...]<br>
That's cool!  Didn't think of that.  The modal dialog can be harnessed<br>
for non-modal duty.<br>
<br>
I dithered about whether to *del* the thread and popup structures.  In<br>
my extended test suite, they are replaced by new ones for each<br>
scenario, and presumably the old ones are garbage-collected soon<br>
thereafter.  Not bothering about garbage collection is one of the<br>
principal virtues of coding in Python, and I shouldn't have worried<br>
about trying to show their destruction explicitly.  Aren't explicit<br>
deletes like *del* or *deleteLater* truely rundundant?<br></blockquote><div><br></div><div>Well.</div><div>One of the main issues about PyQt is that the Python and "C++"</div><div>counterparts of Qt objects are not always "sync'd", and that's due to</div><div>the fact that PyQt is a "binding" to "C++" objects.</div><div>You can "delete" a python "Qt" object, leaving its C++ counterpart still</div><div>existing, and viceversa.</div><div>For example:</div><div><br></div><div class="gmail_quote"><div class="gmail_quote"><font face="monospace">class SomeObject(QtCore.QObject):</font></div><div class="gmail_quote"><font face="monospace">    def __init__(self):</font></div><div class="gmail_quote"><font face="monospace">        super(SomeObject, self).__init__()</font></div><div class="gmail_quote"><font face="monospace">        child = QtCore.QObject(self)</font></div></div><div><br></div><div>will garbage collect the "child" *python* object as soon as the function</div><div>returns, since it's outside the function's scope, but, technically, the </div><div>object still exists as a C++ counterpart:</div><div><br></div><div><div><font face="monospace">obj = SomeObject()</font></div><div><font face="monospace">print('Object children:', obj.children())</font></div></div><div><font face="monospace">>>> Object children: [<PyQt5.QtCore.QObject object at 0xb21540bc>]</font><br></div><div><font face="monospace"><br></font></div><div class="gmail_quote">This would be a seriuos issue on the C++ side of your project, but it's</div><div class="gmail_quote">something that (thinking from a Python perspective) we "could" just</div><div class="gmail_quote">ignore.</div>The same goes on the other way:</div><div class="gmail_quote"><br><div><font face="monospace"><div>class SomeObject(QtCore.QObject):</div><div>    def __init__(self):</div><div>        super(SomeObject, self).__init__()</div><div>        self.child = QtCore.QObject(self)</div><div>        self.child.deleteLater()</div><div><br></div><div><div>def showChildren():</div><div>    print('self.child: {}'.format(obj.child))</div><div>    print('Object children:', obj.children())</div></div><div><br></div><div>import sys</div><div>obj = SomeObject()</div><div>app = QtWidgets.QApplication(sys.argv)</div><div>QtCore.QTimer.singleShot(0, showChildren)</div><div>sys.exit(app.exec_())</div><div><br></div><div><div>>>> self.child: <PyQt5.QtCore.QObject object at 0xb218d14c></div><div>Object children: []</div></div></font><br>In this case the python object still "exists", but its C++ "Qt object" doesn't.</div><div><br></div><div>You can read more about this in here also:</div><div><a href="http://enki-editor.org/2014/08/23/Pyqt_mem_mgmt.html">http://enki-editor.org/2014/08/23/Pyqt_mem_mgmt.html</a><br></div><div><br></div><div>So, finally, I'd suggest you to look into what your separated thread</div><div>actually does, because I think that it's possible that you're dealing </div><div>with thread-unsafe functions. I had a similar problem just days ago,</div><div>when I was trying to deal with a python object run through python's</div><div>threading.Thread(). When I implemented a "fake" signal/slot system,</div><div>which obviously wasn't really compatible with Qt connection system,</div><div>I had to face unexpected behaviour from a looped QAbstractAnimation</div><div>descendant (strangely enough, it started to run faster and faster</div><div>each time it was started).<br>As soon as I made that object a QObject, everything worked as</div><div>expected, obviously, since its [sub]thread was correctly treated as Qt</div><div>would expect.</div><div><br></div><div><br></div><div>Cheers,</div><div>Maurizio</div></div><div><br></div>-- <br><div dir="ltr" class="gmail_signature">È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi<br><a href="http://www.jidesk.net" target="_blank">http://www.jidesk.net</a></div></div></div></div></div></div></div></div></div></div></div>