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

B站的标签创建框 之前投稿时候,发现B站的标签创建框很有意思,如下图所示。按回车生成标签,点击标签或者按退格删除标签。
记录|Qt自定义控件-----仿B站标签创建框
文章图片

第一次见到这东西(在下孤陋寡闻),觉得挺有意思,而且挺有用的。趁着端午节假日休闲的下午,把它还原一下。
自己的标签框 以下是还原效果图
记录|Qt自定义控件-----仿B站标签创建框
文章图片

还是有挺多缺漏,比如删除和添加时候,滚动条好像没有滚到最合适的位置,不过因为要吃饭了,等之后用到再修改吧。还有按钮的叉叉,实在懒得找图片,所以干脆不搞了。
记录|Qt自定义控件-----仿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_OBJECTpublic: 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::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; } } }

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

    推荐阅读