Qt自定义控件-----仿B站标签创建框

B站的标签创建框

之前投稿时候,发现B站的标签创建框很有意思,如下图所示。按回车生成标签,点击标签或者按退格删除标签。

在这里插入图片描述

第一次见到这东西(在下孤陋寡闻),觉得挺有意思,而且挺有用的。趁着端午节假日休闲的下午,把它还原一下。

自己的标签框

以下是还原效果图
在这里插入图片描述

还是有挺多缺漏,比如删除和添加时候,滚动条好像没有滚到最合适的位置,不过因为要吃饭了,等之后用到再修改吧。还有按钮的叉叉,实在懒得找图片,所以干脆不搞了。
在这里插入图片描述

设计思路

现在开始写下我还原的思路(这只是我的个人想法,肯定有更好的,不要被局限住了)。

首先可以无限添加,那么肯定有个ScrollArea,然后接着就是标签,为了方便响应点击,选用了Button。至于输入,因为没有做多行,所以毫不犹豫选用LineEdit。同时,为了方便插入和删除,Button和LineEdit可以统一放入Layout,方便Take和Insert。

当回车按下时,在LineEdit前插入一个Button(直接获取Layout的Count然后扣去编辑框就对了)。为了方便点击时候删除Button,把所有Button统一插入ButtonGroup去响应事件。接着就是响应LineEdit的Backspace,所以我们得继承LineEdit,然后在按键事件那边发射一个信号。

继承QLineEdit,响应Backspace

#ifndef CUSTOMEDIT_H
#define CUSTOMEDIT_H

#include 
#include 

class CustomEdit : public QLineEdit
{
    Q_OBJECT
public:
    explicit CustomEdit(QWidget* parent = nullptr);
    ~CustomEdit();
protected:
    void keyPressEvent(QKeyEvent *event) override;

signals:
    void BackspaceSignal();
};

#endif // CUSTOMEDIT_H

#include "CustomEdit.h"
#include 

CustomEdit::CustomEdit(QWidget *parent) : QLineEdit(parent)
{

}

CustomEdit::~CustomEdit()
{

}

void CustomEdit::keyPressEvent(QKeyEvent *event)
{
    QLineEdit::keyPressEvent(event);
    if(event->key() == Qt::Key_Backspace )
    {
        if(text().isEmpty())
        {
            emit(BackspaceSignal());
        }
    }
}

标签框

#ifndef EDITLABEL_H
#define EDITLABEL_H

#include 
#include 
#include "CustomEdit.h"
#include 
#include 

namespace Ui {
class EditLabel;
}

class EditLabel : public QWidget
{
    Q_OBJECT

public:
    explicit EditLabel(QWidget *parent = nullptr);
    ~EditLabel();

protected:
    void paintEvent(QPaintEvent* event) override;
    void keyPressEvent(QKeyEvent *event) override;

private:
    Ui::EditLabel *ui;
    QWidget* m_pCanvas;
    QScrollArea* m_pScroll;
    CustomEdit* m_pEdit;
    QHBoxLayout* m_pHLayout;
    QButtonGroup* m_pBtnGroup;

private slots:
    void DeleteItem();
    void DeleteButton(QAbstractButton *button);
};

#endif // EDITLABEL_H

#include "EditLabel.h"
#include "ui_EditLabel.h"
#include 
#include 
#include 
#include 
#include 

EditLabel::EditLabel(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::EditLabel)
{
    ui->setupUi(this);

    m_pCanvas = new QWidget;
    m_pScroll = new QScrollArea(this);
    m_pScroll->resize(200, 50);
    m_pScroll->setWidget(m_pCanvas);
    m_pScroll->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    m_pScroll->setWidgetResizable( true );
    m_pEdit = new CustomEdit(this);
    m_pHLayout = new QHBoxLayout(m_pCanvas);
    m_pBtnGroup = new QButtonGroup(this);
    m_pHLayout->addWidget(m_pEdit);
    m_pHLayout->setMargin(1);

    setObjectName(QStringLiteral("editlabel"));
    m_pCanvas->setObjectName(QStringLiteral("canvas"));
    m_pScroll->setObjectName(QStringLiteral("scroll"));
    m_pEdit->setObjectName(QStringLiteral("edit"));

    setStyleSheet(QStringLiteral("QWidget#editlabel{border: none;}"));
    m_pCanvas->setStyleSheet(QStringLiteral("QWidget#canvas{background-color:white;}"));
    m_pScroll->setStyleSheet(QStringLiteral("QScrollArea#scroll{border:1px solid rgb(241, 91, 108); border-radius: 6px;background-color:white;padding: 2px;}"));
    m_pEdit->setStyleSheet(QStringLiteral("QLineEdit#edit{border: none;font-family:Microsoft Yahei; font-size: 14px;}"));

    m_pScroll->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    m_pScroll->setFixedHeight(50);
    m_pEdit->setFixedSize(150, 20);
    m_pEdit->setPlaceholderText(QObject::tr("按回车键创建标签"));

    connect(m_pEdit, &CustomEdit::BackspaceSignal, this, &EditLabel::DeleteItem);
    connect(m_pBtnGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), this, &EditLabel::DeleteButton);
}

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

void EditLabel::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void EditLabel::keyPressEvent(QKeyEvent *event)
{
    QWidget::keyPressEvent(event);
    if(event->key() == Qt::Key_Return && m_pEdit->hasFocus())
    {
        QString content = m_pEdit->text();
        QFont font;
        font.setFamily("Microsoft Yahei");
        font.setPointSize(14);
        QFontMetrics fm(font); // 获取字体像素宽高
        QPushButton* pBtn = new QPushButton(m_pScroll);
        pBtn->setFont(font);
        pBtn->setText(content);
        pBtn->setFixedSize(fm.horizontalAdvance(content) + 5, fm.height());
        pBtn->setStyleSheet(QStringLiteral("QPushButton{border-radius:5px;background-color:rgb(241,91,108);}"));
        pBtn->setCursor(QCursor(Qt::PointingHandCursor));

        int cnt = m_pHLayout->count();
        m_pHLayout->insertWidget(cnt - 1, pBtn, Qt::AlignCenter);
        m_pBtnGroup->addButton(pBtn);
        m_pEdit->clear(); // 输入完一次后要清空
        m_pScroll->horizontalScrollBar()->setValue(m_pScroll->horizontalScrollBar()->maximum()); // 滚到当前最大值
    }
}

void EditLabel::DeleteItem()
{
    int cnt = m_pHLayout->count();
    if(cnt <= 1) return;
    auto item = m_pHLayout->itemAt(cnt - 2);
    m_pHLayout->removeItem(item);
    item->widget()->setParent(nullptr);
    delete item;
    item = nullptr;
}

void EditLabel::DeleteButton(QAbstractButton *button)
{
    int cnt = m_pHLayout->count();
    cnt -= 1;
    for(int i = 0; i < cnt; i++)
    {
        auto item = m_pHLayout->itemAt(i);
        if(item->widget() == button)
        {
            m_pHLayout->removeItem(item);
            item->widget()->setParent(nullptr);
            delete item;
            item = nullptr;
            return;
        }
    }
}




滚动条这边因为还要资源文件,所以就没贴出来了,需要的自己写下style很快的。
如果有更好的方法或者建议,欢迎评论区讨论。
Qt自定义控件-----仿B站标签创建框_第1张图片

你可能感兴趣的:(记录,学习笔记,qt,c++)