Qt 实现自定义分段控制器

分段控制器在前端交互使用较为广泛,相比 Qt 常用的下拉框、单选框、复选框,选择交互上更为便捷,样式上更加简洁可控,使用 Qt 实现带类似功能的控件,可复用到选项需求的功能开发,提高软件质量。

功能包括选项输入、样式接口、默认选中、互斥检测、结果回传,以 https://forgeglobal.com/ 网站的实现为参考。

QSegmentedWidget.h

cpp 复制代码
class QSegmentedWidget : public QWidget
{
    Q_OBJECT

public:
    QSegmentedWidget(QWidget *parent = nullptr);
    ~QSegmentedWidget();
    bool eventFilter(QObject *watched, QEvent *event);

    void setSource(QStringList lst, QString ss);

    void setHoverColor(QString color)
    {
        hoverColor = color;
        updateColor();
    }

    void setHoverTextColor(QString color)
    {
        hoverTextColor = color;
        updateColor();
    }

    void setCheckColor(QString color)
    {
        checkColor = color;
        updateColor();
    }

private slots:
    void setChecked();

    void updateColor()
    {
        btnStyleNormal = QString("QPushButton{background-color: rgb(255,255,255);color: rgb(95,110,124); font: 14pt \"Microsoft YaHei\"; border: 1px solid;border-radius:0px;}QPushButton:hover{background-color: rgb(%1);color: rgb(%2);}").arg(hoverColor).arg(hoverTextColor);

        btnStyleCheck = QString("QPushButton{background-color: rgb(%2);color: rgb(247,249,250); font: 14pt \"Microsoft YaHei\"; border: 1px solid;border-radius:0px;}QPushButton:hover{background-color: rgb(%1);color: rgb(%3);}").arg(hoverColor).arg(checkColor).arg(hoverTextColor);

        btnStyleNormalFirst = QString("QPushButton{background-color: rgb(255,255,255);color: rgb(95,110,124); font: 14pt \"Microsoft YaHei\"; border: 1px solid;border-top-left-radius: 5px;border-top-right-radius: 0px;border-bottom-left-radius: 5px;border-bottom-right-radius: 0px;}QPushButton:hover{background-color: rgb(%1);color: rgb(%2);}").arg(hoverColor).arg(hoverTextColor);

        btnStyleCheckFirst = QString("QPushButton{background-color: rgb(%2);color: rgb(247,249,250); font: 14pt \"Microsoft YaHei\"; border: 1px solid;border-top-left-radius: 5px;border-top-right-radius: 0px;border-bottom-left-radius: 5px;border-bottom-right-radius: 0px;}QPushButton:hover{background-color: rgb(%1);color: rgb(%3);}").arg(hoverColor).arg(checkColor).arg(hoverTextColor);

        btnStyleNormalLast = QString("QPushButton{background-color: rgb(255,255,255);color: rgb(95,110,124); font: 14pt \"Microsoft YaHei\"; border: 1px solid;border-top-left-radius: 0px;border-top-right-radius: 5px;border-bottom-left-radius: 0px;border-bottom-right-radius: 5px;}QPushButton:hover{background-color: rgb(%1);color: rgb(%2);}").arg(hoverColor).arg(hoverTextColor);

        btnStyleCheckLast = QString("QPushButton{background-color: rgb(%2);color: rgb(247,249,250); font: 14pt \"Microsoft YaHei\"; border: 1px solid;border-top-left-radius: 0px;border-top-right-radius: 5px;border-bottom-left-radius: 0px;border-bottom-right-radius: 5px;}QPushButton:hover{background-color: rgb(%1);color: rgb(%3);}").arg(hoverColor).arg(checkColor).arg(hoverTextColor);
    }

signals:
    void emitChecked(QString ss);

private:
    QString hoverColor = "30,36,42";
    QString hoverTextColor = "247,249,250";
    QString checkColor = "30,36,42";
    QStringList sourceLst;
    QList<QPushButton*> btnLst;
    QHBoxLayout *layout = nullptr;
    QString btnStyleNormal;
    QString btnStyleCheck;
    QString btnStyleNormalFirst;
    QString btnStyleCheckFirst;
    QString btnStyleNormalLast;
    QString btnStyleCheckLast;
    QPushButton *curBtn = nullptr;
    QPixmap pixmap;
};

QSegmentedWidget.cpp

cpp 复制代码
#include <QSvgRenderer>
QPixmap svg2Pixmap(QString svg)
{
    QSvgRenderer render;
    render.load(svg);

    QPixmap pix(render.defaultSize());
    pix.fill(Qt::transparent);

    QPainter painter(&pix);
    painter.setRenderHints(QPainter::Antialiasing);
    render.render(&painter);

    return pix;
}

QSegmentedWidget::QSegmentedWidget(QWidget *parent)
    : QWidget(parent)
{
    layout = new QHBoxLayout;
    layout->setSpacing(0);
    setLayout(layout);

    updateColor();

    pixmap = svg2Pixmap("check.svg");
}

QSegmentedWidget::~QSegmentedWidget()
{

}

bool QSegmentedWidget::eventFilter(QObject *watched, QEvent *event)
{
    Q_UNUSED(watched);

    if (event->type() == QEvent::Enter)
    {
        setCursor(Qt::PointingHandCursor);
        return true;
    }

    if (event->type() == QEvent::Leave)
    {
        setCursor(Qt::ArrowCursor);
        return true;
    }

    return false;
}

