Python 带有 QGis 的脚本 - Python.exe 停止工作

Python Script with QGis - Python.exe Stopped Working

我购买了 this book called Building Mapping Applications with QGIS,我正在尝试完成其中一项练习。我尝试 运行 的一个脚本崩溃 python,生成错误消息 "python.exe has stopped working"。

import sys
import os
from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *
from PyQt4.QtCore import Qt



#############################################################################


class MapViewer(QMainWindow):
    def __init__(self, shapefile):
        QMainWindow.__init__(self)
        self.setWindowTitle("Map Viewer")

        canvas = QgsMapCanvas()
        canvas.useImageToRender(False)
        canvas.setCanvasColor(Qt.white)
        canvas.show()

        layer = QgsVectorLayer(shapefile, "layer1", "ogr")
        if not layer.isValid():
            raise IOError("Invalid shapefile")

        QgsMapLayerRegistry.instance().addMapLayer(layer)
        canvas.setExtent(layer.extent())
        canvas.setLayerSet([QgsMapCanvasLayer(layer)])

        layout = QVBoxLayout()
        layout.addWidget(canvas)

        contents = QWidget()
        contents.setLayout(layout)
        self.setCentralWidget(contents)

#############################################################################


def main():
    """  Our main program.
    """
    QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'], True)
    QgsApplication.initQgis()

    app = QApplication(sys.argv)

    viewer = MapViewer("C:/folder/shapefile.shp")
    viewer.show()

    app.exec_()

    QgsApplication.exitQgis()

#############################################################################

if __name__ == "__main__":
    main()

我对 QGIS 的 Python 了解不多,所以我不太确定是什么导致 python 崩溃。我确信所有模块都正确导入,因为如果我定义我的路径,然后使用 OSGeo4W Shell 在脚本中导入模块,则没有错误消息。

我的路径是这样定义的:

SET OSGEO4W_ROOT=C:\OSGeo4W64
SET QGIS_PREFIX=%OSGEO4W_ROOT%\apps\qgis
SET PATH=%PATH%;%QGIS_PREFIX%\bin
SET PYTHONPATH=%QGIS_PREFIX%\python;%PYTHONPATH%

鉴于所有这些,我认为脚本中一定有问题。但是,当我使用 http://pep8online.com/ 检查脚本时,没有我可以修复的错误,这些错误会导致 python 不崩溃。

请注意,我已经尝试过 SET PATH=%QGIS_PREFIX%\bin;%PATH% 而不是 SET PATH=%PATH%;%QGIS_PREFIX%\bin 但没有成功。

有一件事看起来很可疑,即您在创建 gui 元素时没有给它一个父元素 - QgsMapCanvas() - 然后在将它添加到布局之前尝试手动 show() 它。您永远不必在子小部件上调用 show(),并且所有子小部件都应该是主小部件(或其其他子小部件之一)的父级。

此外,您应该存储对 python 对象的持久引用;否则,底层 C++ 对象可能会被垃圾回收并导致程序崩溃。为此,您可以将小部件和布局分配给 self

上的属性

例如

self.layout = QVBoxLayout(...
self.layer = ...

你应该像这样添加 canvas,你应该不需要调用 .show()

self.canvas = QgsMapCanvas(self)
layout.addWidget(self.canvas)

我有幸与本书的作者取得联系,所以我将在这里分享他的回应:

I suspect I may know what the problem is...after looking at this reader's problems in more depth, I've discovered that something has changed in newer versions of QGIS, and the example code no longer works as it is written. In technical terms, it seems that you now need to instantiate the QApplication object before making the call to QgsApplication.initQgis() -- the example program in the book instantiates the QApplication object after calling QgsApplication.initQgis(), which causes the program to crash. To fix this, change the main() function to look like the following:

def main():
    """  Our main program.
    """
    app = QApplication(sys.argv)
    QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'],True)
    QgsApplication.initQgis()

    viewer = MapViewer("C:/folder/shapefile.shp")
    viewer.show()

    app.exec_()

    QgsApplication.exitQgis()

As you can see, I've moved the "app = QApplication(sys.argv)" line to the top.

重要提示:确保forward斜杠在[=14=中使用] - 使用反斜杠会产生一条错误消息,指出 shapefile 无效。

我还认为值得一提的是 none 上述修复(对问题的评论)是必要的。因此,如果路径定义如下,脚本将运行:

SET OSGEO4W_ROOT=C:\OSGeo4W64
SET QGIS_PREFIX=%OSGEO4W_ROOT%\apps\qgis
SET PATH=%PATH%;%QGIS_PREFIX%\bin
SET PYTHONPATH=%QGIS_PREFIX%\python;%PYTHONPATH%

然后,整个脚本如下所示:

import sys
import os
from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *
from PyQt4.QtCore import Qt



#############################################################################


class MapViewer(QMainWindow):
    def __init__(self, shapefile):
        QMainWindow.__init__(self)
        self.setWindowTitle("Map Viewer")

        canvas = QgsMapCanvas()
        canvas.useImageToRender(False)
        canvas.setCanvasColor(Qt.white)
        canvas.show()

        layer = QgsVectorLayer(shapefile, "layer1", "ogr")
        if not layer.isValid():
            raise IOError("Invalid shapefile")

        QgsMapLayerRegistry.instance().addMapLayer(layer)
        canvas.setExtent(layer.extent())
        canvas.setLayerSet([QgsMapCanvasLayer(layer)])

        layout = QVBoxLayout()
        layout.addWidget(canvas)

        contents = QWidget()
        contents.setLayout(layout)
        self.setCentralWidget(contents)

#############################################################################


def main():
    """  Our main program.
    """
    app = QApplication(sys.argv)
    QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'],True)
    QgsApplication.initQgis()

    viewer = MapViewer("C:/folder/shapefile.shp")
    viewer.show()

    app.exec_()

    QgsApplication.exitQgis()

#############################################################################

if __name__ == "__main__":
    main()

使用以下命令在 OSGEO4W Shell 中执行它:

python "C:\script.py"

最后,请注意,在撰写本文时,脚本可以正常运行并启动显示引用的 shapefile 的查看器,但是 returns shell 中的一些错误似乎并不存在有问题:

ERROR: Opening of authentication db FAILED
ERROR: Unable to establish authentication database connection
ERROR: Auth db could not be created and opened
QSqlDatabasePrivate::database: unable to open database: "unable to open database file Error opening database"
ERROR: Opening of authentication db FAILED

非常感谢作者 Erik Westra 为我提供了这个解决方案。