QPushButton 使用详情与总结

时间:2023-03-25 14:18:39


相关函数使用

设置位置和大小

// 重新设定按钮的位置
pBtnTest->move(100, 50);

// 重新设定按钮的大小
pBtnTest->resize(80, 50);

// 设置按钮的位置和大小
pBtnTest->setGeometry(100, 50, 80, 50);

设置显示文本信息的字体

pBtnTest->setFont(QFont("宋体", 18));

根据文本长度自动调整大小

pBtnTest->setText("我是一个很长很长很长的文本");
    
// adjustSize():自动调整控件的大小,以适应其内容;
pBtnTest->adjustSize();

设置按钮获取焦点

// 设置控件获取焦点
pBtnTest->setFocus();

// 获取控件是否具有焦点;如果控件有焦点,返回 true;
bool b = pBtnTest->hasFocus();
qDebug() << b;

// 清除控件的焦点
pBtnTest->clearFocus();

设置鼠标位于按钮区域时,光标的类型

pBtnTest->setCursor(QCursor(Qt::BusyCursor));

设置按钮的 禁用 和 启用

// 禁用控件
pBtnTest->setDisabled(true);

// 启用控件
pBtnTest->setEnabled(true);

设置按钮背景透明:即将按钮外观设为平铺

pBtnTest->setFlat(true);

设置在控件上按下 回车键 时,响应控件的 click 事件

pBtnTest->setDefault(true);

设置按钮上显示的图标

// 设置按钮上显示的图标
pBtnTest->setIcon(QIcon(":/Image/Luffy.png"));

// 设置图标的大小
pBtnTest->setIconSize(QSize(24, 24));

设置可选按钮

auto earMonitorSwitch = new QPushButton(this);
earMonitorSwitch->setCheckable(true);
earMonitorSwitch->setStyleSheet("QPushButton{border-image:url(./resource/audio/audio_setting/btn_earmonitor_close.png);}"
"QPushButton:checked{border-image:url(./resource/audio/audio_setting/btn_earmonitor_open.png);}");

设置不同状态下的通用CSS

pBtnTest->setStyleSheet("QPushButton{border-image:url(./resource/audio/audio_setting/close_normal.png);border:none;}"
		"QPushButton:hover{border-image:url(./resource/audio/audio_setting/close_hover.png);}"
		"QPushButton:pressed{border-image:url(./resource/audio/audio_setting/close_press.png);}");

设置按钮样式:前景色,背景色,边框等

// 定义初始样式集合
QStringList list;
list.append("color:white");                         // 前景色
list.append("background-color:rgb(85,170,255)");    // 背景色
list.append("border-style:outset");                 // 边框风格
list.append("border-width:5px");                    // 边框宽度
list.append("border-color:rgb(10,45,110)");         // 边框颜色
list.append("border-radius:20px");                  // 边框倒角
list.append("font:bold 30px");                      // 字体
list.append("padding:4px");                         // 内边距

// 设置按钮初始样式
pBtnTest->setStyleSheet(list.join(';'));                      
 
// 按钮按下时修改样式
list.replace(6, "font:bold 35px");
connect(pBtnTest, &QPushButton::pressed, [=](){
       pBtnTest->setStyleSheet(list.join(';'));
});

// 按钮弹起时恢复样式
list.replace(6, "font:bold 30px");
connect(pBtnTest, &QPushButton::released, [=](){
       pBtnTest->setStyleSheet(list.join(';'));
});

为按钮添加右键菜单

auto button = new QPushButton(u8"按钮");
button->setContextMenuPolicy(Qt::ActionsContextMenu);
if (type == AccomSoundType::mySound)
{
	auto deleteAction = new QAction(left);
	deleteAction->setText(u8"删除");
	connect(deleteAction, &QAction::triggered, this, [=]() {
		trace("删除");
	});
	button->addAction(deleteAction);
}

为按钮添加左键菜单

// 菜单
QMenu *pMenu = new QMenu(this);
pMenu->addAction(QString::fromLocal8Bit("设置"));
pMenu->addAction(QString::fromLocal8Bit("版本检测"));
pMenu->addSeparator();
pMenu->addAction(QString::fromLocal8Bit("关于我们"));
pMenu->addAction(QString::fromLocal8Bit("退出"));

// 按钮
QPushButton *pButton = new QPushButton(this);
pButton->setText(QString::fromLocal8Bit("主菜单"));

// 设置菜单
pButton->setMenu(pMenu);

