Client-applyfriendlist类
1.设计要点解析
-
事件过滤器 (Event Filter):这是 Qt 中一种强大的事件处理机制。通过
installEventFilter()
安装一个过滤器后,目标对象的所有事件在到达目标对象之前,都会先经过过滤器的eventFilter()
函数。这使得我们可以在不子类化目标对象的情况下,为其添加自定义的事件响应。 -
监视视口 (Viewport):对于
QListWidget
、QTableWidget
这类可滚动的控件,用户交互(如点击、滚动)实际上是发生在其内部的一个叫做 “视口” 的子控件上。因此,我们必须为this->viewport()
而不是this
安装事件过滤器。 -
滚动条的智能显示:通过捕捉
QEvent::Enter
和QEvent::Leave
事件,可以实现当鼠标悬停在列表上时才显示滚动条,鼠标离开时则隐藏,从而让界面在不需要滚动时看起来更简洁。 -
自定义滚轮行为:通过拦截
QEvent::Wheel
事件,并手动计算和设置滚动条的值,我们可以完全控制滚轮滚动时列表的移动幅度。在这个例子中,滚动幅度很小,可能是为了实现一种更精细或更平滑的滚动效果。return true;
是关键,它阻止了 Qt 默认的滚动行为。 -
与其他控件通信:当用户点击列表时,
ApplyFriendList
会发出sig_show_search(false)
信号。这表明在程序的其他地方(例如包含这个列表的主窗口),会有一个槽函数连接到这个信号,用于执行隐藏搜索框的操作。这是一个典型的解耦设计,列表本身不需要知道搜索框的存在。
2.applyfriendlist.h类
#ifndef APPLYFRIENDLIST_H
#define APPLYFRIENDLIST_H
#include <QListWidget> // 继承自Qt的标准列表控件
#include <QEvent> // 用于事件处理/*** @brief 好友申请列表控件** 这个类是一个自定义的QListWidget,主要用于显示好友申请。* 它通过事件过滤器实现了一些特殊的交互效果,例如:* 1. 鼠标悬停时显示滚动条,离开时隐藏。* 2. 鼠标滚轮滚动时,自定义滚动速度。* 3. 点击列表时,隐藏搜索框。*/
class ApplyFriendList: public QListWidget
{Q_OBJECT // 必须包含这个宏才能使用信号和槽机制
public:// 构造函数ApplyFriendList(QWidget *parent = nullptr);protected:/*** @brief 事件过滤器** 重写这个函数是实现自定义事件处理的关键。* 当一个对象安装了事件过滤器后,这个函数会在目标对象的事件被处理前被调用。* @param watched 被监视的对象* @param event 发生的事件* @return 如果事件被处理并希望停止传播,返回true;否则返回false。*/bool eventFilter(QObject *watched, QEvent *event) override;private slots:// 这里可以添加槽函数来响应信号,但当前类中没有用到。signals:/*** @brief 信号:通知显示或隐藏搜索框** 当用户点击列表区域时,会发出此信号。* @param 一个布尔值,通常用来控制搜索框的可见性。*/void sig_show_search(bool);
};#endif // APPLYFRIENDLIST_H
3.applyfriendlist.cpp类
#include "applyfriendlist.h"
#include <QWheelEvent> // 用于处理鼠标滚轮事件
#include <QScrollBar> // 用于操作滚动条
#include "listitembase.h" // 列表项的基类/*** @brief 构造函数** 初始化列表控件的属性,并为其视图(viewport)安装事件过滤器。*/
ApplyFriendList::ApplyFriendList(QWidget *parent)
{Q_UNUSED(parent); // 标记parent参数未使用,避免编译器警告// 初始状态下隐藏水平和垂直滚动条this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);// 关键步骤:为列表的视口(viewport)安装事件过滤器。// QListWidget的滚动区域是其内部的一个QAbstractScrollArea::viewport()。// 我们需要监视这个视口上发生的事件,而不是QListWidget本身。this->viewport()->installEventFilter(this);
}/*** @brief 事件过滤器的具体实现** 这个函数是整个类的核心,它拦截并处理视口上的特定事件。*/
bool ApplyFriendList::eventFilter(QObject *watched, QEvent *event)
{// 1. 处理鼠标进入和离开事件,用于显示/隐藏滚动条// 检查事件是否发生在我们关注的视口上if (watched == this->viewport()) {// 鼠标进入视口if (event->type() == QEvent::Enter) {// 设置垂直滚动条为“需要时显示”,这样当内容超出可视区域时就会出现this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);} // 鼠标离开视口else if (event->type() == QEvent::Leave) {// 隐藏垂直滚动条this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);}}// 2. 处理鼠标按下事件,用于隐藏搜索框if (watched == this->viewport()) {if (event->type() == QEvent::MouseButtonPress) {// 发出信号,通知其他对象(如父窗口)隐藏搜索框emit sig_show_search(false);}}// 3. 处理鼠标滚轮事件,用于自定义滚动行为// 检查事件是否是发生在视口上的滚轮事件if (watched == this->viewport() && event->type() == QEvent::Wheel) {// 将通用事件转换为具体的滚轮事件QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);// 计算滚动的距离。QWheelEvent::angleDelta()返回的是1/8度,通常一个步长是15度。// 所以除以8再除以15,得到滚动的“步数”。int numDegrees = wheelEvent->angleDelta().y() / 8;int numSteps = numDegrees / 15;// 获取当前的垂直滚动条QScrollBar *scrollBar = this->verticalScrollBar();// 设置滚动条的新位置。// scrollBar->value()是当前位置,减去numSteps实现向上滚动(正值)或向下滚动(负值)。scrollBar->setValue(scrollBar->value() - numSteps);// 返回true,表示这个事件已经被我们处理了,不要再传递给其他对象(比如QListWidget的默认处理)。return true; }// 对于我们不关心的所有其他事件,都交给基类的eventFilter来处理。// 这是一个非常重要的步骤,否则其他事件(如点击列表项、键盘操作等)将失效。return QListWidget::eventFilter(watched, event);
}