Bootstrap

关于QLineEdit 添加的QAction图标的交互问题

如上图,我们创建了一个搜索栏,添加了一个带有图标的动作,然后你可能会想将鼠标移动到这个图标上面时让这个图标变色首先,我需要回忆一下Qt的信号和槽机制。QAction有hovered信号,但可能没有直接的“离开”信号。也就是说,当鼠标进入动作时会触发hovered。给出如下代码:

 连接 hovered 信号
    connect(searchAction, &QAction::hovered, this, [=]() {
    
        searchAction->setIcon(QIcon(":/Res/menuIcon/search-blue.svg")); // 设置为手形指针
    
     });

在代码中,用户连接了hovered信号,当鼠标悬停在动作上时,图标变成蓝色。刚开始可能会以为成功了,实则不然。在鼠标移出该图标时,图标仍然为蓝色。。。该怎么办呢?

这时候可能需要用到QWidget的enterEvent和leaveEvent,或者考虑使用事件过滤器来捕捉鼠标的进入和离开事件。

不过,QAction本身并不是QWidget的子类,所以不能直接处理鼠标事件。那怎么办呢?可能应该查找与QAction相关联的控件,比如QToolButton,因为QLineEdit添加的QAction通常会有一个内部的QToolButton来实现显示

当将QAction添加到QLineEdit时,QLineEdit会为这个动作创建一个QToolButton作为它的子控件。这时候可以尝试获取这个按钮,然后监听它的enter和leave事件,或者使用样式表来改变图标的状态。

或者,考虑使用事件过滤器,监控QLineEdit的QAction的位置,当鼠标移动到该区域之外时,恢复图标。但这样可能比较复杂。

另一个思路是,当鼠标进入QAction时改变图标,当离开时恢复。但QAction本身可能不提供离开的信号,所以可能需要通过事件过滤器来监听鼠标离开事件。

具体步骤可能是这样的:首先,获取QAction对应的widget,也就是那个按钮。可以通过QLineEdit的findChild方法查找QToolButton,或者遍历子控件。找到对应的QToolButton之后,安装事件过滤器到该按钮,然后在事件过滤器中处理鼠标进入和离开的事件,改变图标。

或者,使用样式表来设置不同状态下的图标。例如,设置按钮的hover状态图标为蓝色,普通状态为黑色。这样可能更简单,不需要编写额外的代码。

但用户使用的是QAction的图标,可能样式表的方法需要针对具体的按钮设置。或者,如果QAction的图标设置是通过样式表的话,可能需要调整。不过用户目前是在代码中直接设置图标,所以可能需要另一种方式。

例如,当QToolButton的hover状态改变时,自动切换图标。或者,直接使用QToolButton的setIcon方法,并在事件过滤器中处理enter和leave事件。

所以,可能的解决方案是:

  1. 获取QAction对应的QToolButton
    使用findChildren遍历QLineEdit的子控件,找到关联的QToolButton。

  2. 安装事件过滤器
    监听按钮的鼠标进入和离开事件。

  3. 处理事件切换图标
    在事件过滤器中根据事件类型切换图标。

那具体如何实现呢?代码入下:

// 搜索栏设置
ui->search_lineEdit->setPlaceholderText(QStringLiteral("搜索"));
ui->search_lineEdit->setFixedWidth(200); // 使用 fixedWidth 正确设置宽度

// 创建动作并设置图标
const auto searchAction = new QAction(QIcon(":/Res/menuIcon/search-black.svg"), "搜索", ui->search_lineEdit);
ui->search_lineEdit->addAction(searchAction, QLineEdit::TrailingPosition);

// 获取关联的QToolButton
QToolButton* searchButton = nullptr;
foreach (QToolButton* btn, ui->search_lineEdit->findChildren<QToolButton*>()) {
    if (btn->defaultAction() == searchAction) {
        searchButton = btn;
        break;
    }
}

// 安装事件过滤器
if (searchButton) {
    searchButton->installEventFilter(this);
}

// 在类头文件中声明 eventFilter 函数
// protected:
//     bool eventFilter(QObject *watched, QEvent *event) override;

// 实现事件过滤器
bool YourClass::eventFilter(QObject* watched, QEvent* event) {
    QToolButton* button = qobject_cast<QToolButton*>(watched);
    if (button && button->defaultAction() == searchAction) {
        if (event->type() == QEvent::Enter) {
            searchAction->setIcon(QIcon(":/Res/menuIcon/search-blue.svg"));
        } else if (event->type() == QEvent::Leave) {
            searchAction->setIcon(QIcon(":/Res/menuIcon/search-black.svg"));
        }
    }
    return QObject::eventFilter(watched, event);
}

代码解释

  • 使用findChildren查找QLineEdit中所有QToolButton,通过比较defaultAction确认目标按钮。

  • 通过事件过滤器监听按钮的QEvent::Enter(鼠标进入)和QEvent::Leave(鼠标离开)事件。

  • 在事件处理中切换图标,实现悬停变色效果。

这样即可在鼠标移入时显示蓝色图标,移出时恢复黑色图标。

;