美化QTabWidget[通俗易懂]

美化QTabWidget[通俗易懂]美化QTabWidget1.效果展示2.用法展示MainWindow::MainWindow(QWidget*parent):QMainWindow(parent),ui(newUi::MainWindow){ui->setupUi(this);setupUI();ui->tabWidget->addTab2(newQWidget(),tr(“thisisfirsttab”));}MainWindo

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

美化QTabWidget

在这里插入图片描述

1.效果展示

在这里插入图片描述

2.用法展示

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{ 
   
    ui->setupUi(this);
    setupUI();
    ui->tabWidget->addTab2(new QWidget(), tr("this is first tab"));
}

MainWindow::~MainWindow()
{ 
   
    delete ui;
}

void MainWindow::setupUI()
{ 
   
    connect(ui->tabWidget, SIGNAL(TabInserted(int)), this, SLOT(OnTabInserted(int)));
    connect(ui->tabWidget, SIGNAL(AddBtnClicked()), this, SLOT(OnAddBtnClicked()));
    connect(ui->tabWidget, SIGNAL(TabClosed(int)), this, SLOT(OnCloseTab(int)));
}

void MainWindow::OnTabInserted(int index)
{ 
   
    QPushButton *button = new QPushButton();
    button->setFixedSize(this->iconSize());
    button->setStyleSheet("border-image: url(:/images/x-capture-options.png);");
    ui->tabWidget->setTabButton2(index, QTabBar::LeftSide, button);

    button = new QPushButton();
    button->setStyleSheet("QPushButton{border-image: url(:/images/close.png)}"
                          "QPushButton:hover{border-image: url(:/images/close_hover.png)}");
    ui->tabWidget->setTabButton2(index, QTabBar::RightSide, button);
}

void MainWindow::OnTabClosed(int index)
{ 
   
    //todo something
}

void MainWindow::OnAddBtnClicked()
{ 
   
    ui->tabWidget->addTab2(new QWidget(), tr("this is first tab"));
}

3.原理简介

主要原理就是对paintEvent重写,以及QProxyStyle继承重新实现。我也是翻了很多资料,看了实现的源码才知道的。

  • QExtTabBarStyle继承自QProxyStyle
void QExtTabBarStyle::drawPrimitive(PrimitiveElement pe, 
                const QStyleOption *option, 
                QPainter *painter,
                const QWidget *widget) const
{ 
   
    if (pe == QStyle::PE_IndicatorArrowLeft) { 
   
        drawArrow(pe, option, painter, widget);
    } else if (pe == QStyle::PE_IndicatorArrowRight) { 
   
        drawArrow(pe, option, painter, widget);
    } else{ 
   
        QProxyStyle::drawPrimitive(pe, option, painter, widget);
    }
}

int QExtTabBarStyle::pixelMetric(PixelMetric metric, 
            const QStyleOption *option, 
            const QWidget *widget) const
{ 
   
    if (PM_TabBarScrollButtonWidth == metric) { 
   
        return 30;
    } else { 
   
        return QProxyStyle::pixelMetric(metric, option, widget);
    }
}

QRect QExtTabBarStyle::subElementRect(SubElement element, 
                                        const QStyleOption *option, 
                                        const QWidget *widget) const
{ 
   
    if (SE_TabBarTabLeftButton == element) { 
   
        return calcIconRect(true, option);
    } else if (SE_TabBarTabRightButton == element) { 
   
        return calcIconRect(false, option);
    } else { 
   
        return QProxyStyle::subElementRect(element, option, widget);
    }
}

