使用QGis的Python脚本 - Python.exe停止工作

时间:2016-06-22 01:27:32

标签: python python-2.7 pyqt pyqt4 qgis

我购买了this book called Building Mapping Applications with QGIS,我正在努力完成其中一项练习。我尝试运行一个脚本崩溃python,生成错误消息" python.exe已停止工作"。

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,但没有成功。

2 个答案:

答案 0 :(得分:3)

我很幸运能够与这位书的作者取得联系,所以我将在这里分享他的回应:

  

我怀疑在看到这个之后我可能知道问题是什么   读者的问题更深入,我发现有些东西   在较新版本的QGIS中更改,示例代码不再更新   按原样写作。从技术角度来看,现在看来你   需要在调用之前实例化QApplication对象   QgsApplication.initQgis() - 本书中的示例程序   调用后实例化QApplication对象   QgsApplication.initQgis(),导致程序崩溃。修理   这样,将main()函数更改为如下所示:

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()
  

正如您所看到的,我已经移动了" app = QApplication(sys.argv)"排到最前面。

重要提示:确保在viewer = MapViewer("C:/folder/shapefile.shp")中使用 转发 斜杠 - 使用反斜杠会导致出现错误消息声明shapefile无效。

我还认为值得一提的是,上述修正案(对问题的评论)都不是必要的。因此,如果路径定义如下,脚本将起作用:

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的查看器,但在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为我提供了这个解决方案。

答案 1 :(得分:1)

有一件事似乎令人怀疑的是,你创建了一个gui元素而没有给它一个父级 - QgsMapCanvas() - 然后在将它添加到布局之前尝试手动show()它。您永远不必在子窗口小部件上调用show(),并且所有子窗口小部件都应该是主窗口小部件(或其他子窗口小部件)的父级。

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

上的属性来执行此操作

实施例

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

您应该像这样添加画布,您不需要调用.show()

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