#include "choosefrienddialog.h" //////////////////////////////////////////////// /// 选择好友窗口中的一个 元素/好友项 //////////////////////////////////////////////// ChooseFriendItem::ChooseFriendItem(ChooseFriendDialog* owner, const QString& userId, const QIcon& avatar, const QString& name, bool checked) :userId(userId) { // 1. 设置控件的基本属性 this->setFixedHeight(50); this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // 2. 设置布局管理器 QHBoxLayout* layout = new QHBoxLayout(); layout->setSpacing(10); layout->setContentsMargins(20, 0, 20, 0); this->setLayout(layout); // 3. 创建复选框 checkBox = new QCheckBox(); checkBox->setChecked(checked); checkBox->setFixedSize(25, 25); QString style = "QCheckBox { background-color: transparent; } QCheckBox::indicator { width: 20px; height: 20px; image: url(:/resource/image/unchecked.png);}"; style += "QCheckBox::indicator:checked { image: url(:/resource/image/checked.png);}"; checkBox->setStyleSheet(style); // 4. 创建头像 avatarBtn = new QPushButton(); avatarBtn->setFixedSize(40, 40); avatarBtn->setIconSize(QSize(40, 40)); avatarBtn->setIcon(avatar); // 5. 创建名字 nameLabel = new QLabel(); nameLabel->setText(name); nameLabel->setStyleSheet("QLabel {background-color: transparent;}"); // 6. 添加上述内容到布局管理器中 layout->addWidget(checkBox); layout->addWidget(avatarBtn); layout->addWidget(nameLabel); // 7. 连接信号槽 connect(checkBox, &QCheckBox::toggled, this, [=](bool checked) { if (checked) { // 勾选了复选框, 把当前这个 Item, 添加到右侧的已选择区域 owner->addSelectedFriend(userId, avatar, name); } else { // 取消勾选 owner->deleteSelectedFriend(userId); } }); } void ChooseFriendItem::paintEvent(QPaintEvent* event) { //根据鼠标进入的状态,来决定绘制成不同的颜色 QPainter painter(this); if (isHover) { //绘制成深色 painter.fillRect(this->rect(), QColor(230, 230, 230)); } else { //绘制成浅色 painter.fillRect(this->rect(), QColor(255, 255, 255)); } } void ChooseFriendItem::enterEvent(QEnterEvent* event) { (void)event; isHover = true; //相当于界面更新 this->update(); //this->repaint(); //也可以 } void ChooseFriendItem::leaveEvent(QEvent* event) { (void)event; isHover = false; this->update(); } ChooseFriendDialog::ChooseFriendDialog(QWidget *parent) : QDialog(parent) { // 1. 设置窗口的基本属性 this->setWindowTitle("选择好友"); this->setWindowIcon(QIcon(":/resource/image/logo.png")); this->setFixedSize(750, 550); this->setStyleSheet("QDialog { background-color: rgb(255, 255, 255);}"); this->setAttribute(Qt::WA_DeleteOnClose); // 2. 创建布局管理器 QHBoxLayout* layout = new QHBoxLayout(); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); this->setLayout(layout); // 3. 针对左侧窗口进行初始化 initLeft(layout); // 4. 针对右侧窗口进行初始化 initRight(layout); } void ChooseFriendDialog::initLeft(QHBoxLayout* layout) { // 1. 创建滚动区域 QScrollArea* scrollArea = new QScrollArea(); scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); scrollArea->setWidgetResizable(true); scrollArea->horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { height: 0px;}"); scrollArea->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 2px; background-color: rgb(255, 255, 255) }"); scrollArea->setStyleSheet("QScrollArea { border:none; }"); layout->addWidget(scrollArea, 1); // 2. 创建 QWidget 设置到滚动区域中. totalContainer = new QWidget(); totalContainer->setObjectName("totalContainer"); totalContainer->setStyleSheet("#totalContainer { background-color: rgb(255, 255, 255); }"); scrollArea->setWidget(totalContainer); // 3. 创建左侧子窗口内部的 垂直布局管理器 QVBoxLayout* vlayout = new QVBoxLayout(); vlayout->setSpacing(0); vlayout->setContentsMargins(0, 0, 0, 0); vlayout->setAlignment(Qt::AlignTop); totalContainer->setLayout(vlayout); // 还需要进一步的添加 vlayout 内部的元素, 才能看到效果! // 此处也是先构造测试数据, 后续接入服务器之后, 从服务器拿到真实的好友列表, 再添加真实的数据 #if TEST_UI QIcon defaultAvatar(":/resource/image/defaultAvatar.png"); for (int i = 0; i < 15; ++i) { this->addFriend(QString::number(1000 + i), defaultAvatar, "张三" + QString::number(i), false); } #endif } void ChooseFriendDialog::initRight(QHBoxLayout* layout) { // 1. 创建右侧的布局管理器 QGridLayout* gridLayout = new QGridLayout(); gridLayout->setContentsMargins(20, 0, 20, 20); gridLayout->setSpacing(10); layout->addLayout(gridLayout, 1); // 2. 创建 "提示" label QLabel* tipLabel = new QLabel(); tipLabel->setText("选择联系人"); tipLabel->setFixedHeight(30); tipLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); tipLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); tipLabel->setStyleSheet("QLabel { font-size: 16px; font-weight: 700}"); // 3. 创建滚动区域 QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidgetResizable(true); scrollArea->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 2px; background-color: rgb(255, 255, 255);}"); scrollArea->horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal {height: 0px;}"); scrollArea->setStyleSheet("QScrollArea {border: none;}"); scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 4. 创建滚动区域中的 QWidget selectedContainer = new QWidget(); selectedContainer->setObjectName("selectedContainer"); selectedContainer->setStyleSheet("#selectedContainer { background-color: rgb(255, 255, 255); }"); scrollArea->setWidget(selectedContainer); // 5. 创建 selectedContainer 中的 "垂直布局" QVBoxLayout* vlayout = new QVBoxLayout(); vlayout->setSpacing(0); vlayout->setContentsMargins(0, 0, 0, 0); vlayout->setAlignment(Qt::AlignTop); selectedContainer->setLayout(vlayout); // 6. 创建底部按钮 QString style = "QPushButton { color: rgb(7, 191, 96); background-color: rgb(240, 240, 240); border: none; border-radius: 5px;}"; style += "QPushButton:hover { background-color: rgb(220, 220, 220); } QPushButton:pressed { background-color: rgb(200, 200, 200); }"; QPushButton* okBtn = new QPushButton(); okBtn->setFixedHeight(40); okBtn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); okBtn->setText("完成"); okBtn->setStyleSheet(style); QPushButton* cancelBtn = new QPushButton(); cancelBtn->setFixedHeight(40); cancelBtn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); cancelBtn->setText("取消"); cancelBtn->setStyleSheet(style); // 7. 把上述控件添加到布局中 gridLayout->addWidget(tipLabel, 0, 0, 1, 9); gridLayout->addWidget(scrollArea, 1, 0, 1, 9); gridLayout->addWidget(okBtn, 2, 1, 1, 3); gridLayout->addWidget(cancelBtn, 2, 5, 1, 3); // 构造一些数据用来进行测试界面 #if 0 // 此处的数据通过勾选左侧列表来生成. QIcon defaultAvatar(":/resource/image/defaultAvatar.png"); for (int i = 0; i < 10; ++i) { this->addSelectedFriend(QString::number(1000 + i), defaultAvatar, "张三" + QString::number(i)); } #endif //// 8. 添加信号槽, 处理 ok 和 cancel 的点击 //connect(okBtn, &QPushButton::clicked, this, &ChooseFriendDialog::clickOkBtn); //connect(cancelBtn, &QPushButton::clicked, this, [=]() { // this->close(); // }); } void ChooseFriendDialog::addFriend(const QString& userId, const QIcon& avatar, const QString& name, bool checked) { ChooseFriendItem* item = new ChooseFriendItem(this, userId, avatar, name, checked); totalContainer->layout()->addWidget(item); } void ChooseFriendDialog::addSelectedFriend(const QString& userId, const QIcon& avatar, const QString& name) { ChooseFriendItem* item = new ChooseFriendItem(this, userId, avatar, name, true); selectedContainer->layout()->addWidget(item); } void ChooseFriendDialog::deleteSelectedFriend(const QString& userId) { //遍历selectedContainer中的所有的Item,并对比其userId QVBoxLayout* vlayout = dynamic_cast(selectedContainer->layout()); //由于是要遍历加删除所以,要从后向前进行 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(item->widget()); //判定当前的Item的userId是否是要删除的userId if (chooseFriendItem->getUserId() != userId) { continue; } vlayout->removeWidget(chooseFriendItem); //会报错!!! // 要释放对象,不是直接delete,而是告诉qt让qt在信号槽这一轮 // 执行完成后,自行负责释放 //delete chooseFriendItem; chooseFriendItem->deleteLater(); } //再遍历一下左侧的列表,把左侧对应的item的checkBox的勾选状态给取消 QVBoxLayout* vlayoutLeft = dynamic_cast(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(item->widget()); if (chooseFriendItem->getUserId() != userId) { continue; } //已找到,取消勾选状态 chooseFriendItem->getCheckBox()->setChecked(false); } }