pyqt4

时间:2022-10-23 06:55:04

PyQt4 工具包简介
1.1 关于本指南 这是一个入门级的 PyQt 指南。其目的在于引导读者快速上手 PyQt4 工具包。该指南在 Linux 环境下创建并通过测试。 关于 PyQt PyQt 是用来创建 GUI 应用程序的工具包。它是 Python 编程语言与已获得成功的 Qt 库 的 混 合 体 。 其 中 Qt 库 是 这 个 星 球 上 最 强 大 的 GUI 库 之 一 。 PyQt 的 官 方 网 站 是 http://www.riverbankcomputing.com/software/pyqt/intro 它由 Phil Thompson 创建。 PyQt 的实现被视作 Python 的一个模块。它由 300 多个类和接近 6000 个函数与方法构 成。作为一个跨平台的工具包,PyQt 可以在所有主流的操作系统上运行(Unix、Windows、 Mac) 。PyQt 有两种许可,开发者可以在 GPL 和商业许可证之间做出选择。之前,PyQt 的 GPL 许可证只在 Unix 系统上可用,但在 PyQt4 之后,其 GPL 许可证适用于所有支持它的 系统。 因为 PyQt 有大量的类,为便于管理,它们被划分到如下的几个模块中。

QtGui QtNetWork

QtCore QtXml

QtOpenGL QtSql

QtSvg

