聊天项目(25) 实现好友申请界面

简介

本文介绍如何实现好友申请界面, 其效果如下图所示

https://cdn.llfc.club/1720423649556.jpg

在此之前我们需要先定义一个ClickedOnceLabel类,支持点击一次的label功能。

接着新增一个ClickedOnceLabel类

  1. class ClickedOnceLabel : public QLabel
  2. {
  3. Q_OBJECT
  4. public:
  5. ClickedOnceLabel(QWidget *parent=nullptr);
  6. virtual void mouseReleaseEvent(QMouseEvent *ev) override;
  7. signals:
  8. void clicked(QString);
  9. };

实现

  1. ClickedOnceLabel::ClickedOnceLabel(QWidget *parent):QLabel(parent)
  2. {
  3. setCursor(Qt::PointingHandCursor);
  4. }
  5. void ClickedOnceLabel::mouseReleaseEvent(QMouseEvent *event)
  6. {
  7. if (event->button() == Qt::LeftButton) {
  8. emit clicked(this->text());
  9. return;
  10. }
  11. // 调用基类的mousePressEvent以保证正常的事件处理
  12. QLabel::mousePressEvent(event);
  13. }

完善ClickedLabel

我们之前实现了ClickedLabel类,接下来修改下clicked信号,使其携带参数

  1. void clicked(QString, ClickLbState);

然后在其实现的鼠标释放事件的逻辑中添加

  1. void ClickedLabel::mouseReleaseEvent(QMouseEvent *event)
  2. {
  3. if (event->button() == Qt::LeftButton) {
  4. if(_curstate == ClickLbState::Normal){
  5. // qDebug()<<"ReleaseEvent , change to normal hover: "<< _normal_hover;
  6. setProperty("state",_normal_hover);
  7. repolish(this);
  8. update();
  9. }else{
  10. // qDebug()<<"ReleaseEvent , change to select hover: "<< _selected_hover;
  11. setProperty("state",_selected_hover);
  12. repolish(this);
  13. update();
  14. }
  15. emit clicked(this->text(), _curstate);
  16. return;
  17. }
  18. // 调用基类的mousePressEvent以保证正常的事件处理
  19. QLabel::mousePressEvent(event);
  20. }

好友申请

好友申请界面和逻辑,我们可以创建一个设计师界面类叫做ApplyFriend类,我们在类的声明中添加如下成员。

  1. class ApplyFriend : public QDialog
  2. {
  3. Q_OBJECT
  4. public:
  5. explicit ApplyFriend(QWidget *parent = nullptr);
  6. ~ApplyFriend();
  7. void InitTipLbs();
  8. void AddTipLbs(ClickedLabel*, QPoint cur_point, QPoint &next_point, int text_width, int text_height);
  9. bool eventFilter(QObject *obj, QEvent *event);
  10. void SetSearchInfo(std::shared_ptr<SearchInfo> si);
  11. private:
  12. Ui::ApplyFriend *ui;
  13. void resetLabels();
  14. //已经创建好的标签
  15. QMap<QString, ClickedLabel*> _add_labels;
  16. std::vector<QString> _add_label_keys;
  17. QPoint _label_point;
  18. //用来在输入框显示添加新好友的标签
  19. QMap<QString, FriendLabel*> _friend_labels;
  20. std::vector<QString> _friend_label_keys;
  21. void addLabel(QString name);
  22. std::vector<QString> _tip_data;
  23. QPoint _tip_cur_point;
  24. std::shared_ptr<SearchInfo> _si;
  25. public slots:
  26. //显示更多label标签
  27. void ShowMoreLabel();
  28. //输入label按下回车触发将标签加入展示栏
  29. void SlotLabelEnter();
  30. //点击关闭,移除展示栏好友便签
  31. void SlotRemoveFriendLabel(QString);
  32. //通过点击tip实现增加和减少好友便签
  33. void SlotChangeFriendLabelByTip(QString, ClickLbState);
  34. //输入框文本变化显示不同提示
  35. void SlotLabelTextChange(const QString& text);
  36. //输入框输入完成
  37. void SlotLabelEditFinished();
  38. //输入标签显示提示框,点击提示框内容后添加好友便签
  39. void SlotAddFirendLabelByClickTip(QString text);
  40. //处理确认回调
  41. void SlotApplySure();
  42. //处理取消回调
  43. void SlotApplyCancel();
  44. };

