pyqt5中文教程

pyqt5中文教程本文转载自:http://code.py40.com/pyqt5/一、PyQt5基本功能简单的例子PyQt5是一种高级的语言,下面只有几行代码就能显示一个小窗口。底层已经实现了窗口的基本功能。#!/usr/bin/python3#-*-coding:utf-8-*-"&

大家好,欢迎来到IT知识分享网。

本文转载自:http://code.py40.com/pyqt5/

一、PyQt5基本功能

简单的例子

PyQt5是一种高级的语言,下面只有几行代码就能显示一个小窗口。底层已经实现了窗口的基本功能。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40.com PyQt5 tutorial 

In this example, we create a simple
window in PyQt5.

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys

#这里我们提供必要的引用。基本控件位于pyqt5.qtwidgets模块中。
from PyQt5.QtWidgets import QApplication, QWidget


if __name__ == '__main__':
    #每一pyqt5应用程序必须创建一个应用程序对象。sys.argv参数是一个列表,从命令行输入参数。
    app = QApplication(sys.argv)
    #QWidget部件是pyqt5所有用户界面对象的基类。他为QWidget提供默认构造函数。默认构造函数没有父类。
    w = QWidget()
    #resize()方法调整窗口的大小。这离是250px宽150px高
    w.resize(250, 150)
    #move()方法移动窗口在屏幕上的位置到x = 300,y = 300坐标。
    w.move(300, 300)
    #设置窗口的标题
    w.setWindowTitle('Simple')
    #显示在屏幕上
    w.show()
    
    #系统exit()方法确保应用程序干净的退出
    #的exec_()方法有下划线。因为执行是一个Python关键词。因此,exec_()代替
    sys.exit(app.exec_())

View Code

上面的示例代码在屏幕上显示一个小窗口。

simple

应用程序的图标

应用程序图标是一个小的图像,通常在标题栏的左上角显示。在下面的例子中我们将介绍如何做pyqt5的图标。同时我们也将介绍一些新方法。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
py40 PyQt5 tutorial 

This example shows an icon
in the titlebar of the window.

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QIcon


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI() #界面绘制交给InitUi方法
        
        
    def initUI(self):
        #设置窗口的位置和大小
        self.setGeometry(300, 300, 300, 220)  
        #设置窗口的标题
        self.setWindowTitle('Icon')
        #设置窗口的图标,引用当前目录下的web.png图片
        self.setWindowIcon(QIcon('web.png'))        
        
        #显示窗口
        self.show()
        
        
if __name__ == '__main__':
    #创建应用程序和对象
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_()) 

View Code

前面的例子是在程序风格。Python编程语言支持程序和面向对象编程风格。Pyqt5使用OOP编程。

class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        ...

面向对象编程有三个重要的方面:类、变量和方法。这里我们创建一个新的类为Examle。Example继承自QWidget类。

icon

显示提示语

在下面的例子中我们显示一个提示语

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

This example shows a tooltip on 
a window and a button.

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import (QWidget, QToolTip, 
    QPushButton, QApplication)
from PyQt5.QtGui import QFont    


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):
        #这种静态的方法设置一个用于显示工具提示的字体。我们使用10px滑体字体。
        QToolTip.setFont(QFont('SansSerif', 10))
        
        #创建一个提示,我们称之为settooltip()方法。我们可以使用丰富的文本格式
        self.setToolTip('This is a <b>QWidget</b> widget')
        
        #创建一个PushButton并为他设置一个tooltip
        btn = QPushButton('Button', self)
        btn.setToolTip('This is a <b>QPushButton</b> widget')
        
        #btn.sizeHint()显示默认尺寸
        btn.resize(btn.sizeHint())
        
        #移动窗口的位置
        btn.move(50, 50)       
        
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Tooltips')    
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

运行程序,显示一个窗口
tooltips

关闭窗口

关闭一个窗口可以点击标题栏上的X。在下面的例子中,我们将展示我们如何通过编程来关闭窗口。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

This program creates a quit
button. When we press the button,
the application terminates. 

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.QtCore import QCoreApplication


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):               
        
        qbtn = QPushButton('Quit', self)
        qbtn.clicked.connect(QCoreApplication.instance().quit)
        qbtn.resize(qbtn.sizeHint())
        qbtn.move(50, 50)       
        
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Quit button')    
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

quitbutton

消息框

默认情况下,如果我们单击x按钮窗口就关门了。有时我们想修改这个默认的行为。例如我们在编辑器中修改了一个文件,当关闭他的时候,我们显示一个消息框确认。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

This program shows a confirmation 
message box when we click on the close
button of the application window. 

author: Jan Bodnar
website: zetcode.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QWidget, QMessageBox, QApplication


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):               
        
        self.setGeometry(300, 300, 250, 150)        
        self.setWindowTitle('Message box')    
        self.show()
        
        
    def closeEvent(self, event):
        
        reply = QMessageBox.question(self, 'Message',
            "Are you sure to quit?", QMessageBox.Yes | 
            QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()        
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

我们关闭窗口的时候,触发了QCloseEvent。我们需要重写closeEvent()事件处理程序。

reply = QMessageBox.question(self, 'Message',
    "Are you sure to quit?", QMessageBox.Yes | 
    QMessageBox.No, QMessageBox.No)

我们显示一个消息框,两个按钮:“是”和“不是”。第一个字符串出现在titlebar。第二个字符串消息对话框中显示的文本。第三个参数指定按钮的组合出现在对话框中。最后一个参数是默认按钮,这个是默认的按钮焦点。

if reply == QtGui.QMessageBox.Yes:
    event.accept()
else:
    event.ignore()  

我们处理返回值,如果单击Yes按钮,关闭小部件并终止应用程序。否则我们忽略关闭事件。

messagebox

窗口显示在屏幕的中间

下面的脚本显示了如何在屏幕中心显示窗口。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

This program centers a window 
on the screen. 

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QWidget, QDesktopWidget, QApplication


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):               
        
        self.resize(250, 150)
        self.center()
        
        self.setWindowTitle('Center')    
        self.show()
        
    
    #控制窗口显示在屏幕中心的方法    
    def center(self):
        
        #获得窗口
        qr = self.frameGeometry()
        #获得屏幕中心点
        cp = QDesktopWidget().availableGeometry().center()
        #显示到屏幕中心
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())  

View Code

QtGui,QDesktopWidget类提供了用户的桌面信息,包括屏幕大小。

 

二、PyQt5布局管理

PyQt5布局有两种方式,绝对定位和布局类

绝对定位

程序指定每个控件的位置和大小(以像素为单位)。

绝对定位有以下限制:

  • 如果我们调整窗口,控件的大小和位置不会改变
  • 在各种平台上应用程序看起来会不一样
  • 如果改变字体,我们的应用程序的布局就会改变
  • 如果我们决定改变我们的布局,我们必须完全重做我们的布局

下面的例子显示了一个绝对定位

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

This example shows three labels on a window
using absolute positioning. 

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):
        
        lbl1 = QLabel('Zetcode', self)
        lbl1.move(15, 10)

        lbl2 = QLabel('tutorials', self)
        lbl2.move(35, 40)
        
        lbl3 = QLabel('for programmers', self)
        lbl3.move(55, 70)        
        
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Absolute')    
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

我们使用move()方法来控制控件的位置。

框布局 Boxlayout

