Friday 22 July 2016

qgis - How to reference to my in QT designer created buttons in python?



I have created an own QDialog (using QT Designer) with three push buttons. The names are pButton1, pButton2 and pButton3. After saving the file I created the ui file by using:


pyuic4 ui_xy.ui > ui_xy.py

I can see my created GUI in QGIS, but I have no idea how to get a reference to the buttons. When I use QMessagebox it is very easy to get to know wich button was pushed, but using the same way for this GUI doesn´t work.


Using QMessagebox the following code works:


ret = QMessageBox(..., QMessageBox.Ok)
if (ret = QMessageBox.Ok):
DO SOMETHING
else:
DO SOMETHING


When I use the standard GUI with the Ok and Cancel button, the following code works:


dlg = xyDialog()
dlg.show
result = dlg.exec_()
if result = 0:
...

How can I obtain the same result using my buttons? Replacing the 0 with pbutton1 (or 2 or 3) doesn´t seem to work.


Do you know a good solution or tutorial?



Thanks!


Best,



Answer



kopi,


QMessageBox, and similar convenience classes, allow for quick creation of standard dialogs, generally using static methods within their class. Creating custom buttons and Qt widgets requires making the Qt signal/slot connections between them, as per the desired GUI interaction for the purpose.


When using QtDesigner and after the compilation of your form to a ui.py file, you will want to import it into a Python module and instantiate it, so that you can directly reference the form's widgets. With PyQGIS plugins, this is usually done in a module specific to the dialog, though with very simple plugins it can be done inside the plugin's base class.


A very good reference for creating PyQGIS plugins, in addition to the PyQGIS Cookbook, is the QGIS Workshop v1.0.0: for help with your question, specifically the section on integrating a tool's output with the GUI:


01  from PyQt4 import QtCore, QtGui
02 from ui_vector_selectbypoint import Ui_vector_selectbypoint
03

04 class vector_selectbypointDialog(QtGui.QDialog):
05
06 def __init__(self):
07 QtGui.QDialog.__init__(self)
08 # Set up the user interface from Designer.
09 self.ui = Ui_vector_selectbypoint()
10 self.ui.setupUi(self)

Line by line:




01 Basic PyQt4 imports.
02 Import of custom form's class from its compiled ui file.
04 Your custom dialog's class, which inherits from QDialog.
06 init method called when your dialog is instantiated.
07 Instantiate parent QDialog class, so your class gains its attributes.
09 Instantiate and assign your QtDesigner form class.
10 Call the form class's setupUi() method, so its widgets are available.



Once you have self.ui referencing your custom layout form, you can access its widgets anywhere in your custom dialog class and set up signal/slot connections or named slots.


Example showing new style signal/slot connection (using some object names from comments) and named slot connection:



from PyQt4 import QtCore, QtGui
from ui_ubsearch import Ui_UBSearchDialog # don't know name of your form class

class UBSearchDialog(QtGui.QDialog):

def __init__(self):
QtGui.QDialog.__init__(self)
# Set up the user interface from Designer.
self.ui = Ui_UBSearchDialog()
self.ui.setupUi(self)


# make new style signal/slot connection
self.ui.bgrz.clicked.connect(self.exec_grz)

# slot for connection
def exec_grz(self):
# do something
pass # <-- replace with actual code

# named slot example

# (doesn't require a previously built connection for form widgets)
@QtCore.pyqtSlot()
def on_myOtherFormButton_clicked(self):
# do something
pass # <-- replace with actual code

Your UBSearchDialog class will, in turn, need to be instantiated elsewhere (e.g. imported into your plugin's base class and instantiated in its run() method):


ubs_dlg = UBSearchDialog()
ubs_dlg.exec_()


Also, see https://stackoverflow.com/questions/2462401 for more examples concerning named slots and how new style connections keep things cleaner and more 'Pythonic.'




Concerning your second question, there are a couple of things you'll want to clean up before testing more. First, you have multiple imports for the same modules. Your custom dialog module could look like this instead ...


from PyQt4.QtCore import pyqtSlot
from PyQt4.QtGui import QDialog

import datavisualization
from ui_ubsearch import Ui_ubsearch



class ubsearchDialog(QDialog):

def __init__(self, iface):
QDialog.__init__(self)

# Set up the user interface from Designer.
self.ui = Ui_ubsearch()
self.ui.setupUi(self)

# Save reference to the QGIS interface

self.iface = iface

@pyqtSlot()
def on_bgrz_clicked(self):
# Get an instance of the class
d = datavisualization.datavisualization(self.iface)

# Call the method of the intance
d.data_visualization()


# Close UI
self.close()

Of note here is the import of only those names from the PyQt4 modules that are used in the script (QDialog and pyqtSlot). See working with Python modules, for more info. All other unused module imports were removed. You can use pylint to help with finding those unused modules.


Also, when constructing an instance of the class the iface reference is gathered and assigned so it can be passed to your datavisualization module (fixing the parameter error). This means you have to pass iface in from your original plugin module that calls the construction of the custom dialog, e.g. ubsearchDialog(self.iface). So, iface needs a saved reference in your base plugin module as well, in order to be passed to your dialog. This is usually already set up for you if you use tools like Plugin Builder.


You will want to clean up your datavisualization module's imports in a similar fashion.


import os
import datetime
import time
import psycopg2


from PyQt4.QtGui import QMessageBox
from qgis import core

Lastly, you will want to read up on PEP8, Python style guide. Your pasted code contained a mix of spaces and tabs for indention: only-spaces is generally preferred.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...