接下来我们修改ui使其变成如下布局

https://cdn.llfc.club/1720423721312.jpg

然后我们逐个实现功能,构造函数分别实现信号的链接和成员初始化,析构函数回收必要的资源。

  1. ApplyFriend::ApplyFriend(QWidget *parent) :
  2. QDialog(parent),
  3. ui(new Ui::ApplyFriend),_label_point(2,6)
  4. {
  5. ui->setupUi(this);
  6. // 隐藏对话框标题栏
  7. setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
  8. this->setObjectName("ApplyFriend");
  9. this->setModal(true);
  10. ui->name_ed->setPlaceholderText(tr("恋恋风辰"));
  11. ui->lb_ed->setPlaceholderText("搜索、添加标签");
  12. ui->back_ed->setPlaceholderText("燃烧的胸毛");
  13. ui->lb_ed->SetMaxLength(21);
  14. ui->lb_ed->move(2, 2);
  15. ui->lb_ed->setFixedHeight(20);
  16. ui->lb_ed->setMaxLength(10);
  17. ui->input_tip_wid->hide();
  18. _tip_cur_point = QPoint(5, 5);
  19. _tip_data = { "同学","家人","菜鸟教程","C++ Primer","Rust 程序设计",
  20. "父与子学Python","nodejs开发指南","go 语言开发指南",
  21. "游戏伙伴","金融投资","微信读书","拼多多拼友" };
  22. connect(ui->more_lb, &ClickedOnceLabel::clicked, this, &ApplyFriend::ShowMoreLabel);
  23. InitTipLbs();
  24. //链接输入标签回车事件
  25. connect(ui->lb_ed, &CustomizeEdit::returnPressed, this, &ApplyFriend::SlotLabelEnter);
  26. connect(ui->lb_ed, &CustomizeEdit::textChanged, this, &ApplyFriend::SlotLabelTextChange);
  27. connect(ui->lb_ed, &CustomizeEdit::editingFinished, this, &ApplyFriend::SlotLabelEditFinished);
  28. connect(ui->tip_lb, &ClickedOnceLabel::clicked, this, &ApplyFriend::SlotAddFirendLabelByClickTip);
  29. ui->scrollArea->horizontalScrollBar()->setHidden(true);
  30. ui->scrollArea->verticalScrollBar()->setHidden(true);
  31. ui->scrollArea->installEventFilter(this);
  32. ui->sure_btn->SetState("normal","hover","press");
  33. ui->cancel_btn->SetState("normal","hover","press");
  34. //连接确认和取消按钮的槽函数
  35. connect(ui->cancel_btn, &QPushButton::clicked, this, &ApplyFriend::SlotApplyCancel);
  36. connect(ui->sure_btn, &QPushButton::clicked, this, &ApplyFriend::SlotApplySure);
  37. }
  38. ApplyFriend::~ApplyFriend()
  39. {
  40. qDebug()<< "ApplyFriend destruct";
  41. delete ui;
  42. }

因为此时还未与服务器联调数据,此时我们写一个InitLabel的函数模拟创建多个标签展示

  1. void ApplyFriend::InitTipLbs()
  2. {
  3. int lines = 1;
  4. for(int i = 0; i < _tip_data.size(); i++){
  5. auto* lb = new ClickedLabel(ui->lb_list);
  6. lb->SetState("normal", "hover", "pressed", "selected_normal",
  7. "selected_hover", "selected_pressed");
  8. lb->setObjectName("tipslb");
  9. lb->setText(_tip_data[i]);
  10. connect(lb, &ClickedLabel::clicked, this, &ApplyFriend::SlotChangeFriendLabelByTip);
  11. QFontMetrics fontMetrics(lb->font()); // 获取QLabel控件的字体信息
  12. int textWidth = fontMetrics.width(lb->text()); // 获取文本的宽度
  13. int textHeight = fontMetrics.height(); // 获取文本的高度
  14. if (_tip_cur_point.x() + textWidth + tip_offset > ui->lb_list->width()) {
  15. lines++;
  16. if (lines > 2) {
  17. delete lb;
  18. return;
  19. }
  20. _tip_cur_point.setX(tip_offset);
  21. _tip_cur_point.setY(_tip_cur_point.y() + textHeight + 15);
  22. }
  23. auto next_point = _tip_cur_point;
  24. AddTipLbs(lb, _tip_cur_point,next_point, textWidth, textHeight);
  25. _tip_cur_point = next_point;
  26. }
  27. }

