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

带有QGis-Python.exe的Python脚本停止工作,python,python-2.7,pyqt,pyqt4,qgis,Python,Python 2.7,Pyqt,Pyqt4,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 ################################################################

我购买了,我正在努力完成其中一个练习。我尝试运行的一个脚本使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%
考虑到所有这些,我认为剧本中一定有什么地方出错了。但是,当我使用检查脚本时,没有可以修复的错误会导致python不会崩溃


请注意,我已尝试设置路径=%QGIS\u前缀%\bin;%路径%而不是设置路径=%PATH%;%QGIS_PREFIX%\bin没有成功。

有一点似乎值得怀疑,即您正在创建一个gui元素,但没有给它一个父元素-QgsMapCanvas-然后尝试在将其添加到布局之前手动显示它。您不必在子小部件上调用show,所有子小部件都应该是主小部件或其一个子部件的父级

此外,还应该存储对python对象的持久引用;否则,可能会使用底层的C++对象,获取垃圾,并导致程序崩溃。您可以通过将小部件和布局分配给self上的属性来实现这一点

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


有一点似乎值得怀疑,那就是您在创建gui元素时没有给它一个父元素——QgsMapCanvas——然后在将其添加到布局之前尝试手动显示它。您不必在子小部件上调用show,所有子小部件都应该是主小部件或其一个子部件的父级

此外,还应该存储对python对象的持久引用;否则,可能会使用底层的C++对象,获取垃圾,并导致程序崩溃。您可以通过将小部件和布局分配给self上的属性来实现这一点

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


我很幸运地与该书的作者取得了联系,因此我将在这里分享他的回答:

我想在看了这个之后,我可能知道问题出在哪里了 读者的问题更深入,我发现有些东西 在QGIS的较新版本中进行了更改,示例代码不再使用 照它写的那样工作。从技术角度看,你现在似乎 在调用之前需要实例化QApplication对象 QgsApplication.initQgis-本书中的示例程序 调用后实例化QApplication对象 QgsApplication.initQgis,这会导致程序崩溃。修理 为此,将main函数更改为如下所示:

如您所见,我已将app=QApplicationsys.argv行移到顶部

重要提示:确保在viewer=MapViewerC:/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

非常感谢作者埃里克·韦斯特拉为我提供了这个解决方案。

我很幸运地与本书的作者取得了联系,因此我将在这里分享他的回答:

我想在看了这个之后,我可能知道问题出在哪里了 读者的问题更深入,我发现有些东西 在QGIS的较新版本中进行了更改,示例代码不再使用 照它写的那样工作。从技术角度看,你现在似乎 在调用之前需要实例化QApplication对象 QgsApplication.initQgis-本书中的示例程序 调用后实例化QApplication对象 QgsApplication.initQgis,这会导致程序崩溃。修理 为此,将main函数更改为如下所示:

如您所见,我已将app=QApplicationsys.argv行移到顶部

重要提示:确保在viewer=MapViewerC:/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为我提供了此解决方案。

仅供参考,我没有编写此脚本,它是本书的直接副本,本应在不做任何更改的情况下工作。听起来我需要对脚本进行多次修改才能解决这些问题。我试过了,但似乎没有什么进展。如果您有任何其他指导意见,我将不胜感激。或者,如果你愿意的话,我会很乐意试用你修改过的脚本!仅供参考,我没有写这个脚本,它是一本书的直接副本,本应在不做任何更改的情况下工作。听起来我需要对脚本进行多次修改才能解决这些问题。我试过了,但似乎没有什么进展。如果您有任何其他指导意见,我将不胜感激。或者,如果你愿意的话,我会很乐意试用你修改过的脚本!