【问题标题】:QCombo box to set layer (for Python QGIS plugin)QCombobox 设置图层(用于 Python QGIS 插件)
【发布时间】:2014-05-23 06:13:31
【问题描述】:

我正在尝试创建一个函数来根据在 QComboBox 中选择的项目来声明一个变量。它是用于 QGIS 2.0 和 2.2 的插件。我收到“列表索引超出范围”错误,但不明白为什么。我想知道我的 combobox.currentIndex() 是否没有给我我的想法。如果是这种情况,我想知道是否应该在程序运行之前找到一种方法将组合框的索引设置为默认值。

#connecting the combo boxes to function
def initGui(self):
    QObject.connect(self.dlg.ui.indivCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)
    QObject.connect(self.dlg.ui.grosCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)
    QObject.connect(self.dlg.ui.resCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)

#function to set my layer parameter to the equal the item at index chosen
def layerChanged(self):
    self.layerMap = QgsMapLayerRegistry.instance().mapLayers().values()
    self.indivLayer = self.layerMap[self.dlg.ui.indivCombo.currentIndex()]
    self.grosLayer = self.layerMap[self.dlg.ui.grosCombo.currentIndex()]
    self.resLayer = self.layerMap[self.dlg.ui.resCombo.currentIndex()]

#populating combo box with layers in stack
def run(self):
    # show the dialog
    self.dlg.show()
    for layer in self.iface.legendInterface().layers():
        if layer.type() == QgsMapLayer.VectorLayer:
            self.dlg.indivCombo.addItem(layer.name())
            self.dlg.grosCombo.addItem(layer.name())
            self.dlg.resCombo.addItem(layer.name())
    # Run the dialog event loop
    result = self.dlg.exec_()
    # See if OK was pressed
    if result == 1:
        pass

感谢下面的近似答案,我现在对代码进行了一些更改。 layerChanged() 现在使用标识符方法,并且 run() 根据线程 http://lists.osgeo.org/pipermail/qgis-developer/2010-November/011505.html 的想法不同地将层添加到组合框。然而,这两个领域仍然给我带来问题。前者为“None type object has no attribute mapLayer”,后者为“语法错误”。

def layerChanged(self, index):
    #globals previously initialized as None
    global registry, indivID, grosID, resID
    registry = QgsMapLayerRegistry.instance()
    indivID = self.dlg.ui.indivCombo.data(index).toPyObject()
    grosID = self.dlg.ui.grosCombo.data(index).toPyObject()
    resID = self.dlg.ui.resCombo.data(index).toPyObject()
    self.indivLayer = registry.mapLayer(indivID)
    self.grosLayer = registry.mapLayer(grosID)
    self.resLayer = registry.mapLayer(resID)