下面这个函数是将标签添加到展示区

  1. void ApplyFriend::AddTipLbs(ClickedLabel* lb, QPoint cur_point, QPoint& next_point, int text_width, int text_height)
  2. {
  3. lb->move(cur_point);
  4. lb->show();
  5. _add_labels.insert(lb->text(), lb);
  6. _add_label_keys.push_back(lb->text());
  7. next_point.setX(lb->pos().x() + text_width + 15);
  8. next_point.setY(lb->pos().y());
  9. }

重写事件过滤器展示滑动条

  1. bool ApplyFriend::eventFilter(QObject *obj, QEvent *event)
  2. {
  3. if (obj == ui->scrollArea && event->type() == QEvent::Enter)
  4. {
  5. ui->scrollArea->verticalScrollBar()->setHidden(false);
  6. }
  7. else if (obj == ui->scrollArea && event->type() == QEvent::Leave)
  8. {
  9. ui->scrollArea->verticalScrollBar()->setHidden(true);
  10. }
  11. return QObject::eventFilter(obj, event);
  12. }

后期搜索用户功能用户数据会从服务器传回来,所以写了下面的接口

  1. void ApplyFriend::SetSearchInfo(std::shared_ptr<SearchInfo> si)
  2. {
  3. _si = si;
  4. auto applyname = UserMgr::GetInstance()->GetName();
  5. auto bakname = si->_name;
  6. ui->name_ed->setText(applyname);
  7. ui->back_ed->setText(bakname);
  8. }

当点击按钮,可展示更多标签的功能。

  1. void ApplyFriend::ShowMoreLabel()
  2. {
  3. qDebug()<< "receive more label clicked";
  4. ui->more_lb_wid->hide();
  5. ui->lb_list->setFixedWidth(325);
  6. _tip_cur_point = QPoint(5, 5);
  7. auto next_point = _tip_cur_point;
  8. int textWidth;
  9. int textHeight;
  10. //重拍现有的label
  11. for(auto & added_key : _add_label_keys){
  12. auto added_lb = _add_labels[added_key];
  13. QFontMetrics fontMetrics(added_lb->font()); // 获取QLabel控件的字体信息
  14. textWidth = fontMetrics.width(added_lb->text()); // 获取文本的宽度
  15. textHeight = fontMetrics.height(); // 获取文本的高度
  16. if(_tip_cur_point.x() +textWidth + tip_offset > ui->lb_list->width()){
  17. _tip_cur_point.setX(tip_offset);
  18. _tip_cur_point.setY(_tip_cur_point.y()+textHeight+15);
  19. }
  20. added_lb->move(_tip_cur_point);
  21. next_point.setX(added_lb->pos().x() + textWidth + 15);
  22. next_point.setY(_tip_cur_point.y());
  23. _tip_cur_point = next_point;
  24. }
  25. //添加未添加的
  26. for(int i = 0; i < _tip_data.size(); i++){
  27. auto iter = _add_labels.find(_tip_data[i]);
  28. if(iter != _add_labels.end()){
  29. continue;
  30. }
  31. auto* lb = new ClickedLabel(ui->lb_list);
  32. lb->SetState("normal", "hover", "pressed", "selected_normal",
  33. "selected_hover", "selected_pressed");
  34. lb->setObjectName("tipslb");
  35. lb->setText(_tip_data[i]);
  36. connect(lb, &ClickedLabel::clicked, this, &ApplyFriend::SlotChangeFriendLabelByTip);
  37. QFontMetrics fontMetrics(lb->font()); // 获取QLabel控件的字体信息
  38. int textWidth = fontMetrics.width(lb->text()); // 获取文本的宽度
  39. int textHeight = fontMetrics.height(); // 获取文本的高度
  40. if (_tip_cur_point.x() + textWidth + tip_offset > ui->lb_list->width()) {
  41. _tip_cur_point.setX(tip_offset);
  42. _tip_cur_point.setY(_tip_cur_point.y() + textHeight + 15);
  43. }
  44. next_point = _tip_cur_point;
  45. AddTipLbs(lb, _tip_cur_point, next_point, textWidth, textHeight);
  46. _tip_cur_point = next_point;
  47. }
  48. int diff_height = next_point.y() + textHeight + tip_offset - ui->lb_list->height();
  49. ui->lb_list->setFixedHeight(next_point.y() + textHeight + tip_offset);
  50. //qDebug()<<"after resize ui->lb_list size is " << ui->lb_list->size();
  51. ui->scrollcontent->setFixedHeight(ui->scrollcontent->height()+diff_height);
  52. }

