一、QAbstractButton介绍(官翻)
QAbstractButton实现了一个抽象按钮。通常使用它的子类处理用户操作,并指定如何绘制按钮。
QAbstractButton支持按压类(push)按钮和可选类(checkable )按钮。可选按钮在QRadioButton和QCheckBox类中实现。按压按钮在QPushButton和QToolButton类中实现;如果需要,这些还提供切换行为。
任何按钮都可以显示一个包含文本和图标的标签。setText()设置文本;setIcon()设置图标。如果按钮是禁用的,它的标签样式(颜色)就会改变,使按钮看起来像“禁用”的。
如果按钮的文本是一个包含&(' & ')字符,QAbstractButton会自动创建一个快捷键。例如:
button = QPushButton("Ro &ck and Roll", self)
这个按钮具有了Alt+C快捷键,也就是说,当用户按下Alt+C时,这个按钮会调用animateClick()。详细信息请参阅QShortcut文档。要显示实际的&符号,请使用` && `。
也可以使用setShortcut()函数设置自定义快捷键。这对于没有任何文本的按钮非常有用,因为这些按钮没有任何自动快捷方式。(下面例子中,官网是“Alt +F7”,但是一些键盘布局对应平台是其它系统快捷键,被占用,或其它未知原因无法启用。这里为防止产生困惑,改为“Alt +B”)
button.setIcon(QIcon(":/images/print.png"))
button.setShortcut("Alt+B")
Pyside6提供的所有按钮(QPushButton、QToolButton、QCheckBox和QRadioButton)都可以显示文本和图标。
通过setDefault()和setAutoDefault(),可以使按钮成为对话框中的默认按钮。
QAbstractButton提供了大部分用于按钮的状态:
- isDown()表示按钮是否按下。
- isChecked()表示是否选中按钮只有可选中的按钮可以被选中或不选中(见下文)。
- isEnabled()表示用户是否可以按下按钮(请注意:与其他部件不同,由QAbstractButton派生的按钮在禁用时接受鼠标和上下文菜单事件。)
- setAutoRepeat()设置用户按住按钮不放时按钮是否自动重复autoRepeatDelay和autoRepeatInterval定义了自动重复的方式。
- setCheckable()设置按钮是否为切换按钮
isDown()和isChecked()的区别如下。当用户单击切换按钮进行检查时,首先按下按钮,然后释放按钮,使其处于选中状态。当用户再次单击它(取消选中它)时,按钮首先变为按下状态,然后变为未选中状态(isChecked()和isDown()都为false)。
QAbstractButton提供四种信号:
- pressed()在鼠标左键被按下且光标在按钮内部时触发。
- release()在鼠标左键松开时触发。
- clicked()在第一次按下按钮然后松开、键入快捷键、调用click()或animateClick()时触发。
- toggle()在切换按钮的状态改变时触发。
要子类化(自定义按钮)QAbstractButton,必须至少重新实现paintEvent()来绘制按钮的轮廓和文本或pixmap。一般来说,我们建议也重新实现sizeHint()方法,有时也可以实现hitButton()方法(用于确定按钮是否被按下)。对于有两个以上状态的按钮(比如三态按钮),还需要重新实现checkStateSet()和nextCheckState()。
二、QAbstractButton的常用方法
QAbstractButton是所有按钮的基类,且是一个抽象类,无法直接实例化使用。Pyside6提供了一系列已经实现好的子类供编程人员使用,如QPushButton、QToolButton等。这些内置提供的子类基本能够满足常用需求,如果不满足就需要编程人员自己子类化进行自定义(相对不难,但要将绘制事件、图片类等学完。想要完美,QSS、QPalette、QStyle绕不过)。
官方的说明对于新手来说都显得过于简单,比如快捷键的设置,按钮的状态等。尤其对于抽象类来说,无法实例化就不能直接进行测试,那么就需要通过其子类来观察各种属性和方法的作用。这里先列出其常用方法,再一 一解释。
API函数 | 参数说明 | 返回值 | 功能作用 |
setAutoExclusive(self, arg__1) | arg_1:bool | None | 设置按钮的是否排他 |
autoExclusive(self) | None | bool | 获取按钮是否排他 |
click(self) | None | None | 用代码的方式让按钮被点击或切换勾选状态。 同时,发送点击信号 |
animateClick(self) | None | None | 用代码的方式让按钮被点击或切换勾选状态(动画点击)。同时,发送点击信号 |
toggle(self) | None | None | 用代码的方式切换勾选状态。不发送点击信号 |
hitButton(self, pos) | pos:QPoint | bool | 设置按钮点击的有效区域 |
group(self) | None | QButtnGroup | 返回按钮所在的按钮组 |
nextCheckState(self) | None | None | 当单击按钮时,会调用这个虚拟处理程序。默认实现调用setChecked (!isChecked())如果按钮是可检查的它允许子类实现中间按钮状态。 |
setText(self, text) | text:str | None | 设置按钮的显示文本 |
text(self) | None | str | 获取按钮的显示文本 |
setIcon(self, icon) | icon: Union[QIcon, QPixmap] | None | 设置按钮的图标 |
icon(self) | None | QIcon | 获取按钮的图标 |
setIconSize(self, size) | size: QSize | None | 设置按钮图标尺寸 |
iconSize(self) | None | QSize | 获取按钮图标尺寸 |
setShortcut(self, arg__1) | arg__1: union(str,QKeySequence) | None | 为按钮设置快捷键 |
shortcut(self) | None | QKeySequence | 获取快捷键 |
setAutoRepeat(self, arg__1) | arg_1:bool | None | 设置按钮是否开启自动重复 |
autoRepeat(self) | None | bool | 获取按钮是否开启自动重复 |
setAutoRepeatInterval(self, arg__1) | arg_1:int | None | 设置按钮自动重复间隔时间,参数为毫秒 |
autoRepeatInterval(self) | None | int | 设置按钮自动重复间隔时间 |
setAutoRepeatDelay(self, arg__1) | arg_1:int | None | 设置按钮首次自动重复延迟时间,参数为毫秒 |
autoRepeatDelay(self) | None | int | 获取按钮首次自动重复延迟时间 |
setDown(self, arg__1) | arg_1:bool | None | 设置按钮是否为按下状态 |
isDown(self) | None | bool | 获取按钮是否为按下状态 |
setCheckable(self, arg__1) | arg_1:bool | None | 设置按钮是否可以选中或标记 |
isCheckable(self) | None | bool | 获取按钮是否可以选中或标记 |
setChecked(self, arg__1) | arg_1:bool | None | 设置按钮是否处于选中状态 |
isChecked(self) | None | bool | 获取按钮是否处于选中状态 |
三、按钮的尺寸、焦点、鼠标、外观等设置
按钮类继承自QWidget,所以,其大小设置同QWidget。常用的尺寸设置方法如reSize()、move()等;焦点设置setFocus()等(按钮获取焦点会有围绕的线框标识);鼠标设置setCursor()等,以及外观的所有设置按钮类都可以使用。
四、按钮的标题、图标、自动重复设置
1.标题及图标设置
按钮的标题的设置与获取使用setText()与text()方法,图标使用setIcon()与icon()方法。
setIcon()方法的参数是QIcon(图标)类。这里对QIcon进行简要介绍,具体在图片类中学习。
QIcon可以从给定的像素图集合中生成较小的、较大的、激活的和禁用的像素图。Qt UI组件使用这样的像素图来显示代表特定操作的图标。它有多个实例的创建方式,如下:
API函数 | 参数说明 | 返回值 | 功能作用 |
QIcon(fileName) | fileName:str | None | 设置按钮的是否排他 |
QIcon(pixmap) | pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str] | None | 获取按钮是否排他 |
想要图标美观统一,如果使用图片,需要图片是透明背景、大小适中的。目前大部分实际开发工作中采用的是矢量图标或者字体图标,深入的将在图片类的图标章节中学习,现阶段我们只使用“*png”图片。由于QPixmap也没有学习,这里只使用最简单方式QIcon(fileName)来创建,fileName参数就是我们使用图片的路径。需要说明的是所使用的的图片最好是“.png”和“.jpeg”格式的。
另外,可能我们使用的图片过大或者过小(图片过大会使得按钮尺寸变化,过小看不清),QAbstractButton还提供setIconSize( )方法便于我们调整图标的尺寸。
example:
from PySide6.QtWidgets import QApplication,QWidget,QPushButton
from PySide6.QtGui import QIcon
from PySide6.QtCore import Qt
import sys
class testWindow(QWidget):
def __init__(self):
super(testWindow, self).__init__()
self.setWindowTitle("按钮标题与图标设置")
self.resize(500,500)
btn = QPushButton(self)
btn.resize(200,50)
# 按钮位置居中
x = (self.width() - btn.width())/2
y = (self.height() - btn.height())/2
btn.move(x,y)
btn.setText("测试按钮")
icon = QIcon("C:/Users/Administrator/Pictures/打印.jpg")
btn.setIcon(icon)
# 获取当前图标大小
iconSize = btn.iconSize()
# 对图标尺寸进行宽高等比缩放
iconSize.scale(btn.size(),Qt.AspectRatioMode.KeepAspectRatio)
btn.setIconSize(iconSize)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = testWindow()
win.show()
sys.exit(app.exec())
运行结果:
字体显得小了,那就需要学了QFont类之后再调整,哈哈!
2.按钮的自动重复设置
所谓按钮的自动重复,就是当我们用鼠标按住按钮时能否多次触发点击事件。通常,我们在按钮上按下鼠标左、右键后会触发按钮的点击事件,同时按钮会有相应的外观改变,如颜色变深(视觉上被按下)、执行动画点击等。此时,如果我们不松开按键,那么那就只会触发一次点击事件。
如果使用自动重复设置setAutoRepeat(True),则在不松开按键的情况下,在每间隔一定的时间后会模拟点击按钮的行为,这个行为只触发按钮点击事件,外观不会显现出被点击的样式改变。那么,这个间隔的事件如定时器一样,通过setAutoRepeatInterval()方法设置触发的间隔毫秒数。另外,setAutoRepeatDelay()用来设置从鼠标点击触发事件后至第一次自动重复时中间的间隔时间。
3.按钮的点击
通常按钮的点击是用户通过鼠标或者键盘的enter键完成的(当按钮拥有焦点时),但Pyside6提供了几个点击按钮的方法供开发人员使用:
其中click()、animateClick()可用于所有按钮,这两者的区别在于,animateClick()在外观上模拟鼠标点击按钮后的按钮变化,而click()只是事件相应,外观无变化。toggle()只能用与QRadioButton和QCheckBox,对按钮的勾选状态进行改变。click()、animateClick()可以触发所有按钮的clicked信号,也可以触发QRadioButton和QCheckBox的toggled信号,toggle()只能触发toggled信号。
example:
from PySide6.QtWidgets import QApplication,QWidget,QPushButton,QCheckBox
from PySide6.QtGui import QIcon
from PySide6.QtCore import Qt
import sys
class testWindow(QWidget):
def __init__(self):
super(testWindow, self).__init__()
self.setWindowTitle("按钮测试")
self.resize(500,500)
btn = QPushButton(self)
btn.resize(200,50)
# 按钮位置居中
x = (self.width() - btn.width())/2
y = (self.height() - btn.height())/2
btn.move(x,y)
btn.setText("测试按钮")
icon = QIcon("C:/Users/Administrator/Pictures/打印.jpg")
btn.setIcon(icon)
# 获取当前图标大小
iconSize = btn.iconSize()
# 对图标尺寸进行宽高等比缩放
iconSize.scale(btn.size(),Qt.AspectRatioMode.KeepAspectRatio)
btn.setIconSize(iconSize)
# 自动重复的相关设置
btn.setAutoRepeat(True)
btn.setAutoRepeatInterval(2000)
btn.setAutoRepeatDelay(3000)
# 按钮链接到槽函数,打印“按钮被点击了”
btn.clicked.connect(lambda :print("按钮btn被点击了"))
btn_test1 = QPushButton("测试动画点击",self)
btn_test1.clicked.connect(lambda :btn.animateClick())
btn_test1.move(50,50)
btn_test2 = QPushButton("测试clicked()方法",self)
btn_test2.clicked.connect(lambda :btn.click())
btn_test2.move(150,50)
checkbox = QCheckBox("测试复选框",self)
checkbox.toggled.connect(lambda :print("勾选状态改变了"))
checkbox.clicked.connect(lambda :print("checkBox被点击了"))
checkbox.move(150,150)
btn_test3 = QPushButton("测试toggle()方法",self)
btn_test3.clicked.connect(lambda :checkbox.toggle())
btn_test3.move(300,50)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = testWindow()
win.show()
sys.exit(app.exec())
运行结果:
20240926-214530
五、按钮的状态
按钮的状态需要分两种情况来说:
一种是按压类按钮,拥有状态:是否可用;是否按下
第二种是勾选类按钮,拥有状态:是否可用;是否可以更改勾选状态;是否已更改了勾选状态
example:
from PySide6.QtWidgets import QApplication,QWidget,QPushButton,QCheckBox,QFormLayout,QSizePolicy
from PySide6.QtGui import QIcon
import sys
class testWindow(QWidget):
def __init__(self):
super(testWindow, self).__init__()
self.setWindowTitle("按钮状态菜单测试")
self.resize(500,500)
layout = QFormLayout()
self.setLayout(layout)
pushbtnAble = QPushButton(self)
pushbtnAble.setIcon(QIcon("C:/Users/Administrator/Pictures/打印.jpg"))
pushbtnAble.setEnabled(True)
pushbtnAble.setSizePolicy(QSizePolicy.Policy.Preferred,QSizePolicy.Policy.Expanding)
pushbtnNoable = QPushButton(self)
pushbtnNoable.setIcon(QIcon("C:/Users/Administrator/Pictures/打印.jpg"))
pushbtnNoable.setEnabled(False)
pushbtnNoable.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
pushbtnNodown = QPushButton(self)
pushbtnNodown.setIcon(QIcon("C:/Users/Administrator/Pictures/打印.jpg"))
pushbtnNodown.setDown(False)
pushbtnNodown.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
pushbtndown = QPushButton(self)
pushbtndown.setIcon(QIcon("C:/Users/Administrator/Pictures/打印.jpg"))
pushbtndown.setDown(True)
pushbtndown.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
checkboxAble = QCheckBox(self)
checkboxAble.setEnabled(True)
checkboxAble.setIcon(QIcon("woman.jpeg"))
checkboxNoable = QCheckBox(self)
checkboxNoable.setEnabled(False)
checkboxNoable.setIcon(QIcon("woman.jpeg"))
checkbox_checkable = QCheckBox(self)
checkbox_checkable.setCheckable(True)
checkbox_checkable.setIcon(QIcon("man.jpeg"))
checkbox_checkNoable = QCheckBox(self)
checkbox_checkNoable.setCheckable(False)
checkbox_checkNoable.setIcon(QIcon("man.jpeg"))
checkbox_checked= QCheckBox(self)
checkbox_checked.setChecked(True)
checkbox_checked.setIcon(QIcon("man.jpeg"))
layout.addRow("按压按钮可用:",pushbtnAble)
layout.addRow("按压按钮不可用:", pushbtnNoable)
layout.addRow("按压按钮未被按下:",pushbtnNodown)
layout.addRow("按压按钮被按下:", pushbtndown)
layout.addRow("复选按钮可用:",checkboxAble)
layout.addRow("复选按钮不可用:", checkboxNoable)
layout.addRow("复选按钮可以更改状态:", checkbox_checkable)
layout.addRow("复选按钮不可更改状态:", checkbox_checkNoable)
layout.addRow("复选按钮处于勾选状态:", checkbox_checked)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = testWindow()
win.show()
sys.exit(app.exec())
运行结果:
上例中说明了这些状态的区别,对于不可用状态,按压按钮和勾选按钮都是无法操作的(鼠标点击没反应),而且图标成灰色状态。对于按钮按钮的是否按下状态,可以看到被按下的按钮有明显的背景色改变。对于勾选按钮,不可更改状态,即setCheckable(False)外观上虽然没有什么区别,但是也是不可操作的。
五、按钮的独占设置
按钮的独占的意思是同父级的情况下,多个按钮只有一个按钮可以操作,这个属性对于按压类按钮没有意义,主要是针对勾选类按钮。也就是说存在多个同类的勾选按钮时,这里按钮都设置了独占,那么勾选任一一个,其他的都不能再勾选。
默认情况下,QRadio的独占是True,而QCheckBox则是False。
具体效果在QRadio和QCheckBox控件中学习。
六、按钮的点击有效区设置
所谓的按钮点击的有效区域,就是我们用鼠标指针点击按钮时,在按钮的哪个范围才能生效。默认情况下是,按钮的整个边框范围内都可以。但,我们可以通过hitButton()方法进行更改。更改时需要重写hitButton(),在hitButton()方法中重新定义有效区域,即位于定义区域只能函数返回值为True,否则返回False。
example:
from PySide6.QtWidgets import QWidget,QApplication,QPushButton
from PySide6.QtGui import QPainter,QPen,QColor
import sys
import math
class mybtn(QPushButton):
def hitButton(self, pot):
#这里的pot是局部坐标,相对于控件自身的坐标
x,y = pot.x(),pot.y()
x0,y0 = self.width()/2,self.height()/2
# 圆的方程
r = math.sqrt((x-x0)*(x-x0)+(y-y0)*(y-y0))
# 当r > self.width()/2,说明点已经在已self.width()/2为半径的圆外面
if r > self.width()/2:
return False
return True
def paintEvent(self, evt):
#这里注意父类绘制事件要写在前面,不然遮盖掉了,看不到圈圈
super(mybtn, self).paintEvent(evt)
painter = QPainter(self)
# 设置红色画笔
painter.setPen(QPen(QColor(200,100,50),6))
# 在控件的rect范围内绘制圆,这个圆与点击有效区重合
painter.drawEllipse(self.rect())
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QAbstractButton的有效区设置")
self.resize(500, 500)
self.move(400, 200)
self.setup_ui()
def setup_ui(self):
btn = mybtn(self)
btn.setText("按钮")
btn.move(100,100)
btn.resize(200,200)
btn.pressed.connect(self.test)
def test(self):
print("点击到了有效区")
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
运行结果:
最后,还有一个group()方法,这个是获取按钮所在的按钮组对象,将在后面QButtonGroup类中学习。
七、QAbstractButton的信号
信号 | 参数说明 | 返回值 | 功能作用 |
pressed() | None | 按下按钮时发射信号,同时将参数传递给槽函数 | |
released() | None | 释放按钮时发射信号,同时将参数传递给槽函数 | |
clicked(bool) | bool | 点击按钮(按下和释放)时发射信号,同时将参数传递给槽函数 | |
toggled(bool) | bool | 按钮选中和未选中状态切换时发射信号,同时将参数传递给槽函数 |