我们使用QHBoxLayout和QVBoxLayout,来分别创建横向布局和纵向布局。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

In this example, we position two push
buttons in the bottom-right corner 
of the window. 

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, 
    QHBoxLayout, QVBoxLayout, QApplication)


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):
        
        okButton = QPushButton("OK")
        cancelButton = QPushButton("Cancel")

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(okButton)
        hbox.addWidget(cancelButton)

        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addLayout(hbox)
        
        self.setLayout(vbox)    
        
        self.setGeometry(300, 300, 300, 150)
        self.setWindowTitle('Buttons')    
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在这个例子中,我们使用HBoxLayout和QVBoxLayout并添加伸展因子,在窗口的右下角显示两个按钮。

hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)

我们创建一个水平布局和添加一个伸展因子和两个按钮。两个按钮前的伸展增加了一个可伸缩的空间。这将推动他们靠右显示。

vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)

创建一个垂直布局,并添加伸展因子,让水平布局显示在窗口底部

self.setLayout(vbox)

最后,我们设置窗口的布局界面

buttons

表格布局 QGridLayout

表格布局将空间划分为行和列。我们使用QGridLayout类创建一个网格布局。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

In this example, we create a skeleton
of a calculator using a QGridLayout.

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout, 
    QPushButton, QApplication)


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):
        
        grid = QGridLayout()
        self.setLayout(grid)
 
        names = ['Cls', 'Bck', '', 'Close',
                 '7', '8', '9', '/',
                '4', '5', '6', '*',
                 '1', '2', '3', '-',
                '0', '.', '=', '+']
        
        positions = [(i,j) for i in range(5) for j in range(4)]
        
        for position, name in zip(positions, names):
            
            if name == '':
                continue
            button = QPushButton(name)
            grid.addWidget(button, *position)
            
        self.move(300, 150)
        self.setWindowTitle('Calculator')
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在我们的示例中,我们创建一个网格的按钮。

grid = QGridLayout()
self.setLayout(grid)

QGridLayout的实例被创建并设置应用程序窗口的布局。

names = ['Cls', 'Bck', '', 'Close',
            '7', '8', '9', '/',
        '4', '5', '6', '*',
            '1', '2', '3', '-',
        '0', '.', '=', '+']

这些按钮的标签。

positions = [(i,j) for i in range(5) for j in range(4)]

我们创建一个网格中的位置的列表。

for position, name in zip(positions, names):
    
    if name == '':
        continue
    button = QPushButton(name)
    grid.addWidget(button, *position)

创建按钮并使用addWidget()方法添加到布局中。

calculator

评论的例子

控件可以在网格中跨越多个行或列。在下一个示例中,我们说明了这一点。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

In this example, we create a bit
more complicated window layout using
the QGridLayout manager. 

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit, 
    QTextEdit, QGridLayout, QApplication)


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):
        
        title = QLabel('Title')
        author = QLabel('Author')
        review = QLabel('Review')

        titleEdit = QLineEdit()
        authorEdit = QLineEdit()
        reviewEdit = QTextEdit()

        grid = QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(title, 1, 0)
        grid.addWidget(titleEdit, 1, 1)

        grid.addWidget(author, 2, 0)
        grid.addWidget(authorEdit, 2, 1)

        grid.addWidget(review, 3, 0)
        grid.addWidget(reviewEdit, 3, 1, 5, 1)
        
        self.setLayout(grid) 
        
        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('Review')    
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

我们创建一个窗口,其中有三个标签,两个行编辑和一个文本编辑窗口小控件。然后使用QGridLayout完成布局。

grid = QGridLayout()
grid.setSpacing(10)

创建一个网格布局和设置组件之间的间距。

grid.addWidget(reviewEdit, 3, 1, 5, 1)

在添加一个小的控件到网格的时候,我们可以提供小部件的行和列跨。在例子中,reviewEdit控件跨度5行。

review

 

三、PyQt5菜单和工具栏

主窗口

QMainWindow 类提供了一个主要的应用程序窗口。你用它可以让应用程序添加状态栏,工具栏和菜单栏。

状态栏

状态栏用于显示状态信息。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

This program creates a statusbar.

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication


class Example(QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):               
        
        self.statusBar().showMessage('Ready')
        
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Statusbar')    
        self.show()


if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

你用QMainWindow创建状态栏的小窗口。

self.statusBar().showMessage('Ready')

QMainWindow类第一次调用statusBar()方法创建一个状态栏。后续调用返回的状态栏对象。showMessage()状态栏上显示一条消息。

菜单栏

菜单栏是常见的窗口应用程序的一部分。(Mac OS将菜单条不同。得到类似的结果,我们可以添加以下行:menubar.setNativeMenuBar(假)。)

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

This program creates a menubar. The
menubar has one menu with an exit action.

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication
from PyQt5.QtGui import QIcon


class Example(QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):               
        
        exitAction = QAction(QIcon('exit.png'), '&Exit', self)        
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(qApp.quit)

        self.statusBar()

        #创建一个菜单栏
        menubar = self.menuBar()
        #添加菜单
        fileMenu = menubar.addMenu('&File')
        #添加事件
        fileMenu.addAction(exitAction)
        
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Menubar')    
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())  

View Code

在上面的例子中,我们创建一个菜单栏和一个菜单。这个菜单将终止应用程序。Ctrl + Q的行动是可访问的快捷方式。

exitAction = QAction(QIcon('exit.png'), '&Exit', self)        
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')

QAction可以操作菜单栏,工具栏,或自定义键盘快捷键。上面三行,我们创建一个事件和一个特定的图标和一个“退出”的标签。然后,在定义该操作的快捷键。
第三行创建一个鼠标指针悬停在该菜单项上时的提示。

exitAction.triggered.connect(qApp.quit)

当我们点击菜单的时候,调用qApp.quit,终止应用程序。

工具栏

工具栏提供了一个快速访问的入口。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

This program creates a toolbar.
The toolbar has one action, which
terminates the application, if triggered.

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication
from PyQt5.QtGui import QIcon


