GEOG 489
Advanced Python Programming for GIS

4.11.2 Modifying the Plugin GUI and Adding Functionality

PrintPrint

The file random_number_generator_dialog.py defines the class RandomNumberGeneratorDialog derived from QDialog. This is the widget class for our dialog box. The GUI itself is defined in the .ui file random_number_generator_dialog_base.ui. In contrast to first compiling the .ui file into a Python .py file and then using the Python code resulting from this to set up the GUI, this class uses the previously briefly mentioned approach of directly reading in the .ui file. That means to change the GUI, all we have to do is modify the .ui file in QT Designer, no compilation needed.

We open random_number_generator_dialog_base.ui with QT Designer and make the following small changes:

  • We delete the button box with the Ok and cancel buttons.
  • The layout of the dialog box is changed to a vertical layout.
  • We add a push button and a label to the dialog box with vertical spacers in between.
  • The button text is set to “Press here to generate random number between 1 and 100”.
  • The label text is set to “The number is:” and its horizontal alignment property is changed to be horizontally centered.

The image below shows the produced layout in QT Designer.

screenshot of layout and object inspector      
Figure 4.36 Creating the GUI for our plugin in QT Designer

After saving the form, we want to see if we now get the new version of the GUI in QGIS as well. However, for this to happen, the plugin needs to be reloaded. For this, we use the Plugin Reloader plugin that we also installed at the beginning of the lesson. We pick the Plugins -> Plugin Reloader -> Configure option. Then we pick our random_number_generator plugin from the list and press OK.

screenshot of reloader with select plugin and ok options      
Figure 4.37 Configuring Plugin Reloader to reload the code for our plugin

Now we just have to go Plugins -> Plugin Reloader -> Reload: random_number_generator, whenever we want to reload the plugin after making some changes. After doing so and starting our plugin again, it should show up like this in QGIS:

screenshot of plugin with layout in popup window      
Figure 4.38 Running the plugin in QGIS now shows the dialog box with the GUI we just created

Now we just have to implement the functionality for our plugin, which for this toy example is extremely simple. We just need to write some code for rolling a random number between 1 and 100 and updating the text of the label accordingly when the button is pressed. We implement this in the definition of our class RandomNumberGeneratorDialog in file random_number_generator_dialog.py. The changes we make are the following:

  • In the line where the os module is imported, we also import the random module from the Python standard library.
  • We add a new method to the class definition with the event handler code:
    def generateNewNumber(self): 
    	r = random.randint(1,100) 
    	self.label.setText("The number is: " + str(r))
  • Finally, we connect the button to this new method by adding the following line at the end of the __init__() method:
    self.pushButton.clicked.connect(self.generateNewNumber)

Below is the entire code part of random_number_generator_dialog.py after making these changes:

import os, random 

from PyQt5 import uic 
from PyQt5 import QtWidgets 

FORM_CLASS, _ = uic.loadUiType(os.path.join( os.path.dirname(__file__), 'random_number_generator_dialog_base.ui')) 
 
class RandomNumberGeneratorDialog(QtWidgets.QDialog, FORM_CLASS): 
    def __init__(self, parent=None): 
        """Constructor.""" 
        super(RandomNumberGeneratorDialog, self).__init__(parent) 
        # Set up the user interface from Designer. 
        # After setupUI you can access any designer object by doing 
        # self.<objectname>, and you can use autoconnect slots - see 
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html 
        # #widgets-and-dialogs-with-auto-connect 
        self.setupUi(self) 

        self.pushButton.clicked.connect(self.generateNewNumber) 

    def generateNewNumber(self): 
        r = random.randint(1,100) 
        self.label.setText("The number is: " + str(r))

Now the only thing we have to do is reload the plugin again in QGIS, and when we then start the plugin one more time, the button should work and allow us to create random numbers. Please note that the dialog box is opened non-modally from our main plugin class so that you can keep the dialog box open in the background while still interacting with the rest of the QGIS GUI.

screenshot of plugin working: random number is 56      
Figure 4.39 The Random Number Generator plugin in QGIS after adding the main functionality

In this small example, all code changes needed were about wiring up the GUI of the dialog box. In such cases, modifying the file with the class definition for the main widget can be sufficient. In the next section, we will implement a plugin that is significantly more complex and interacts with QGIS in more sophisticated ways, e.g., by adding new layers to the currently open project and continuously updating the content of these layers. However, the general approach is the same in that we are mainly going to modify the .ui file and the file with the main widget class from the template files created by Plugin Builder 3. If you want to learn more about QGIS plugin development and the role the other files play, the official documentation is a good starting point.