Functions get called more and more times with reopening plugin - python

I have a QGIS plugin written in Python 2.7.3 with PyQt 4.9.1, Qt 4.8.1. When I run this plugin every function works just fine. But when I close the window and reopen it again, every function happens twice. Then I close/open again and it goes 3 times, etc., etc.
Where should I look for an error here? My def run(self) part looks just like this:
def run(self):
self.dlg.show()
self.availableLayers()
self.dlg.pushButton_2.clicked.connect(self.openFile)
self.dlg.pushButton.clicked.connect(self.groupBy)
self.dlg.toolButton_4.clicked.connect(self.toggleRightPanel)
If I reload the plugin by clicking the button from "Plugin Builder", it starts again from one.
I should also mention I wouldn't like to lose the view user created (the plugin is a table viewer), but rather be able to close the window, open it and have it again there without the cells being cleared.

Every time you call connect, it adds another connection - even if it's to the same slot. So you need to move the connections out of the run() method and put them in the setup method for the dialog, so that they are only made once.

Related

Correct way to close QMainWindow

I recently changed from tkinter to Pyqt5 as I'm developing a semi-large application in Python 3.7.8
Every time I had to close windows I used the method self.destroy(), and there was a small chance that, when I closed all the program and having no windows, the interpreter was still running and I needed to terminate the process manually, even when using sys.exit(app.exec_())
I could had the program running for 15 seconds or 30 minutes, it was completely random.
I just saw another method that is called self.close(), so I replaced the self.destroy() with it, but I'm not sure if this is the intended practice or if there is a better way. I still have to check if the problem doesn't appear again.
It's better to use self.destroy or self.close for pyqt5 applications?
Is there a better way?
close():
Closes this widget.
destroy():
Frees up window system resources.
[...]
This function is usually called from the QWidget destructor.
If you close() the widget, it can be opened/shown again later if required, but if the widget is a top level window and is the last visible one, Qt will automatically quit the application (assuming the QApplication has the quitOnLastWindowClosed() set, which is the default behavior). In this case PyQt will automatically destroy the window and free up memory, meaning that destroy() will be called anyway.
Note that the window will also be automatically destroyed when closed if it has no other reference or parent: as much as any other python object, the garbage collector will delete the widget and its children, which causes a call to the QWidget destroyer.
So, you should always call close(), since it ensures that Qt follows the correct steps: send a QCloseEvent (which could be ignored, if required) and notify the application about that, so that it can actually quit if the window was the last one.

Python GUI using os.system to run python script cause main GUI "Not Responding"

StackOverflow community.
I am writing a python GUI to monitor another program's data in OSX environment and at one point I decide to click one button to open another python script that I wrote. It does work but it also causes a lag problem of the main GUI program as soon as I click the button. For the lag problem I mean the GUI window is "Not Responding" and I need to force quit. The method I use to run the new script is,
def create_html():
os.system('python realtime.py')
My program doesn't have the multiple class structure, just the simple canvas, and framework. I wonder if this is also the problem to cause my program running slow.
The problem is you are using os.system, which is a blocking call. It will not return control to your main code until python realtime.py is done executing and returned.
You need to use a call that will not block the rest of your program, such as subprocess.Popen.
You can also see this QA for further information

How to kill a pure console application in PySide/PyQt?

I am attempting to convert code from Summerfield's article on (old-style) PyQt Signals/Slots to new-style PySide code. One example is a pure console application, which I have never worked with before. Unfortunately, when I try to run it multiple times, I am told that the previous application is still running.
It is a simple app: it basically lets you set a number, and reports back if the number is new:
from PySide import QtCore
import sys
class TaxRate(QtCore.QObject):
rateChangedSig=QtCore.Signal(float)
def __init__(self):
QtCore.QObject.__init__(self)
self.rate = 17.5
def getRate(self):
return self.rate
def setRate(self, newRate):
if newRate != self.rate:
self.rate = newRate
self.rateChangedSig.emit(self.rate) #was self.emit(SIGNAL("rateChanged"), self.rate)
#QtCore.Slot() #technically not really needed
def rateChangedSlot(value):
print("Tax rate changed to {0:.2f} %".format(value))
if __name__=="__main__":
qtApp = QtCore.QCoreApplication(sys.argv) #origional had QtGui.QApplication, but there is no GUI
vat = TaxRate()
vat.rateChangedSig.connect(rateChangedSlot) #was vat.connect(vat, SIGNAL("rateChanged"), rateChanged)
vat.setRate(8.5) # A change will occur (new rate is different)
qtApp.quit()
sys.exit(qtApp.exec_())
Overall, it works as expected, except the final two lines do not kill the process. When I try to run the program twice, the second time my IDE (Spyder) always tells me that it is already running in a separate process. If I try running it from the command line, the window just hangs.
Strangely, when I comment out the last two lines I do not get this warning. This is the opposite of what I expect (based on previous experience with PySide GUI applications and the documentation for quit()).
Following the Closing a window example at Zetcode, I tried replacing qtApp.quit() with qtApp.instance().quit(), which yielded the same non-killing result.
So, how do I kill this thing?
One idea is that I shouldn't have even started it in the first place (as suggested here). Even though it is a pure console app, Summerfield's original program initializes with app=QtGui.QApplication(sys.argv), and it does not contain the last two lines. Things run fine, multiple times. However, isn't there a concern that each run would create a new process, so his program seems to be effectively multiplying processes without warning? (Note in practice I don't think this is happening on my system, so the answer seems to be 'No' for reasons I don't understand).
What is the correct way to control/initialize/kill a console app using PySide?
(This is ignoring the question, for the time being, why one would ever use PySide for a pure console application in Python as has been pointed out previously. But if anyone were to be interested in answering that separate question, I could start a separate question for it).
Potentially relevant post:
Pyside applications not closing properly
The problem is because you call QCoreApplication.quit() before you call QCoreApplication.exec_(). The call to quit is not queued up in the event loop, it happens immediately. The call to QCoreApplication.exec_() starts the event loop which only ends when a call to QCoreApplication.exit() (or QCoreApplication.quit()) is made while the event loop is running.
This is somewhat explained in the Qt documentation of QCoreApplication but it is very easy to miss.
I imagine you don't really need to call exec_() as you aren't using any events in your current code (most events are to do with window/mouse/keyboard though you might conceivably use some in the future like those generated by QTimer). It really depends what you want to do with the program in the future.
If you don't call exec_(), then your script will exit as you would normally expect any Python script to do (the only blocking function in your code is the call to exec_(), remove that and nothing keeps it running.)

