QT实现自定义tag标签

需求

近期项目上需要用到QT,刚接触不久就遇到一个需求。需要在form表单上实现标签,标签长度随着文字的长度而变化,并且支持关闭和选中两种状态。

从遇到问题到解决问题总共用了3天时间,有一段时间没有钻研技术问题了,决定记录一下。

需求两种情况如下图所示(下图是已经实现的结果):
支持选中的状态支持关闭的状态

思考

遇到这个需求的第一反映是去网上找现成的控件来使用,找了一圈发现没有。

期间还尝试用QViewList+委托来实现,但是遇到item大小都是固定的问题,没法根据文字的长度进行分别显示,花了一天时间没有解决,果断放弃!

进而想到QT官方给的示例很强大,于是到官方示例是去寻找解药,发现有一个差不多的示例,叫:Fridge Magnets Example(冰箱磁铁示例),如下图所示:
在这里插入图片描述翻看了官方示例的源码之后,决定在其基础上进行改造。
主要就是添加点击事件、在右侧绘制关闭按钮。
想要实现这些功能,需要自义Label类、自定义关闭按钮,在自定义的类文件中添加个性化实现方法即可满足需求。

代码

我的代码目录结构如下图所示:
在这里插入图片描述主要代码如下:

#ifndef CLUETAG_H
#define CLUETAG_H

#include <QLabel>
#include "mainwindow.h"

class ClueTag : public QLabel
{
public:
    /**
     * @brief ClueTag  标签构造函数
     * @param tagText  标签显示文字
     * @param allowSelect  是否允许选中
     * @param isShowBtn  是否显示关闭按钮
     * @param selectedTags  已选择的标签集合指针
     * @param mainWindow  主窗口
     * @param parent  父窗口
     */
    ClueTag(const QString& tagText, const bool allowSelect, const bool isShowBtn, QStringList* selectedTags, MainWindow* mainWindow, QWidget *parent);
    //获取标签文字
    QString tagText() const;
    //设置标签选中
    void setSelected();
    //设置标签未选中
    void setUnSelected();

protected:
    //鼠标点击事件
    void mousePressEvent(QMouseEvent* event);

private:
    //标签文字
    QString m_tagText;
    //被选中的标签指针变量
    QStringList* m_selectedTags;
    //是否显示关闭按钮
    bool m_isShowBtn;
    //是否允许选中
    bool m_allowSelect;

};

#endif // CLUETAG_H

#ifndef CLUETAGBTN_H
#define CLUETAGBTN_H

#include <QObject>
#include <QPushButton>
#include "mainwindow.h"

class ClueTagBtn : public QPushButton
{
    Q_OBJECT

public:
    ClueTagBtn(QString tagText, QStringList* selectedTags, MainWindow* mainWindow, QWidget *parent);

signals:
    void delSelectedTagSignal(QString tagText);

};

#endif // CLUETAGBTN_H

#include "cluetag.h"
#include "mainwindow.h"

#include <QtWidgets>
#include "cluetagbtn.h"

ClueTag::ClueTag(const QString& tagText, const bool allowSelect, const bool isShowBtn,  QStringList* selectedTags, MainWindow* mainWindow, QWidget *parent)
    : QLabel(parent)
{
    m_isShowBtn = isShowBtn;
    m_allowSelect = allowSelect;

    QFontMetrics metric(font());
    QSize size = metric.size(Qt::TextSingleLine, tagText);

    QImage image(size.width() + 12 + (m_isShowBtn ? 30 : 0), size.height() + 12, QImage::Format_ARGB32_Premultiplied);
    image.fill(qRgba(0, 0, 0, 0));

    QFont font;
    font.setStyleStrategy(QFont::ForceOutline);
    //font.setFamily("Microsoft YaHei");

    QLinearGradient gradient(0, 0, 0, image.height()-1);
    gradient.setColorAt(0.0, Qt::white);
    //gradient.setColorAt(0.2, QColor(200, 200, 255));
    //gradient.setColorAt(0.8, QColor(200, 200, 255));
    //gradient.setColorAt(1.0, QColor(200, 200, 255));

    QPainter painter;
    painter.begin(&image);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(gradient);
    painter.setPen(QPen(QColor(175, 125, 255)));
    painter.drawRoundedRect(QRectF(0.5, 0.5, image.width()-1, image.height()-1),
                            20, 80, Qt::RelativeSize);

    painter.setFont(font);
    painter.setBrush(Qt::blue);
    painter.setPen(QPen(QColor(175, 125, 255)));
    painter.drawText(QRect(QPoint(6, 6), size), Qt::AlignCenter, tagText);
    painter.end();

    setPixmap(QPixmap::fromImage(image));
    m_tagText = tagText;
    m_selectedTags = selectedTags;
    this->setToolTip("点击关闭标签");

    if(isShowBtn)
    {
        ClueTagBtn *btnIco = new ClueTagBtn(tagText, selectedTags, mainWindow, this);
        btnIco->setIcon(QIcon(":/img/close.png"));
        btnIco->setFlat(true);
        btnIco->setCursor(QCursor(Qt::PointingHandCursor));

        QHBoxLayout * pLay = new QHBoxLayout();
        pLay->setContentsMargins(0,0,0,0);
        pLay->addSpacing(size.width() + 12);
        pLay->addWidget(btnIco);
        pLay->addStretch(5);
        setLayout(pLay);
        setContentsMargins(0,0,0,0);
    }
}

