自学内容网 自学内容网

IM项目-----客户端部分选择好友窗口

文章目录


前言

介绍选择好友窗口的实现


在这里插入图片描述

选择好友类

这个类中有两个Widget,代表左右部分。
在构造函数中使用水平布局管理进行布局。
左边部分使用垂直布局管理,右边部分使用网格布局。

class ChooseFriendDialog : public QDialog
{
    Q_OBJECT
public:
    ChooseFriendDialog(const QString& userId,QWidget* parent = nullptr);


    void initLeft(QHBoxLayout* layout);
    void addFriend(const QString& userId,const QIcon& avatar, const QString& name, bool checked);
    void addSelectedFriend(const QString& userId,const QIcon& avatar, const QString& name, bool checked);
    void deleteSelectedFriend(const QString& userId);
    void initRight(QHBoxLayout* layout);

    //加载好友列表
    void initData();
    void clickOkBtn();

    //获取已选中的好友userId
    QList<QString> generateMemberList();

private:
    // 保存左侧全部好友列表的 QWidget
    QWidget* totalContainer;
    // 保存右侧选中好友列表的 QWidget
    QWidget* selectedContainer;

    QPushButton* okBtn;
    QPushButton* cancelBtn;


    QString userId;//该会话的用户Id
};

其中滑动区域中的一个一个item的实现是自定义控件。

class ChooseFriendItem : public QWidget
{
    Q_OBJECT
public:
    //checked代表当前item的复选框是否被选中
    ChooseFriendItem(ChooseFriendDialog* owner,const QString &userId,const QIcon& avatar, const QString& name, bool checked);
    //重写绘制事件来绘制鼠标放到item上的颜色效果
    void paintEvent(QPaintEvent* event) override;
    void enterEvent(QEnterEvent* event) override;
    void leaveEvent(QEvent* event) override;

    QString getUserId();
    QCheckBox* getCheckBox();
private:
    QCheckBox* checkBox;
    QPushButton* avatarBtn;
    QLabel* nameLabel;

    //鼠标是否选中
    bool isHover = false;

    //这个item是属于哪个控件的,这里是属于ChooseFriendDialog
    ChooseFriendDialog* owner;
    //这个好友的userId,用来作为item唯一标识,方便复选框取消选择进行删除
    QString userId;
};

重写了鼠标移动和离开的事件来进行颜色的改变。通过QPainter来实现,和前面qss实现不同。

void ChooseFriendItem::paintEvent(QPaintEvent *event)
{
    (void) event;

    QPainter painter(this);
    if (isHover) {
        // 绘制成深色
        painter.fillRect(this->rect(), QColor(230, 230, 230));
    } else {
        // 绘制成浅色
        painter.fillRect(this->rect(), QColor(255, 255, 255));
    }
}

在构造函数中连接了信号槽,用于处理复选框选中和取消选中。
在这个对象中保存了一个选择好友类的指针,用于完成UI的更新。

 //连接槽函数,选中复选框执行对应操作
    connect(checkBox,&QCheckBox::toggled,this,[=](bool checked){
        if(checked){
            //复选框为勾选状态
            owner->addSelectedFriend(userId,avatarBtn->icon(),nameLabel->text(),true);
        }else{
            //复选框取消勾选
            owner->deleteSelectedFriend(userId);
        }
    });

在好友窗口构造时,就会调用addFriend函数,将好友列表中的好友添加进来。
当我们勾选复选框后,就会调用第二个函数,构造一个item添加到右侧滑动窗口中。

void ChooseFriendDialog::addFriend(const QString& userId,const QIcon &avatar, const QString &name, bool checked)
{
    ChooseFriendItem* chooseFriendItem = new ChooseFriendItem(this,userId,avatar,name,checked);
    totalContainer->layout()->addWidget(chooseFriendItem);
}

void ChooseFriendDialog::addSelectedFriend(const QString& userId,const QIcon &avatar, const QString &name, bool checked = true)
{
    ChooseFriendItem* chooseFriendItem = new ChooseFriendItem(this,userId,avatar,name,checked);
    selectedContainer->layout()->addWidget(chooseFriendItem);
}

当取消勾选复选框,就需要清除右侧已选择的item,这个的实现逻辑就是遍历右侧滑动区域的item,比较点击的item中的userID和右侧滑动区域的item是否一致,删除一致的item。
另外需要遍历左侧的滑动区域,将勾选状态设置为false。

void ChooseFriendDialog::deleteSelectedFriend(const QString &userId)
{
    //获取已选择好友窗口的layout
    QVBoxLayout* vlayout = dynamic_cast<QVBoxLayout*>(selectedContainer->layout());
    //遍历这个layout的所有item
    for(int i = vlayout->count() - 1;i >= 0; i--)
    {
        auto* item = vlayout->itemAt(i);
        if (item == nullptr || item->widget() == nullptr) {
            continue;
        }
        ChooseFriendItem* chooseFriendItem = dynamic_cast<ChooseFriendItem*>(item->widget());
        // 判定当前的 Item 的 userId 是否是要删除的 userId
        if (chooseFriendItem->getUserId() != userId) {
            continue;
        }
        vlayout->removeWidget(chooseFriendItem);
        // 此处直接使用 delete 可能导致程序直接崩溃. 因为 delete 该对象的时候, 该对象内部的 QCheckBox 还在使用中 (触发着信号槽呢)
        // 改成 deleteLater, 就相当于把 delete 操作委托给 Qt 自身来完成了. 告诉 Qt 框架说, 你要删除这个对象. 至于啥时候删除 Qt
        // 会确保在 Qt 自身用完了之后, 去真正删除.
        // delete chooseFriendItem;
        chooseFriendItem->deleteLater();
    }

    // 再遍历一下左侧列表, 把左侧列表中对应 item 的 checkBox 勾选状态取消掉.
    QVBoxLayout* vlayoutLeft = dynamic_cast<QVBoxLayout*>(totalContainer->layout());
    for (int i = 0; i < vlayoutLeft->count(); ++i) {
        auto* item = vlayoutLeft->itemAt(i);
        if (item == nullptr || item->widget() == nullptr) {
            continue;
        }
        ChooseFriendItem* chooseFriendItem = dynamic_cast<ChooseFriendItem*>(item->widget());
        if (chooseFriendItem->getUserId() != userId) {
            continue;
        }
        // 取消 checkBox 选中状态
        chooseFriendItem->getCheckBox()->setChecked(false);
    }
}

原文地址:https://blog.csdn.net/2301_77412625/article/details/143923100

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!