void QSegmentedWidget::setSource(QStringList lst, QString cc)
{
    curBtn = nullptr;

    foreach (QPushButton* btn, btnLst)
    {
        layout->removeWidget(btn);
        delete btn;
    }

    btnLst.clear();

    sourceLst = lst;

    foreach (QString data, lst)
    {
        QPushButton *btn = new QPushButton(data);
        btn->setFixedSize(90, 50);
        btn->setObjectName(data);
        if (data == sourceLst.first())
        {
            btn->setStyleSheet(btnStyleNormalFirst);
        }
        else if (data == sourceLst.last())
        {
            btn->setStyleSheet(btnStyleNormalLast);
        }
        else
        {
            btn->setStyleSheet(btnStyleNormal);
        }
        btn->installEventFilter(this);
        connect(btn, SIGNAL(clicked(bool)), this, SLOT(setChecked()));
        layout->addWidget(btn);
        btnLst.append(btn);
    }

    if (lst.contains(cc))
    {
        foreach (QPushButton* btn, btnLst)
        {
            if (btn->objectName() == cc)
            {
                btn->click();
                break;
            }
        }
    }
    else
    {
        btnLst[0]->click();
    }
}

void QSegmentedWidget::setChecked()
{
    QPushButton *btn = qobject_cast<QPushButton *>(sender());
    if (curBtn == btn)
    {
        return;
    }

    btn->setIcon(QIcon(pixmap));

    QString data = btn->objectName();
    if (data == sourceLst.first())
    {
        btn->setStyleSheet(btnStyleCheckFirst);
    }
    else if (data == sourceLst.last())
    {
        btn->setStyleSheet(btnStyleCheckLast);
    }
    else
    {
        btn->setStyleSheet(btnStyleCheck);
    }

    if (curBtn != nullptr)
    {
        curBtn->setIcon(QIcon());
        QString data = curBtn->objectName();
        if (data == sourceLst.first())
        {
            curBtn->setStyleSheet(btnStyleNormalFirst);
        }
        else if (data == sourceLst.last())
        {
            curBtn->setStyleSheet(btnStyleNormalLast);
        }
        else
        {
            curBtn->setStyleSheet(btnStyleNormal);
        }
    }

    curBtn = btn;

    emit emitChecked(btn->objectName());
}

check.svg

css 复制代码
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M4.33,8.92l-2.92-3.06c-.33-.34-.84-.34-1.17,0-.33.34-.33.88,0,1.22l3.49,3.67c.33.34.85.34,1.18,0L13.76,1.48c.33-.34.33-.88,0-1.22-.33-.34-.84-.34-1.17,0L4.33,8.92Z" fill="#F7F9FA"></path></svg>

setSource选项输入和默认选中、set**Color样式接口、emitChecked结果回传。

cpp 复制代码
segmentedWidget = new QSegmentedWidget;
connect(segmentedWidget, SIGNAL(emitChecked(QString)), this, SLOT(segmentedChecked(QString)));
QStringList lst;
lst.append("7D");
lst.append("1M");
lst.append("3M");
lst.append("6M");
lst.append("1Y");
lst.append("ALL");
segmentedWidget->setSource(lst, "6M");

void MainWindow::segmentedChecked(QString cc)
{
    qDebug() << cc;
}

QStringList lst;
lst.append("Mon");
lst.append("Tue");
lst.append("Wed");
lst.append("Thu");
lst.append("Fri");
lst.append("Sat");
lst.append("Sun");
segmentedWidget->setHoverColor("64,158,255");
segmentedWidget->setHoverTextColor("96,98,102");
segmentedWidget->setCheckColor("64,158,255");
segmentedWidget->setSource(lst, "Wed");
相关推荐
2601_966949651 小时前
只拿到股票代码还不够:量化程序到底还需要哪些标的信息?——从数据建模开始理解股票元数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
m0_734571761 小时前
深入理解5g <十八>传输块tbsize的计算
开发语言·5g
RAN11426760083 小时前
1.3第一个程序的介绍
开发语言·qt
blue_ice .3 小时前
Verilog DDS 数字信号发生器:DAC 输出模拟波形与 ADC 回采观测
开发语言·单片机·嵌入式硬件·fpga开发
远翔调光芯片^138287988724 小时前
ECP5702能芯科技PD取电芯片在市场上的优势有哪些?
开发语言·人工智能·单片机·嵌入式硬件·智能家居
泡海椒4 小时前
规则引擎对比:JQuick-Java vs Drools 轻量场景选型对比
java·开发语言
泡泡鱼(敲代码中)5 小时前
Python 容器类型学习笔记:列表、元组、字典、集合
开发语言·笔记·python·pycharm
2501_933670795 小时前
平台招商运营校招能力模型:数据分析、SQL与增长场景拆解
开发语言
菜鸟~noob2336 小时前
【Bonjour】华为Peerium架构深度解析:从冯·诺依曼到百万处理器“一台计算机”,附MATLAB性能仿真【含matlab代码,可直接运行】
开发语言·matlab·华为·peerium
白远山6 小时前
24小时自助健身房系统开发实战:从需求分析到完整指南
java·开发语言·数据库·数据挖掘·需求分析