Progress Bar over getOpenFileName

In my application I have the following line which opens a file dialog window. Once I get the file name, I do a bunch of processing which takes quite some time, and once this is done the workspace is ready for the user.
filename, _ = QtGui.QFileDialog.getOpenFileName(self, 'Open file', os.curdir, "*.cws")
The file dialog is a modal window (by default), which is great, because it's preventing the user from doing stupid stuff while the workspace is not ready for use yet. I want to put a progress bar somewhere to give a sense of how much has be processed. I made another dialog window which displays a progress bar and some other information.
Now, since the file dialog window is modal, it just sits there frozen while my workspace is processing, and the progress dialog only pops up after everything is done.
I've looked into setting the file dialog window to not modal, but I don't think that is possible. I was thinking to maybe force it to close, and immediately have my progress dialog window pop up and take over the modality. How can I close the file dialog window programmatically? I don't know how to get a reference for the form.
Or perhaps you have a better suggestion on how to address this?
As thuga mentioned, your application event loop is stuck by your heavy processing.
So events (and especialy paint events) are not processed while your processing is running causing the GUI to freeze.
In my opinion, you have 2 options:
Force events to be processesed (not very classy but may work):
It depends on how your "heavy processing" is done.
Assuming the code hanging the loop is "under your hands" (not in a third party lib).
You can add as much call to QApplication.processEvents as you can in it.
If the processing is loop based, it can look like:
for item in itemList:
...processitem...
QtGui.QApplication.processEvents()
This as the main drawback of adding dependencies to GUI in parts of code that should not be aware of.
If your code is not loop based then you'll have to add several calls to processEvents that will pollute the processing code.
Stop hanging the event loop (more complicated but more maintainable)
That means you will have to deal with Threads and/or subprocesses as thuga suggested.
This solution assumes that GUI code and business code are separated well enough.
You can have a look at this article from Qt Quarterly that gives some highlights on this issue.
Because of python Global Interpreter Lock (GIL) you may not see better results with threads.
Consider using the multiprocessing library.

Writing an active program with wxPython. Where to start?

I spent the last hours trying to get to know wxPython, because I want to write a GUI program. I found some tutorials on that (not too many), but all of them just explain how to add yet another kind of widget, down to fancy things like LED number outputs and mouse gestures (this one e.g. takes it quite far: Another Tutorial). But everything I could find so far does nothing more than create a static GUI, waiting for the user to do something, then execute some handlers and wait again. It took me a while to even find out that wx.App takes a part in all of that, and that you can subclass it.
I want to write a program, that does things without input! The GUI is supposed to be a client that logs in on a server, and when the server sends something, I want the GUI to show what happened. I could not find a single tutorial even mentioning, that such programs exist. How can I write such a thing? How do they integrate with wxpython?
Do I need to span another thread? Is there a way to hook into the MainLoop and have some code executed periodically, that checks for change and then updates some of those fancy GUI things? And is there any page that teaches you, how to do this?
First of all, you should figure out how to do what you want WITHOUT a GUI. In this case, you'll need to figure out how to login to a server. You'll probably need to use something like paramiko for that. See http://www.lag.net/paramiko/
Once you've got that figured out, then you can add it to your GUI. Probably in a button handler so when the user presses a button, it pops up a dialog asking for a user name and password to pass to paramiko to login to the server.
If the server query takes a long time to execute (like say you're querying a database for a huge set of data), then you'll want to run the query in a separate thread. Why? Because that query will block the GUI's main loop and make your app freeze until it finishes. See the following articles for information on wxPython and threads:
http://wiki.wxpython.org/LongRunningTasks
http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
I wrote up a tutorial on making wxPython talk to a socket server, so you might find that useful: http://www.blog.pythonlibrary.org/2013/06/27/wxpython-how-to-communicate-with-your-gui-via-sockets/
I also have an article on how to make an image viewer, and do CRUD ops to a database on there.

Categories