13. 与用户通信
提示
如果您在pyqgis控制台之外,则此页面上的代码片段需要以下导入:
1from qgis.core import (
2 QgsMessageLog,
3 QgsGeometry,
4)
5
6from qgis.gui import (
7 QgsMessageBar,
8)
9
10from qgis.PyQt.QtWidgets import (
11 QSizePolicy,
12 QPushButton,
13 QDialog,
14 QGridLayout,
15 QDialogButtonBox,
16)
本部分介绍了一些方法和元素,这些方法和元素应该用于与用户通信,以保持用户界面的一致性。
13.1. 显示消息。QgsMessageBar类
从用户体验的角度来看,使用消息框可能不是一个好主意。对于显示小信息行或警告/错误消息,QGIS消息栏通常是更好的选择。
使用对QGIS接口对象的引用,您可以使用以下代码在消息栏中显示一条消息
from qgis.core import Qgis
iface.messageBar().pushMessage("Error", "I'm sorry Dave, I'm afraid I can't do that", level=Qgis.Critical)
Messages(2): Error : I'm sorry Dave, I'm afraid I can't do that

图 13.10 QGIS消息栏
您可以设置一个持续时间以在有限的时间内显示它
iface.messageBar().pushMessage("Ooops", "The plugin is not working as it should", level=Qgis.Critical, duration=3)
Messages(2): Ooops : The plugin is not working as it should

图 13.11 带计时器的QGIS消息栏
上面的示例显示了一个错误条,但 level
参数可用于创建警告消息或信息消息,使用 Qgis.MessageLevel
枚举。您最多可以使用4个不同的级别:
信息
警告
批判性
成功

图 13.12 QGIS消息栏(信息)
可以将小部件添加到消息栏,例如显示更多信息的按钮
1def showError():
2 pass
3
4widget = iface.messageBar().createMessage("Missing Layers", "Show Me")
5button = QPushButton(widget)
6button.setText("Show Me")
7button.pressed.connect(showError)
8widget.layout().addWidget(button)
9iface.messageBar().pushWidget(widget, Qgis.Warning)
Messages(1): Missing Layers : Show Me

图 13.13 带有按钮的QGIS消息栏
您甚至可以在自己的对话框中使用消息栏,这样就不必显示消息框,或者在QGIS主窗口中显示消息框没有意义
1class MyDialog(QDialog):
2 def __init__(self):
3 QDialog.__init__(self)
4 self.bar = QgsMessageBar()
5 self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed )
6 self.setLayout(QGridLayout())
7 self.layout().setContentsMargins(0, 0, 0, 0)
8 self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok)
9 self.buttonbox.accepted.connect(self.run)
10 self.layout().addWidget(self.buttonbox, 0, 0, 2, 1)
11 self.layout().addWidget(self.bar, 0, 0, 1, 1)
12 def run(self):
13 self.bar.pushMessage("Hello", "World", level=Qgis.Info)
14
15myDlg = MyDialog()
16myDlg.show()

图 13.14 自定义对话框中的QGIS消息栏
13.2. 显示出进步
进度条也可以放在QGIS消息栏中,因为我们已经看到,它接受窗口小部件。下面是一个您可以在控制台中尝试的示例。
1import time
2from qgis.PyQt.QtWidgets import QProgressBar
3from qgis.PyQt.QtCore import *
4progressMessageBar = iface.messageBar().createMessage("Doing something boring...")
5progress = QProgressBar()
6progress.setMaximum(10)
7progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
8progressMessageBar.layout().addWidget(progress)
9iface.messageBar().pushWidget(progressMessageBar, Qgis.Info)
10
11for i in range(10):
12 time.sleep(1)
13 progress.setValue(i + 1)
14
15iface.messageBar().clearWidgets()
Messages(0): Doing something boring...
此外,您还可以使用内置状态栏来报告进度,如下例所示:
1vlayer = iface.activeLayer()
2
3count = vlayer.featureCount()
4features = vlayer.getFeatures()
5
6for i, feature in enumerate(features):
7 # do something time-consuming here
8 print('.') # printing should give enough time to present the progress
9
10 percent = i / float(count) * 100
11 # iface.mainWindow().statusBar().showMessage("Processed {} %".format(int(percent)))
12 iface.statusBarIface().showMessage("Processed {} %".format(int(percent)))
13
14iface.statusBarIface().clearMessage()
13.3. 日志记录
QGIS中有三种不同类型的日志记录,可用于记录和保存有关代码执行的所有信息。每个都有其特定的输出位置。请考虑为您的目的使用正确的日志记录方式:
QgsMessageLog
是让消息将问题传达给用户。QgsMessageLog的输出显示在日志消息面板中。内置的 Python logging 模块用于在QGIS Python API(PyQGIS)级别上进行调试。建议需要调试其Python代码(例如要素ID或几何)的Python脚本开发人员使用此工具
QgsLogger
用于以下对象的消息 QGIS internal 调试/开发人员(即您怀疑某些损坏的代码触发了某些内容)。消息仅在开发人员版本的QGIS中可见。
以下各节显示了不同日志记录类型的示例。
警告
Python 的使用 print
语句在任何可能是多线程的代码中执行都是不安全的 extremely slows down the algorithm 。这包括 expression functions , renderers , symbol layers 和 Processing algorithms (在其他方面)。在这些情况下,您应该始终使用 logging 模块或线程安全类 (QgsLogger
或 QgsMessageLog
)相反。
13.3.1. QgsMessageLog
# You can optionally pass a 'tag' and a 'level' parameters
QgsMessageLog.logMessage("Your plugin code has been executed correctly", 'MyPlugin', level=Qgis.Info)
QgsMessageLog.logMessage("Your plugin code might have some problems", level=Qgis.Warning)
QgsMessageLog.logMessage("Your plugin code has crashed!", level=Qgis.Critical)
MyPlugin(0): Your plugin code has been executed correctly
(1): Your plugin code might have some problems
(2): Your plugin code has crashed!
备注
您可以看到 QgsMessageLog
在 日志消息面板
13.3.2. 内置的日志记录模块
1import logging
2formatter = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
3logfilename=r'c:\temp\example.log'
4logging.basicConfig(filename=logfilename, level=logging.DEBUG, format=formatter)
5logging.info("This logging info text goes into the file")
6logging.debug("This logging debug text goes into the file as well")
BasicConfig方法配置日志记录的基本设置。在上面的代码中,定义了文件名、日志级别和格式。文件名是指将日志文件写入的位置,日志记录级别定义了要输出的级别,格式定义了输出每条消息的格式。
2020-10-08 13:14:42,998 - root - INFO - This logging text goes into the file
2020-10-08 13:14:42,998 - root - DEBUG - This logging debug text goes into the file as well
如果要在每次执行脚本时擦除日志文件,可以执行如下操作:
if os.path.isfile(logfilename):
with open(logfilename, 'w') as file:
pass
有关如何使用Python日志记录工具的更多资源,请访问:
警告
请注意,如果不通过设置文件名来记录到文件,则记录可能是多线程的,这会大大降低输出速度。