上面的方法会让按钮显示一个下拉的三角形图标,如果想取消这个图片可以用 qss 去除:

QPushButton::menu-indicator#btn_room_setting{
	image:none;
}

按钮菜单实现

实现部分

void MainWidget::initBtnMeun()
{

    this->setStyleSheet("background-color:rgb(54,54,54)");

    QMenu *fileMenuItems = new QMenu;

    //菜单添加icon
    fileMenuItems->setIcon(QIcon(":/resources/file.png"));
    fileMenuItems->setTitle(u8"文件");
    fileMenuItems->setStyleSheet(QString::fromStdString(menuItemQss));

    QList<QAction*> acList;

    // action添加icon
    QAction *openFileAc = new QAction(QIcon(":/resources/file.png"), u8"打开文件", this);
    //openFileAc->setShortcuts(QKeySequence::Print);       //设置快捷键
    openFileAc->setShortcut(QKeySequence("Ctrl+8"));  //随意指定快捷键
    QAction *openFloderAc = new QAction(u8"打开文件夹", this);

    QAction *openUrlAc = new QAction(u8"打开url", this);

    //多级子菜单项
    acList << openFileAc << openFloderAc << openUrlAc;
    fileMenuItems->addActions(acList);

    QMenu *pMenu = new QMenu;  //主菜单
    pMenu->addMenu(fileMenuItems);

    QAction *play = new QAction(QIcon(":/resources/play.png"), u8"播放", this);
    QAction *tools = new QAction(QIcon(":/resources/tools.png"), u8"工具", this);
    pMenu->addAction(play);
    pMenu->addAction(tools);

    pMenu->addSeparator();

    QMenu *setMenuItems = new QMenu;
    setMenuItems->setTitle(u8"设置");
    setMenuItems->setIcon(QIcon(":/resources/set.png"));
    QList<QAction*> setList;

    QAction *sysSetAc = new QAction(u8"系统设置", this);
    QAction *playSetAc = new QAction(u8"播放设置", this);
    QAction *zimuSetAc = new QAction(u8"字幕设置", this);
    setList << sysSetAc << playSetAc << zimuSetAc;
    setMenuItems->addActions(setList);
    setMenuItems->setStyleSheet(QString::fromStdString(menuItemQss));
    pMenu->addMenu(setMenuItems);

    pMenu->addSeparator();

    QAction *exitAc = new QAction(QIcon(":/resources/exit.png"), u8"退出", this);
    pMenu->addAction(exitAc);

    ui->pushButton->setMenu(pMenu);

    connect(openFileAc, &QAction::triggered, [=]{
        QString fileName = QFileDialog::getOpenFileName(this,
                                                        u8"请选择视频文件",
                                                        "D:/",
                                                        "视频(*.mp4 *.flv);;");

        if(fileName.isEmpty())
        {
            return;
        }
    });

    ui->pushButton->setText(u8"QW影音");
    ui->pushButton->setFixedSize(100, 32);
    ui->pushButton->setStyleSheet(QString::fromStdString(button_qss));
    pMenu->setStyleSheet(QString::fromStdString(menuQss));
}

qss 的实现

#ifndef QSS_H
#define QSS_H

#include <string>

using namespace std;

string button_qss = R"(
    QPushButton
    {
        font:18px "Microsoft YaHei";
        color:rgb(255,255,255);
        border:none
    }

    QPushButton::menu-indicator:open
    {
        image:url(:/resources/down_arrow.svg);
        subcontrol-position:right center;
        subcontrol-origin:padding;border:none;
    }

    QPushButton::menu-indicator:closed
    {
        image:url(:/resources/up_arrow.svg);
        subcontrol-position:right center;
        subcontrol-origin:padding;border:none;
    }
)";

string menuQss = R"(
    QMenu
    {
        background-color:rgb(53, 63, 73);
    }

    QMenu::item
    {
         font:16px;
         color:white;
         background-color:rgb(53, 63, 73);
         padding:8px 32px;
         margin:8px 8px;
         /*border-bottom:1px solid #DBDBDB;  item底部颜色*/
    }

    /*选择项设置*/
    QMenu::item:selected
    {
         background-color:rgb(54, 54, 54);
    }
)";

string menuItemQss = R"(
    QMenu
    {
        background-color:rgb(73, 73, 73);
    }

    QMenu::item
    {
         font:16px;
         color:white;
         background-color:rgb(73, 73, 73);
         padding:8px 32px;
         margin:8px 8px;
         /*border-bottom:1px solid #DBDBDB;  item底部颜色*/
    }

    /*选择项设置*/
    QMenu::item:selected
    {
         background-color:rgb(54, 54, 54);
    }
)";

