Creating the UI and first logic

To create the UI you will need Qt Designer. This is shipped with QGIS and installed in the bin folder of the install.

Run the application called designer.exe

After we open designer we are going to select Open.. and select feature_template_dockwidget_base.ui

Image

Select and delete the label that is already in the dock widget.

Widgets

Image

Properties

Image

For our widget we are going to need a Stacked Widget.

  • Drag the stack widget onto the form
  • Right click in the empty form and select Layout -> Layout in Grid

All Qt widgets are contained in layouts. The layout controls how the widgets fit together.

We can use the stacked widget to add move "pages" to our widget later if we connect the define new button.

You will also need 3x Push Button and a List Widget.

Drag the buttons and list widget inside the stacked widget

Image

Don't worry if they don't look right. When we set the layout it will fix them up for us

Image

  • Select a button and hit F2 to label the buttons. We need Define new, Delete, Apply
  • Also update the object name on the buttons and list widget (templatesList, newButton, deleteButton, applyButton)
  • Drag the widget around the form to change the layout

The name of the object is important because we will use this in the code to set more things.

  • Save the UI file into your plugin working folder. Call it ui_templatedock.ui

Generating the UI files

Qt has a handy function for creating the UI files on the fly. This removes the build step for generating the UI files

Qt only needs the path to the .ui file and it will generate the Python object on the fly ready to use.

Open feature_template_dockwidget.py

FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'feature_template_dockwidget_base.ui'))

uic.loadUiType will load the UI on the fly from the .ui file without the need for the compile step.

Adding some items to the list

Before we start on doing anything in QGIS itself. Let's just add a few items to the list.

It's going to be a hard-coded list for now but we can add config for it later.

Define it like this in the feature_template_dockwidget.py file

items = {
    "water pipe - 100mm":
        {
            "type": "water pipe",
            "size": 100
        },
    "sewer pipe - 200mm":
        {
            "type": "sewer pipe",
            "size": 200
        }
}

In the FeatureTemplatesDockWidget class we need to add new method to load the items

    def load_items(self):
        self.templatesList.clear()
        for key in items:
            self.templatesList.addItem(key)

in the run method of feature_template.py. Make sure you call load_items

    def run(self):
        ... 
        self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget)
        self.dockwidget.show()
        self.dockwidget.load_items()

Signals and Slots

Qt, and QGIS, uses Signals and Slots to message objects about events that have happened. They are a great thing to use when parts of your applications need to talk to each other.

Here is a quick run down.

  • Objects can define signals which are emitted.
  • Object can connect slots to these signals to handle the event
  • Normal Python functions can be used for slots without any extra work

Here is an example:

def do_event(self):
    print "Do something"

mybuttton.pressed.connect(self.do_event)

Connect the Update/Apply button

With that we are going to connect the Apply/Update button in our FeatureTemplateDockWidget object to emit a signal to tell something else to handle the apply logic.

In FeatureTemplateDockWidget we need to define a signal called templateApplied like so

class FeatureTemplatesDockWidget(QtGui.QDockWidget, FORM_CLASS):

    templateApplied = pyqtSignal(str, dict)
    closingPlugin = pyqtSignal()

This signal will emit a string and a dictionary.

Note: Take note on where templateApplied is defined. Outside of any methods at the class level

Inside the __init__ method we need to connect the Apply button pressed event and handle the extra logic

    def __init__(self, parent=None):
        super(TemplateDock, self).__init__(parent)
        self.setupUi(self)
        self.applyButton.pressed.connect(self.apply_template)

    def apply_template(self):
        # Don't do anything if there is no selection text
        if not self.templatesList.currentItem():
            return

        name = self.templatesList.currentItem().text()

        # Get the fields from the items list
        fields = items[name]
        self.templateApplied.emit(name, fields)

We now need to connect to this signal in the FeatureTemplates class

    def initGui(self):
        self.dock = TemplateDock()
        self.dock.templateApplied.connect(self.apply_template)
        ....

    def apply_template(self, name, fields):
        pass

We will come back and wire up apply_template soon

Run pb_tool deploy again and restart QGIS (or use the plugin reloader) to test the plugin. You should now see this:

Image

Lets move on using the QGIS API