相关函数使用
设置位置和大小
// 重新设定按钮的位置
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
效果图如下:
鼠标悬浮弹出按钮实现
两个关键类如下:
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);
}
源码实现