当您想要构建完全自包含的类时,可能会遇到一些问题,可能原因是您缺少一些众所周知的基础知识。考虑以下示例:
class Main_Window (QtGui.QMainWindow):
def __init__ (self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_bookingSystemMain()
self.ui.setupUi(self)
# Connect slots
QtCore.QObject.connect(self.ui.submitRecord, QtCore.SIGNAL("clicked()"), self.__clickSubmitRecord)
QtCore.QObject.connect(self.ui.btnListBookings, QtCore.SIGNAL("clicked()"), self.__show_list)
def __clickSubmitRecord (self):
global bookings
name = self.ui.edtName.text()
event = str(self.ui.comEvent.currentText())
amount = self.ui.spinBox.value()
if name == '':
QtGui.QMessageBox.warning(self, "Error", "Please enter a name!")
elif amount == 0:
QtGui.QMessageBox.warning(self, "Error", "You can't reserve 0 tickets!")
elif event == '':
QtGui.QMessageBox.warning(self, "Error", "Please choose an event!")
else:
bookings.append(Booking(name, event, amount))
QtGui.QMessageBox.information(self, "Booking added", "Your booking for " + str(amount) + " ticket(s) to see " + event + " in the name of " + name + " was sucessful.")
self.__clear_widgets()
def __clear_widgets (self):
self.ui.edtName.clear()
self.ui.comEvent.setCurrentIndex(-1)
self.ui.spinBox.setValue(0)
def __show_list (self):
listdialog = List_Window(self)
listdialog.show()
这个类实现了另一个模块中描述的 UI。clickSubmitRecord() 方法使用全局“booking”列表并向其中添加内容——现在这个类肯定不应该与 UI 之外的任何事情有任何关系?
2. 解决方案
您可以使用以下步骤来实现良好的面向对象方式:
- 在窗口对象中定义一个“bookingAdded”信号。
- 让外部对象之一(可能是调用 UI 的那个)将槽连接到此信号。
- 在 clickSubmitRecord 中触发此信号,并将新的预订数据随信号一起传递给外部对象。
这样,UI 对象就不需要了解任何外部信息,而所有外部对象需要了解的 UI 只是它公开的信号。如果您使用队列连接到信号,这也可能有助于线程安全。
以下是用 C++ 编写的一个示例:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
public slots:
void onBookingAdded(const Booking& booking);
private:
Ui::MainWindow ui;
// ...
};
class ExternalObject
{
public:
ExternalObject();
public slots:
void onBookingAdded(const Booking& booking);
private:
// ...
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.submitRecordButton, &QPushButton::clicked, this, &MainWindow::onBookingAdded);
}
void MainWindow::onBookingAdded(const Booking& booking)
{
// Do something with the booking data
}
ExternalObject::ExternalObject()
{
connect(this, &ExternalObject::bookingAdded, this, &ExternalObject::onBookingAdded);
}
void ExternalObject::onBookingAdded(const Booking& booking)
{
// Do something with the booking data
}
在这个示例中,MainWindow 类定义了一个“bookingAdded”信号。ExternalObject 类将一个槽连接到此信号。当用户单击添加预订按钮时,onBookingAdded() 方法将在 MainWindow 类中触发,并将新的预订数据随信号一起传递给 ExternalObject 类。这样,MainWindow 类就不需要了解任何外部信息,而 ExternalObject 类只需要了解 MainWindow 类公开的信号。