| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- import random
- import sys
- from collections import UserDict
- from PyQt5.QtCore import QObject, pyqtSignal, Qt
- from PyQt5.QtWidgets import QMainWindow, QApplication, QFormLayout, QLineEdit, QSpinBox, QComboBox, QPushButton, \
- QCheckBox, QWidget
- class DataModelSignals(QObject):
- # Emit an "updated" signal when a property changes.
- updated = pyqtSignal()
- class DataModel(UserDict):
- def __init__(self, *args, **kwargs):
- self.signals = DataModelSignals()
- super().__init__(*args, **kwargs)
- def __setitem__(self, key, value):
- previous = self.get(key) # Get the existing value.
- super().__setitem__(key, value)
- if value != previous: # There is a change
- self.signals.updated.emit() # Emit the signal
- print(self) # Show the current state.
- model = DataModel(
- name="Johnina Smith",
- age=10,
- favorite_icecream="Vanilla",
- disable_details=False,
- )
- class Controller:
- """ Simple controller, which handles backups and other operations. """
- backups = []
- def capitalize(self):
- model["name"] = model["name"].upper()
- def store_backup(self):
- self.backups.append(model.copy())
- def restore_backup(self):
- if not self.backups:
- return
- random.shuffle(self.backups)
- backup = self.backups.pop()
- model.update(backup) # Overwrite the data in the model
- print("RESTORE:", model)
- print("BACKUPS:", len(self.backups))
- def apply_title_case(self):
- model["name"] = model["name"].title()
- controller = Controller()
- class MainWindow(QMainWindow):
- def __init__(self):
- super().__init__()
- self.setWindowTitle("MVC Example")
- layout = QFormLayout()
- # Dictionary to store the form data, with default data.
- self.name = QLineEdit()
- self.name.textChanged.connect(self.on_name_changed)
- self.age = QSpinBox()
- self.age.setRange(0, 200)
- self.age.valueChanged.connect(self.on_age_changed)
- self.icecream = QComboBox()
- self.icecream.addItems(["Vanilla", "Strawberry", "Chocolate"])
- self.icecream.currentTextChanged.connect(self.on_icecream_changed)
- self.title_btn = QPushButton("Set Title Case")
- self.title_btn.pressed.connect(controller.apply_title_case)
- # tag::connect[]
- self.save_btn = QPushButton("Save")
- self.save_btn.pressed.connect(controller.store_backup)
- self.restore_btn = QPushButton("Restore")
- self.restore_btn.pressed.connect(controller.restore_backup)
- # end::connect[]
- self.disable_details = QCheckBox("Disable Details?")
- self.disable_details.toggled.connect(self.on_disable_details_toggled)
- layout.addRow("Name", self.name)
- layout.addRow(self.title_btn)
- layout.addRow("Age", self.age)
- layout.addRow("Favorite Ice Cream", self.icecream)
- layout.addWidget(self.disable_details) # QCheckBox has its own label.
- layout.addRow(self.save_btn)
- layout.addRow(self.restore_btn)
- layout.setLabelAlignment(Qt.AlignLeft)
- widget = QWidget()
- widget.setLayout(layout)
- self.setCentralWidget(widget)
- self.update_ui()
- # Hook our UI sync into the model updated signal
- model.signals.updated.connect(self.update_ui)
- def update_ui(self):
- self.name.setText(model["name"])
- self.age.setValue(model["age"])
- self.icecream.setCurrentText(model["favorite_icecream"])
- self.disable_details.setChecked(model["disable_details"])
- self.age.setDisabled(model["disable_details"])
- self.icecream.setDisabled(model["disable_details"])
- def on_name_changed(self, name):
- model["name"] = name
- def on_age_changed(self, age):
- model["age"] = age
- def on_icecream_changed(self, icecream):
- model["favorite_icecream"] = icecream
- def on_disable_details_toggled(self, checked):
- model["disable_details"] = checked
- if __name__ == "__main__":
- app = QApplication(sys.argv)
- window = MainWindow()
- window.show()
- sys.exit(app.exec_())
|