重排好友标签编辑栏的标签

  1. void ApplyFriend::resetLabels()
  2. {
  3. auto max_width = ui->gridWidget->width();
  4. auto label_height = 0;
  5. for(auto iter = _friend_labels.begin(); iter != _friend_labels.end(); iter++){
  6. //todo... 添加宽度统计
  7. if( _label_point.x() + iter.value()->width() > max_width) {
  8. _label_point.setY(_label_point.y()+iter.value()->height()+6);
  9. _label_point.setX(2);
  10. }
  11. iter.value()->move(_label_point);
  12. iter.value()->show();
  13. _label_point.setX(_label_point.x()+iter.value()->width()+2);
  14. _label_point.setY(_label_point.y());
  15. label_height = iter.value()->height();
  16. }
  17. if(_friend_labels.isEmpty()){
  18. ui->lb_ed->move(_label_point);
  19. return;
  20. }
  21. if(_label_point.x() + MIN_APPLY_LABEL_ED_LEN > ui->gridWidget->width()){
  22. ui->lb_ed->move(2,_label_point.y()+label_height+6);
  23. }else{
  24. ui->lb_ed->move(_label_point);
  25. }
  26. }

添加好友标签编辑栏的标签

  1. void ApplyFriend::addLabel(QString name)
  2. {
  3. if (_friend_labels.find(name) != _friend_labels.end()) {
  4. return;
  5. }
  6. auto tmplabel = new FriendLabel(ui->gridWidget);
  7. tmplabel->SetText(name);
  8. tmplabel->setObjectName("FriendLabel");
  9. auto max_width = ui->gridWidget->width();
  10. //todo... 添加宽度统计
  11. if (_label_point.x() + tmplabel->width() > max_width) {
  12. _label_point.setY(_label_point.y() + tmplabel->height() + 6);
  13. _label_point.setX(2);
  14. }
  15. else {
  16. }
  17. tmplabel->move(_label_point);
  18. tmplabel->show();
  19. _friend_labels[tmplabel->Text()] = tmplabel;
  20. _friend_label_keys.push_back(tmplabel->Text());
  21. connect(tmplabel, &FriendLabel::sig_close, this, &ApplyFriend::SlotRemoveFriendLabel);
  22. _label_point.setX(_label_point.x() + tmplabel->width() + 2);
  23. if (_label_point.x() + MIN_APPLY_LABEL_ED_LEN > ui->gridWidget->width()) {
  24. ui->lb_ed->move(2, _label_point.y() + tmplabel->height() + 2);
  25. }
  26. else {
  27. ui->lb_ed->move(_label_point);
  28. }
  29. ui->lb_ed->clear();
  30. if (ui->gridWidget->height() < _label_point.y() + tmplabel->height() + 2) {
  31. ui->gridWidget->setFixedHeight(_label_point.y() + tmplabel->height() * 2 + 2);
  32. }
  33. }

