需求
最近有一个需求就是一个QTabWidget要求有四个tab页在左侧用于显示主页面,在右侧有一个关于按钮,点击后用于弹出窗口显示一些程序相关信息。主要是怎么实现右侧按钮
- 直接new一个QPushButton,然后以QTabWidget作为父对象,然后将按钮移动到正确位置上。在每次QTabWidget大小发生变化时修改QPushButton的位置即可。
- 使用QStyle QStyleOptionButton 直接绘制按钮实现相关功能 考虑到用尽费退选择第二种方法实现
关键代码
CustomTableWidget
#include "CustomTableWidget.h"
#include <QPaintEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QTabBar>
#include <QDebug>
#include <QEvent>
CustomTableWidget::CustomTableWidget(QWidget *parent) : QTabWidget(parent)
{
setMouseTracking(true);
m_aboutBtn = new QPushButton;
m_aboutBtn->setStyleSheet("QPushButton{border: 1px solid red; color: white}"
"QPushButton:hover{color: #e9bbc0}");
m_aboutBtnOption.state |= QStyle::State_Enabled;
m_aboutBtnOption.text = QStringLiteral("关于");
}
CustomTableWidget::~CustomTableWidget()
{
delete m_aboutBtn;
m_aboutBtn = nullptr;
}
void CustomTableWidget::paintEvent(QPaintEvent *event)
{
QTabWidget::paintEvent(event);
QPainter painter(this);
QRect tabWidgetRect = event->rect();
if(this->tabBar()){
if(tabWidgetRect == this->tabBar()->rect() || tabWidgetRect == this->tabBar()->tabRect(0) || tabWidgetRect == this->tabBar()->tabRect(1)){
return;
}
}
m_aboutBtnRect = QRect(tabWidgetRect.topRight().x() - 60, tabWidgetRect.topRight().y(), 60, 37);
m_aboutBtnOption.rect = m_aboutBtnRect;
m_aboutBtn->style()->drawControl(QStyle::CE_PushButton, &m_aboutBtnOption, &painter, m_aboutBtn);
}
void CustomTableWidget::mouseMoveEvent(QMouseEvent *event)
{
QTabWidget::mouseMoveEvent(event);
if(m_aboutBtnRect.contains(event->pos())){
if(!m_aboutBtnOption.state.testFlag(QStyle::State_MouseOver)){
m_aboutBtnOption.state |= QStyle::State_MouseOver;
this->repaint();
}
}else{
if(m_aboutBtnOption.state.testFlag(QStyle::State_MouseOver)){
m_aboutBtnOption.state = m_aboutBtnOption.state & (~QStyle::State_MouseOver);
this->repaint();
}
}
}
void CustomTableWidget::leaveEvent(QEvent *event)
{
QTabWidget::leaveEvent(event);
if(m_aboutBtnOption.state.testFlag(QStyle::State_MouseOver)){
m_aboutBtnOption.state = m_aboutBtnOption.state & (~QStyle::State_MouseOver);
this->repaint();
}
}
main.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTabBar>
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->tabWidget->setAttribute(Qt::WA_StyledBackground);
m_widget1 = new QWidget;
m_widget1->setMouseTracking(true);
m_widget2 = new QWidget;
m_widget2->setMouseTracking(true);
ui->tabWidget->addTab(m_widget1, QStringLiteral("页面一"));
ui->tabWidget->addTab(m_widget2, QStringLiteral("页面二"));
m_widget1->parentWidget()->setMouseTracking(true);
}
Widget::~Widget()
{
delete ui;
}
解析
m_widget1->setMouseTracking(true);
m_widget2->setMouseTracking(true);
子控件遮挡父控件导致父控件接受不到 鼠标移动 事件。虽然
void QWidget::mouseMoveEvent(QMouseEvent *event)
{
event->ignore();
}
QWidget的鼠标移动默认行为就是没有行为而且会向上传递。但是我们必须 setMouseTracking(true)
否则它根本不会由notify
发送给event
。所以我们要设置m_widget1
m_widget2
为true。
QTabWidget的结构如下
m_widget1->parentWidget()->setMouseTracking(true);
所以还要设置这个,因为 m_widget1
还套了一个 QStackedWidget
if(this->tabBar()){
if(tabWidgetRect == this->tabBar()->rect() || tabWidgetRect == this->tabBar()->tabRect(0) || tabWidgetRect == this->tabBar()->tabRect(1)){
return;
}
}
如上图所示,当我们点击tabBar
相关区域时也会触发 tabWidget
的paintEvent
函数。此时QRect tabWidgetRect = event->rect();
tabWidgetRect
是 这个tabBar的 rect或者是某一个 tab 页的宽度,需要被排除在外。
效果图
最后在看看效果吧,家人们