class Example(QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):               
        
        exitAction = QAction(QIcon('exit24.png'), 'Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.triggered.connect(qApp.quit)
        
        self.toolbar = self.addToolBar('Exit')
        self.toolbar.addAction(exitAction)
        
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Toolbar')    
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在上面的例子中,我们创建一个简单的工具栏。工具栏有有一个按钮,点击关闭窗口。

exitAction = QAction(QIcon('exit24.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(qApp.quit)

类似于上面的菜单栏的例子,我们创建一个QAction事件。该事件有一个标签、图标和快捷键。退出窗口的方法

toolbar

把他们放在一起

在本节的最后一个例子中,我们将创建一个菜单条,工具栏和状态栏的小窗口

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

This program creates a skeleton of
a classic GUI application with a menubar,
toolbar, statusbar, and a central widget. 

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtWidgets import QMainWindow, QTextEdit, QAction, QApplication
from PyQt5.QtGui import QIcon


class Example(QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):               
        
        textEdit = QTextEdit()
        self.setCentralWidget(textEdit)

        exitAction = QAction(QIcon('exit24.png'), 'Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)

        self.statusBar()

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(exitAction)

        toolbar = self.addToolBar('Exit')
        toolbar.addAction(exitAction)
        
        self.setGeometry(300, 300, 350, 250)
        self.setWindowTitle('Main window')    
        self.show()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

创建了一个窗口

textEdit = QTextEdit()
self.setCentralWidget(textEdit)

我们创建了一个QTextEdit,并把他设置为窗口的布局

mainwindow

 

四、PyQt5事件和信号

事件 Event

所有的GUI程序都是事件驱动的。事件主要由用户触发,但也可能有其他触发方式:例如网络连接、window manager或定时器。当我们调用QApplication的exec_()方法时会使程序进入主循环。主循环会获取并分发事件。

在事件模型中,有三个参与者:

  • 事件源
  • 事件对象
  • 事件接收者

事件源是状态发生变化的对象。它会生成事件。事件(对象)封装了事件源中状态的变动。事件接收者是要通知的对象。事件源对象将事件处理的工作交给事件接收者。

PyQt5有一个独特的signal&slot(信号槽)机制来处理事件。信号槽用于对象间的通信。signal在某一特定事件发生时被触发,slot可以是任何callable对象。当signal触发时会调用与之相连的slot。

信号槽 Signals & slots

这是一个使用信号槽的PyQt5例子。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Py40 PyQt5 tutorial 

In this example, we connect a signal
of a QSlider to a slot of a QLCDNumber. 

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, 
    QVBoxLayout, QApplication)


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):
        
        lcd = QLCDNumber(self)
        sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(lcd)
        vbox.addWidget(sld)

        self.setLayout(vbox)
        sld.valueChanged.connect(lcd.display)
        
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal & slot')
        self.show()
        

if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

这个例子中展示了一个QtGui.QLCDNumber和QtGui.QSlider。lcd的值会随着滑块的拖动而改变。

sld.valueChanged.connect(lcd.display)

在这里我们将滚动条的valueChanged信号连接到lcd的display插槽。

sender是发出信号的对象。receiver是接收信号的对象。slot(插槽)是对信号做出反应的方法。

sigslot

重新实现事件处理器

在PyQt5中常通过重新实现事件处理器来处理事件。

pyqt5中文教程
pyqt5中文教程

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
pyu40 PyQt5 tutorial 

In this example, we reimplement an 
event handler. 

author: Jan Bodnar
website: py40.com 
last edited: January 2015
"""

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QApplication


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      
        
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Event handler')
        self.show()
        
        
    def keyPressEvent(self, e):
        
        if e.key() == Qt.Key_Escape:
            self.close()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在示例中我们重新实现了keyPressEvent()事件处理器。

def keyPressEvent(self, e):
    if e.key() == Qt.Key_Escape:
        self.close()

我们按下Escape键会使程序退出。

事件发送者

有时需要知道信号是由哪个控件发出的。对此PyQt5提供了sender()方法。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we determine the event sender
object.

author: py40.com
last edited: 2017年3月
"""

import sys
from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication


class Example(QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      

        btn1 = QPushButton("Button 1", self)
        btn1.move(30, 50)

        btn2 = QPushButton("Button 2", self)
        btn2.move(150, 50)
      
        btn1.clicked.connect(self.buttonClicked)            
        btn2.clicked.connect(self.buttonClicked)
        
        self.statusBar()
        
        self.setGeometry(300, 300, 290, 150)
        self.setWindowTitle('Event sender')
        self.show()
        
        
    def buttonClicked(self):
      
        sender = self.sender()
        self.statusBar().showMessage(sender.text() + ' was pressed')
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

我们创建了两个按钮。在buttonClicked()方法中通过调用sender()方法来判断当前按下的是哪个按钮。

btn1.clicked.connect(self.buttonClicked)            
btn2.clicked.connect(self.buttonClicked)

两个按钮连接到了同一个插槽。

def buttonClicked(self):
  
    sender = self.sender()
    self.statusBar().showMessage(sender.text() + ' was pressed')

我们通过调用sender()方法来判断信号源, 并将其名称显示在窗体的状态栏中。

 

五、PyQt5对话框

对话框窗口或对话框是现代GUI应用程序最不可或缺的一部分。一个对话框被定义为两个或两个以上的人之间的谈话。在计算机应用程序对话框窗口用于“交谈”应用程序。一个对话框用于输入数据,修改数据,更改应用程序设置等。

QInputDialog

QInputDialog提供了一种简单方便的对话框从用户得到一个值。输入值可以是字符串,一个数字,或一个项目从一个列表。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we determine the event sender
object.

author: py40.com
last edited: 2017年3月
"""


import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit, 
    QInputDialog, QApplication)


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      

        self.btn = QPushButton('Dialog', self)
        self.btn.move(20, 20)
        self.btn.clicked.connect(self.showDialog)
        
        self.le = QLineEdit(self)
        self.le.move(130, 22)
        
        self.setGeometry(300, 300, 290, 150)
        self.setWindowTitle('Input dialog')
        self.show()
        
        
    def showDialog(self):
        
        text, ok = QInputDialog.getText(self, 'Input Dialog', 
            'Enter your name:')
        
        if ok:
            self.le.setText(str(text))
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

这个例子显示一个按钮和一个文本框,用户点击按钮显示一个输入框,用户输入信息会显示在文本框中。

text, ok = QInputDialog.getText(self, 'Input Dialog', 
    'Enter your name:')

这行代码显示输入对话框。第一个字符串是一个对话框标题,第二个是对话框中的消息。对话框返回输入的文本和一个布尔值。点击Ok按钮,布尔值是True。

if ok:
    self.le.setText(str(text))

对话框收到的文本消息会显示在文本框中

QColorDialog

QColorDialog显示一个用于选择颜色值的对话框。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we determine the event sender
object.

author: py40.com
last edited: 2017年3月
"""


import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QFrame, 
    QColorDialog, QApplication)
from PyQt5.QtGui import QColor


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      

        col = QColor(0, 0, 0) 

        self.btn = QPushButton('Dialog', self)
        self.btn.move(20, 20)

        self.btn.clicked.connect(self.showDialog)

        self.frm = QFrame(self)
        self.frm.setStyleSheet("QWidget { background-color: %s }" 
            % col.name())
        self.frm.setGeometry(130, 22, 100, 100)            
        
        self.setGeometry(300, 300, 250, 180)
        self.setWindowTitle('Color dialog')
        self.show()
        
        
    def showDialog(self):
      
        col = QColorDialog.getColor()

        if col.isValid():
            self.frm.setStyleSheet("QWidget { background-color: %s }"
                % col.name())
            
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

这个应用程序显示一个按钮和一个QFrame。QFrame的背景为黑色。通过QColorDialog,我们可以改变它的背景。

col = QColor(0, 0, 0) 

初始化QFrame的颜色为黑色

col = QColorDialog.getColor()

这一行代码弹出QColorDialog

if col.isValid():
    self.frm.setStyleSheet("QWidget { background-color: %s }"
        % col.name())

我们要先检查col的值。如果点击的是Cancel按钮,返回的颜色值是无效的。当颜色值有效时,我们通过样式表(style sheet)来改变背景颜色。

QFontDialog

QFontDialog对话框用以选择字体

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we determine the event sender
object.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QPushButton, 
    QSizePolicy, QLabel, QFontDialog, QApplication)


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      

        vbox = QVBoxLayout()

        btn = QPushButton('Dialog', self)
        btn.setSizePolicy(QSizePolicy.Fixed,
            QSizePolicy.Fixed)
        
        btn.move(20, 20)

        vbox.addWidget(btn)

        btn.clicked.connect(self.showDialog)
        
        self.lbl = QLabel('Knowledge only matters', self)
        self.lbl.move(130, 20)

        vbox.addWidget(self.lbl)
        self.setLayout(vbox)          
        
        self.setGeometry(300, 300, 250, 180)
        self.setWindowTitle('Font dialog')
        self.show()
        
        
    def showDialog(self):

        font, ok = QFontDialog.getFont()
        if ok:
            self.lbl.setFont(font)
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在这个例子中,我们创建了一个按钮和一个标签,通过QFontDialog来改变标签的字体

font, ok = QFontDialog.getFont()

这一行代码弹出字体选择对话框,getFont()方法返回字体名称和ok参数,如果用户点击了ok他就是True,否则就是false

if ok:
    self.label.setFont(font)

如果我们点击了ok,标签的字体就会被改变

QFileDialog

QFileDialog是一个让用户选择文件和目录的对话框,可用以选择打开或保存文件

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we determine the event sender
object.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QMainWindow, QTextEdit, 
    QAction, QFileDialog, QApplication)
