I need to display a GUI including two checkboxes (referring to the two fields of a polyline shapefile representing the roads of an OSM data). The first checkbox ("sidewalk"), has three radio buttons (i.e. left, right and both as a sidewalk could take one of these values). The second checkbox ("highway") has two radio buttons (i.e. residential and secondary).
My requirements:
- The radio buttons do belong to the relevant checkbox. Therefore, they have to be grouped.
- Initially, no check box or radio button is selected. Once the user checks one of the checkboxes, the relevant radio buttons will be enabled. If the user deselects the checkbox, then the radio buttons will get back to their initial state - all of them are disabled and none is selected.
- Each click will cause to select some of the roads belonging to OSM data. For instance, once the user checks the "sidewalk" checkbox, the roads having the value "left", "right" or "both" would be selected. If the user then selects one of these radio buttons, the selection would be refined accordingly. Similarly, the user could check the "highway", and the selection would again be refined so that only those roads having the values "residential" or "secondary" will be selected.
- These actions are reversible, and once we deselect everything, we will not have any selection.
Once the attached code is executed on QGIS, we will obtain the following outcome:
.
For example, going from the default configuration (a) to (b), there will be two actions in the map (first we have to check the "sidewalk" check box and then the "right" radio button). However, if we first uncheck the checkbox when we are at (b), we should get the default configuration (one action). Similarly, if we want to move from (c) to (d), there should be two updates on the map. The following code print the updates:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
#Create our custom class for the checkboxes and textboxes:
class CheckBox(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.layout = QVBoxLayout()
# Add the check box and radio buttons for the first field -sidewalk
self.cb1 = QCheckBox('sidewalk')
self.cb1_rb1 = QRadioButton('left')
self.cb1_rb2 = QRadioButton('right')
self.cb1_rb3 = QRadioButton('both')
# Add the check box and radio button for the second field -highway
self.cb2 = QCheckBox('highway')
self.cb2_rb1 = QRadioButton('residential')
self.cb2_rb2 = QRadioButton('secondary')
# Initially, all radio buttons are inactive
self.cb1_rb1.setEnabled(False)
self.cb1_rb2.setEnabled(False)
self.cb1_rb3.setEnabled(False)
self.cb2_rb1.setEnabled(False)
self.cb2_rb2.setEnabled(False)
# Connect the status signals of the checkboxes to the check box methods:
self.cb1.toggled.connect(self.cb1_active)
self.cb2.toggled.connect(self.cb2_active)
# Select the according roads.. One slot for both of the checkboxes
self.cb1.toggled.connect(self.selectRoads)
self.cb2.toggled.connect(self.selectRoads)
#Add the widgets to the layout:
self.layout.addWidget(self.cb1)
self.layout.addWidget(self.cb1_rb1)
self.layout.addWidget(self.cb1_rb2)
self.layout.addWidget(self.cb1_rb3)
# Checkbox 2 (highway)
self.layout.addWidget(self.cb2)
self.layout.addWidget(self.cb2_rb1)
self.layout.addWidget(self.cb2_rb2)
# Group the radio buttons based on the field
self.sidewalk=QButtonGroup()
self.highway=QButtonGroup()
# Add the radio buttons to the groups accordingly
self.sidewalk.addButton(self.cb1_rb1)
self.sidewalk.addButton(self.cb1_rb2)
self.sidewalk.addButton(self.cb1_rb3)
self.highway.addButton(self.cb2_rb1)
self.highway.addButton(self.cb2_rb2)
#Set the layout:
self.setLayout(self.layout)
# First checkbox
def cb1_active(self, on):
if on:
# Enable the radio buttons
self.cb1_rb1.setEnabled(True)
self.cb1_rb2.setEnabled(True)
self.cb1_rb3.setEnabled(True)
# Once a radio button is toggled, select the roads accordingly
self.cb1_rb1.toggled.connect(self.selectRoads)
self.cb1_rb2.toggled.connect(self.selectRoads)
self.cb1_rb3.toggled.connect(self.selectRoads)
else:
# Radio buttons should be inactive:
self.cb1_rb1.setEnabled(False)
self.cb1_rb2.setEnabled(False)
self.cb1_rb3.setEnabled(False)
# Uncheck the checked radio button in order to provide a better display:
#https://stackoverflow.com/questions/8689909/uncheck-radiobutton-pyqt4
self.sidewalk.setExclusive(False)
# Return to the default
self.cb1_rb1.setChecked(False)
self.cb1_rb2.setChecked(False)
self.cb1_rb3.setChecked(False)
self.sidewalk.setExclusive(True)
# ----------------------------------------------------------------------------------
# Second checkbox
def cb2_active(self, on):
if on:
self.cb2_rb1.setEnabled(True)
self.cb2_rb2.setEnabled(True)
self.cb2_rb1.toggled.connect(self.selectRoads)
self.cb2_rb2.toggled.connect(self.selectRoads)
else:
self.cb2_rb1.setEnabled(False)
self.cb2_rb2.setEnabled(False)
# Uncheck the radio buttons:
self.highway.setExclusive(False)
self.cb2_rb1.setChecked(False)
self.cb2_rb2.setChecked(False)
self.highway.setExclusive(True)
def selectRoads(self):
# Obtain the configuration of the buttons:
cb1 = self.cb1.isChecked()
cb2 = self.cb2.isChecked()
cb1_rb1 = self.cb1_rb1.isChecked()
cb1_rb2 = self.cb1_rb2.isChecked()
cb1_rb3 = self.cb1_rb3.isChecked()
cb2_rb1 = self.cb2_rb1.isChecked()
cb2_rb2 = self.cb2_rb2.isChecked()
print cb1, cb1_rb1, cb1_rb2, cb1_rb3, cb2, cb2_rb1, cb2_rb2
buttons = CheckBox()
buttons.show()
With this, I could get more than one print statement for an update. Each click different from the previous configuration should produce only a single print statement; because we'll be updating the selection once even if we uncheck a checkbox whose radio button is selected.
I would like to satisfy my requirements as I am learning PyQGIS, but I am also happy to hear different designs to achieve the same purpose.
__init__
but still I am getting more than one printed statement for some of the updates. For example, let's assume the order of clicking is as follows: (highway-secondary-residential); then we'll receive 1-1-2 print statements.