点击回车后,在好友标签编辑栏添加标签,在标签展示栏添加标签

  1. void ApplyFriend::SlotLabelEnter()
  2. {
  3. if(ui->lb_ed->text().isEmpty()){
  4. return;
  5. }
  6. auto text = ui->lb_ed->text();
  7. addLabel(ui->lb_ed->text());
  8. ui->input_tip_wid->hide();
  9. auto find_it = std::find(_tip_data.begin(), _tip_data.end(), text);
  10. //找到了就只需设置状态为选中即可
  11. if (find_it == _tip_data.end()) {
  12. _tip_data.push_back(text);
  13. }
  14. //判断标签展示栏是否有该标签
  15. auto find_add = _add_labels.find(text);
  16. if (find_add != _add_labels.end()) {
  17. find_add.value()->SetCurState(ClickLbState::Selected);
  18. return;
  19. }
  20. //标签展示栏也增加一个标签, 并设置绿色选中
  21. auto* lb = new ClickedLabel(ui->lb_list);
  22. lb->SetState("normal", "hover", "pressed", "selected_normal",
  23. "selected_hover", "selected_pressed");
  24. lb->setObjectName("tipslb");
  25. lb->setText(text);
  26. connect(lb, &ClickedLabel::clicked, this, &ApplyFriend::SlotChangeFriendLabelByTip);
  27. qDebug() << "ui->lb_list->width() is " << ui->lb_list->width();
  28. qDebug() << "_tip_cur_point.x() is " << _tip_cur_point.x();
  29. QFontMetrics fontMetrics(lb->font()); // 获取QLabel控件的字体信息
  30. int textWidth = fontMetrics.width(lb->text()); // 获取文本的宽度
  31. int textHeight = fontMetrics.height(); // 获取文本的高度
  32. qDebug() << "textWidth is " << textWidth;
  33. if (_tip_cur_point.x() + textWidth + tip_offset + 3 > ui->lb_list->width()) {
  34. _tip_cur_point.setX(5);
  35. _tip_cur_point.setY(_tip_cur_point.y() + textHeight + 15);
  36. }
  37. auto next_point = _tip_cur_point;
  38. AddTipLbs(lb, _tip_cur_point, next_point, textWidth, textHeight);
  39. _tip_cur_point = next_point;
  40. int diff_height = next_point.y() + textHeight + tip_offset - ui->lb_list->height();
  41. ui->lb_list->setFixedHeight(next_point.y() + textHeight + tip_offset);
  42. lb->SetCurState(ClickLbState::Selected);
  43. ui->scrollcontent->setFixedHeight(ui->scrollcontent->height() + diff_height);
  44. }

当我们点击好友标签编辑栏的标签的关闭按钮时会调用下面的槽函数

  1. void ApplyFriend::SlotRemoveFriendLabel(QString name)
  2. {
  3. qDebug() << "receive close signal";
  4. _label_point.setX(2);
  5. _label_point.setY(6);
  6. auto find_iter = _friend_labels.find(name);
  7. if(find_iter == _friend_labels.end()){
  8. return;
  9. }
  10. auto find_key = _friend_label_keys.end();
  11. for(auto iter = _friend_label_keys.begin(); iter != _friend_label_keys.end();
  12. iter++){
  13. if(*iter == name){
  14. find_key = iter;
  15. break;
  16. }
  17. }
  18. if(find_key != _friend_label_keys.end()){
  19. _friend_label_keys.erase(find_key);
  20. }
  21. delete find_iter.value();
  22. _friend_labels.erase(find_iter);
  23. resetLabels();
  24. auto find_add = _add_labels.find(name);
  25. if(find_add == _add_labels.end()){
  26. return;
  27. }
  28. find_add.value()->ResetNormalState();
  29. }

当我们点击标签展示栏的标签,可以实现标签添加和删除

  1. //点击标已有签添加或删除新联系人的标签
  2. void ApplyFriend::SlotChangeFriendLabelByTip(QString lbtext, ClickLbState state)
  3. {
  4. auto find_iter = _add_labels.find(lbtext);
  5. if(find_iter == _add_labels.end()){
  6. return;
  7. }
  8. if(state == ClickLbState::Selected){
  9. //编写添加逻辑
  10. addLabel(lbtext);
  11. return;
  12. }
  13. if(state == ClickLbState::Normal){
  14. //编写删除逻辑
  15. SlotRemoveFriendLabel(lbtext);
  16. return;
  17. }
  18. }