from PyQt5.QtGui import QIcon


class Example(QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      

        self.textEdit = QTextEdit()
        self.setCentralWidget(self.textEdit)
        self.statusBar()

        openFile = QAction(QIcon('open.png'), 'Open', self)
        openFile.setShortcut('Ctrl+O')
        openFile.setStatusTip('Open new File')
        openFile.triggered.connect(self.showDialog)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(openFile)       
        
        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('File dialog')
        self.show()
        
        
    def showDialog(self):

        fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')

        if fname[0]:
            f = open(fname[0], 'r')

            with f:
                data = f.read()
                self.textEdit.setText(data)        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

这个例子展示了一个菜单栏,中部TextEdit控件和一个状态栏。菜单项Open会显示用于选择文件的QtGui.QFileDialog对话框。选定文件的内容会加载到TextEdit控件中。

class Example(QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()

示例窗体继承自QMainWindow,因为我们要将TextEdit控件置于窗体中央。

fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')

弹出QFileDialog对话框,第一个字符串参数是对话框的标题,第二个指定对话框的工作目录,默认情况下文件筛选器会匹配所有类型的文件(*)

if fname[0]:
    f = open(fname[0], 'r')

    with f:
        data = f.read()
        self.textEdit.setText(data)        

读取了选择的文件并将文件内容显示到了TextEdit控件。

 

六、PyQt5控件

控件是构建应用程序的基本模块,PyQt5提供各种各样的控件,包括按钮、复选框、滑动条、列表框等。在这部分的教程中,我们将详细介绍几个常用的控件:QCheckBox,ToggleButton,QSlider,QProgressBar,QCalendarWidget。

QCheckBox

QCheckBox复选框控件,它有两个状态:打开和关闭,他是一个带有文本标签(Label)的控件。复选框常用于表示程序中可以启用或禁用的功能。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we determine the event sender
object.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import QWidget, QCheckBox, QApplication
from PyQt5.QtCore import Qt


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      

        cb = QCheckBox('Show title', self)
        cb.move(20, 20)
        cb.toggle()
        cb.stateChanged.connect(self.changeTitle)
        
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('QCheckBox')
        self.show()
        
        
    def changeTitle(self, state):
      
        if state == Qt.Checked:
            self.setWindowTitle('QCheckBox')
        else:
            self.setWindowTitle('')
            
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在我们的示例中,我们将创建一个复选框,将切换窗口标题。

cb = QCheckBox('Show title', self)

这是QCheckBox的构造行数

cb.toggle()

我们有设置窗口标题,所以我们也必须检查复选框。默认情况下,没有设置窗口标题和也没有勾选复选框。

cb.stateChanged.connect(self.changeTitle)

我们将自定义的changeTitle()方法连接到stateChanged信号。这个方法会切换窗体的标题。

def changeTitle(self, state):
    
    if state == Qt.Checked:
        self.setWindowTitle('QCheckBox')
    else:
        self.setWindowTitle('')

复选框的状态经由state参数传入changeTitle()方法。在勾选复选框时设置窗体标题,取消勾选时就将标题设为空字符串。

pyqt5中文教程

开关按钮 Toggle button

ToggleButton是QPushButton的一种特殊模式。它是一个有两种状态的按钮:按下与未按下。通过点击在这两种状态间来回切换。这种功能在某些场景会很实用。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we create three toggle buttons.
They will control the background color of a 
QFrame.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, 
    QFrame, QApplication)
from PyQt5.QtGui import QColor


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      

        self.col = QColor(0, 0, 0)       

        redb = QPushButton('Red', self)
        redb.setCheckable(True)
        redb.move(10, 10)

        redb.clicked[bool].connect(self.setColor)

        greenb = QPushButton('Green', self)
        greenb.setCheckable(True)
        greenb.move(10, 60)

        greenb.clicked[bool].connect(self.setColor)

        blueb = QPushButton('Blue', self)
        blueb.setCheckable(True)
        blueb.move(10, 110)

        blueb.clicked[bool].connect(self.setColor)

        self.square = QFrame(self)
        self.square.setGeometry(150, 20, 100, 100)
        self.square.setStyleSheet("QWidget { background-color: %s }" %  
            self.col.name())
        
        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('Toggle button')
        self.show()
        
        
    def setColor(self, pressed):
        
        source = self.sender()
        
        if pressed:
            val = 255
        else: val = 0
                        
        if source.text() == "Red":
            self.col.setRed(val)                
        elif source.text() == "Green":
            self.col.setGreen(val)             
        else:
            self.col.setBlue(val) 
            
        self.square.setStyleSheet("QFrame { background-color: %s }" %
            self.col.name())  
       
       
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

代码中我们创建了三个ToggleButton与一个QWidget。我们将QWidget的背景色设为黑色。ToggleButton会切换颜色值中的红色、绿色与蓝色部分。QWidget的背景颜色依赖于按下的按钮。

self.col = QColor(0, 0, 0)

这是初始黑颜色的值。

redb = QPushButton('Red', self)
redb.setCheckable(True)
redb.move(10, 10)

我们创建一个QPushButton并通过其setCheckable()方法来得到一个ToggleButton。

redb.clicked[bool].connect(self.setColor)

将clicked信号连接到用户自定义的方法。我们通过clicked信号操作一个布尔值。

if source.text() == "Red":
    self.col.setRed(val)

我们得到了按下的按钮。

if source.text() == "Red":
    self.col.setRed(val)

如果按下的是red按钮,我们要相应地更新颜色中的红包部分。

self.square.setStyleSheet("QFrame { background-color: %s }" %
    self.col.name())   

pyqt5中文教程

滑动条 QSlider

QSlider是一个带有简单滑块的控件。滑块可以前后拖动。我们可以通过拖动选择一个特定的值。有时使用滑动条比直接输入数字或使用旋转框更加自然。

在下面的例子中,我们会显示一个滑动条与一个标签,标签用于显示图片,并通过滑动条控件图片的显示 。

注意这里图片只能用ico格式的,png格式图片会显示不了。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

This example shows a QSlider widget.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QSlider, 
    QLabel, QApplication)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap


class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      

        sld = QSlider(Qt.Horizontal, self)
        sld.setFocusPolicy(Qt.NoFocus)
        sld.setGeometry(30, 40, 100, 30)
        sld.valueChanged[int].connect(self.changeValue)
        
        self.label = QLabel(self)
        self.label.setPixmap(QPixmap('audio.ico'))
        self.label.setGeometry(160, 40, 80, 30)
        
        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('QSlider')
        self.show()
        
        
    def changeValue(self, value):

        if value == 0:
            self.label.setPixmap(QPixmap('audio.ico'))
        elif value > 0 and value <= 30:
            self.label.setPixmap(QPixmap('min.ico'))
        elif value > 30 and value < 80:
            self.label.setPixmap(QPixmap('med.ico'))
        else:
            self.label.setPixmap(QPixmap('max.ico'))
            

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())    

View Code

例子中我们模拟了一个音量控制。通过拖动滑块来改变标签上的图像。

sld = QSlider(Qt.Horizontal, self)

创建一个水平滑块

self.label = QLabel(self)
self.label.setPixmap(QPixmap('mute.png'))

创建了一个QLabel控件并为它设置了一个初始音量图像。

sld.valueChanged[int].connect(self.changeValue)

我们将valueChanged信号连接到自定义的changeValue()方法。

if value == 0:
    self.label.setPixmap(QPixmap('mute.png'))
...

我们根据滑动条的值来设置标签的图像。在上面的代码中,当滑动条的值为0时我们为标签设置audio.ico图像。

pyqt5中文教程

进度条QProgressBar

一个进度条是一个显示任务进展的控件。QProgressBar控件提供了一个水平或垂直PyQt5工具包的进度条。程序员可以设置进度条的最小和最大值。默认值是0到99。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

This example shows a QProgressBar widget.


author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QProgressBar,
                             QPushButton, QApplication)
from PyQt5.QtCore import QBasicTimer


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):

        self.pbar = QProgressBar(self)
        self.pbar.setGeometry(30, 40, 200, 25)

        self.btn = QPushButton('Start', self)
        self.btn.move(40, 80)
        self.btn.clicked.connect(self.doAction)

        self.timer = QBasicTimer()
        self.step = 0

        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('QProgressBar')
        self.show()

    def timerEvent(self, e):

        if self.step >= 100:
            self.timer.stop()
            self.btn.setText('Finished')
            return

        self.step = self.step + 1
        self.pbar.setValue(self.step)

    def doAction(self):

        if self.timer.isActive():
            self.timer.stop()
            self.btn.setText('Start')
        else:
            self.timer.start(100, self)
            self.btn.setText('Stop')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

这个例子显示一个水平的进度条和一个按钮,用户通过点击按钮开始和停止进度条

self.pbar = QProgressBar(self)

QProgressBar的构造方法

self.timer = QtCore.QBasicTimer()

我们使用定时器timer来激活QProgressBar

self.timer.start(100, self)

我们调用start()方法启动一个计时器。这个方法有两个参数:超时和对象将接收的事件。

def timerEvent(self, e):
  
    if self.step >= 100:
    
        self.timer.stop()
        self.btn.setText('Finished')
        return
        
    self.step = self.step + 1
    self.pbar.setValue(self.step)

每个QObject及其子类都有一个timerEvent()事件处理器。我们要重新实现这个事件处理器来响应定时器事件。

def doAction(self):
  
    if self.timer.isActive():
        self.timer.stop()
        self.btn.setText('Start')
        
    else:
        self.timer.start(100, self)
        self.btn.setText('Stop')

我们在doAction()方法中启动/停止定时器。

pyqt5中文教程

日历控件 QCalendarWidget

QCalendarWidget提供了一个基于月份的日历控件。它使用户以一种简单直观的方式来选择日期。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

This example shows a QCalendarWidget widget.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QCalendarWidget,
                             QLabel, QApplication)
from PyQt5.QtCore import QDate


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        cal = QCalendarWidget(self)
        cal.setGridVisible(True)
        cal.move(20, 20)
        cal.clicked[QDate].connect(self.showDate)

        self.lbl = QLabel(self)
        date = cal.selectedDate()
        self.lbl.setText(date.toString())
        self.lbl.move(130, 260)

        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('Calendar')
        self.show()

    def showDate(self, date):
        self.lbl.setText(date.toString())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

示例中创建了一个日历控件和一个标签控件。选择的日期会显示在标签控件中。

cal = QCalendarWidget(self)

QCalendarWidget被创建

cal.clicked[QDate].connect(self.showDate)

如果我们从部件选择一个日期,点击[QDate]发出信号。我们将这个信号连接到用户定义的showDate()方法。

def showDate(self, date):     
    
    self.lbl.setText(date.toString())

我们检索所选日期通过调用selectedDate()方法。然后我们将date对象转换为字符串,并将其设置为小部件的标签。

 

七、PyQt5控件2

在这里我们将继续介绍PyQt5控件。我们将介绍QPixmap、QLineEdit QSplitter,QComboBox。

QPixmap

QPixmap是用于处理图像的控件。是优化的显示图像在屏幕上。在我们的代码示例中,我们将使用QPixmap窗口显示一个图像。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we dispay an image
on the window.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QHBoxLayout,
                             QLabel, QApplication)
from PyQt5.QtGui import QPixmap


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        hbox = QHBoxLayout(self)
        pixmap = QPixmap("icon.png")

        lbl = QLabel(self)
        lbl.setPixmap(pixmap)

        hbox.addWidget(lbl)
        self.setLayout(hbox)

        self.move(300, 200)
        self.setWindowTitle('Red Rock')
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在窗口上显示一个图片

pixmap = QPixmap("icon.png")

创建一个QPixmap 对象,它将传入的文件名作为参数。

lbl = QLabel(self)
lbl.setPixmap(pixmap)

我们将这个pixmap放到QLabel控件中。

文本框 QLineEdit

QLineEdit是用于输入或编辑单行文本的控件。它还有撤销重做、剪切复制和拖拽功能。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

This example shows text which
is entered in a QLineEdit
in a QLabel widget.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QLabel,
                             QLineEdit, QApplication)


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.lbl = QLabel(self)
        qle = QLineEdit(self)

        qle.move(60, 100)
        self.lbl.move(60, 40)

        qle.textChanged[str].connect(self.onChanged)

        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('QLineEdit')
        self.show()

    def onChanged(self, text):
        self.lbl.setText(text)
        self.lbl.adjustSize()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

示例中展示了一个QLineEdit与一个QLabel。我们在QLineEdit中输入的文字会实时显示在QLabel控件中。

qle = QLineEdit(self)

创建QLineEdit

qle.textChanged[str].connect(self.onChanged)

文本框的内容发生改变的时候,会调用onChanged方法

def onChanged(self, text):
    
    self.lbl.setText(text)
    self.lbl.adjustSize() 

在onChanged()方法中我们将QLabel控件的文本设置为输入的内容。通过调用adjustSize()方法将QLabel控件的尺寸调整为文本的长度。

QSplitter

通过QSplitter,用户可以拖动子控件边界来调整子控件的尺寸。在下面的示例中,我们展示了三个由两个QSplitter组织的QFrame控件。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

This example shows
how to use QSplitter widget.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QHBoxLayout, QFrame,
                             QSplitter, QStyleFactory, QApplication)
