【问题标题】:Dynamically changeable QCheckBox list动态变化的 QCheckBox 列表
【发布时间】:2018-02-13 21:54:27
【问题描述】:

我目前正在使用 Python 2.7 和 PyQt 4 为 QGIS 开发插件。我的插件应该有可检查的地图层列表(可能是项目列表,无关),每次用户打开“设置”选项卡时都会重新生成。尽管我设法创建了 QCheckBoxes 的可检查列表,每次单击“设置”按钮时都会重新生成,但它仍然远非良好和实用的列表。据我所知,我的问题主要是父子关系和布局删除。

    self.layers = qgis_api.get_layers()
    #ScrollArea setup
    if (api.selected_upload_layers == [] and
        api.project.layerTreeRoot().children() != []):
        self.tmp_layers = qgis_api.get_layers()
        self.layout = QVBoxLayout(self.settingsDock.groupBox)
        self.scroll = QScrollArea()
        self.layout.addWidget(self.scroll)
        self.scroll.setWidgetResizable(True)
        self.scroll.setFixedHeight(111)
        self.scrollContent = QWidget(self.scroll)
        self.scrollLayout = QVBoxLayout(self.scrollContent)
        self.scrollContent.setLayout(self.scrollLayout)
        self.scroll.setWidget(self.scrollContent)

    i = 0
    self.checkboxes = []
    for layer in self.layers:
        self.checkboxes.append(QCheckBox("{0}".format(layer.name())))
        self.checkboxes[i].stateChanged.connect(lambda checked, i = i : self.cBoxChecked(self.checkboxes[i])) #inverts logic if run every time
        # check logic
        if i < len(self.layers)-1:
            i += 1
    # Create checkboxes first time
    if not api.upload:  #api.upload becomes true when clicked save in settings
        for i in range(0, len(self.layers)):
            try:
                self.scrollLayout.addWidget(self.checkboxes[i])
                self.checkboxes[i].setChecked(True)
            except Exception as e:
                print str(e)
    # compare layer list at creation and now to notice difference
    elif self.tmp_layers != self.layers:
        for i in range(0, self.scrollLayout.count()):
            self.scrollLayout.removeItem(self.scrollLayout.itemAt(0))
            try:  # delete old layer items
                for i in range(0, len(self.layers)):
                    self.scrollLayout.addWidget(self.checkboxes[i])
                    self.checkboxes[i].setChecked(True)
            except Exception as e:
                print str(e)

函数cBoxChecked()如下:

    def cBoxChecked(self, cBox):
    """ Add functionality  to ScrollArea checkboxes."""
    if cBox.isChecked():
          if cBox.text() not in api.selected_upload_layers:
               api.selected_upload_layers.append(cBox.text())
    else:
          try:
               api.selected_upload_layers.remove(cBox.text())
          except Exception as e:
               print str(e)

虽然现在我没有遇到任何异常,但列表已重新生成。我注意到新列表下方的旧列表,这意味着我没有正确删除布局(布局删除有各种问题),但我无法完全弄清楚。把它们加起来。在这个具体的例子中,销毁和重新创建布局的最方便的方法是什么以及如何弄清楚父子 QObject 关系?还有一个困扰我的问题是,每次打开设置选项卡时,似乎都会在 lambda 函数中进行逻辑恢复,从而为选择某些 CheckBox 完成所有繁重的工作。如何解决? 谢谢你的时间:)