当标签文本变化时,下面提示框的文本跟随变化

  1. void ApplyFriend::SlotLabelTextChange(const QString& text)
  2. {
  3. if (text.isEmpty()) {
  4. ui->tip_lb->setText("");
  5. ui->input_tip_wid->hide();
  6. return;
  7. }
  8. auto iter = std::find(_tip_data.begin(), _tip_data.end(), text);
  9. if (iter == _tip_data.end()) {
  10. auto new_text = add_prefix + text;
  11. ui->tip_lb->setText(new_text);
  12. ui->input_tip_wid->show();
  13. return;
  14. }
  15. ui->tip_lb->setText(text);
  16. ui->input_tip_wid->show();
  17. }

如果编辑完成,则隐藏编辑框

  1. void ApplyFriend::SlotLabelEditFinished()
  2. {
  3. ui->input_tip_wid->hide();
  4. }

点击提示框,也会添加标签,功能如下

  1. void ApplyFriend::SlotAddFirendLabelByClickTip(QString text)
  2. {
  3. int index = text.indexOf(add_prefix);
  4. if (index != -1) {
  5. text = text.mid(index + add_prefix.length());
  6. }
  7. addLabel(text);
  8. auto find_it = std::find(_tip_data.begin(), _tip_data.end(), text);
  9. //找到了就只需设置状态为选中即可
  10. if (find_it == _tip_data.end()) {
  11. _tip_data.push_back(text);
  12. }
  13. //判断标签展示栏是否有该标签
  14. auto find_add = _add_labels.find(text);
  15. if (find_add != _add_labels.end()) {
  16. find_add.value()->SetCurState(ClickLbState::Selected);
  17. return;
  18. }
  19. //标签展示栏也增加一个标签, 并设置绿色选中
  20. auto* lb = new ClickedLabel(ui->lb_list);
  21. lb->SetState("normal", "hover", "pressed", "selected_normal",
  22. "selected_hover", "selected_pressed");
  23. lb->setObjectName("tipslb");
  24. lb->setText(text);
  25. connect(lb, &ClickedLabel::clicked, this, &ApplyFriend::SlotChangeFriendLabelByTip);
  26. qDebug() << "ui->lb_list->width() is " << ui->lb_list->width();
  27. qDebug() << "_tip_cur_point.x() is " << _tip_cur_point.x();
  28. QFontMetrics fontMetrics(lb->font()); // 获取QLabel控件的字体信息
  29. int textWidth = fontMetrics.width(lb->text()); // 获取文本的宽度
  30. int textHeight = fontMetrics.height(); // 获取文本的高度
  31. qDebug() << "textWidth is " << textWidth;
  32. if (_tip_cur_point.x() + textWidth+ tip_offset+3 > ui->lb_list->width()) {
  33. _tip_cur_point.setX(5);
  34. _tip_cur_point.setY(_tip_cur_point.y() + textHeight + 15);
  35. }
  36. auto next_point = _tip_cur_point;
  37. AddTipLbs(lb, _tip_cur_point, next_point, textWidth,textHeight);
  38. _tip_cur_point = next_point;
  39. int diff_height = next_point.y() + textHeight + tip_offset - ui->lb_list->height();
  40. ui->lb_list->setFixedHeight(next_point.y() + textHeight + tip_offset);
  41. lb->SetCurState(ClickLbState::Selected);
  42. ui->scrollcontent->setFixedHeight(ui->scrollcontent->height()+ diff_height );
  43. }

确认申请和取消申请只是打印了对应信息,并且回收界面

  1. void ApplyFriend::SlotApplyCancel()
  2. {
  3. qDebug() << "Slot Apply Cancel";
  4. this->hide();
  5. deleteLater();
  6. }
  7. void ApplyFriend::SlotApplySure()
  8. {
  9. qDebug()<<"Slot Apply Sure called" ;
  10. this->hide();
  11. deleteLater();
  12. }

美化界面