QRect QExtTabBarStyle::calcIconRect(bool left, const QStyleOption *option) const
{ 
   
    const QStyleOptionTab *tab_option = qstyleoption_cast<const QStyleOptionTab *>(option);
    QSize icon_size = tab_option->iconSize;
    const QRect tab_rect = tab_option->rect;
    QPoint center_pos;
    QRect button_rect;
    const int icon_padding = 8;
    if (left) { 
   
        center_pos = QPoint(icon_padding+icon_size.width()/2+tab_rect.x(), 
                            tab_rect.y()+(tab_rect.height()-icon_size.height())/2+icon_size.height()/2);
    } else { 
   
        center_pos = QPoint(tab_rect.x()+tab_rect.width()-icon_padding-icon_size.width()/2, 
                                tab_rect.y()+(tab_rect.height()-icon_size.height())/2+icon_size.height()/2);
    }
    button_rect = QRect(QPoint(0, 0), icon_size);
    button_rect.moveCenter(center_pos);
    return button_rect;
}

void QExtTabBarStyle::drawArrow(PrimitiveElement pe, const QStyleOption *option, 
                                QPainter *painter,
                                const QWidget *widget) const
{ 
   
    const QToolButton *tool_btn = static_cast<const QToolButton *>(widget);
    if (nullptr != tool_btn && !tool_btn->isVisible()) 
        return;
    painter->save();
    const QStyleOptionTab *tab_option = qstyleoption_cast<const QStyleOptionTab *>(option);
    QBrush rect_brush;
    if (!tool_btn->isEnabled()) { 
   
        rect_brush = Qt::transparent;
    } else if (tool_btn->underMouse()) { 
   
        rect_brush = QColor(214, 214, 214);
    } else { 
   
        rect_brush = Qt::transparent;
    }
    QRect draw_rect = QRect(0, 0, 16, 16);
    draw_rect.moveCenter(option->rect.center());
    RoundShadowHelper round_helper;
    round_helper.FillRoundShadow(painter, option->rect,rect_brush.color(), 4);
    painter->restore();
    QProxyStyle::drawPrimitive(pe, option, painter, widget);
}
  • QTabBar中的paintEvent重写
void QtExtTabBar::paintEvent(QPaintEvent *event)
{ 
   
    QPainter painter(this);
    drawTab(&painter);
    if (tab_add_button_.draw_plus_btn_)
        drawPlusBtn(&painter);
}

void QtExtTabBar::drawTab(QPainter *painter)
{ 
   
    RoundShadowHelper helper(6,4);
    int border = helper.GetShadowWidth()/2.0;
    painter->save();
    int tab_count = tab_add_button_.draw_plus_btn_ ? count()-1 : count();
    QStyleOptionTabV3 option;
    for (int index = 0; index < tab_count; index++) { 
   
        QRect rect = tabRect(index);
        initStyleOption(&option, index);
        // draw background 
        QRect draw_rect = QRect(QPoint(rect.x()+border, rect.y() + border), QSize(rect.width()-border*2, rect.height()-border*2));
        drawTabBg(painter, helper, option, draw_rect, rect);
        drawTabText(painter, draw_rect, option);
    }
    painter->restore();
}

void QtExtTabBar::drawTabText(QPainter *painter, const QRect &draw_rect, const QStyleOptionTabV3 &option)
{ 
   
    // draw text
    QColor text_color = tb_text_color_.Normal_;
    QRect text_rect = draw_rect.marginsAdded(margins_);
    if (QStyle::State_Selected & option.state) { 
   
        text_color = tb_text_color_.Selected_;
    } else if (QStyle::State_MouseOver & option.state) { 
   
        text_color = tb_text_color_.Hover_;
    }
    painter->setPen(text_color);
    QString text = fontMetrics().elidedText(option.text, Qt::ElideRight, text_rect.width(), 0); 
    painter->drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, text);
}

void QtExtTabBar::drawTabBg(QPainter *painter, RoundShadowHelper &helper, 
                            const QStyleOptionTabV3 &option, QRect draw_rect, QRect real_rect)
{ 
   
    painter->setPen(Qt::NoPen);
    if(QStyle::State_Selected & option.state) { 
   
        helper.RoundShadow(painter, real_rect);
        helper.FillRoundShadow(painter, draw_rect, tb_bg_color_.Selected_, helper.GetRadius());
    } else if(QStyle::State_MouseOver & option.state) { 
   
        helper.FillRoundShadow(painter, draw_rect, tb_bg_color_.Hover_, helper.GetRadius());
    }
}

