При реализации паттерна "Наблюдатель" сообщения виджетов QComboBox отправляются наблюдателям в обратном порядке и задваиваются
Есть две радиокнопки, за изменением состояния которых следит класс PageLayout
. /
За изменением состояния комбобокса ComboBoxPrinter
следит другой комбобокс ComboBoxPaperSize
.
За изменением ComboBoxPaperSize
следит класс PageLayout
.
За изменением PageLayout
следит класс Scene
.
Всё это я реализовал с помощью паттерна «Наблюдатель».
Код такой:
from PyQt6.QtWidgets import *
from PyQt6.QtCore import *
from PyQt6.QtGui import *
import sys
list1 = ["a3", "a4", "a5"]
list2 = ["a1", "a2", "a3", "a4"]
printer = {"Samsung": list1,
"HP": list2 }
class Func():
################# методы изменяющие PageLayout #################
def function_portrait (*args):
print(f"function_portrait: виджет {args[1].get_name()} посылает сигнал {args[0].get_name()}")
def function_landscape(*args):
print(f"function_landscape: виджет {args[1].get_name()} посылает сигнал {args[0].get_name()}")
def function_papersize(*args):
print(f"function_papersize: виджет {args[1].get_name()} посылает сигнал {args[0].get_name()}")
function_for_pagelayout = {
"portrait": function_portrait,
"landscape": function_landscape,
"papersize": function_papersize
}
#### методы на клик по выбору принтера ComboBoxPrinter ###################
def function_choise_printer(*args):
args[0].clear()
args[0].addItems(printer[args[1].currentText()])
print(f"function_choise_printer: виджет {args[1].get_name()} посылает сигнал {args[0].get_name()}")
function_for_combobox_printer = {
"printers": function_choise_printer
}
#### методы измененяющие Scene ##################################
def function_scene_page_layout(*args):
print(f"function_scene_page_layout: виджет {args[1].get_name()} посылает сигнал {args[0].get_name()}")
function_for_scene = {
"pagelayout": function_scene_page_layout
}
# наблюдатель
class Observer():
def update_observer():
pass
#наблюдаемое
class Subject():
#имя
def set_name(self, name: str):
pass
def get_name(self) -> str:
pass
# сообщение наблюдателю
def notify(self):
pass
# добавление наблюдателей
def attach(self, observer: Observer):
pass
# удаление наблюдателей
def detach(self, observer: Observer):
pass
class RadioButtonPortraitAndLandscape(QRadioButton, Subject):
def __init__(self, name: str, parent=None):
super().__init__(name)
self.list_observers = []
def set_name(self, name: str):
self.__name = name
def get_name(self) -> str:
return self.__name
def mousePressEvent(self, event):
self.setChecked(True)
self.notify()
def notify(self):
for i in self.list_observers:
i.update_observer(self)
def attach(self, observer: Observer):
self.list_observers.append(observer)
def detach(self, observer: Observer):
self.list_observers.remove(observer)
class ComboBoxPaperSize(QComboBox, Subject, Observer):
def __init__(self, parent=None):
super().__init__()
self.addItems(list1)
self.list_observers = []
self.currentTextChanged[str].connect(self.notify)
def set_name(self, name: str):
self.__name = name
def get_name(self) -> str:
return self.__name
def notify(self):
for i in self.list_observers:
i.update_observer(self)
def attach(self, observer: Observer):
self.list_observers.append(observer)
def detach(self, observer: Observer):
self.list_observers.remove(observer)
def update_observer(self, subject: Subject):
Func.function_for_combobox_printer[subject.get_name()](self, subject)
class ComboBoxPrinter(QComboBox, Subject):
def __init__(self, parent=None):
super().__init__()
self.addItems([key for key, value in printer.items()])
self.list_observers = []
self.currentTextChanged[str].connect(self.notify)
def set_name(self, name: str):
self.__name = name
def get_name(self) -> str:
return self.__name
def notify(self):
for i in self.list_observers:
i.update_observer(self)
def attach(self, observer: Observer):
self.list_observers.append(observer)
def detach(self, observer: Observer):
self.list_observers.remove(observer)
class PageLayout(QPageLayout, Observer, Subject):
def __init__(self):
super().__init__()
self.list_observers = []
def set_name(self, name: str):
self.__name = name
def get_name(self) -> str:
return self.__name
def update_observer(self, subject: Subject):
Func.function_for_pagelayout[subject.get_name()](self, subject)
self.notify()
def notify(self):
for i in self.list_observers:
i.update_observer(self)
def attach(self, observer: Observer):
self.list_observers.append(observer)
def detach(self, observer: Observer):
self.list_observers.remove(observer)
class Scene(QGraphicsScene, Observer):
def __init__(self):
super().__init__()
def set_name(self, name: str):
self.__name = name
def get_name(self) -> str:
return self.__name
def update_observer(self, subject: Subject):
Func.function_for_scene[subject.get_name()](self, subject)
##################################################################
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("Print")
scene = Scene()
scene.set_name("scene")
pagelayout = PageLayout()
pagelayout.set_name("pagelayout")
pagelayout.attach(scene)
port = RadioButtonPortraitAndLandscape("portrait")
port.setChecked(True)
port.set_name("portrait")
port.attach(pagelayout)
land = RadioButtonPortraitAndLandscape("landscape")
land.set_name("landscape")
land.attach(pagelayout)
paper = ComboBoxPaperSize()
paper.set_name("papersize")
paper.attach(pagelayout)
prin = ComboBoxPrinter()
prin.set_name("printers")
prin.attach(paper)
layout = QVBoxLayout()
layout.addWidget(port)
layout.addWidget(land)
layout.addWidget(prin)
layout.addWidget(paper)
window.setLayout(layout)
window.show()
app.exec()
Всё работает. Только есть один нюанс в последовательности отправки сообщений от источника к наблюдателям.
При выборе принтера из ComboBoxPrinter
почему-то первым посылает сообщения своим наблюдателям не ComboBoxPrinter
, а ComboBoxPaperSize
, и эти сообщения задваиваются.
Не могу понять, в чём причина?