【问题讨论】:

    标签: python qt pyqt qgis


    【解决方案1】:

    我修好了。主要问题是 removeItem 方法没有按计划工作。虽然整个事情一团糟。我现在做了什么?我在类初始化时将复选框列表创建为空列表,并且在正确的条件下,我正在检查是第一次调用 SettingsDock,还是在层接口列表中发生更改后调用它。代码如下。如果在 cmets 中没有正确解释某些内容,请随时问我为什么这样做。干杯

        self.layers = qgis_api.get_layers()
        reduced_layers = []
        # reduced_layers is list variable which is populated with all layers
        # without redundant ones (same names of multiple files .shp/.shx/.dbf)
        # shapefile file format 
        for layer in self.layers:
            if layer.name() not in reduced_layers:
                reduced_layers.append(layer.name())
    
        # ScrollArea setup
        # Set up settingsDock.groupBox as a parent of Vertical layout
        # Check if Settings was clicked before api.upload would be handy for
        # that, scroll is QScrollArea and is added as widget with layout as
        # parent, after that I set up Scroll Content as widget with scroll
        # as parent, while scroll Layout is Vertical layout with scrollContent
        # as parent, but then i use scroll.setWidget method to define it as
        # a parent to scrollContent 
        if (api.selected_upload_layers == [] and
            api.project.layerTreeRoot().children() != []):
            self.tmp_layers = qgis_api.get_layers()
            self.layout = QVBoxLayout(self.settingsDock.groupBox)
            self.scroll = QScrollArea()
            # self.layout.addWidget(self.scroll)
            self.scroll.setWidgetResizable(True)
            self.scroll.setFixedHeight(111)
            self.layout.addWidget(self.scroll)
            self.scrollContent = QWidget(self.scroll)
            self.scrollLayout = QVBoxLayout(self.scrollContent)
            self.scroll.setWidget(self.scrollContent)
    
        # As self.checkboxes are initialized as empty list, here are we
        # generating a list of QCheckBox items with layer names(if there are
        # multiple layers with same name(shapefile format), only one will be
        # added as checkbox
        # After generating checkboxes list we use it to populate widgets,
        # QCheckBoxes in ScrollLayout, and set it in default as Checked
        # This is basically 1st time initialization
        if self.checkboxes == []:
            try:
                for i in range(0, len(self.layers)):
                    if self.layers[i].name() not in map(lambda x: x.text(),
                                                        self.checkboxes):
                        self.checkboxes.append(QCheckBox('{}'.format(
                                                self.layers[i].name())))
                for i in range(0, len(self.checkboxes)):
                    self.scrollLayout.addWidget(self.checkboxes[i])
                    self.checkboxes[i].setChecked(True)
                    api.selected_upload_layers = map(lambda x: x.text(),
                                                     self.checkboxes)
            except Exception as e:
                print str(e)
    
        # if checkboxes are different from layer list (that is generated) in
        # the moment of clicking show settings which basically indicates that
        # interface layer list has been chaged, we must update checkboxes
        # To update checkboxes list it's firstly deleted with ScrollContent
        elif map(lambda x: x.text(), self.checkboxes) != reduced_layers:
            num = self.scrollLayout.count()
            self.scrollLayout.removeWidget(self.scrollContent)
            self.scrollContent.deleteLater()
            self.scrollContent = QWidget(self.scroll)
            self.scrollLayout = QVBoxLayout(self.scrollContent)
            self.scroll.setWidget(self.scrollContent)
            try:
                self.checkboxes = []
                for i in range(0, len(self.layers)):
                    if self.layers[i].name() not in map(lambda x: x.text(), self.checkboxes):
                        self.checkboxes.append(QCheckBox('{}'.format(
                                                self.layers[i].name())))
                for i in range(0, len(self.checkboxes)):
                    self.scrollLayout.addWidget(self.checkboxes[i])
                    self.checkboxes[i].setChecked(True)
            except Exception as e:
                print (e)
    
        for i in range(0, len(self.checkboxes)):
            self.checkboxes[i].stateChanged.connect(lambda checked, i=i:
                                                self.checkBoxChecked())
    

    函数checkBoxChecked()如下:

        def checkBoxChecked(self):
        """Add functionality to ScrollArea checkboxes."""
        #print api.selected_upload_layers
        indices = []
        for i in range(0, len(self.checkboxes)):
            if self.checkboxes[i].isChecked():
                # print cBox.isChecked()
                print self.checkboxes[i].text() + " is selected"
                indices.append(i)
            else:
                print self.checkboxes[i].text() + " is deselected"
    
        api.selected_upload_layers = [map(lambda x: x.text(), self.checkboxes)[i] for i in indices]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-21
      • 1970-01-01
      • 2016-06-24
      • 2021-09-11
      • 2011-03-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多