该控件模仿的是比较常见的应用程序中的搜索框。实现了输入文本后按回车搜索(也可以点击搜索按钮开始搜索),和记住最近的几个搜索记录的功能。使用者通过响应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();
    }
}

 

原文地址:http://www.cnblogs.com/mengxiangdu/p/16919688.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性