其中 QtCore 模块包含了核心的非 GUI 功能函数,用于以下方面:日期、文件和目录、 数据结构、数据流、URL、MIME、线程和进程。QtGui 模块则包含了绘图组件以及与绘图 相关的类,比如按钮、窗口、状态栏、工具栏、滑块、位图、颜色、字体等。QtNetWork 模 块包含用于网络编程的类, 用户可以用这些类实现 TCP/IP 和 UDP 的客户端或服务器。 并且 使用这些类会使网络编程更加容易、轻便。QtXml 包含用于处理 XML 文件的类,该模块提 供了 SAX 和 DOM API 两种 XML 文件处理方式的实现。QtSvg 模块包含了用于显示 SVG (可缩放矢量图形,参考 http://zh.wikipedia.org/wiki/SVG)文件内容的类。QtOpenGL 模块 用于渲染使用 OpenGL 库创建的 3D 或 2D 图形。 并且它支持 Qt GUI 库和 OpenGL 库的无缝 结合。QtSql 则库提供了用于操作数据库的类。 1.2 使用 PyQt4 创建入门程序 在本章的 PyQt4 指南中我们将学习一些基本的功能。我们讲解的速度会很慢,就像是 在和一个孩子说话一样。对于一个孩子来说,他迈出的第一步是笨拙迟缓的。同样,对于一 个编程新手来说,他接受新事物的过程也会比较的迟缓。但请谨记,没有愚蠢的人,只有懒 人和人,并且懒人和人之间可以相互转换。 一个简单的示例 下面的示例代码非常简单,它只显示一个小窗口。然而,我们可以对窗口进行的操作却 有很多,比如我们可以修改它的大小、最大化、最小化等。而这些操作却需要大量的代码, 由于这些操作在很多程序中都需要用到, 所以前人已经写好了这些操作的代码。 我们没有必 要一遍一遍的重新编写这些代码,因此这些代码对程序员来说是隐藏的。PyQt 是一个高度
2

抽象的工具包,因此,如果我们使用较底层的工具包来实现相同的功能,下面的示例代码就 会增长很多。 #!/usr/bin/python # simple.py import sys from PyQt4 import QtGui app = QtGui.QApplication(sys.argv) widget = QtGui.QWidget() widget.resize(250, 150) widget.setWindowTitle('simple') widget.show() sys.exit(app.exec_()) ----------------------------------------------------------------------------------------------------------------import sys from PyQt4 import QtGui 这两句用来载入必须的模块。基本的 GUI 窗口部件在 QtGui 模块中。 app = QtGui.QApplication(sys.argv) 每一个 PyQt4 程序都需要有一个 application 对象,application 类包含在 QtGui 模块中。 sys.argv 参数是一个命令行参数列表。 Python 脚本可以从 shell 中执行, 参数可以让我们选择 启动脚本的方式。 widget = QtGui.QWidget() QWidget 部件是 PyQt4 中所有用户界面类的父类。 这里我们使用没有参数的默认构造函 数,它没有继承其它类。我们称没有父类的 widget 为一个 window。
widget.resize(250, 150)

resize()方法可以改变窗口部件的大小, 在这里我们将其设置为 250 像素宽, 像素高。 150
widget.setWindowTitle('simple')

这句用来设置窗口部件的标题,该标题将在标题栏中显示。
widget.show()

show()方法将窗口部件显示在屏幕上。
sys.exit(app.exec_())

最后我们进入该程序的主循环。 事件处理从本行语句开始。 主循环接受事件消息并将其 分发给程序的各个部件。如果调用 exit()或主部件被销毁,主循环就会结束。使用 sys.exit() 方法退出可以确保程序可以完整的结束, 这种情况下系统的环境变量会记录程序是如何退出 的。 也许你会疑惑, 为什么 exec_()方法会有一个下划线。 这是因为 exec 是 Python 的关键字, 为避免冲突,PyQt 使用 exec_()替代。

3

截图:simple

1.3 程序图标

程序图标就是一个小图片,通常显示在程序标题栏的左上角。在以下的示例中,我们将 学习如何在 PyQt 中使用程序图标,另外我们还将学习一些新的方法。 #!/usr/bin/python # icon.py import sys from PyQt4 import QtGui class Icon(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self, parent) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Icon') self.setWindowIcon(QtGui.QIcon('icons/web.png')) app = QtGui.QApplication(sys.argv) icon = Icon() icon.show() sys.exit(app.exec_()) ----------------------------------------------------------------------------------------------------------------上一个示例采用了面向过程的方法编写。 Python 语言同时支持面向过程和面向对象两 种编程方法。PyQt 编程是面向对象的。 class Icon(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self, parent) 面向对象编程中最重要的是类、属性和方法。以上代码中,我们创建了一个名为 Icon 的新类,该类继承 QtGui.QWidget 类。因此我们必须调用两个构造函数——Icon 的构造函数
4

和继承类 QtGui.QWidget 类的构造函数。 self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Icon') self.setWindowIcon(QtGui.QIcon('icons/web.png')) setGeometry()方法完成两个功能——设置窗口在屏幕上的位置和设置窗口本身的大小。 它的前两个参数是窗口在屏幕上的 x 和 y 坐标。后两个参数是窗口本身的宽和高。 setWindowIcon()方法用来设置程序图标, 它需要一个 QIcon 类型的对象作为参数。 调用 QIcon 构造函数时,我们需要提供要显示的图标的路径(相对或绝对路径) 。

截图:Icon

1.4 显示提示信息

我们可以为任何窗口部件设置一个气球提示。 #!/usr/bin/python # tooltip.py import sys from PyQt4 import QtGui from PyQt4 import QtCore class Tooltip(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self, parent) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Tooltip') self.setToolTip('This is a <b>QWidget</b> widget') QtGui.QToolTip.setFont(QtGui.QFont('OldEnglish', 10))

5

app = QtGui.QApplication(sys.argv) tooltip = Tooltip() tooltip.show() sys.exit(app.exec_()) ----------------------------------------------------------------------------------------------------------------在本示例中,我们为一个 QWidget 类型的窗口部件设置工具提示。 self.setToolTip('This is a <b>QWidget</b> widget') 要创建工具提示,则需要调用 setToolTip()方法。该方法接受富文本格式的参数。 QtGui.QToolTip.setFont(QtGui.QFont('OldEnglish', 10)) 因为默认的 QToolTip 字体看起来比较糟糕,我们可以通过上面的语句设置想要的字体 和字体大小。

截图:tooltip 关闭窗口 一个显而易见的关闭窗口的方式是单击标题栏右上角的 X 标记。在接下来的示例中, 我们将展示如何用代码来关闭程序,并简要介绍 Qt 的信号和槽机制。 下面是 QPushButton 的构造函数,我们将会在下面的示例中使用它。 QPushButton(string text, QWidget parent = None) text 表示将显示在按钮上的文本。parent 是其对象,用于指定按钮显示在哪个部件中。 在我们的示例中,parent 为是一个 QWidget 对象。 #!/usr/bin/python # quitbutton.py import sys from PyQt4 import QtGui, QtCore class QuitButton(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self, parent) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('quitbutton')

6

quit = QtGui.QPushButton('Close', self) quit.setGeometry(10, 10, 60, 35) self.connect(quit, QtCore.SIGNAL('clicked()'), QtGui.qApp, QtCore.SLOT('quit()')) app = QtGui.QApplication(sys.argv) qb = QuitButton() qb.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------------quit = QtGui.QPushButton('Close', self) quit.setGeometry(10, 10, 60, 35) 以上两句用来创建一个按钮并将其放在 QWidget 部件上,就像我们将 QWidget 部件放 在屏幕上一样。 self.connect(quit, QtCore.SIGNAL('clicked()'), QtGui.qApp,QtCore.SLOT('quit()')) PyQt4 的事件处理系统建立在信号-槽机制之上。如果我们单击 quit 按钮,那么信号 clicked()就会被触发,槽函数可以是 PyQt 自带的槽函数,也可以是任何 Python 可以调用的 函数等。QtCore.QObject.connect()方法可以将信号和槽函数连接起来。在我们的示例中槽函 数是 PyQt 中已定义的 quit()函数。通过 connect 方法就可以建立发送者(quit 按钮)和接受 者(应用程序对象)之间的通信。

截图:quitbutton 消息窗口 默认情况下,如果我们单击了窗口标题栏上的 X 标记,窗口就会被关闭。但是有些时 候我们想要改变这一默认行为。比如,我们正在编辑的文件内容发生了变化,这时若单击 X 标记关闭窗口,编辑器就应当弹出确认窗口。 #!/usr/bin/python # messagebox.py import sys from PyQt4 import QtGui

7

class MessageBox(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self, parent) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('message box') def closeEvent(self, event): reply = QtGui.QMessageBox.question(self, 'Message', "Are you sure to quit?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: event.accept() else: event.ignore() app = QtGui.QApplication(sys.argv) qb = MessageBox() qb.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------------如果我们关闭 QWidget 窗口, QCloseEvent 事件就会被触发。 要改变原有的 wdiget 行为 阻止查窗口的关闭,我们就需要重新实现 closeEvent()方法。 reply = QtGui.QMessageBox.question(self, 'Message', "Are you sure to quit?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) 通过上面的语句我们可以显示一个带有两个按钮(Yes/No)的消息窗口。第一个字符串 参数'Message'在消息窗口的标题栏显示。第二个字符串参数以对话的形式显示在消息窗口 中。返回的结果被保存在 reply 变量中。 if reply == QtGui.QMessageBox.Yes: event.accept() else: event.ignore() 我们使用上面的 if 语句来判断用户选择的结果。如果用户选择了 Yes 按钮,那么关闭 widget 窗口并终止应用程序的动作会被允许执行。否则,关闭窗口的动作会被忽略。

截图:messagebox

8

将窗口放在屏幕中间 以下的脚本显示了将窗口放在屏幕的中间位置的方法。 #!/usr/bin/python # center.py import sys from PyQt4 import QtGui class Center(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self, parent) self.setWindowTitle('center') self.resize(250, 150) self.center() def center(self): screen = QtGui.QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)

app = QtGui.QApplication(sys.argv) qb = Center() qb.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------------self.resize() 该语句用来设置 QWidget 窗口的大小为 250 像素宽,150 像素高。 screen = QtGui.QDesktopWidget().screenGeometry() 该语句用来计算出显示器的分辨率(screen.width , screen.height) 。 size = self.geometry() 该语句用来获取 QWidget 窗口的大小(size.width, size.height) 。 self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2) 该语句将窗口移动到屏幕的中间位置。 3.PyQt4 中的菜单和工具栏 主窗口 QMainWindow 类用来创建应用程序的主窗口。通过该类,我们可以创建一个包含状态 栏、工具栏和菜单栏的经典应用程序框架。

