Issue
I think the easiest way to ask this question is to simply show a Microsoft Paint mockup of what I'm trying to accomplish (see below).
I'm trying to create a widget that allows the user to (effectively) customize a database query that happens in the background. Most of the customizations can be done through simple checkboxes and radio buttons, but two of them seem to make the most sense to use radio buttons with text fields inside of them. The image below shows my idea for how to allow the user to select files described by the database in terms of their sizes: no size constraint, specify maximum size, minimum size, or a range of sizes.
I feel like this should be doable, but my searches aren't bearing much fruit. For example, this related question and its answer show a neat approach for one specific situation, but I don't know how much sense it makes in my situation. So, does anyone know if this is possible?
Solution
It's not really difficult to create this widget, it's just a combination of QRadioButtons, QLabels, QLineEdits, using a few of the basic Layouts notions.
In the example below, I used QHBoxLayouts
to create the QRadioButtons
texts, and display QLineEdits
between the labels. I used a single QGridLayout
to group all the Radio Buttons and their following Texts and Line Edits together.
By using a QVBoxLayout
, I grouped the Grid Layout and the QPushButton
, so you can extract information from the current selected option.
The application's output uses a QMessageBox
to inform the user about the current result.
I didn't used a Spin Box to certify that the user types only integers inside the Line Edits. Instead, I used a try-except
block to prevent any errors when calling the built-in int()
function. However, using a Spin Box should be the right aproach.
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtWidgets import QGridLayout, QHBoxLayout, QVBoxLayout, QMessageBox
from PySide2.QtWidgets import QWidget, QLabel, QRadioButton, QButtonGroup, QLineEdit, QPushButton
class Form(QWidget):
def __init__(self):
QWidget.__init__(self)
self.maximumSizeOnly = QLineEdit()
self.betweenMinimum = QLineEdit()
self.betweenMaximum = QLineEdit()
self.minimumSizeOnly = QLineEdit()
# magic's method logic
self.lineEdits = [[], [self.maximumSizeOnly], [self.betweenMinimum, self.betweenMaximum], [self.minimumSizeOnly]]
self.option1 = QRadioButton("")
self.option2 = QRadioButton("")
self.option3 = QRadioButton("")
self.option4 = QRadioButton("")
self.applyButton = QPushButton("Apply")
self.applyButton.clicked.connect(self.apply)
grid = QGridLayout()
vbox = QVBoxLayout()
self.setLayout(vbox)
grid.addWidget(self.option1, 0, 0)
grid.addWidget(self.option2, 1, 0)
grid.addWidget(self.option3, 2, 0)
grid.addWidget(self.option4, 3, 0)
grid.addWidget(QLabel("Any Size"), 0, 1)
hbox = QHBoxLayout()
hbox.addWidget(QLabel("Maximum Size: "))
hbox.addWidget(self.maximumSizeOnly)
grid.addLayout(hbox, 1, 1)
hbox = QHBoxLayout()
hbox.addWidget(QLabel("Between "))
hbox.addWidget(self.betweenMinimum)
hbox.addWidget(QLabel(" and "))
hbox.addWidget(self.betweenMaximum)
grid.addLayout(hbox, 2, 1)
hbox = QHBoxLayout()
hbox.addWidget(QLabel("Minimum Size: "))
hbox.addWidget(self.minimumSizeOnly)
grid.addLayout(hbox, 3, 1)
vbox.addLayout(grid)
hbox = QHBoxLayout()
hbox.addWidget(self.applyButton)
hbox.addStretch(1)
vbox.addLayout(hbox)
self.maximumSizeOnly.setEnabled(False)
self.betweenMinimum.setEnabled(False)
self.betweenMaximum.setEnabled(False)
self.minimumSizeOnly.setEnabled(False)
# Each ID is bound to self.lineEdits list.
self.bGroup = QButtonGroup()
self.bGroup.addButton(self.option1, 0)
self.bGroup.addButton(self.option2, 1)
self.bGroup.addButton(self.option3, 2)
self.bGroup.addButton(self.option4, 3)
self.bGroup.buttonToggled.connect(self.magic)
def magic(self, button, down):
index = self.bGroup.id(button)
lineEdits = self.lineEdits[index]
if (down):
for le in lineEdits:
le.setEnabled(True)
else:
for le in lineEdits:
le.setEnabled(False)
le.setText('')
def apply(self):
index = self.bGroup.checkedId()
text = ''
if (index == 0):
text = 'Any Size set.'
elif (index == 1):
le = self.lineEdits[1][0]
try:
text = 'Maximum Size: %d' % (int(le.text()))
except:
text = 'Maximum Size: Undefined'
elif (index == 2):
leMin = self.lineEdits[2][0]
leMax = self.lineEdits[2][1]
try:
text = 'Size Between: [%d, %d]' % (int(leMin.text()), int(leMax.text()))
except:
text = 'Size Between: Undefined'
elif (index == 3):
le = self.lineEdits[3][0]
try:
text = 'Minimum Size: %d' % (int(le.text()))
except:
text = 'Minimum Size: Undefined'
else:
dialog = QMessageBox()
dialog.setWindowTitle('Error')
dialog.setIcon(QMessageBox.Warning)
dialog.setText('No option is selected.')
dialog.exec_()
return
dialog = QMessageBox()
dialog.setWindowTitle('Success')
dialog.setIcon(QMessageBox.NoIcon)
dialog.setText(text)
dialog.exec_()
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle('Syzygy\'s Answer')
self.form = Form()
self.setCentralWidget(self.form)
self.setMinimumWidth(300)
def main():
app = QApplication()
win = MainWindow()
win.show()
app.exec_()
if __name__ == '__main__':
main()
The main idea of this example is to make only the selected option's QLineEdits
enabled at a time. When the user selects another option, the enabled widgets are disabled, and the new QLineEdits
, if any, are enabled.
When a QLineEdit
is disabled, all content is lost, as I call le.setText("")
inside magic()
method.
Inside apply()
method, I show how to retrieve the selected Radio Button and display the desired result using their bound Line Edits.
I use PySide2 instead of PyQt5, so before executing the script, change each PySide2
occurrence to PyQt5
. The rest of the script should remain the same as only a few variables and methods names should change from one module to another.
Answered By - Carl HR
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.