添加如下qss文件美化界面

  1. #ApplyFriend{
  2. border: 2px solid #f1f1f1;
  3. font-size: 14px;
  4. background: #f7f7f8;
  5. }
  6. #scrollArea{
  7. background: #f7f7f8;
  8. border: none;
  9. }
  10. #scrollcontent{
  11. background: #f7f7f8;
  12. }
  13. #scrollcontent #apply_lb{
  14. font-family: "Microsoft YaHei";
  15. font-size: 16px;
  16. font-weight: normal;
  17. }
  18. #apply_wid QLabel{
  19. color:rgb(140,140,140);
  20. font-size: 14px;
  21. font-family: "Microsoft YaHei";
  22. height: 25px;
  23. }
  24. #apply_wid #name_ed, #apply_wid #back_ed{
  25. border: 1px solid #f7f7f8;
  26. font-size: 14px;
  27. font-family: "Microsoft YaHei";
  28. }
  29. #apply_wid #lb_ed {
  30. border: none;
  31. font-size: 14px;
  32. font-family: "Microsoft YaHei";
  33. }
  34. #apply_wid #more_lb{
  35. border-image: url(:/res/arowdown.png);
  36. }
  37. #apply_wid #tipslb[state='normal'] {
  38. padding: 2px;
  39. background: #e1e1e1;
  40. color: #1e1e1e;
  41. border-radius: 10px;
  42. }
  43. #apply_wid #tipslb[state='hover'] {
  44. padding: 2px;
  45. background: #e1e1e1;
  46. color: #1e1e1e;
  47. border-radius: 10px;
  48. }
  49. #apply_wid #tipslb[state='pressed'] {
  50. padding: 2px;
  51. background: #e1e1e1;
  52. color: #48bf56;
  53. border-radius: 10px;
  54. }
  55. #apply_wid #tipslb[state='selected_normal'] {
  56. padding: 2px;
  57. background: #e1e1e1;
  58. color: #48bf56;
  59. border-radius: 10px;
  60. }
  61. #apply_wid #tipslb[state='selected_hover'] {
  62. padding: 2px;
  63. background: #e1e1e1;
  64. color: #48bf56;
  65. border-radius: 10px;
  66. }
  67. #apply_wid #tipslb[state='selected_pressed'] {
  68. padding: 2px;
  69. background: #e1e1e1;
  70. color: #1e1e1e;
  71. border-radius: 10px;
  72. }
  73. #input_tip_wid {
  74. background: #d3eaf8;
  75. }
  76. #apply_wid #FriendLabel {
  77. background: #daf6e7;
  78. color: #48bf56;
  79. border-radius: 10px;
  80. }
  81. #apply_wid #tip_lb {
  82. padding-left: 2px;
  83. color:rgb(153,153,153);
  84. font-size: 14px;
  85. font-family: "Microsoft YaHei";
  86. }
  87. #gridWidget {
  88. background: #fdfdfd;
  89. }
  90. #close_lb[state='normal'] {
  91. border-image: url(:/res/tipclose.png);
  92. }
  93. #close_lb[state='hover'] {
  94. border-image: url(:/res/tipclose.png);
  95. }
  96. #close_lb[state='pressed'] {
  97. border-image: url(:/res/tipclose.png);
  98. }
  99. #close_lb[state='select_normal'] {
  100. border-image: url(:/res/tipclose.png);
  101. }
  102. #close_lb[state='select_hover'] {
  103. border-image: url(:/res/tipclose.png);
  104. }
  105. #close_lb[state='select_pressed'] {
  106. border-image: url(:/res/tipclose.png);
  107. }
  108. #apply_sure_wid #sure_btn[state='normal'] {
  109. background: #f0f0f0;
  110. color: #2cb46e;
  111. font-size: 16px; /* 设置字体大小 */
  112. font-family: "Microsoft YaHei"; /* 设置字体 */
  113. border-radius: 20px; /* 设置圆角 */
  114. }
  115. #apply_sure_wid #sure_btn[state='hover'] {
  116. background: #d2d2d2;
  117. color: #2cb46e;
  118. font-size: 16px; /* 设置字体大小 */
  119. font-family: "Microsoft YaHei"; /* 设置字体 */
  120. border-radius: 20px; /* 设置圆角 */
  121. }
  122. #apply_sure_wid #sure_btn[state='press'] {
  123. background: #c6c6c6;
  124. color: #2cb46e;
  125. font-size: 16px; /* 设置字体大小 */
  126. font-family: "Microsoft YaHei"; /* 设置字体 */
  127. border-radius: 20px; /* 设置圆角 */
  128. }
  129. #apply_sure_wid #cancel_btn[state='normal'] {
  130. background: #f0f0f0;
  131. color: #2e2f30;
  132. font-size: 16px; /* 设置字体大小 */
  133. font-family: "Microsoft YaHei"; /* 设置字体 */
  134. border-radius: 20px; /* 设置圆角 */
  135. }
  136. #apply_sure_wid #cancel_btn[state='hover'] {
  137. background: #d2d2d2;
  138. color: #2e2f30;
  139. font-size: 16px; /* 设置字体大小 */
  140. font-family: "Microsoft YaHei"; /* 设置字体 */
  141. border-radius: 20px; /* 设置圆角 */
  142. }
  143. #apply_sure_wid #cancel_btn[state='press'] {
  144. background: #c6c6c6;
  145. color: #2e2f30;
  146. font-size: 16px; /* 设置字体大小 */
  147. font-family: "Microsoft YaHei"; /* 设置字体 */
  148. border-radius: 20px; /* 设置圆角 */
  149. }