9

状态栏 状态栏是用来显示状态信息的串口部件。 #!/usr/bin/python # statusbar.py import sys from PyQt4 import QtGui class MainWindow(QtGui.QMainWindow): def __init__(self, parent = None): QtGui.QMainWindow.__init__(self) self.resize(250, 150) self.setWindowTitle('statusbar') self.statusBar().showMessage('Ready') app = QtGui.QApplication(sys.argv) main = MainWindow() main.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------------self.statusBar().showMessage('Ready') 使用 QApplication 类的 statusBar()方法创建状态栏。使用 showMessage()方法将信息显 示在状态栏中。

截图:statusbar 菜单栏 菜单栏是 GUI 程序最明显的组成部分。它由一组位于不同菜单中的命令组成。在控制 台程序中,我们必须记住那些晦涩难懂的命令。但在 GUI 程序中,通过菜单栏我们将命令 合理的放置在不同的菜单中来降低学习新应用程序的时间开销。 #!/usr/bin/python

10

# menubar.py import sys from PyQt4 import QtGui, QtCore class MainWindow(QtGui.QMainWindow): def __init__(self, parent = None): QtGui.QMainWindow.__init__(self) self.resize(250, 150) self.setWindowTitle('menubar') exit = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Exit', self) exit.setShortcut('Ctrl+Q') exit.setStatusTip('Exit application') exit.connect(exit, QtCore.SIGNAL('triggered()'), QtGui.qApp, QtCore.SLOT('quit()')) self.statusBar() menubar = self.menuBar() file = menubar.addMenu('&File') file.addAction(exit) app = QtGui.QApplication(sys.argv) main = MainWindow() main.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------------menubar = self.menuBar() file = menubar.addMenu('&File') file.addAction(exit) 首先我们使用 QMainWindow 类的 menuBar()方法创建一个菜单栏。 然后使用 addMenu() 方法添加一个菜单。最后我们把动作对象(这里是 exit)添加到 file 菜单中。