from PyQt5.QtCore import Qt


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        hbox = QHBoxLayout(self)

        topleft = QFrame(self)
        topleft.setFrameShape(QFrame.StyledPanel)

        topright = QFrame(self)
        topright.setFrameShape(QFrame.StyledPanel)

        bottom = QFrame(self)
        bottom.setFrameShape(QFrame.StyledPanel)

        splitter1 = QSplitter(Qt.Horizontal)
        splitter1.addWidget(topleft)
        splitter1.addWidget(topright)

        splitter2 = QSplitter(Qt.Vertical)
        splitter2.addWidget(splitter1)
        splitter2.addWidget(bottom)

        hbox.addWidget(splitter2)
        self.setLayout(hbox)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('QSplitter')
        self.show()

    def onChanged(self, text):
        self.lbl.setText(text)
        self.lbl.adjustSize()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

示例中我们创建了三个QFrame与两个QSplitter。注意在某些主题中这些QSplitter可能会不可见。

topleft = QFrame(self)
topleft.setFrameShape(QFrame.StyledPanel)

我们使用一个风格框架为了看到QFrame小部件之间的界限。

splitter1 = QSplitter(Qt.Horizontal)
splitter1.addWidget(topleft)
splitter1.addWidget(topright)

我们创建一个QSplitter小部件和添加两个帧。

splitter2 = QSplitter(Qt.Vertical)
splitter2.addWidget(splitter1)

我们也可以将QSplitter添加到另一个QSplitter控件中。

下拉列表 QComboBox

QComboBox是允许用户从下拉列表中进行选择的控件。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

This example shows how to use
a QComboBox widget.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QLabel,
                             QComboBox, QApplication)


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.lbl = QLabel("Ubuntu", self)

        combo = QComboBox(self)
        combo.addItem("Ubuntu")
        combo.addItem("Mandriva")
        combo.addItem("Fedora")
        combo.addItem("Arch")
        combo.addItem("Gentoo")

        combo.move(50, 50)
        self.lbl.move(50, 150)

        combo.activated[str].connect(self.onActivated)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('QComboBox')
        self.show()

    def onActivated(self, text):
        self.lbl.setText(text)
        self.lbl.adjustSize()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

示例中展示了一个QComboBox与一个QLabel,QComboBox控件中有5个选项(Linux系统的几个发行版名称)。QLabel控件会显示QComboBox中选中的某个选项。

combo = QComboBox(self)
combo.addItem("Ubuntu")
combo.addItem("Mandriva")
combo.addItem("Fedora")
combo.addItem("Arch")
combo.addItem("Gentoo")

创建了一个有五个选项的QComboBox

combo.activated[str].connect(self.onActivated) 

当选中某个条目时会调用onActivated()方法。

def onActivated(self, text):
  
    self.lbl.setText(text)
    self.lbl.adjustSize() 

在方法中我们将QLabel控件的内容设置为选中的条目,然后调整它的尺寸。

 

八、PyQt5拖拽

在这部分PyQt5教程中,我们将讨论拖拽相关操作。

在计算机图形用户界面中,拖放的操作(或支持的作用)点击虚拟对象和拖动到另一个位置或到另一个虚拟对象。一般来说,它可以用于调用多种行动,或创建各种类型的两个抽象对象之间的关联。
拖放是图形用户界面的一部分。拖拽操作让用户直观地做复杂的事情。
通常,我们可以拖放两件事:数据或一些图形对象。如果我们把一个图像从一个应用程序到另一个地方,我们拖拽二进制数据。如果我们把一个标签在Firefox中并将其移动到另一个地方,我们拖拽一个图形组件。

简单拖放

在第一个示例中,我们有一个QLineEdit QPushButton。我们拖着纯文本的行编辑窗口小部件,然后放到按钮部件。按钮的标签会改变。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

This is a simple drag and
drop example.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QPushButton, QWidget,
                             QLineEdit, QApplication)


class Button(QPushButton):
    def __init__(self, title, parent):
        super().__init__(title, parent)

        self.setAcceptDrops(True)

    def dragEnterEvent(self, e):

        if e.mimeData().hasFormat('text/plain'):
            e.accept()
        else:
            e.ignore()

    def dropEvent(self, e):

        self.setText(e.mimeData().text())


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        edit = QLineEdit('', self)
        edit.setDragEnabled(True)
        edit.move(30, 65)

        button = Button("Button", self)
        button.move(190, 65)

        self.setWindowTitle('Simple drag & drop')
        self.setGeometry(300, 300, 300, 150)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()  

View Code

这个列子演示了一个简单的拖拽操作

class Button(QPushButton):
  
    def __init__(self, title, parent):
        super().__init__(title, parent)
        
        self.setAcceptDrops(True)

我们需要重新实现某些方法才能使QPushButton接受拖放操作。因此我们创建了继承自QPushButton的Button类。

self.setAcceptDrops(True)

使该控件接受drop(放下)事件。

def dragEnterEvent(self, e):
    
    if e.mimeData().hasFormat('text/plain'):
        e.accept()
    else:
        e.ignore() 

首先我们重新实现了dragEnterEvent()方法,并设置可接受的数据类型(在这里是普通文本)。

def dropEvent(self, e):

    self.setText(e.mimeData().text()) 

通过重新实现dropEvent()方法,我们定义了在drop事件发生时的行为。这里我们改变了按钮的文字。

edit = QLineEdit('', self)
edit.setDragEnabled(True)

QLineEdit内置了对drag(拖动)操作的支持。我们只需要调用setDragEnabled()方法就可以了。

pyqt5中文教程

拖放一个按钮

在下面的示例中我们将演示如何对一个按钮控件进行拖放。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

This is a simple drag and
drop example.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import QPushButton, QWidget, QApplication
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag


class Button(QPushButton):
    def __init__(self, title, parent):
        super().__init__(title, parent)

    def mouseMoveEvent(self, e):

        if e.buttons() != Qt.RightButton:
            return

        mimeData = QMimeData()

        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(e.pos() - self.rect().topLeft())

        dropAction = drag.exec_(Qt.MoveAction)

    def mousePressEvent(self, e):

        QPushButton.mousePressEvent(self, e)

        if e.button() == Qt.LeftButton:
            print('press')


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setAcceptDrops(True)

        self.button = Button('Button', self)
        self.button.move(100, 65)

        self.setWindowTitle('Click or Move')
        self.setGeometry(300, 300, 280, 150)

    def dragEnterEvent(self, e):
        e.accept()

    def dropEvent(self, e):
        position = e.pos()
        self.button.move(position)

        e.setDropAction(Qt.MoveAction)
        e.accept()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()  

View Code

在这个例子中,在窗口显示一个QPushButton 。如果用鼠标左键点击这个按钮会在控制台中输出’press’消息。鼠标右击进行拖动。

class Button(QPushButton):
  
    def __init__(self, title, parent):
        super().__init__(title, parent)

我们从QPushButton派生了一个Button类,并重新实现了mouseMoveEvent()与mousePressEvent()方法。mouseMoveEvent()方法是拖放操作产生的地方。

if e.buttons() != Qt.RightButton:
    return

在这里我们设置只在鼠标右击时才执行拖放操作。鼠标左击用于按钮的点击事件。

mimeData = QMimeData()

drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())

QDrag提供了对基于MIME的拖放的数据传输的支持。

dropAction = drag.exec_(Qt.MoveAction)

Drag对象的exec_()方法用于启动拖放操作。

def mousePressEvent(self, e):

    QPushButton.mousePressEvent(self, e)

    if e.button() == Qt.LeftButton:
        print('press')