视频

https://www.bilibili.com/video/BV1ZM4m127z8/?vd_source=8be9e83424c2ed2c9b2a3ed1d01385e9

源码链接

https://gitee.com/secondtonone1/llfcchat

热门评论

热门文章

  1. 解密定时器的实现细节

    喜欢(566) 浏览(2262)
  2. C++ 类的继承封装和多态

    喜欢(588) 浏览(3175)
  3. Linux环境搭建和编码

    喜欢(594) 浏览(6837)
  4. windows环境搭建和vscode配置

    喜欢(587) 浏览(1850)
  5. slice介绍和使用

    喜欢(521) 浏览(1927)

最新评论

  1. 线程基础 mzx2023:新手好奇问一下,这是什么原因呢?
  2. interface应用 secondtonone1:interface是万能类型,但是使用时要转换为实际类型来使用。interface丰富了go的多态特性,也降低了传统面向对象语言的耦合性。
  3. 堆排序 secondtonone1:堆排序非常实用,定时器就是这个原理制作的。
  4. asio多线程模式IOThreadPool secondtonone1:这么优秀吗
  5. 互斥与死锁 Vstronzw://仅提供一份参考代码给同样初学者的我们[脱单doge] /* 定义了如下栈, 对于多线程访问时判断栈是否为空, 此后两个线程同时出栈,可能会造成崩溃 */ #include <iostream> #include <string> #include <thread> #include <vector> #include <mutex> #include <stack> #include <exception> using namespace std; struct empty_stack : public std::exception { public: const char* what()const throw() //函数后面必须跟throw(),括号里面不能有任务参数,表示不抛出任务异常 //因为这个已经是一个异常处理信息了,不能再抛异常。 { return "empty_stack"; } }; //struct empty_stack : std::exception //{ // const char* what() const throw(); //}; template<typename T> class threadsafe_stack { private: std::stack<T> data; mutable std::mutex m; public: threadsafe_stack() {} threadsafe_stack(const threadsafe_stack& other) { std::lock_guard<std::mutex> lock(other.m); //①在构造函数的函数体(constructor body)内进行复制操作 data = other.data; } threadsafe_stack& operator=(const threadsafe_stack&) = delete; void push(T new_value) { std::lock_guard<std::mutex> lock(m); data.push(std::move(new_value)); } T pop() { std::lock_guard<std::mutex> lock(m); if (data.empty()) throw empty_stack(); auto element = data.top(); data.pop(); return element; } bool empty() const { std::lock_guard<std::mutex> lock(m); return data.empty(); } }; void test_threadsafe_stack() { threadsafe_stack<int> safe_stack; safe_stack.push(1); std::thread t1([&safe_stack]() { if (!safe_stack.empty()) { std::this_thread::sleep_for(std::chrono::seconds(1)); try { safe_stack.pop(); } catch (empty_stack &e) { cout << e.what() << endl; } } }); std::thread t2([&safe_stack]() { if (!safe_stack.empty()) { std::this_thread::sleep_for(std::chrono::seconds(1)); try { safe_stack.pop(); } catch (empty_stack &e) { cout << e.what() << endl; } } }); t1.join(); t2.join(); } int main() { test_threadsafe_stack(); return 0; } /* empty_stack */

个人公众号

个人微信