Building Mapping Applications with QGIS
上QQ阅读APP看书,第一时间看更新

Scripting the QGIS user interface

While the example program we created earlier has very limited user interaction, it is quite possible to build your program to directly use the QGIS user interface elements such as the status bar, the message bar, progress indicators, and the QGIS logging window. You can also create custom forms and windows so that the output of your program looks just like any other feature of QGIS itself. Let's take a closer look at how some of these QGIS user-interface elements can be used from within your Python programs.

The status bar

The QGIS window has a status bar. You can use it to display the current status of your Python program, for example:

iface.mainWindow().statusBar().showMessage("Please wait...")

The status message will appear at the bottom of the window, like this:

The status bar

As you can see, there isn't much room on the status bar, so you'll need to keep your status message short. To hide the message again, do the following:

iface.mainWindow().statusBar().clearMessage()

The message bar

A message bar appears within a window to display messages to the user, for example:

The message bar

Message bars have several useful features:

  • Messages can be stacked so that if multiple messages appear at once, the user won't miss the earlier messages
  • Messages have a level, which indicates the importance of the message, and affects how the message is displayed
  • Messages have an optional title as well as the text to be displayed
  • Messages can stay on the screen until the user closes them, or they can time out, disappearing automatically after a given number of seconds
  • You can add various Qt widgets to the message bar to customize its behavior and appearance

Any window in QGIS can have its own message bar. The iface variable has a messageBar() method, which returns the message bar for the main QGIS window, but you can also add a message bar to your own custom windows if you wish.

To add a message to a message bar, you call the message bar's pushMessage() method. To create a message without a title, you use the following method signature:

messageBar.pushMessage(text, level=QsgMessageBar.INFO, duration=None)

For example:

from qgis.gui import *
iface.messageBar().pushMessage("Hello World",
         level=QgsMessageBar.INFO)

To include a title, use the following method signature:

messageBar.pushMessage(title, text, level=QgsMessageBar.INFO, duration=None)

In both cases, the level parameter can be set to QgsMessageBar.INFO, QgsMessageBar.WARNING, or QgsMessageBar.CRITICAL, and if the duration parameter is specified, it will be the number of seconds before the message is hidden.

To remove all the messages currently being shown, you can call the messageBar.clearWidgets() method.

Progress indicators

You can also make use of the message bar to display a Qt progress indicator. To do this, use the messageBar.createMessage() method to create a widget to display your message, then modify the widget to include additional Qt controls, and finally call the messageBar.pushWidget() method to display the message and the controls you added. For example:

progressMessage = iface.messageBar().createMessage("Please wait")
progressBar = QProgressBar()
progressBar.setMaximum(100)
progressBar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
progressMessage.layout().addWidget(progressBar)
iface.messageBar().pushWidget(progressMessage)
...
progressBar.setValue(n)
...
iface.messageBar().clearWidgets()

Note

There is a bug in the Mac version of QGIS 2.2, which prevents the user interface from updating while your Python code is running. A workaround for this is to use threads, as described in the following article: http://snorf.net/blog/2013/12/07/multithreading-in-qgis-python-plugins

QGIS logging

You can use the built-in logging facilities of QGIS to display the output in a separate window. For example:

for i in range(100):
    QgsMessageLog.logMessage("Message %d" % i)

The log messages will be shown in the log view, which you can show by navigating to View | Panels | Log Messages.

If you wish, you can change the importance of your message by adding a message level to the logMessage() call, for example:

QgsMessageLog.logMessage("Something is wrong",
                         level=QgsMessageLog.CRITICAL)

Rather than being mixed in with other QGIS messages, you can also choose to have all your log messages appear in a pane by themselves, by adding a tag to the logMessage() call as follows:

QgsMessageLog.logMessage("Test Message", tag="my panel")

Your log messages will then appear in a panel by themselves, like this:

QGIS logging

Custom dialogs and windows

As QGIS is built on top of Qt, you can use the PyQt classes to create your own windows and dialog boxes, and display them directly from within your Python code. For example, here's a script that displays a custom dialog box that prompts the user to enter a latitude and longitude value:

from PyQt4.QtGui import *

class MyDialog(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.setWindowTitle("Enter Coordinate")

        layout = QFormLayout(self)

        self.lat_label = QLabel("Latitude", self)
        self.lat_field = QLineEdit(self)

        self.long_label = QLabel("Longitude", self)
        self.long_field = QLineEdit(self)

        self.ok_btn = QPushButton("OK", self)
        self.ok_btn.clicked.connect(self.accept)

        self.cancel_btn = QPushButton("Cancel", self)
        self.cancel_btn.clicked.connect(self.reject)

        btn_layout = QHBoxLayout(self)
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)

        layout.addRow(self.lat_label, self.lat_field)
        layout.addRow(self.long_label, self.long_field)
        layout.addRow(btn_layout)

        self.setLayout(layout)

dialog = MyDialog()
if dialog.exec_() == QDialog.Accepted:
    lat = dialog.lat_field.text()
    long = dialog.long_field.text()
    print lat,long

Running this script will cause the following dialog box to be displayed:

Custom dialogs and windows

If the user clicks on the OK button, the entered latitude and longitude values will be printed to the console. Of course, this is just a simple example—there's no error checking or conversion of the entered values from text back to numbers. However, this is just a simple example. There's a lot more that can be done using the PyQt libraries, and people have written entire books on the subject. However, the main thing to realize now is that, because QGIS is built on top of Qt, you can use all of the features of PyQt to build sophisticated user interfaces. You're certainly not limited to using the Python console to interact with the user.