鼠标左击按钮时我们会在控制台打印‘press’。注意我们也调用了父按钮的mousePressEvent()方法。否则会看不到按钮的按下效果。

position = e.pos()
self.button.move(position)

释放右键后调用dropEvent()方法中,即找出鼠标指针的当前位置,并将按钮移动过去。

e.setDropAction(Qt.MoveAction)
e.accept()

我们可以对指定的类型放弃行动。在我们的例子中它是一个移动动作。

 

九、PyQt5绘图

PyQt5绘画系统能够呈现矢量图形,图像,和大纲font-based文本。我们也可以在程序中调用系统api自定义绘图控件。

绘图要在paintEvent()方法中实现。在QPainter对象的begin()与end()方法间编写绘图代码。它会在控件或其他图形设备上进行低级的图形绘制。

绘制文本

我们先以窗体内Unicode文本的绘制为例。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial 

In this example, we draw text in Russian azbuka.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QColor, QFont
from PyQt5.QtCore import Qt


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.text = u'\u041b\u0435\u0432 \u041d\u0438\u043a\u043e\u043b\u0430\
\u0435\u0432\u0438\u0447 \u0422\u043e\u043b\u0441\u0442\u043e\u0439: \n\
\u0410\u043d\u043d\u0430 \u041a\u0430\u0440\u0435\u043d\u0438\u043d\u0430'

        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('Draw text')
        self.show()

    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        self.drawText(event, qp)
        qp.end()

    def drawText(self, event, qp):
        qp.setPen(QColor(168, 34, 3))
        qp.setFont(QFont('Decorative', 10))
        qp.drawText(event.rect(), Qt.AlignCenter, self.text)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在我们的示例中,我们绘制一些Cylliric文本。文本垂直和水平对齐。

def paintEvent(self, event):
...

绘制工作在paintEvent的方法内部完成。

qp = QPainter()
qp.begin(self)
self.drawText(event, qp)
qp.end()

QPainter类负责所有的初级绘制。之间的所有绘画方法去start()和end()方法。实际的绘画被委托给drawText()方法。

qp.setPen(QColor(168, 34, 3))
qp.setFont(QFont('Decorative', 10))

在这里,我们定义一个画笔和一个字体用于绘制文本。

qp.drawText(event.rect(), Qt.AlignCenter, self.text)

drawText()方法将文本绘制在窗体,显示在中心

画点

点是可以绘制的最简单的图形对象。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial

In the example, we draw randomly 1000 red points
on the window.

author: py40.com
last edited: 2017年3月
"""
import sys, random
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('Points')
        self.show()

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        self.drawPoints(qp)
        qp.end()

    def drawPoints(self, qp):
        qp.setPen(Qt.red)
        size = self.size()

        for i in range(1000):
            x = random.randint(1, size.width() - 1)
            y = random.randint(1, size.height() - 1)
            qp.drawPoint(x, y)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在这例子中,我们在窗口上随机绘制了1000个红点

qp.setPen(Qt.red)

设置画笔为红色,我们使用了预定义的Qt.red常量

size = self.size()

每次我们改变窗口的大小,生成一个 paint event 事件。我们得到的当前窗口的大小size。我们使用窗口的大小来分配点在窗口的客户区。

qp.drawPoint(x, y)

通过drawpoint绘制圆点

颜色

颜色是一个对象代表红、绿、蓝(RGB)强度值。有效的RGB值的范围从0到255。我们可以用不同的方法定义了一个颜色。最常见的是RGB十进制或十六进制值的值。我们也可以使用一个RGBA值代表红色,绿色,蓝色,透明度。我们添加一些额外的信息透明度。透明度值255定义了完全不透明,0是完全透明的,例如颜色是无形的。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial

This example draws three rectangles in three
#different colours.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QColor, QBrush


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 350, 100)
        self.setWindowTitle('Colours')
        self.show()

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        self.drawRectangles(qp)
        qp.end()

    def drawRectangles(self, qp):
        col = QColor(0, 0, 0)
        col.setNamedColor('#d4d4d4')
        qp.setPen(col)

        qp.setBrush(QColor(200, 0, 0))
        qp.drawRect(10, 15, 90, 60)

        qp.setBrush(QColor(255, 80, 0, 160))
        qp.drawRect(130, 15, 90, 60)

        qp.setBrush(QColor(25, 0, 90, 200))
        qp.drawRect(250, 15, 90, 60)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

实例中我们绘制了3个不同颜色的矩形

color = QColor(0, 0, 0)
color.setNamedColor('#d4d4d4')

在这里,我们定义一个使用十六进制符号颜色。

qp.setBrush(QColor(200, 0, 0))
qp.drawRect(10, 15, 90, 60)

我们为QPainter设置了一个笔刷(Bursh)对象并用它绘制了一个矩形。笔刷是用于绘制形状背景的基本图形对象。drawRect()方法接受四个参数,前两个是起点的x,y坐标,后两个是矩形的宽和高。这个方法使用当前的画笔与笔刷对象进行绘制。

QPen(画笔)

QPen是一个基本的图形对象。用于绘制线条、曲线和轮廓的矩形、椭圆、多边形或其他形状。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial

In this example we draw 6 lines using
different pen styles.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 280, 270)
        self.setWindowTitle('Pen styles')
        self.show()

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        self.drawLines(qp)
        qp.end()

    def drawLines(self, qp):
        pen = QPen(Qt.black, 2, Qt.SolidLine)

        qp.setPen(pen)
        qp.drawLine(20, 40, 250, 40)

        pen.setStyle(Qt.DashLine)
        qp.setPen(pen)
        qp.drawLine(20, 80, 250, 80)

        pen.setStyle(Qt.DashDotLine)
        qp.setPen(pen)
        qp.drawLine(20, 120, 250, 120)

        pen.setStyle(Qt.DotLine)
        qp.setPen(pen)
        qp.drawLine(20, 160, 250, 160)

        pen.setStyle(Qt.DashDotDotLine)
        qp.setPen(pen)
        qp.drawLine(20, 200, 250, 200)

        pen.setStyle(Qt.CustomDashLine)
        pen.setDashPattern([1, 4, 5, 4])
        qp.setPen(pen)
        qp.drawLine(20, 240, 250, 240)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

示例中我们画六行。线条勾勒出了六个不同的笔风格。有五个预定义的钢笔样式。我们也可以创建自定义的钢笔样式。最后一行使用一个定制的钢笔绘制风格。

pen = QPen(Qt.black, 2, Qt.SolidLine)

我们创建一个QPen对象。颜色是黑色的。宽度设置为2像素,这样我们可以看到笔风格之间的差异。Qt.SolidLine是预定义的钢笔样式。

pen.setStyle(Qt.CustomDashLine)
pen.setDashPattern([1, 4, 5, 4])
qp.setPen(pen)

这里我们定义了一个画笔风格。我们设置了Qt.CustomDashLine并调用了setDashPattern()方法,它的参数(一个数字列表)定义了一种风格,必须有偶数个数字;其中奇数表示绘制实线,偶数表示留空。数值越大,直线或空白就越大。这里我们定义了1像素的实线,4像素的空白,5像素实线,4像素空白。。。

QBrush(笔刷)

QBrush是一个基本的图形对象。它用于油漆的背景图形形状,如矩形、椭圆形或多边形。三种不同类型的刷可以:一个预定义的刷,一个梯度,或纹理模式。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial

This example draws 9 rectangles in different
brush styles.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QBrush
from PyQt5.QtCore import Qt


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 355, 280)
        self.setWindowTitle('Brushes')
        self.show()

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        self.drawBrushes(qp)
        qp.end()

    def drawBrushes(self, qp):
        brush = QBrush(Qt.SolidPattern)
        qp.setBrush(brush)
        qp.drawRect(10, 15, 90, 60)

        brush.setStyle(Qt.Dense1Pattern)
        qp.setBrush(brush)
        qp.drawRect(130, 15, 90, 60)

        brush.setStyle(Qt.Dense2Pattern)
        qp.setBrush(brush)
        qp.drawRect(250, 15, 90, 60)

        brush.setStyle(Qt.DiagCrossPattern)
        qp.setBrush(brush)
        qp.drawRect(10, 105, 90, 60)

        brush.setStyle(Qt.Dense5Pattern)
        qp.setBrush(brush)
        qp.drawRect(130, 105, 90, 60)

        brush.setStyle(Qt.Dense6Pattern)
        qp.setBrush(brush)
        qp.drawRect(250, 105, 90, 60)

        brush.setStyle(Qt.HorPattern)
        qp.setBrush(brush)
        qp.drawRect(10, 195, 90, 60)

        brush.setStyle(Qt.VerPattern)
        qp.setBrush(brush)
        qp.drawRect(130, 195, 90, 60)

        brush.setStyle(Qt.BDiagPattern)
        qp.setBrush(brush)
        qp.drawRect(250, 195, 90, 60)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

示例中绘制九个不同的矩形

brush = QBrush(Qt.SolidPattern)
qp.setBrush(brush)
qp.drawRect(10, 15, 90, 60)

我们定义了一个笔刷对象,然后将它设置给QPainter对象,并调用painter的drawRect()方法绘制矩形。

 

十、PyQt5自定义控件

PyQt5包含种类丰富的控件。但能满足所有需求的控件库是不存在的。通常控件库只提供了像按钮、文本控件、滑块等最常用的控件。但如果需要某种特殊的控件,我们只能自己动手来实现。 自定义控件需要使用工具库提供的绘图工具,可能有两种方式:在已有的控件上进行拓展或从头开始创建自定义控件。

Burning widget(烧录控件)

这个控件可能会在Nero,K3B或其他CD/DVD烧录软件中见到。

pyqt5中文教程
pyqt5中文教程

# -*- coding: utf-8 -*-

"""
PyQt5 tutorial