QString ClueTag::tagText() const
{
    return m_tagText;
}

void ClueTag::mousePressEvent(QMouseEvent* event)
{
    Q_UNUSED(event);
    if(!m_allowSelect)
    {
        return;
    }

    //先判断是否加入列表中,如果已经加入,则移除并设置未选中状态
    if(m_selectedTags->contains(tagText()))
    {
        //设置未选中状态
        setUnSelected();
        for(int i=0; i<m_selectedTags->size(); i++)
        {
            if(m_selectedTags->at(i) == tagText())
            {
                m_selectedTags->removeAt(i);
            }
        }
        qDebug() << m_selectedTags[0];
    }
    else
    {
        //设置选中状态
        setSelected();
        m_selectedTags->append(tagText());
    }

    qDebug() << m_selectedTags[0];
}

void ClueTag::setSelected()
{
    QString text = tagText();

    QFontMetrics metric(font());
    QSize size = metric.size(Qt::TextSingleLine, text);

    QImage image(size.width() + 12 + (m_isShowBtn ? 30 : 0), size.height() + 12, QImage::Format_ARGB32_Premultiplied);
    image.fill(qRgba(0, 0, 0, 0));

    QFont font;
    font.setStyleStrategy(QFont::ForceOutline);

    QLinearGradient gradient(0, 0, 0, image.height()-1);
    gradient.setColorAt(0.0, Qt::white);
    gradient.setColorAt(0.2, QColor(200, 200, 255));
    gradient.setColorAt(0.8, QColor(200, 200, 255));
    gradient.setColorAt(1.0, QColor(200, 200, 255));

    QPainter painter;
    painter.begin(&image);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(gradient);
    painter.setPen(QPen(QColor(175, 125, 255)));
    painter.drawRoundedRect(QRectF(0.5, 0.5, image.width()-1, image.height()-1),
                            20, 80, Qt::RelativeSize);

    painter.setFont(font);
    painter.setBrush(Qt::black);
    painter.setPen(QPen(QColor(255, 255, 255)));
    painter.drawText(QRect(QPoint(6, 6), size), Qt::AlignCenter, text);
    painter.end();

    setPixmap(QPixmap::fromImage(image));
}

void ClueTag::setUnSelected()
{
    QString text = tagText();

    QFontMetrics metric(font());
    QSize size = metric.size(Qt::TextSingleLine, text);

    QImage image(size.width() + 12 + (m_isShowBtn ? 30 : 0), size.height() + 12, QImage::Format_ARGB32_Premultiplied);
    image.fill(qRgba(0, 0, 0, 0));

    QFont font;
    font.setStyleStrategy(QFont::ForceOutline);

    QLinearGradient gradient(0, 0, 0, image.height()-1);
    gradient.setColorAt(0.0, Qt::white);
    //gradient.setColorAt(0.2, QColor(200, 200, 255));
    //gradient.setColorAt(0.8, QColor(200, 200, 255));
    //gradient.setColorAt(1.0, QColor(200, 200, 255));

    QPainter painter;
    painter.begin(&image);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(gradient);
    painter.setPen(QPen(QColor(175, 125, 255)));
    painter.drawRoundedRect(QRectF(0.5, 0.5, image.width()-1, image.height()-1),
                            20, 80, Qt::RelativeSize);

    painter.setFont(font);
    painter.setBrush(Qt::black);
    painter.setPen(QPen(QColor(175, 125, 255)));
    painter.drawText(QRect(QPoint(6, 6), size), Qt::AlignCenter, text);
    painter.end();

    setPixmap(QPixmap::fromImage(image));
}
#include "cluetagbtn.h"

ClueTagBtn::ClueTagBtn(QString tagText, QStringList* selectedTags, MainWindow* mainWindow, QWidget *parent)
    : QPushButton(parent)
{

    connect(this, &QPushButton::clicked, this, [=](){
        emit delSelectedTagSignal(tagText);
    });
    connect(this, &ClueTagBtn::delSelectedTagSignal, mainWindow, &MainWindow::delSelectedTagSignal);

}

调用类代码如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "cluetag.h"
#include <QDebug>
#include <QCompleter>
#include <QMessageBox>

//已选择的标签列表
QStringList* m_selectedTags;
//待选择的标签列表
QStringList m_tags;
//是否显示关闭按钮
bool isShowBtn;
//是否允许选中
bool allowSelect;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    initData();
    initWidget();
}

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

void MainWindow::initData()
{
    m_tags << "<请选择>" << "小宋" << "小李" << "java" << "c++" << "cad" << "solidworks" << "ug" << "table tennes";
    m_selectedTags = new QStringList;
    //m_selectedTags[0] = m_tags;
    isShowBtn = true;
    allowSelect = false;
}