11

截图:menubar 工具栏 菜单对程序中的所有命令进行分组放置,而工具栏则提供了快速执行最常用命令的方 法。 #!/usr/bin/python # toolbar.py import sys from PyQt4 import QtGui, QtCore class MainWindow(QtGui.QMainWindow): def __init__(self, parent = None): QtGui.QMainWindow.__init__(self) self.resize(250, 150) self.setWindowTitle('toolbar') self.exit = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Exit', self) self.exit.setShortcut('Ctrl+Q') self.connect(self.exit, QtCore.SIGNAL('triggered()'), QtGui.qApp, QtCore.SLOT('quit()')) self.toolbar = self.addToolBar('Exit') self.toolbar.addAction(self.exit) app = QtGui.QApplication(sys.argv) main = MainWindow() main.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------------self.exit = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Exit', self) self.exit.setShortcut('Ctrl+Q') GUI 应用程序的行为是由命令来控制的,这些命令可以来自菜单、上下文菜单、工具栏 或它们的快捷方式。 PyQt 通过引入 actions 来简化编程难度, 一个 action 对象可以拥有菜单、 文本、图标、快捷方式、状态信息、 “这是什么?”文本或工具提示等。在我们的示例程序 中,我们定义了一个拥有图标、工具提示和快捷方式的 action 对象。 self.connect(self.exit, QtCore.SIGNAL('triggered()'), QtGui.qApp, QtCore.SLOT('quit()')) 该语句将 action 对象的 triggered()信号连接到预定义的 quit()槽函数。 self.toolbar = self.addToolBar('Exit') 该语句创建一个工具栏, 然后使用语句 self.toolbar.addAction(self.exit)将 action 对象 (这 里是 exit)添加到该工具栏。

12

截图:toolbar 将它们聚合在一起 在本章的最后一个示例中,我们将创建一个菜单栏、一个工具栏和一个状态栏。我们还 会创建一个中心部件。 #!/usr/bin/python # mainwindow import sys from PyQt4 import QtGui, QtCore class MainWindow(QtGui.QMainWindow): def __init__(self, parent = None): QtGui.QMainWindow.__init__(self) self.resize(350, 250) self.setWindowTitle('mainwindow') textEdit = QtGui.QTextEdit() self.setCentralWidget(textEdit) exit = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Exit', self) exit.setShortcut('Ctrl+Q') exit.setStatusTip('Exit application') self.connect(exit, QtCore.SIGNAL('triggered()'), QtGui.qApp, QtCore.SLOT('quit()')) self.statusBar() menubar = self.menuBar() file = menubar.addMenu('&File') file.addAction(exit)

13

toolbar = self.addToolBar('Exit') toolbar.addAction(exit) app = QtGui.QApplication(sys.argv) main = MainWindow() main.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------------在该示例中, 我们创建了一个文本编辑部件, 并将它设置为 QMainWindow 的中心部件。 中心部件将占据所有的窗口剩余空间。

截图:mainwindow 4.PyQt4 中的布局管理器 布局管理器是编程中重要的一部分。 所谓布局管理是指我们在窗口中安排部件位置的方 法。 布局管理有两种工作方式: 绝对定位方式 (absolute positioning) 和布局类别方式 (layout classes) 。 绝对定位方式 该方式下, 程序员编程指定每一个部件的位置和尺寸像素。 当使用绝对定位方式时, 需要注意以下几点: ·改变窗口大小时,窗口中部件的大小和位置不会随之改变。 ·在不同的平台上,应用程序可能会看起来不尽相同。 ·在应用程序中改变字体可能会导致布局混乱。 ·如果你打算改变窗口布局,你就必须得重新书写所有部件的布局,这一工作会非 常乏味且耗时较多。 #!/usr/bin/python # absolute.py

14

