1. 描述
- 所有可视空间的基类
- 是一个最简单的空白控件
- 控件是用户界面的最小元素
- 接收各种事件(鼠标、键盘)
- 绘制在桌面上,显示给用户看
- 每个控件都是矩形的,它们按z轴顺序排序
- 控件由其父控件和前面的控件剪切
- 没有父控件的控件,称之为窗口
- 一般会被包装一个框架(标题栏等)
- 可以通过某些设置更改
2. 继承
- QObject
- QPaintDevice
3. 功能
3.1 控件的创建
3.1.1 API
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | |
3.2 大小位置
3.2.1 API
3.2.1.1 获取
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | |
3.2.1.1.1 代码
from PyQt5.Qt import *import sysif __name__ == '__main__':app = QApplication(sys.argv)window = QWidget()window.setWindowTitle('位置大小')window.resize(500, 500)window.move(100, 100)# 在窗口显示前获取尺寸信息print(window.size())print(window.geometry())print(window.frameSize())print(window.frameGeometry())print("--"*20)window.show()# 在窗口显示之后获取尺寸信息print(window.size())print(window.geometry())print(window.frameSize())print(window.frameGeometry())sys.exit(app.exec_())
运行结果:
注意:控件显示完毕后,具体尺寸数据才会正确
3.2.1.2 设置
3.2.1.1 获取
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | |
3.2.1.2 案例
通过给定的的个数, 你负责在一个窗口内创建相应个数的子控件
要求:按照九宫格的布局进行摆放,一行放给定的列
from PyQt5.Qt import *import sysif __name__ == '__main__':app = QApplication(sys.argv)window = QWidget()window.show()window.resize(500, 500)window.move(500, 500)# 总的控件个数widget_count = 500# 每一行列的个数column_count = 5# 计算一个控件的宽度widget_width = window.width() / column_count# 总共有多少行row_count = (widget_count-1)//column_count + 1widget_height = window.height() / row_countfor i in range(0, widget_count):w = QWidget(window)w.resize(int(widget_width), int(widget_height))widget_x = i % column_count * widget_widthwidget_y = i // column_count * widget_heightw.move(int(widget_x), int(widget_y))w.setStyleSheet('background-color: red;border:1px solid yellow;')w.show()sys.exit(app.exec_())
运行结果:(500个控件,每一行放5个控件)
3.3 最大和最小尺寸
3.3.1 API
3.3.1.1 获取
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | |
3.3.1.2 设置
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | |
3.3.1.3 注意
控件完全展示前后会有差异
3.4 内容边距
3.4.1 API
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | |
注意:必须是控件本身留够对应的大小
3.4.2 应用场景
调整控件内容边距,使得显示更加好看
3.4.3 案例
创建一个窗口,包含一个标签
要求:
- 标签内容为xujie
- 标签大小为100, 60
- 将内容放在标签右下角
from PyQt5.Qt import *import sysif __name__ == '__main__':app = QApplication(sys.argv)window = QWidget()window.setWindowTitle('内容边距')window.resize(500, 500)label = QLabel(window)label.setText('xujie')label.resize(100, 60)label.move(200, 200)label.setStyleSheet('background-color: cyan;')label.setContentsMargins(60, 40, 0, 0)print(label.getContentsMargins())window.show()sys.exit(app.exec_())
运行结果:
3.5 鼠标操作
3.5.1 API
3.5.1.1 设置鼠标形状
setCursor(鼠标参数)
参数:
- Qt.ArrowCursor
- Qt.UpArrowCursor
- Qt.CrossCursor
- Qt.IBeamCursor
- Qt.WaitCursor
- Qt.BusyCursor
- Qt.ForbiddenCursor
- Qt.PointingHandCursor
- Qt.WhatsThisCursor
- Qt.SizeVerCursor
- Qt.SizeHorCursor
- Qt.SizeBDiagCursor
- Qt.SizeAllCursor
- Qt.SplitVCursor
- Qt.SplitHCursor
- Qt.OpenHandCursor
- Qt.ClosedHandCursor
- Qt.BlankCursor
- 自定义
QCurser对象
3.5.1.2 重置形状
unsetCursor()
3.5.1.3 获取鼠标
cursor() -> QCursor
3.5.1.4 鼠标跟踪
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | ②不跟踪:鼠标移动时,必须处于按下状态,才会触发mouseMoveEvent事件; ③跟踪:鼠标移动时,不处于按下状态,也会触发mouseMoveEvent事件 |
3.5.1.5 QCursor对象
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | |
3.5.2 应用场景
根据特定场景, 设置鼠标样式; 使得用户交互时更加明确
3.5.3 案例
创建一个窗口, 内部有一个label控件
要求:
- 鼠标移入窗口时, 让label位置跟随鼠标位置
- 让鼠标设置为指定图标
from PyQt5.Qt import *
import sysclass MyWidget(QWidget):def mouseMoveEvent(self, a0):"""重写鼠标移动事件方法"""print(a0.localPos())label = self.findChild(QLabel)label.move(int(a0.localPos().x()), int(a0.localPos().y()))if __name__ == '__main__':app = QApplication(sys.argv)window = MyWidget()window.setWindowTitle('鼠标操作')window.resize(500, 500)# 设置鼠标跟踪if not window.hasMouseTracking():window.setMouseTracking(True)# 设置一个标签控件label = QLabel(window)label.setText('我是标签')label.setStyleSheet('background-color: cyan;')label.move(200, 200)# 设置指定图标pixmap = QPixmap('img.png').scaled(50, 50)cursor = QCursor(pixmap, 10, 10)window.setCursor(cursor)window.show()sys.exit(app.exec_())
运行结果:
3.6 事件
3.6.1 API
3.6.1.1 显示和关闭事件
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | |
3.6.1.2 移动事件
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | |
3.6.1.3 调整大小
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | |
3.6.1.4 鼠标事件
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | |
3.6.1.5 键盘事件
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | |
3.6.1.6 焦点事件
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | |
3.6.1.7 拖拽事件
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | |
3.6.1.8 绘制事件
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | |
3.6.1.9 改变事件
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | |
3.6.1.10 右键菜单
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | |
3.6.1.11 输入法
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | |
3.6.2 应用场景
- 当一个控件被触发了一个特定的行为时, 就会调用特定的方法, 来将事件传递给开发人员, 方便处理
- 重写这些事件方法, 就可以监听相关的信息
3.6.3 案例1
创建一个窗口包含一个标签
要求:
- 鼠标进入标签时, 展示"欢迎光临"
- 鼠标离开标签时, 展示"谢谢惠顾"
from PyQt5.Qt import *import sysclass QWindow(QWidget):"""window窗口类"""def __init__(self):super().__init__()def enterEvent(self, a0):label = self.findChild(QLabel)label.setText('欢迎光临')def leaveEvent(self, a0):label = self.findChild(QLabel)label.setText('请慢走')class MyLabel(QLabel):"""label控件类"""def __init__(self, parent=None):super().__init__(parent)self.setStyleSheet('background-color: cyan;')self.move(350, 480)self.setText('Hello,你好')self.setFixedSize(120, 20)font = QFont("Hei", 10)font.setBold(True)self.setFont(font)self.setAlignment(Qt.AlignCenter)if __name__ == '__main__':app = QApplication(sys.argv)window = QWindow()window.setWindowTitle('事件消息')window.resize(500, 500)# 创建一个标签label = MyLabel(window)window.show()sys.exit(app.exec_())
运行结果:
3.6.4 案例2
创建一个窗口, 监听用户按键
要求:
- 监听用户输入Tab键
- 监听用户输入Ctrl+S组合键
- 监听用户输入Ctrl+Shift+A
补充:修饰键,多个修饰键使用或运算
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | |
补充:普通键:Qt.Key_xxx
from PyQt5.Qt import *import sysclass MyWindow(QWidget):def __init__(self):super().__init__()self.label = MyLabel(self)def keyPressEvent(self, a0):"""键盘输入监听方法"""if a0.key() == Qt.Key_Tab:self.label.setText('用户点击了Tab键')if a0.modifiers() == Qt.ControlModifier and a0.key() == Qt.Key_S:self.label.setText('用户点击了Ctrl+S键')if a0.modifiers() == Qt.ControlModifier | Qt.ShiftModifier and Qt.Key_A:self.label.setText('用户点击了Ctrl+Shift+A键')class MyLabel(QLabel):"""label控件类"""def __init__(self, parent=None):super().__init__(parent)self.setStyleSheet('background-color: cyan;')self.move(0, 480)self.setText('Hello,你好')self.setFixedSize(500, 20)font = QFont("Hei", 10)font.setBold(True)self.setFont(font)self.setAlignment(Qt.AlignCenter)if __name__ == '__main__':app = QApplication(sys.argv)window = MyWindow()window.setWindowTitle('事件消息')window.resize(500, 500)window.show()sys.exit(app.exec_())
运行结果:
3.6.5 案例3
完成窗口, 用户区支持拖拽
要求:
- 鼠标点击了用户区拖拽也可以移动窗口
from PyQt5.Qt import *import sysclass MyWindow(QWidget):def __init__(self):super().__init__()self.origin_y = Noneself.origin_x = Noneself.mouse_y = Noneself.mouse_x = Noneself.move_flag = Falseself.label = MyLabel(self)def mousePressEvent(self, a0):"""鼠标按下方法"""if a0.button() == Qt.LeftButton:self.move_flag = True# 确定两个点:鼠标第一次按下的点,窗口当前所在的原始点self.mouse_x = a0.globalX()self.mouse_y = a0.globalY()self.origin_x = self.x()self.origin_y = self.y()def mouseMoveEvent(self, a0):"""鼠标移动方法"""if self.move_flag:move_x = a0.globalX() - self.mouse_xmove_y = a0.globalY() - self.mouse_ydest_x = self.origin_x + move_xdest_y = self.origin_y + move_yself.move(dest_x, dest_y)def mouseReleaseEvent(self, a0):if self.move_flag:self.move_flag = Falseclass MyLabel(QLabel):"""label控件类"""def __init__(self, parent=None):super().__init__(parent)self.setStyleSheet('background-color: cyan;')self.move(0, 480)self.setText('Hello,你好')self.setFixedSize(500, 20)font = QFont("Hei", 10)font.setBold(True)self.setFont(font)self.setAlignment(Qt.AlignCenter)if __name__ == '__main__':app = QApplication(sys.argv)window = MyWindow()window.setWindowTitle('事件消息')window.resize(500, 500)window.show()sys.exit(app.exec_())
3.7 父子关系
3.7.1 API
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | |
3.7.2 应用场景
看着用吧
3.7.3 案例
创建窗口, 包含若干label控件
要求:
- 点击哪个标签,就让哪个标签变红
- 使用父控件处理,不可以使用自定义Label控件呦
from PyQt5.Qt import *import sys# class MyWidget(QLabel):
# def mousePressEvent(self, event):
# self.setStyleSheet("background-color: cyan;")class Window(QWidget):def mousePressEvent(self, event):local_x = event.pos().x()local_y = event.pos().y()sub_widget = self.childAt(local_x, local_y)if sub_widget:sub_widget.setStyleSheet("background-color: cyan;")if __name__ == '__main__':app = QApplication(sys.argv)window = Window()window.setWindowTitle('事件消息')window.resize(600, 600)for i in range(1, 11):label = QLabel(window)label.setText('标签'+str(i))label.move(50*i, 50*i)window.show()sys.exit(app.exec_())
运行结果:
3.8 层级控制
3.8.1 API
注意: 以下操作专指同级控件API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | |
3.8.2 应用场景
需要调整控件Z轴顺序
3.9 顶层窗口相关
3.9.1 API
3.9.1.1 图标
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | |
3.9.1.2 标题
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | |
3.9.1.3 不透明度
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | |
3.9.1.4 窗口状态
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | Qt.WindowMinimized-最小化 Qt.WindowMaximized-最大化 Qt.WindowFullScreen-全屏 Qt.WindowActive-活动窗口 | ||||||
| | |
3.9.1.5 最大化最小化
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | |
3.9.1.6 窗口标志
3.9.1.6.1 window.setWindowFlags(参数)
参数介绍:
- 窗口样式
参数 | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | |
- 顶层窗口外观标志
参数 | 功能 | |||
---|---|---|---|---|
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| |
3.9.1.6.2 windowFlags()
获取窗口标志
3.9.2 应用场景
调整整个应用程序窗口外观
3.9.3 案例
创建窗口
要求:
- 无边框无标题栏
- 窗口半透明
- 自定义最小化, 最大化, 关闭按钮
- 支持拖拽用户区移动
from PyQt5.Qt import *import sysclass Window(QWidget):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self.move_flag = Falseself.min_btn = Noneself.max_btn = Noneself.close_btn = None# 公共数据self.top_margin = 10self.btn_w = 80self.btn_h = 40# 去掉边框以及标题栏self.setWindowFlag(Qt.FramelessWindowHint)self.resize(500, 500)self.setWindowTitle('窗口案例')# 变成半透明self.setWindowOpacity(0.9)self.initUI()def initUI(self):"""控件操作方法"""# 添加三个子控件 - 窗口右上角self.close_btn = QPushButton(self)self.close_btn.setText('关闭')self.close_btn.resize(self.btn_w, self.btn_h)self.max_btn = QPushButton(self)self.max_btn.setText('最大化')self.max_btn.resize(self.btn_w, self.btn_h)self.min_btn = QPushButton(self)self.min_btn.setText('最小化')self.min_btn.resize(self.btn_w, self.btn_h)self.close_btn.pressed.connect(self.close)def normal():if self.isMaximized():self.showNormal()self.max_btn.setText('最大化')else:self.showMaximized()self.max_btn.setText('恢复')self.max_btn.pressed.connect(normal)self.min_btn.pressed.connect(self.showMinimized)def resizeEvent(self, a0):"""窗口适应方法"""window_w = self.width()close_btn_x = window_w - self.btn_wself.close_btn.move(close_btn_x, self.top_margin)max_btn_x = close_btn_x - self.btn_wself.max_btn.move(max_btn_x, self.top_margin)min_btn_x = max_btn_x - self.btn_wself.min_btn.move(min_btn_x, self.top_margin)def mousePressEvent(self, a0):"""鼠标按下方法"""if a0.button() == Qt.LeftButton:self.move_flag = True# 确定两个点:鼠标第一次按下的点,窗口当前所在的原始点self.mouse_x = a0.globalX()self.mouse_y = a0.globalY()self.origin_x = self.x()self.origin_y = self.y()def mouseMoveEvent(self, a0):"""鼠标移动方法"""if self.move_flag:move_x = a0.globalX() - self.mouse_xmove_y = a0.globalY() - self.mouse_ydest_x = self.origin_x + move_xdest_y = self.origin_y + move_yself.move(dest_x, dest_y)def mouseReleaseEvent(self, a0):if self.move_flag:self.move_flag = Falseif __name__ == '__main__':app = QApplication(sys.argv)# 去掉边框以及标题栏window = Window()# window = QWidget(flags=Qt.FramelessWindowHint)window.show()sys.exit(app.exec_())
运行结果:
3.10 控件交互
3.10.1 API
3.10.1.1 是否可用
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | |
3.10.1.2 是否显示/隐藏
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | 马甲:setHidden(bool), show()展示控件;hide()隐藏控件 | ||||||
| | | ||||||
| | | ||||||
| | |
3.10.1.3 是否编辑
设置窗口标题:xxx[*]
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | 没有被编辑:不显示* | ||||||
| | |
3.10.1.4 关闭
close()
补充:setAttribute(Qt.WA_DeleteOnClose, True) :窗口在被关闭时(例如用户点击关闭按钮或调用 close() 方法时),会自动销毁并释放其占用的内存。
3.10.1.5 注意
visible: 代表最终控件状态,是否被我们可见(被其他控件遮挡也属于可见)
hide: 可理解为相对父控件可见
隐藏不一定是可见的,反之不然
3.10.2 应用场景
合适的时候,设置不用的状态,来控制交互逻辑
3.10.3 案例
创建一个窗口,包含一个文本框,一个按钮,一个标签
要求:
- 默认情况下:①标签隐藏;②文本框按钮显示;③按钮设置为不可用状态
- 当文本框有内容时,让按钮可用,否则为不可用
- 当文本框内容为xujie时,点击按钮则显示标签,并展示文本为登录成功,否则为登录失败
- 支持拖拽用户区移动
from PyQt5.Qt import *
import sysclass Window(QWidget):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self.resize(600, 600)# 设置窗口图标icon = QIcon('cats1.ico')self.setWindowIcon(icon)# 设置标题self.setWindowTitle('控件交互')self.initUI()def initUI(self):# 添加控件label = QLabel(self)label.setText('标签')label.move(100, 50)label.hide()l_edit = QLineEdit(self)l_edit.move(100, 100)btn = QPushButton(self)btn.setText('登录')btn.move(100, 150)btn.setEnabled(False)def text_cao(text):print('文本内容发生改变', text)if len(text) > 0:btn.setEnabled(True)else:btn.setEnabled(False)def check():print('按钮被点击了')content = l_edit.text()if content == 'xujie':label.show()label.setText('登录成功')label.adjustSize()else:label.show()label.setText('登录失败')label.adjustSize()l_edit.textChanged.connect(text_cao)btn.pressed.connect(check)if __name__ == '__main__':app = QApplication(sys.argv)window = Window()window.show()sys.exit(app.exec_())
3.11 信息提示
3.11.1 API
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| | |
3.12 焦点控制
3.12.1 API
3.12.1.1 单个控件角度
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | ②Qt.ClickFocus: 通过单击获得焦点; ③Qt.StrongFocus: 通过两种方式获得焦点; ④Qt.NoFocus: 不通过上面方式获得焦点; | ||||||
| | |
3.12.1.2 父控件角度
API | 功能 | 备注 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | | ||||||
| | | ||||||
| False:下一个 | | ||||||
| | |
3.12.2 应用场景
结合程序的业务逻辑,来调整焦点操作
3.13 其他操作(不重要)
3.12.1.2 父控件角度
列表 | API | 解释 | ||||||
---|---|---|---|---|---|---|---|---|
| | | ||||||
| | 另请参阅setMask(),clearMask(),QRegion :: isEmpty()和形状时钟示例。 | ||||||
| | | ||||||
| ②repaint() | | ||||||
| ②removeAction(),insertAction(),actions() | | ||||||
| ②mouseGrabber() ③grabMouse() ④nextInFocusChain() ⑤previousInFocusChain() ⑥releaseKeyboard() | | ||||||
| ②setShortcutEnabled(int id,bool enable = true) ③grabShortcut() ④releaseShortcut() | | ||||||
| ② mapFromGlobal(const QPoint& pos)const ③将全局屏幕坐标pos转换为小部件坐标。 ④又见mapToGlobal(),mapFrom(),和mapFromParent()。 ⑤: mapTo(const QWidget * parent,const QPoint& pos)const ⑥将小部件坐标pos转换为父项的坐标系。在父母不能为0,且必须调用控件的父。 ⑦又见mapFrom(),mapToParent(),mapToGlobal(),和underMouse()。 ⑧QPoint QWidget :: mapToGlobal(const QPoint& pos)const | |