def calculatelength(self):
    global registry, resID
    self.resLayer = registry.mapLayer(resID)
    idx = self.resLayer.fieldNameIndex('Length')
    #code continues

 def run(self):

    # show the dialog
    self.dlg.show()
    for layer in self.iface.legendInterface().layers():
        if layer.type() == QgsMapLayer.VectorLayer:
            self.dlg.ui.indivCombo.addItem(layer.name(),QVariant(layer.id())
            self.dlg.ui.grosCombo.addItem(layer.name(),QVariant(layer.id())
            self.dlg.ui.resCombo.addItem(layer.name(),QVariant(layer.id())
    # Run the dialog event loop
    result = self.dlg.exec_()
    # See if OK was pressed
    if result == 1:
        pass
        #AEPStats()

【问题讨论】:

  • 很可能该列表(可能是错误命名的self.layerMap)并没有提供您认为的功能。您是否尝试过打印列表和相关索引的简单完整性检查,看看它们是否符合您的期望?
  • 是的,我已经完成了打印测试来检查 layerMap。它为我提供了加载到 QGIS 项目中的所有地图图层的字典值列表。我不确定如何打印测试相关的 currentIndex(),因为此时组合框尚未“显示”(因此未选择项目)。也许我错过了其他东西——“错误命名的 self.layerMap”是什么意思?
  • 由于您有回溯,因此您知道错误发生的行 - 因此在该行之前立即打印列表和相关索引。 一定存在某种差异,那么究竟是什么? (顺便说一句:我对layerMap 有点开玩笑——我将其描述为“命名错误”,因为它实际上是一个list 层而不是一个map)。跨度>
  • 不幸的是,我没有回溯,也不知道错误发生在哪里。安装我的插件后,我只是在插件窗口中收到一条消息“此插件已损坏:列表索引超出范围。”我正在研究使用 eclipse 和 pydev 插件设置调试环境,但我很确定代码的这个 sn-p 导致了我的错误。
  • 我已回滚您最近的更改,因为它们破坏了原始问题。如果您想显示对代码所做的更改,请将它们添加到您的原始示例代码下方。

标签: python pyqt4 qgis qcombobox


【解决方案1】:

以您在表面上发布的示例代码为例,我可以看到几个问题。

首先,从initGuirun方法的区别来看,可能有两组组合框在使用。信号连接到self.dlg.ui.*Combo,而项目添加到self.dlg.*Combo

其次,您似乎一遍又一遍地填充组合框而没有事先清除它们。

第三,您似乎没有保留组合框索引和列表之间的一对一关系,因为您正在根据类型过滤图层。

最后,图层列表来自地图的值,所以当然不能保证它们会以相同的顺序出现。

我建议您将layer id 与每个组合项关联,然后通过mapLayer 方法检索图层。也就是说,像这样添加组合项:

    self.dlg.indivCombo.addItem(layer.name(), layer.id())

然后像这样检索图层:

def layerChanged(self, index):
    registry = QgsMapLayerRegistry.instance()
    identifier = self.dlg.ui.indivCombo.itemData(index)
    self.indivLayer = registry.mapLayer(identifier)

注意:如果您使用的是 Python2,组合数据将存储为 QVariant,因此您需要像这样提取标识符:

    identifier = self.dlg.ui.indivCombo.itemData(index).toString()

或者这个:

    identifier = self.dlg.ui.indivCombo.itemData(index).toPyObject()

【讨论】:

  • 是的,我曾尝试过基于此线程的类似标识符方法:lists.osgeo.org/pipermail/qgis-developer/2010-November/…,现在尝试使用 toPyObject(),但继续得到“此插件已损坏:'NoneType' 对象已没有属性'mapLayer'”。感谢您的洞察力。
  • @user25976。这没有任何意义,因为这意味着QgsMapLayerRegistry.instance() 返回None(因为mapLayer 是它的方法之一)。所以看起来你肯定在某个地方做错了什么。
  • 我刚刚更新了我的代码。我将注册表和标识符全局初始化为 none,因为我在以下函数中使用它们——也许这就是 QgsMapLayerRegistry.instance() 返回 None 的原因。或者,我想知道在 init 中初始化为 self.registry = None 是否会更好。使用 QGIS python 控制台,QgsMapLayerRegistry.instance().mapLayers() 给了我预期的字典。
  • @user25976。您需要使用 itemData() 而不是 data() 从组合中获取标识符(我的原始答案有一些复制/粘贴错误)。此外,绝对没有理由在layerChanged 中使用全局变量。请验证 layerChanged 方法中的 print(repr(QgsMapLayerRegistry.instance())) 是否输出 None,因为我现在很难相信这一点。
  • 不,它按预期返回 。感谢您回滚更改,我添加了一些我对 run() 所做的更改,以作为组合框的填充方式。
【解决方案2】:

感谢@ekhumoro 的帮助,现在可以使用了。 layerChanged() 中只有对回答的建议所做的更改:

def layerChanged(self):
    registry = QgsMapLayerRegistry.instance()
    identifier = str(self.dlg.ui.indivCombo.itemData(self.dlg.ui.indivCombo.currentIndex()))
    self.indivLayer = registry.mapLayer(identifier)

这解决了我所拥有的多个组合框选择的索引混淆和不正确的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-23
    • 1970-01-01
    • 2014-05-27
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多