pyqt GUI编程中如何组织类
How to organize classes in pyqt GUI programming
我使用 qt designer 和 pyqt 构建了一个主 window GUI。随着程序变得越来越复杂,仅使用一个 class 可能会导致管理太多方法和属性。我认为我应该构建新的 classes 以使事情更易于管理。
我的第一个问题是,我如何知道何时为我的应用程序添加新的 class?是否有任何经验法则作为一般指南?为新 windows/tabs 添加新 class 是个好主意吗?
我的第二个问题是,如果我为我的应用程序添加了新的 classes,我的新 class 如何访问我在 Qt 设计器中设计的 Ui_MainWindow 设计文件?下面是我的主要 window 的示例代码。它是一个显示当前时间的简单时钟。比方说,如果我想为时钟显示本身创建一个 class,我怎样才能有效地使用 OOP 重写代码?
from PyQt4 import QtGui
from myMainWindowUI import Ui_MainWindow
class MyMainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MyMainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.Time)
self.timer.timeout.connect(self.Date)
self.timer.start(1000)
self.lcdNumber_time.setDigitCount(8)
self.lcdNumber_time.display(strftime("%H"+":"+"%M"+":"+"%S"))
self.label_dynamic_date.setText(strftime("%Y"+" "+"%B"+" "+"%d"+", "+"%A"))
def Time(self):
self.lcdNumber_time.display(strftime("%H"+":"+"%M"+":"+"%S"))
def Date(self):
self.label_dynamic_date.setText(strftime("%Y"+" "+"%B"+" "+"%d"+", "+"%A"))
app = QtGui.QApplication(sys.argv) # A new instance of QApplication
form = MyMainWindow()
form.show()
app.exec_()
一般来说,这不一定是特定于 Qt 的问题。它也不一定是 python 特定的问题。您可以将此问题扩展到任何支持基于 class 的编程的语言,甚至是任何具有函数的语言。
当你想封装行为时,写一个class是有意义的。 class 通常应该提供一个单一的目的,并向外部公开一个接口,允许 class 的用户与您设计的行为进行交互。一旦你有了这个单一用途 class,你现在就有了可重用的行为。您可以将此推理的一部分应用于函数,您说给定的函数具有特定的目的,一旦您将其设计为执行某一行为,您现在就有了一个可重用的函数。
将其应用于 Qt,当其逻辑不再微不足道时,将代码移动到它自己的 class 中是有意义的。一个例子是您首先从主 window 创建并显示 QMessageBox
。但是在某些时候你需要收集更多类型的信息,甚至在构建对话时传递一些初始信息。虽然您可以根据需要在主 window 中动态构建它,但最好将其移动到自己的对话框 class 中,并使用其自己的构建逻辑。然后你只需根据需要实例化一个,将预期的参数传递给它的构造函数。现在您的主要 window 不再需要关注构建特殊对话框。
另一点(从您的问题中并未完全清楚)是 Qt Designer UI 文件每个代表一个 class。预计此 UI 定义将应用于代码中的单个 class。如果有 ClassA(UI_mainWindow)
和 ClassB
,并且有 ClassB
访问 ClassA
的成员或知道任何关于 ClassA
的内部实现,这将是糟糕的设计。回到我们的话题“separation of concerns”,ClassB
应该有自己的目的和接口,并被ClassA(UI_mainWindow)
用来实现那个目的。您不希望 ClassB
了解主要 window 的任何信息或能够做超出其设计目的的事情。
让我们假设您的计时器示例实际上比您展示的更简单。如果您将其移动到另一个 class,您应该依靠自定义信号将意图传达回其他 class,例如主要 window。或者,您可以将每个 lcd 和标签小部件移动到它们自己的自定义 classes 中,它们具有自己的计时器逻辑,使它们自包含。无论哪种方式,signal/slot 都允许自定义小部件相互连接,而无需了解其他小部件的任何信息。
总而言之,您可以说,当您在另一个 class 中构建任何重要的 UI 元素时,最好在 Qt 中创建单独的 classes(当它需要很多行代码,或者需要一堆 SLOT 功能和内部逻辑布线)。这将使您避免重复您的逻辑,并允许您拥有可重用的代码。它还将使您的 main window 更小并且更易于调试,因为您可以在大脑中保留 main window 正在做什么的更小的心理模型。如果您尝试让您的 UI 元素尽可能专注于单一用途和通用,您最终会得到很多可以重复使用的 class 元素。
我使用 qt designer 和 pyqt 构建了一个主 window GUI。随着程序变得越来越复杂,仅使用一个 class 可能会导致管理太多方法和属性。我认为我应该构建新的 classes 以使事情更易于管理。
我的第一个问题是,我如何知道何时为我的应用程序添加新的 class?是否有任何经验法则作为一般指南?为新 windows/tabs 添加新 class 是个好主意吗?
我的第二个问题是,如果我为我的应用程序添加了新的 classes,我的新 class 如何访问我在 Qt 设计器中设计的 Ui_MainWindow 设计文件?下面是我的主要 window 的示例代码。它是一个显示当前时间的简单时钟。比方说,如果我想为时钟显示本身创建一个 class,我怎样才能有效地使用 OOP 重写代码?
from PyQt4 import QtGui
from myMainWindowUI import Ui_MainWindow
class MyMainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MyMainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.Time)
self.timer.timeout.connect(self.Date)
self.timer.start(1000)
self.lcdNumber_time.setDigitCount(8)
self.lcdNumber_time.display(strftime("%H"+":"+"%M"+":"+"%S"))
self.label_dynamic_date.setText(strftime("%Y"+" "+"%B"+" "+"%d"+", "+"%A"))
def Time(self):
self.lcdNumber_time.display(strftime("%H"+":"+"%M"+":"+"%S"))
def Date(self):
self.label_dynamic_date.setText(strftime("%Y"+" "+"%B"+" "+"%d"+", "+"%A"))
app = QtGui.QApplication(sys.argv) # A new instance of QApplication
form = MyMainWindow()
form.show()
app.exec_()
一般来说,这不一定是特定于 Qt 的问题。它也不一定是 python 特定的问题。您可以将此问题扩展到任何支持基于 class 的编程的语言,甚至是任何具有函数的语言。
当你想封装行为时,写一个class是有意义的。 class 通常应该提供一个单一的目的,并向外部公开一个接口,允许 class 的用户与您设计的行为进行交互。一旦你有了这个单一用途 class,你现在就有了可重用的行为。您可以将此推理的一部分应用于函数,您说给定的函数具有特定的目的,一旦您将其设计为执行某一行为,您现在就有了一个可重用的函数。
将其应用于 Qt,当其逻辑不再微不足道时,将代码移动到它自己的 class 中是有意义的。一个例子是您首先从主 window 创建并显示 QMessageBox
。但是在某些时候你需要收集更多类型的信息,甚至在构建对话时传递一些初始信息。虽然您可以根据需要在主 window 中动态构建它,但最好将其移动到自己的对话框 class 中,并使用其自己的构建逻辑。然后你只需根据需要实例化一个,将预期的参数传递给它的构造函数。现在您的主要 window 不再需要关注构建特殊对话框。
另一点(从您的问题中并未完全清楚)是 Qt Designer UI 文件每个代表一个 class。预计此 UI 定义将应用于代码中的单个 class。如果有 ClassA(UI_mainWindow)
和 ClassB
,并且有 ClassB
访问 ClassA
的成员或知道任何关于 ClassA
的内部实现,这将是糟糕的设计。回到我们的话题“separation of concerns”,ClassB
应该有自己的目的和接口,并被ClassA(UI_mainWindow)
用来实现那个目的。您不希望 ClassB
了解主要 window 的任何信息或能够做超出其设计目的的事情。
让我们假设您的计时器示例实际上比您展示的更简单。如果您将其移动到另一个 class,您应该依靠自定义信号将意图传达回其他 class,例如主要 window。或者,您可以将每个 lcd 和标签小部件移动到它们自己的自定义 classes 中,它们具有自己的计时器逻辑,使它们自包含。无论哪种方式,signal/slot 都允许自定义小部件相互连接,而无需了解其他小部件的任何信息。
总而言之,您可以说,当您在另一个 class 中构建任何重要的 UI 元素时,最好在 Qt 中创建单独的 classes(当它需要很多行代码,或者需要一堆 SLOT 功能和内部逻辑布线)。这将使您避免重复您的逻辑,并允许您拥有可重用的代码。它还将使您的 main window 更小并且更易于调试,因为您可以在大脑中保留 main window 正在做什么的更小的心理模型。如果您尝试让您的 UI 元素尽可能专注于单一用途和通用,您最终会得到很多可以重复使用的 class 元素。