动态可变的 QCheckBox 列表
Dynamically changeable QCheckBox list
我目前正在使用 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 的所有繁重工作。如何解决?
感谢您的宝贵时间:)
我修好了。主要问题是 removeItem 方法没有按计划工作。虽然整个事情一团糟。我现在做了什么?我在 class 初始化时创建了复选框列表作为空列表,并且在正确的条件下我正在检查是第一次调用 SettingsDock 还是在层接口列表中发生某些更改后调用它。代码如 folows.If 注释中没有正确解释,请随时问我为什么那样做。干杯
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]
我目前正在使用 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 的所有繁重工作。如何解决? 感谢您的宝贵时间:)
我修好了。主要问题是 removeItem 方法没有按计划工作。虽然整个事情一团糟。我现在做了什么?我在 class 初始化时创建了复选框列表作为空列表,并且在正确的条件下我正在检查是第一次调用 SettingsDock 还是在层接口列表中发生某些更改后调用它。代码如 folows.If 注释中没有正确解释,请随时问我为什么那样做。干杯
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]