In this example, we create a custom widget.

author: py40.com
last edited: 2017年3月
"""
import sys
from PyQt5.QtWidgets import (QWidget, QSlider, QApplication,
                             QHBoxLayout, QVBoxLayout)
from PyQt5.QtCore import QObject, Qt, pyqtSignal
from PyQt5.QtGui import QPainter, QFont, QColor, QPen


class Communicate(QObject):
    updateBW = pyqtSignal(int)


class BurningWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):

        self.setMinimumSize(1, 30)
        self.value = 75
        self.num = [75, 150, 225, 300, 375, 450, 525, 600, 675]

    def setValue(self, value):

        self.value = value

    def paintEvent(self, e):

        qp = QPainter()
        qp.begin(self)
        self.drawWidget(qp)
        qp.end()

    def drawWidget(self, qp):

        font = QFont('Serif', 7, QFont.Light)
        qp.setFont(font)

        size = self.size()
        w = size.width()
        h = size.height()

        step = int(round(w / 10.0))

        till = int(((w / 750.0) * self.value))
        full = int(((w / 750.0) * 700))

        if self.value >= 700:

            qp.setPen(QColor(255, 255, 255))
            qp.setBrush(QColor(255, 255, 184))
            qp.drawRect(0, 0, full, h)
            qp.setPen(QColor(255, 175, 175))
            qp.setBrush(QColor(255, 175, 175))
            qp.drawRect(full, 0, till - full, h)

        else:

            qp.setPen(QColor(255, 255, 255))
            qp.setBrush(QColor(255, 255, 184))
            qp.drawRect(0, 0, till, h)

        pen = QPen(QColor(20, 20, 20), 1,
                   Qt.SolidLine)

        qp.setPen(pen)
        qp.setBrush(Qt.NoBrush)
        qp.drawRect(0, 0, w - 1, h - 1)

        j = 0

        for i in range(step, 10 * step, step):
            qp.drawLine(i, 0, i, 5)
            metrics = qp.fontMetrics()
            fw = metrics.width(str(self.num[j]))
            qp.drawText(i - fw / 2, h / 2, str(self.num[j]))
            j = j + 1


class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        sld = QSlider(Qt.Horizontal, self)
        sld.setFocusPolicy(Qt.NoFocus)
        sld.setRange(1, 750)
        sld.setValue(75)
        sld.setGeometry(30, 40, 150, 30)

        self.c = Communicate()
        self.wid = BurningWidget()
        self.c.updateBW[int].connect(self.wid.setValue)

        sld.valueChanged[int].connect(self.changeValue)
        hbox = QHBoxLayout()
        hbox.addWidget(self.wid)
        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addLayout(hbox)
        self.setLayout(vbox)

        self.setGeometry(300, 300, 390, 210)
        self.setWindowTitle('Burning widget')
        self.show()

    def changeValue(self, value):
        self.c.updateBW.emit(value)
        self.wid.repaint()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

View Code

在示例中我们使用了滑块与一个自定义控件。自定义控件受滑块控制。控件显示了媒体介质的容量和剩余空间。该控件的最小值为1,最大值为750。在值超过700时颜色变为红色。这通常意味着超刻(即实际写入光盘的容量超过刻录盘片官方标称容量的一种操作)。

BurningWidget控件通过QHBoxLayout与QVBoxLayout置于窗体的底部。

class BurningWidget(QWidget):
  
    def __init__(self):      
        super().__init__() 

烧录的控件,它基于QWidget

self.setMinimumSize(1, 30)

我们改变了控件的最小大小(高度),默认值为有点小。

font = QFont('Serif', 7, QFont.Light)
qp.setFont(font)

我们使用一个比默认要小的字体。

size = self.size()
w = size.width()
h = size.height()

step = int(round(w / 10.0))


till = int(((w / 750.0) * self.value))
full = int(((w / 750.0) * 700))

控件采用了动态绘制技术。窗体越大,控件也随之变大;反之亦然。这也是我们需要计算自定义控件的载体控件(即窗体)尺寸的原因。till参数定义了需要绘制的总尺寸,它根据slider控件计算得出,是整体区域的比例值。full参数定义了红色区域的绘制起点。注意在绘制时为取得较大精度而使用的浮点数运算。

实际的绘制分三个步骤。黄色或红黄矩形的绘制,然后是刻度线的绘制,最后是刻度值的绘制。

metrics = qp.fontMetrics()
fw = metrics.width(str(self.num[j]))
qp.drawText(i-fw/2, h/2, str(self.num[j]))

我们使用字体度量来绘制文本。我们必须知道文本的宽度,以中心垂直线。

def changeValue(self, value):
          
    self.c.updateBW.emit(value)        
    self.wid.repaint()

当滑块发生移动时,changeValue()方法会被调用。在方法内我们触发了一个自定义的updateBW信号,其参数是当前滚动条的值。该值被用于计算Burning widget的容量值。然后对控件进行重绘。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/30615.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信