Reputation: 1027
I have a combo box with 2 options 'time' or 'interval' when 'time' is selected I would like to show a QTimeEdit and When 'interval is selected I would like to show a QSpinBox.
I can hide the interval widget and show the time widget but I do not know how to re-position it so that it is displayed where the interval widget was.
Here is what I have so far:
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
class MainWindow(qtw.QMainWindow):
def __init__(self):
super().__init__()
form = qtw.QWidget()
self.setCentralWidget(form)
layout = qtw.QFormLayout()
form.setLayout(layout)
self.when_list = qtw.QComboBox(currentIndexChanged=self.on_change)
self.when_list.addItem('Every X Minutes', 'interval')
self.when_list.addItem('At a specific time', 'time')
self.interval_box = qtw.QSpinBox()
self.time_edit = qtw.QTimeEdit()
self.event_list = qtw.QComboBox()
self.event_list.addItem('Event 1')
self.event_list.addItem('Event 2')
self.event_msg = qtw.QLineEdit()
self.add_button = qtw.QPushButton('Add Event', clicked=self.add_event)
layout.addRow(self.when_list, self.interval_box)
layout.addRow(self.event_list)
layout.addRow(self.event_msg)
layout.addRow(self.add_button)
self.show()
def on_change(self):
if self.when_list.currentData() == 'time':
# Hide interval
self.interval_box.hide()
# Show time - how do I put this where interval_box was?
self.time_edit.show()
elif self.when_list.currentData() == 'interval':
# Hide time - ERROR object has no attribute time_edit
self.time_edit.hide()
# show interval - ERROR object has no attribute interval_box
self.interval_box.show()
def add_event(self):
pass
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = MainWindow()
sys.exit(app.exec())
How can I fix the errors and dynamically switch between the widgets?
Upvotes: 0
Views: 131
Reputation: 48231
Instead of hiding and showing widgets, you can use a QStackedWidget (which is similar to a tab widget, but without tabs) and use the combo box signal to select which one show.
Note that you should not connect to a *changed
signal in the constructor if you're going to set properties that could call that signal and the slot uses objects that don't exist yet: in your case you connected the currentIndexChanged
signal in the constructor, but that signal is always called when an item is added to a previously empty combobox, and since at that point the time_edit
object has not been created, you'll get an AttributeError as soon as you add the first item.
While using signal connections in the constructor can be useful, it must always be used with care.
class MainWindow(qtw.QMainWindow):
def __init__(self):
# ...
self.when_list = qtw.QComboBox()
self.when_list.addItem('Every X Minutes', 'interval')
self.when_list.addItem('At a specific time', 'time')
self.when_list.currentIndexChanged.connect(self.on_change)
# ...
self.time_stack = qtw.QStackedWidget()
self.time_stack.addWidget(self.interval_box)
self.time_stack.addWidget(self.time_edit)
layout.addRow(self.when_list, self.time_stack)
# ...
def on_change(self):
if self.when_list.currentData() == 'time':
self.time_stack.setCurrentWidget(self.time_edit)
elif self.when_list.currentData() == 'interval':
self.time_stack.setCurrentWidget(self.interval_box)
Another solution could be to remove the widget that is to be hidden and insert a row in the same place using QFormLayout functions, but while that layout is useful in many situations, it's mostly intended for pretty "static" interfaces. The alternative would be to use a QGridLayout, which allows setting more widgets on the same "cell": in that case, you can easily toggle visibility of items, but it could create some issues as the layout would also try to adjust its contents everytime (which can be solved by using setRetainSizeWhenHidden()
for the widget's size policy.
Upvotes: 1