void QtExtTabBar::drawPlusBtn(QPainter *painter)
{ 
   
    painter->save();
    int last_index = count()-1;
    QStyleOptionTabV3 option;
    initStyleOption(&option, last_index);
    QRect draw_rect = QRect(QPoint(0, 0), tab_add_button_.tab_add_btn_size_);
    draw_rect.moveCenter(tabRect(last_index).center());
    DrawCircle::Draw(painter, draw_rect, tab_btn_add_color_);
    DrawCharacter::DrawPlus(painter, draw_rect);
    painter->restore();
}

4.属性设置

  • 可以自定义tab中的左右button。

  • 可以自定义tab中文字的颜色。

  • 可以设置是否需要绘制“+”按钮。

其他的都可以在代码中找到

5.todo list

  • 不支持tab拖拽
  • 不支持tab, tab button 贴图。

关注微信公众号,获取源码。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/190078.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月2日 下午11:22
下一篇 2026年3月3日 上午7:01


相关推荐

  • CAN协议 J1939「建议收藏」

    CAN协议 J1939「建议收藏」转自:http://blog.sina.com.cn/s/blog_bf97bd7e0102wl2y.html这几天在公司看了SAE推行的J1939标准(SAE:美国汽车工程协会),这里整理下学习要点,主要包含以下几个协议:物理层SAEJ1939-11(未看)数据链路层SAEJ1939-21网络层SAEJ1939-31(未看)应用层SAEJ1939-…

    2022年5月26日
    65
  • kafka与rocketmq优劣势_kafka rocketmq rabbitmq

    kafka与rocketmq优劣势_kafka rocketmq rabbitmq前言:公司采用了两种消息队列,一种是阿里云的rocketMQ,一种是kafka.分别用在了两种不同的场景.这里做个记录.rocketMQ使用场景:1.异步解耦:拿我们的项目举例,有一个场景,是需要pc端触发派单接口,然后发送给app端消息通知.此时要求能够做到每个app都能收到消息,但是又希望这个发送的过程尽量的短,也就是派单接口尽量快.那么这个派送的过程可以采用rocketM…

    2022年8月31日
    9
  • spring自定义注解实现(spring里面的注解)

    java注解:附在代码中的一些元信息,用于在编译、运行时起到说明、配置的功能。一、元注解java提供了4中元注解用于注解其他注解,所有的注解都是基于这四种注解来定义的。@Target注解:用于描述注解的使用范围,超出范围时编译失败。 取值类型(ElementType):  1.CONSTRUCTOR:用于描述构造器  2.FIELD:用于描述域(成

    2022年4月15日
    26
  • 零成本自建临时邮箱:Cloudflare 部署避坑指南

    零成本自建临时邮箱:Cloudflare 部署避坑指南

    2026年3月18日
    3
  • python处理亿级大数据(rar暴力破解器安卓版)

    转载请注明出处:https://blog.csdn.net/l1028386804/article/details/85566045今天是2019年元旦,首先祝大家元旦快乐,在这个喜庆的日子里,不知道大家有没有坚持研究自己所在领域的知识。其实,每项知识、技能的积累,需要的是日复一日的坚持,正所谓——持之以恒,贵在坚持,这样才能做到每天进步一点点。好了,步入正题,今天,闲来无事,基于Python…

    2022年4月15日
    53
  • redis客户端连接(error) NOAUTH Authentication required「建议收藏」

    redis客户端连接(error) NOAUTH Authentication required「建议收藏」redis客户端连接成功,但是操作报异常——(error)NOAUTHAuthenticationrequired错误的含义是说你没有认证,说明没有使用密码连接查看密码:进入redis的安装目录(是安装目录的),查看redis.config文件viredis.config打开配置文件后,输入#requirepassfoobared(快速定位的命令)然后回车红框里的就是密码使用密码连接.

    2022年5月2日
    72

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号