#endif // QSS_H

效果图如下:

QPushButton 使用详情与总结

鼠标悬浮弹出按钮实现

两个关键类如下:
CVolumeButton

/*

音量调节按钮

功能:
	1. 鼠标悬浮到音量时显示slider dialog
	2. 点击时mute

注意问题:
	重写按钮类,样式表无效
*/

#pragma once

#include <QPushButton>
#include "CVolumeSliderDialog.h"


class CVolumeButton : public QPushButton
{
	Q_OBJECT

public:
    CVolumeButton(QWidget* parent = nullptr);
	~CVolumeButton();

	bool getMute() const
	{
		return m_isMute;
	}

	void setMute(bool mute) { m_isMute = mute; }

signals:
	void sig_VolumeValue(int value);

protected:
	void paintEvent(QPaintEvent* event) override;
	void enterEvent(QEvent* event) override;
	//void leaveEvent(QEvent* event) override;
	void mousePressEvent(QMouseEvent* event) override;
	void timerEvent(QTimerEvent* event) override;

private:
	bool m_isMute = false;  //是否静音
	CVolumeSliderDialog* m_pVolumeSliderDlg = nullptr;

    int m_timerId = -1;
};
#include "CVolumeButton.h"
#include <QMouseEvent>
#include <QStylePainter>
#include <QStyleOptionButton>
#include <iostream>
#include <QThread>

using namespace std;

CVolumeButton::CVolumeButton(QWidget* parent)
	: QPushButton(parent)
{
    this->setFixedSize(32,32);

    setStyleSheet("QPushButton{background-image:url(:/resources/audio_open.svg);border:none;}"
        "QPushButton:hover{background-image:url(:/resources/audio_open_hover.svg);border:none;}"
        "QPushButton:pressed{background-image:url(:/resources/audio_open.svg);border:none;}");
}

CVolumeButton::~CVolumeButton()
{
}

void CVolumeButton::paintEvent(QPaintEvent*)
{
	QStylePainter p(this);
	QStyleOptionButton option;
	initStyleOption(&option);
	p.drawControl(QStyle::CE_PushButton, option);
}

void CVolumeButton::enterEvent(QEvent* event)
{
	if (!m_pVolumeSliderDlg)
        m_pVolumeSliderDlg = new CVolumeSliderDialog(this);

	QPoint p1 = this->mapToGlobal(QPoint(0, 0));  //声音按钮左上角相对于桌面的绝对位置
	QRect rect1 = this->rect();
	QRect rect2 = m_pVolumeSliderDlg->rect();     //rect包含标题栏,去掉标题栏后height不变

	int x = p1.x() + (rect1.width() - rect2.width()) / 2;
	int y = p1.y() - rect2.height() - 5;
	m_pVolumeSliderDlg->move(x, y);   //move是相对于桌面原点的位置

	m_pVolumeSliderDlg->show();
    m_timerId = startTimer(250);

	connect(m_pVolumeSliderDlg, &CVolumeSliderDialog::sig_SliderValueChanged, [=](int value) {
		emit sig_VolumeValue(value);
		});
}


//void CVolumeButton::leaveEvent(QEvent* event)
//{
//	根据鼠标的位置判断音量调节窗口是否消失
//	//QPoint p1 = QCursor::pos();   //绝对位置
//
//	//cout << "QCursor x= " << p1.x() << " y = " << p1.y() << endl;
//
//	//if (m_pVolumeSliderDlg)
//	//{
//	//	QRect rect1 = this->rect();  //按钮矩形
//	//	QRect rect2 = m_pVolumeSliderDlg->rect();
//	//	QRect rect3 = m_pVolumeSliderDlg->geometry();
//
//	//	QPoint p2 = this->mapToGlobal(QPoint(0, 0));   //声音按钮左上角相对于桌面的绝对位置
//
//	//	//已知:音量框宽40 > 按钮宽30
//	//	QRect area(rect3.left(), rect3.top(), rect2.width(), p2.y() + rect1.height() - rect3.top()); //左上宽高
//
//	//	cout << "p1 x = " << p1.x() << " y = " << p1.y() << endl;
//
//	//	if (!area.contains(p1))
//	//	{
//	//		m_pVolumeSliderDlg->hide();
//	//	}
//	//}
//}