void MainWindow::initWidget()
{
    //初始化标签区域
    int x = 5;
    int y = 5;

    for (int i = 0; i < m_tags.size(); ++i) {

        QString text = QString(m_tags[i]).arg(i);

        if(!text.isEmpty())
        {
            ClueTag *clueTag = new ClueTag(text, allowSelect, isShowBtn, m_selectedTags, this, ui->widget);

            if(allowSelect)
            {
                //设置鼠标悬浮状态变成手形
                clueTag->setCursor(QCursor(Qt::PointingHandCursor));
            }
            clueTag->move(x, y);
            clueTag->show();
            clueTag->setAttribute(Qt::WA_DeleteOnClose);
            x += clueTag->width() + 5;
            if (x >= ui->widget->width() + 350)  //445
            {
                x = 5;
                y += clueTag->height() + 5;
            }
        }

        setMinimumSize(400, qMax(200, y + 5));
        setWindowTitle(tr("自定义标签"));
        setAcceptDrops(true);
    }
}

void MainWindow::delSelectedTagSignal(QString tagText)
{
    //清空所有内容
    QList<ClueTag*> tags = ui->widget->findChildren<ClueTag*>();
    foreach (ClueTag* tag, tags)
    {
        delete tag;
    }

    for(int i=0; i<m_selectedTags[0].size(); i++)
    {
        if(m_selectedTags[0][i] == tagText)
        {
            m_selectedTags[0].removeAt(i);
        }
    }

    int x = 5;
    int y = 5;

    qDebug() << ui->widget->width();

    for (int i = 0; i < m_selectedTags[0].size(); ++i) {

        QString text = QString(m_selectedTags[0][i]);

        if(!text.isEmpty())
        {
            ClueTag *clueTag = new ClueTag(text, allowSelect, isShowBtn, m_selectedTags, this, ui->widget);

            //设置鼠标悬浮状态变成手形
            //wordLabel->setCursor(QCursor(Qt::PointingHandCursor));
            clueTag->move(x, y);
            clueTag->show();
            clueTag->setAttribute(Qt::WA_DeleteOnClose);
            x += clueTag->width() + 5;
            if (x >= + ui->widget->width() - 200)  //445
            {
                x = 5;
                y += clueTag->height() + 5;
            }
        }
        setMinimumSize(200, qMax(200, y + 5));
    }
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
好的,这里给你一个简单的 Qt 实现自定义旋钮的案例。 首先,我们需要在 Qt Designer 中创建一个自定义控件。打开 Qt Designer 后,选择 "Widget",新建一个空白的窗口,然后在左侧的 "Widget Box" 中选择 "Dial" 控件,将其拖拽到窗口中。这时候你就可以在窗口中看到一个简单的旋钮了。接着,我们需要对其进行自定义。 在左侧的 "Object Inspector" 中,选择 "dial" 控件,然后在右侧的 "Property Editor" 中修改其属性。比如,你可以修改它的 "minimum" 值和 "maximum" 值,使其能够旋转到任意角度。你还可以修改其样式,使其更符合你的设计需求。 接下来,我们需要在代码中实现这个自定义控件。打开 Qt Creator,创建一个新的 Qt Widgets 项目,并在其中添加一个自定义控件类。在这个类中,我们需要重写一些事件处理函数,以实现自定义旋钮的功能。以下是一个简单的实现: ```cpp class MyDial : public QDial { Q_OBJECT public: MyDial(QWidget* parent = nullptr) : QDial(parent) {} signals: void valueChanged(double value); protected: void mouseMoveEvent(QMouseEvent* event) override { if (event->buttons() & Qt::LeftButton) { QPoint pos = event->pos() - rect().center(); double angle = atan2(-pos.y(), pos.x()) * 180 / M_PI; setValue(static_cast<int>(angle)); emit valueChanged(angle); } } }; ``` 在这个示例中,我们重写了 `mouseMoveEvent` 函数,以处理鼠标移动事件。当鼠标左键按下时,我们计算出鼠标相对于旋钮中心的角度,然后调用 `setValue` 函数设置旋钮的值,并发出 `valueChanged` 信号。这个信号可以让其他对象在旋钮值发生改变时做出相应的响应。 最后,我们将这个自定义控件添加到主窗口中。打开主窗口的头文件,添加以下代码: ```cpp #include "mydial.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget* parent = nullptr) : QMainWindow(parent) { MyDial* dial = new MyDial(this); dial->setGeometry(50, 50, 100, 100); connect(dial, &MyDial::valueChanged, this, &MainWindow::onDialValueChanged); } private slots: void onDialValueChanged(double value) { qDebug() << "Dial value changed:" << value; } }; ``` 在这个示例中,我们创建了一个 `MyDial` 对象,并将其添加到主窗口中。我们还连接了 `valueChanged` 信号,以在旋钮值发生改变时输出调试信息。 这就是一个简单的 Qt 实现自定义旋钮的案例。希望对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值