import sys from PyQt4 import QtGui class Absolute(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self) self.setWindowTitle('Communication') label = QtGui.QLabel('Couldn\'t', self) label.move(15, 10) label = QtGui.QLabel('care', self) label.move(35, 40) label = QtGui.QLabel('less', self) label.move(55, 65) label = QtGui.QLabel('And', self) label.move(115, 65) label = QtGui.QLabel('then', self) label.move(135, 45) label = QtGui.QLabel('you', self) label.move(115, 25) label = QtGui.QLabel('kissed', self) label.move(145, 10) label = QtGui.QLabel('me', self) label.move(215, 10) self.resize(250, 150) app = QtGui.QApplication(sys.argv) qb = Absolute() qb.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------在该示例中,我们简单是使用 move()方法来设置部件的位置。我们通过 x 和 y 坐 标来指定 QLabel 部件的位置,坐标起点为左上角的顶点。x 坐标从左向右增长,y 坐标 从上向下增长。

15

截图:absolute positioning Box 布局 使用布局类别方式的布局管理器比绝对定位方式的布局管理器更加灵活实用。 它是 窗口部件的首先布局管理方式。最基本的布局类别是 QHBoxLayout 和 QVBoxLayout 布局管理方式,分别将窗口部件水平和垂直排列。 假设我们要将两个按钮放在窗口的右下角。 为创建该布局, 我们需要使用一个水平 Box 和一个垂直 Box,另外为了创建必须的空白空间,我们还需要添加一个伸缩间隔元 素(stretch factor) 。 #!/usr/bin/python # boxlayout.py import sys from PyQt4 import QtGui class Boxlayout(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self) self.setWindowTitle('box layout') ok = QtGui.QPushButton('OK') cancel = QtGui.QPushButton('Cancel') hbox = QtGui.QHBoxLayout() hbox.addStretch(1) hbox.addWidget(ok) hbox.addWidget(cancel) vbox = QtGui.QVBoxLayout() vbox.addStretch(1) vbox.addLayout(hbox) self.setLayout(vbox) self.resize(300, 150) app = QtGui.QApplication(sys.argv) qb = Boxlayout() qb.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------ok = QtGui.QPushButton('OK') cancel = QtGui.QPushButton('Cancel') 以上两句用来创建两个按钮(OK 和 Cancel 按钮) 。

16

hbox = QtGui.QHBoxLayout() hbox.addStretch(1) hbox.addWidget(ok) hbox.addWidget(cancel) 以上四句用来创建一个水平 box 布局,然后加入一个伸缩间隔元素与两个按钮。 vbox = QtGui.QVBoxLayout() vbox.addStretch(1) vbox.addLayout(hbox) 为创建需要的布局, 我们使用以上语句创建了一个垂直 box 布局并将水平 box 布局 放入水平 box 布局中。 self.setLayout(vbox) 最后我们设置窗口的主布局。

截图:box layout 网格布局 最通用的布局类别是网格布局(QGridLayout) 。该布局方式将窗口空间划分为许多行和 列。要创建该布局方式,我们需要使用 QGridLayout 类。 #!/usr/bin/python # gridlayout.py import sys from PyQt4 import QtGui class GridLayout(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self) self.setWindowTitle('grid layout') names = ['Cls', 'Bck', '', 'Close', '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '0', '.', '=', '+']

17

grid = QtGui.QGridLayout() j=0 pos = [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3), (4, 0), (4, 1), (4, 2), (4, 3)] for i in names: button = QtGui.QPushButton(i) if j == 2: grid.addWidget(QtGui.QLabel(''), 0, 2) else: grid.addWidget(button, pos[j][0], pos[j][1]) j=j+1 self.setLayout(grid) app = QtGui.QApplication(sys.argv) qb = GridLayout() qb.show() sys.exit(app.exec_()) ---------------------------------------------------------------------------------------------------------------在这个示例中,我们创建一组按网格布局的按钮。为了填补 Bck 和 Close 按钮之间的空 白,我们使用 QLabel 部件。 grid = QtGui.QGridLayout() 该语句创建了一个网格布局。 if j == 2: grid.addWidget(QtGui.QLabel(''), 0, 2) else: grid.addWidget(button, pos[j][0], pos[j][1]) 使用 addWidget()方法,我们将部件加入到网格布局中。addWidget()方法的参数依次为 要加入到局部的部件,行号和列号。

截图:grid layout

18

部件在网格布局中可以跨越多行或多列。我们将下面的示例中演示该情况。 #!/usr/bin/python # gridlayout2.py import sys from PyQt4 import QtGui class GridLayout(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(self) self.setWindowTitle('grid layout') title = QtGui.QLabel('Title') authot = QtGui.QLabel('Author') review = QtGui.QLabel('Review') titleEdit = QtGui.QLineEdit() authorEdit = QtGui.QLineEdit() reviewEdit = QtGui.QLineEdit() grid = QtGui.QGridLayout() grid.setSpacing(10) grid.addWidget(title, 1, 0) grid.addWidget(titleEdit, 1, 1) grid.addWidget(authot, 2, 0) grid