void CVolumeButton::mousePressEvent(QMouseEvent* event)
{
	if (event->button() == Qt::LeftButton)
	{
		m_isMute = !m_isMute;
		if (m_isMute)
		{
			if (m_pVolumeSliderDlg)
				m_pVolumeSliderDlg->setSliderValue(0);
		}
		else
		{
			if (m_pVolumeSliderDlg)
				m_pVolumeSliderDlg->setSliderValue(50);
		}
	}
}


/**
 * @brief 用定时器模拟leaveEvent,
 * 直接在leaveEvent里让m_pVolumeSliderDlg消失,效果不太好,
 * 用鼠标移动事件也不太好,定时器是比较好的做法
 */
void CVolumeButton::timerEvent(QTimerEvent* event)
{
	if ((m_pVolumeSliderDlg != nullptr) && (m_pVolumeSliderDlg->isVisible()))
	{
		QPoint p1 = QCursor::pos();   //鼠标绝对位置
		if (m_pVolumeSliderDlg)
		{
			QRect rect1 = this->rect();  //按钮矩形
			QRect rect2 = m_pVolumeSliderDlg->rect();
			QRect rect3 = m_pVolumeSliderDlg->geometry();

			QPoint p2 = this->mapToGlobal(QPoint(0, 0));   //声音按钮左上角相对于桌面的绝对位置

			//已知:音量框宽40 > 按钮宽30
			QRect area(rect3.left(), rect3.top(), rect2.width(), p2.y() + rect1.height() - rect3.top()); //左上宽高

			if (!area.contains(p1))
			{
				m_pVolumeSliderDlg->hide();
			}
		}
	}
	else
	{
        killTimer(m_timerId);
	}
}

CVolumeSliderDialog 类

#ifndef CVOLUMESLIDERDIALOG_H
#define CVOLUMESLIDERDIALOG_H

#include <QDialog>
#include <QSlider>

class CVolumeSliderDialog : public QDialog
{
	Q_OBJECT

public:
	CVolumeSliderDialog(QWidget *parent = Q_NULLPTR);
	~CVolumeSliderDialog();

	void setSliderValue(int value)
	{
		m_pSlider->setValue(value);
	}

protected:
	bool event(QEvent* event) override;

signals:
	void sig_SliderValueChanged(int value);

private:
	QSlider* m_pSlider = nullptr;
};

#endif
#include "CVolumeSliderDialog.h"
#include <QVBoxLayout>
#include <QEvent>
#include <windows.h>


//注意由于此类使用了windows的函数SetClassLong,需要包含user32.lib
//如果是在vs2019中使用则不需要包含user32.lib
#pragma comment(lib, "user32.lib")

CVolumeSliderDialog::CVolumeSliderDialog(QWidget* parent)
	: QDialog(parent)
{
	this->setFixedSize(40, 200);
	QVBoxLayout* pVLay = new QVBoxLayout(this);
	m_pSlider = new QSlider(this);
	m_pSlider->setOrientation(Qt::Vertical);
	pVLay->addWidget(m_pSlider);

	setFixedSize(40, 120);
    setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip);   //ToolTip : 悬浮是显示,离开时消失
    setStyleSheet("QDialog{background-color: rgba(54, 54, 54, 0.5);}");  //0.5表示透明度,0表示全透明、1表示不透明;也可以使用百分百表示如: frm->setStyleSheet(“QFrame{background-color: rgba(255, 0, 0, 50%);}”);

	connect(m_pSlider, &QSlider::valueChanged, [=](int value) {
		emit sig_SliderValueChanged(value);
		});
}

CVolumeSliderDialog::~CVolumeSliderDialog()
{
}

//参考qt文档:bool QWidget::event(QEvent *event)
//设置popup后,dialog有窗口阴影,需要去除就重写event函数
bool CVolumeSliderDialog::event(QEvent* event)
{
    static bool class_amended = false;

    if (event->type() == QEvent::WinIdChange)
    {
        HWND hwnd = (HWND)winId();

        if (class_amended == false)
        {
            class_amended = true;
            DWORD class_style = ::GetClassLong(hwnd, GCL_STYLE);
            class_style &= ~CS_DROPSHADOW;
            ::SetClassLong(hwnd, GCL_STYLE, class_style); // windows系统函数
        }
    }

	return QWidget::event(event);
}

实现部分

void MainWidget::initHoteBtnMenu()
{
    QHBoxLayout *pHlay = new QHBoxLayout(this);

    CVolumeButton* pVolumeButton = new CVolumeButton(this);
    pHlay->addWidget(pVolumeButton);

}

源码实现