自定义的Qt搜索框控件
该控件模仿的是比较常见的应用程序中的搜索框。实现了输入文本后按回车搜索(也可以点击搜索按钮开始搜索),和记住最近的几个搜索记录的功能。使用者通过响应inputCompleted信号获取输入文本进行操作。使用该控件是相当的简单。只要把下面的代码复制到你的项目中,在设计师软件里加一个QWidget,然后提升为该类即可。该控件在VS2015和Qt5.9上测试通过。下面是效果图:
上代码,头文件:
class MSearchBar : public QWidget { Q_OBJECT public: MSearchBar(QWidget* parent = 0); QSize sizeHint() const override; signals: void inputCompleted(const QString& str); private slots: void leTextReturnPressed(); private: void addHistory(const QString& str); bool eventFilter(QObject *watched, QEvent *event) override; void paintEvent(QPaintEvent*) override; void resizeEvent(QResizeEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; void showPopup(); enum Status { NONE, HOVERED, PRESSED, }; private: class MDiyListWidget; bool focused; bool oddClick; Status state; QPoint pressPt; QRect magnifier; QStringList history; QLineEdit* leText; MDiyListWidget* lwList; }; class QListWidget; class MSearchBar::MDiyListWidget : public QWidget { Q_OBJECT public: MDiyListWidget(QWidget* parent = 0); void setItems(const QStringList& strs); signals: void textChanged(const QString&); private slots: void lwListItemSelectionChanged(); private: QListWidget* lwList; };
CPP文件:
MSearchBar::MSearchBar(QWidget* parent) : QWidget(parent), focused(false), state(NONE) { oddClick = false; setMouseTracking(true); QHBoxLayout* lay = new QHBoxLayout(this); leText = new QLineEdit(this); leText->setStyleSheet(u8"QLineEdit { border:none; }"); leText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); leText->installEventFilter(this); lay->addWidget(leText); setLayout(lay); connect(leText, &QLineEdit::returnPressed, this, &MSearchBar::leTextReturnPressed); lwList = new MDiyListWidget(this); connect(lwList, &MDiyListWidget::textChanged, leText, &QLineEdit::setText); } void MSearchBar::leTextReturnPressed() { QString str = leText->text(); emit inputCompleted(str); addHistory(str); } void MSearchBar::addHistory(const QString& str) { if (!str.isEmpty() && !history.contains(str)) { history.append(str); } if (history.size() > 10) { history.pop_front(); } } void MSearchBar::resizeEvent(QResizeEvent *event) { QSize sz = event->size(); layout()->setContentsMargins(1, 1, sz.height() - 1, 1); magnifier.setX(sz.width() - sz.height() + 1); magnifier.setY(1); magnifier.setWidth(sz.height() - 2); magnifier.setHeight(sz.height() - 2); } void MSearchBar::paintEvent(QPaintEvent*) { QStyleOption opt; opt.init(this); QPainter painter(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); QPalette pale = palette(); painter.setBrush(Qt::NoBrush); /* 绘制边框 */ if (focused) { painter.setPen(QPen(pale.highlight(), 1)); painter.drawRect(0, 0, width() - 1, height() - 1); } else { painter.setPen(QPen(pale.mid(), 1)); painter.drawRect(0, 0, width() - 1, height() - 1); } /* 绘制放大镜 */ const QPointF ciCenter(0.4, 0.4); const qreal ciRadius = 0.2; const QPointF liStart(0.6, 0.6); const QPointF liEnd(0.83, 0.83); painter.setRenderHint(QPainter::Antialiasing); switch (state) { case MSearchBar::NONE: painter.translate(magnifier.x(), magnifier.y()); painter.setPen(QPen(pale.mid(), 2)); break; case MSearchBar::HOVERED: painter.fillRect(magnifier, pale.highlight()); painter.translate(magnifier.x(), magnifier.y()); painter.setPen(QPen(pale.light(), 2)); break; case MSearchBar::PRESSED: painter.fillRect(magnifier, pale.highlight()); painter.translate(magnifier.x() + 1, magnifier.y() + 1); painter.setPen(QPen(pale.light(), 2)); break; default: // never goto this. break; } int msz = magnifier.width(); painter.drawEllipse(ciCenter * msz, ciRadius * msz, ciRadius * msz); painter.drawLine(msz * liStart, msz * liEnd); } bool MSearchBar::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::FocusIn) { focused = true; update(); } else if (event->type() == QEvent::FocusOut) { focused = false; update(); } else if (event->type() == QEvent::MouseMove && state == HOVERED) { state = NONE; update(); } else if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event); if (mouseEvent->button() == Qt::LeftButton) { oddClick = !oddClick; if (!history.empty() && oddClick) { showPopup(); } } } return false; } void MSearchBar::showPopup() { lwList->setItems(history); QPoint scrPos = mapToGlobal(QPoint(0, height())); lwList->move(scrPos); lwList->setFixedWidth(width()); lwList->show(); } void MSearchBar::mouseMoveEvent(QMouseEvent *event) { bool isHover = magnifier.contains(event->pos()); if (isHover && state != HOVERED) { state = HOVERED; update(); } else if (!isHover && state != NONE) { state = NONE; update(); } } void MSearchBar::mousePressEvent(QMouseEvent *event) { QPoint p = event->pos(); if (magnifier.contains(p)) { pressPt = p; state = PRESSED; update(); } } void MSearchBar::mouseReleaseEvent(QMouseEvent *event) { if (pressPt == event->pos()) { state = HOVERED; QString str = leText->text(); emit inputCompleted(str); addHistory(str); update(); } } void MSearchBar::enterEvent(QEvent *event) { // nothing. } void MSearchBar::leaveEvent(QEvent *event) { state = NONE; update(); } QSize MSearchBar::sizeHint() const { return QSize(160, 24); } ///////////////////////////////////////////////////////////////////////////////////////// MSearchBar::MDiyListWidget::MDiyListWidget(QWidget* parent) : QWidget(parent) { setWindowFlag(Qt::Popup); QHBoxLayout* lay = new QHBoxLayout(this); lay->setContentsMargins(0, 0, 0, 0); lwList = new QListWidget(this); lay->addWidget(lwList); setLayout(lay); connect(lwList, &QListWidget::itemSelectionChanged, this, &MDiyListWidget::lwListItemSelectionChanged); } void MSearchBar::MDiyListWidget::setItems(const QStringList& strs) { lwList->clear(); lwList->addItems(strs); } void MSearchBar::MDiyListWidget::lwListItemSelectionChanged() { QList<QListWidgetItem*> selects = lwList->selectedItems(); if (!selects.empty()) { emit textChanged(selects.first()->text()); close(); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?