科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道应用软件用于 Python 的高级 GUI 库(Qt 和 PyQt)

用于 Python 的高级 GUI 库(Qt 和 PyQt)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文讲解了用于 Python 的高级 GUI 库(Qt 和 PyQt)

作者:Boudewijn Rempt、David Mertz 来源:code173.com  2007年9月15日

关键字: 软件

  • 评论
  • 分享微博
  • 分享邮件
在 Tkinter 中,我们可以这样实现应用程序:

清单 1. Logger.py Tkinter 应用程序

#!/usr/bin/python
import sys, time
from Tkinter import *

class Logger(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.pack(expand=YES, fill=BOTH)
        self.master.title("Timestamp logging application")
        self.tslist = []
        self.tsdisp = Text(height=6, width=25)
        self.count = StringVar()
        self.cntdisp = Message(font=('Sans',24),
                               textvariable=self.count)
        self.log = Button(text="Log Timestamp",
                          command=self.log_timestamp)
        self.quit = Button(text="Quit", command=sys.exit)
        self.tsdisp.pack(side=LEFT)
        self.cntdisp.pack()
        self.log.pack(side=TOP, expand=YES, fill=BOTH)
        self.quit.pack(side=BOTTOM, fill=BOTH)
    def log_timestamp(self):
        stamp = time.ctime()
        self.tsdisp.insert(END, stamp+"")
        self.tsdisp.see(END)
        self.tslist.append(stamp)
        self.count.set("% 3d" % len(self.tslist))

if __name__=='__main__':
    Logger().mainloop()

这个 Tk 版本使用了 log_timestamp() 方法作为按钮的 command= 参数。这个方法需要依次单独操作它要影响的所有窗口构件。如果我们想更改按钮按下的效果(例如还要记录时间戳记),那么这个风格就很脆弱。通过继承您可以实现这一点:

清单 2. StdOutLogger.py Tkinter 增强

class StdOutLogger(Logger):
    def log_timestamp(self):
        Logger.log_timestamp(self)
        print self.tslist[-1]

但是这个子类的作者需要相当精确地理解 Logger.log_timestamp() 已经做了什么;而且除非通过在子类中完全重写 .log_timestamp() 方法并且不调用父方法,否则没有办法除去消息。

一个非常基本的 PyQt 应用程序总有一些样本代码,这些代码在哪里都相同,Tkinter 代码也是这样。但是,当我们进一步研究设置应用程序所需的代码,以及显示窗口构件的代码时,区别就显现出来了。

清单 3. logger-qt.py PyQt 应用程序

#!/usr/bin/env python
import sys, time
from qt import * # Generally advertised as safe

class Logger(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        self.setCaption("Timestamp logging application")
        self.layout = QGridLayout(self, 3, 2, 5, 10)
        self.tsdisp = QTextEdit(self)
        self.tsdisp.setMinimumSize(250, 300)
        self.tsdisp.setTextFormat(Qt.PlainText)
        self.tscount = QLabel("", self)
        self.tscount.setFont(QFont("Sans", 24))
        self.log = QPushButton("&Log Timestamp", self)
        self.quit = QPushButton("&Quit", self)
        self.layout.addMultiCellWidget(self.tsdisp, 0, 2, 0, 0)
        self.layout.addWidget(self.tscount, 0, 1)
        self.layout.addWidget(self.log, 1, 1)
        self.layout.addWidget(self.quit, 2, 1)
        self.connect(self.log, SIGNAL("clicked()"),
                     self.log_timestamp)
        self.connect(self.quit, SIGNAL("clicked()"),
                     self.close)
    def log_timestamp(self):
        stamp = time.ctime()
        self.tsdisp.append(stamp)
        self.tscount.setText(str(self.tsdisp.lines()))
if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.connect(app, SIGNAL('lastWindowClosed()'), app,
                  SLOT('quit()'))
    logger = Logger()
    logger.show()
    app.setMainWidget(logger)
    app.exec_loop()

通过创建布局管理器,Logger 类开始工作了。布局管理器在任何 GUI 系统中都是一个很复杂的主题,但是 Qt 的实现使之变得简单。在大多数情况下,您会使用 Qt Designer 创建一般的 GUI 设计,随后可将它用于生成 Python 或 C++ 代码。然后您可以使生成的代码生成子类,以添加功能。

但是在这个示例中,我们选择手工创建布局管理器。窗口构件被置于网格的各个单元中,或者可以跨多个单元放置。在 Tkinter 需要命名参数的地方,PyQt 就不允许它们。这是一个很重要的差异,它经常会使在两种环境中工作的人们无所适从。

所有 Qt 窗口构件都可以和 QString 对象很自然地一起工作,而不能和 Python 字符串或 Unicode 对象一起工作。幸运的是,转换是自动的。如果您在 Qt 方法中使用了字符串或 Unicode 参数,那么它将自动转换成 QString。不能进行反向转换:如果您调用了一个返回 QString 的方法,那么您获得的是 QString。

应用程序中最有趣的部分是我们将 clicked 信号连接到功能的位置。一个按钮连接到了 log_timestamp 方法;另一个连接到了 QWidget 类的 close 方法。

现在我们想将日志记录添加到这个应用程序的标准输出。这十分容易。我们可以使 Logger 类生成子类,或者为了演示,创建简单的独立函数:

清单 4. logger-qt.py PyQt 增强

def logwrite():
    print(time.ctime())

if __name__ == "__main__":
   app = QApplication(sys.argv)
   app.connect(app, SIGNAL('lastWindowClosed()'), app,
               SLOT('quit()'))
   logger = Logger()
   QObject.connect(logger.log, SIGNAL("clicked()"), logwrite)
   logger.show()
   app.setMainWidget(logger)
   app.exec_loop()

从上述代码我们可以看到,这就是将 log QPushButton 的 clicked() 信号连接到新函数的事情。注:信号也可以将任何数据传送到它们所连接的插槽,尽管在这里我们没有显示这样的示例。

如果您不想调用原始方法,那么可以从插槽 disconnect 信号,例如通过在 logger.show() 行之前添加以下行:

清单 5. logger-qt.py PyQt 增强

QObject.disconnect(logger.log, SIGNAL("clicked()"),
                   logger.log_timestamp)

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章