PyQt5. Возможна ли автоматическая генерация и обработка сигнала при создании экземпляра класса?
Помогите реализовать идею. Код предельно упрощен, но суть будет ясна.
После поиска объектов запрашивается детальная информация по выбранному объекту в момент создания экзепляра класса DetailBox через вызов функции self.get_obj_detail().
Дальше логика простая: если информация найдена, то отображается DetailBox с формами для визуализации информации.
Если же информация не найдена, создается сигнал, который после обработки вместо DetailBox покажет Error404Box.
И вроде все нормально, но работает только по клику если self.get_object_detail() прикрутить к какому-то QPushButton.
Как я понял emit возможен только для QObject. \Как это можно обойти или я рою не в ту сторону?
main.py:
import sys
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import (
QApplication, QMainWindow,
QWidget, QGroupBox, QGridLayout, QHBoxLayout, QTabWidget, QLabel, QLineEdit, QPushButton, QSpacerItem, QSizePolicy
)
class Error404Box(QGroupBox):
def __init__(self, parent=None):
super(Error404Box, self).__init__(parent)
self.setTitle("&Error404")
g_layout = QGridLayout(self)
g_layout.addWidget(QLabel("Error404"), 0, 0)
class DetailBox(QGroupBox):
error_signal = pyqtSignal(str, str)
def __init__(self, object_pkid: str, parent=None):
super(DetailBox, self).__init__(parent)
self.object_pkid = object_pkid
self.get_obj_detail() # Так не работает
self.setTitle("&Obj Detail")
self.detail_tabs = QTabWidget()
self.tab_detail = QWidget()
self.detail_tabs.addTab(self.tab_detail, "Obj Detail")
self.detail_tabs.setStyleSheet("""
QTabBar::tab {
height: 35px;
}
""")
self.copy_button = QPushButton("Copy")
self.copy_button.setStyleSheet("""
QPushButton {
min-width: 70px;
min-height: 20px;
margin: 0px;
}
""")
self.delete_button = QPushButton("Delete")
self.delete_button.setStyleSheet("""
QPushButton {
min-width: 70px;
min-height: 20px;
margin: 0px;
}
""")
self.delete_button.clicked.connect(self.get_obj_detail) # В этом случае все работает корректно
h_layout = QHBoxLayout(self)
h_layout.addWidget(self.copy_button)
h_layout.addWidget(self.delete_button)
obj_events_buttons = QWidget()
obj_events_buttons.setLayout(h_layout)
self.detail_tabs.setCornerWidget(obj_events_buttons, Qt.TopRightCorner)
g_layout = QGridLayout(self)
g_layout.addWidget(self.detail_tabs)
self.tabs_forms_build()
def tabs_forms_build(self):
self.pattern_line = QLineEdit()
self.description_line = QLineEdit()
self.v_spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.tab_detail.g_layout = QGridLayout(self)
self.tab_detail.g_layout.addWidget(QLabel(
"<span style=\" font-size:10pt; font-weight:600;\">Object Definition</span>"), 0, 0, 1, 4)
self.tab_detail.g_layout.addWidget(QLabel("Object"), 1, 0, 1, 1)
self.tab_detail.g_layout.addWidget(QLabel("Description"), 2, 0, 1, 1)
self.tab_detail.g_layout.addWidget(QLabel("..."), 3, 0, 1, 1)
self.tab_detail.g_layout.addWidget(self.pattern_line, 1, 1, 1, 4)
self.tab_detail.g_layout.addWidget(self.description_line, 2, 1, 1, 4)
self.tab_detail.g_layout.addWidget(QLabel("..."), 3, 1, 1, 4)
self.tab_detail.g_layout.addItem(self.v_spacer, 4, 2, 1, 1)
self.tab_detail.setLayout(self.tab_detail.g_layout)
@ pyqtSlot()
def get_obj_detail(self):
self.resp = None # some_fx(self.object_pkid) - backend для запроса информации, возвращает Dict or None
if not self.resp:
self.error_signal.emit("Error404", self.object_pkid)
print(self.error_signal)
class MainApp(QMainWindow):
def __init__(self):
super().__init__()
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.resize(800, 500)
self.setWindowTitle("Device Search")
self.result_box = DetailBox("000000-000-000000")
self.result_box.error_signal.connect(self.show_error)
self.layout = QGridLayout(self.centralWidget)
self.layout.addWidget(self.result_box, 0, 0, 1, 1)
@pyqtSlot(str, str)
def show_error(self, error_type, pkid):
self.result_box.deleteLater()
print("GOT SIGNAL", error_type, pkid)
self.result_box = Error404Box()
self.layout.addWidget(self.result_box, 0, 0, 1, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainApp()
ex.show()
sys.exit(app.exec_())
Ответы (1 шт):
С сигналом все нормально, т.к. QGroupBox наследуется от QObject.
В том месте где вы вызываете, не срабатывает потому что объект result_box еще не сформирован.
я отметил для вас два варианта как и где вызывать get_obj_detail(), чтобы работало правильно.
import sys
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QTimer
from PyQt5.QtWidgets import (
QApplication, QMainWindow,
QWidget, QGroupBox, QGridLayout, QHBoxLayout, QTabWidget, QLabel, QLineEdit, QPushButton, QSpacerItem, QSizePolicy
)
class Error404Box(QGroupBox):
def __init__(self, parent=None):
super(Error404Box, self).__init__(parent)
self.setTitle("&Error404")
g_layout = QGridLayout(self)
g_layout.addWidget(QLabel("Error404"), 0, 0)
class DetailBox(QGroupBox):
error_signal = pyqtSignal(str, str)
def __init__(self, object_pkid: str, parent=None):
super(DetailBox, self).__init__(parent)
self.setTitle("&Obj Detail")
self.object_pkid = object_pkid
# self.get_obj_detail() # Так не работает
# +++ так работает !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
QTimer.singleShot(10, self.get_obj_detail)
self.detail_tabs = QTabWidget()
self.tab_detail = QWidget()
self.detail_tabs.addTab(self.tab_detail, "Obj Detail")
self.detail_tabs.setStyleSheet("""
QTabBar::tab {
height: 35px;
}
""")
self.copy_button = QPushButton("Copy")
self.copy_button.setStyleSheet("""
QPushButton {
min-width: 70px;
min-height: 20px;
margin: 0px;
}
""")
self.delete_button = QPushButton("Delete")
self.delete_button.setStyleSheet("""
QPushButton {
min-width: 70px;
min-height: 20px;
margin: 0px;
}
""")
# В этом случае все работает корректно
self.delete_button.clicked.connect(self.get_obj_detail)
# !!!
h_layout = QHBoxLayout() # - (self)
h_layout.addWidget(self.copy_button)
h_layout.addWidget(self.delete_button)
obj_events_buttons = QWidget()
obj_events_buttons.setLayout(h_layout)
self.detail_tabs.setCornerWidget(obj_events_buttons, Qt.TopRightCorner)
g_layout = QGridLayout(self)
g_layout.addWidget(self.detail_tabs)
self.tabs_forms_build()
def tabs_forms_build(self):
self.pattern_line = QLineEdit()
self.description_line = QLineEdit()
self.v_spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.tab_detail.g_layout = QGridLayout(self)
self.tab_detail.g_layout.addWidget(QLabel(
"<span style=\" font-size:10pt; font-weight:600;\">Object Definition</span>"), 0, 0, 1, 4)
self.tab_detail.g_layout.addWidget(QLabel("Object"), 1, 0, 1, 1)
self.tab_detail.g_layout.addWidget(QLabel("Description"), 2, 0, 1, 1)
self.tab_detail.g_layout.addWidget(QLabel("..."), 3, 0, 1, 1)
self.tab_detail.g_layout.addWidget(self.pattern_line, 1, 1, 1, 4)
self.tab_detail.g_layout.addWidget(self.description_line, 2, 1, 1, 4)
self.tab_detail.g_layout.addWidget(QLabel("..."), 3, 1, 1, 4)
self.tab_detail.g_layout.addItem(self.v_spacer, 4, 2, 1, 1)
self.tab_detail.setLayout(self.tab_detail.g_layout)
@pyqtSlot()
def get_obj_detail(self):
# some_fx(self.object_pkid) -
# backend для запроса информации, возвращает Dict or None
self.resp = None
if not self.resp:
self.error_signal.emit("Error404", self.object_pkid)
print(f'def get_obj_detail(self): {self.error_signal}')
class MainApp(QMainWindow):
def __init__(self):
super().__init__()
self.resize(800, 500)
self.setWindowTitle("Device Search")
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.result_box = DetailBox("000000-000-000000")
self.result_box.error_signal.connect(self.show_error)
self.layout = QGridLayout(self.centralWidget)
self.layout.addWidget(self.result_box, 0, 0, 1, 1)
# +++ или здесь !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# self.result_box.get_obj_detail()
@pyqtSlot(str, str)
def show_error(self, error_type, pkid):
self.result_box.deleteLater()
print("GOT SIGNAL", error_type, pkid)
self.result_box = Error404Box()
self.layout.addWidget(self.result_box, 0, 0, 1, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainApp()
ex.show()
sys.exit(app.exec_())
