QT二 QT使用generate form 生成常用UI,各种UI控件

一 。没有使用general form  和  使用 general form 后,file层面和代码层面的不同比较

file层面的不同

代码层面的不同,

在 使用了general form之后,在主界面的构造方法中,使用ui->setupUi(this),就完成了所有UI的处理。

而之前我们的没有使用general form的时候,需要自己通过写代码一步一步的完成。

比较多出来的file 以及 代码层面的不同 后的 疑问:

在没有使用general form时,我们的代码生成是使用了一系列函数生成的,那么是不是 ui->setupUi(this);的内部也是和我们使用一系列函数差不多呢?

验证:

1.我们先来看多出来的mainwindow.ui是个啥?

在QT Creator中双击 mainwindow.ui,看到会跳转到一个可以操作的UI界面

使用 UE 打开 mainwindow.ui,可以看到是一个xml格式的文件

 
 结论:mainwindow.ui是一个xml的文件。该文件中用xml格式记录了当前mainwindow中的组件。QT Creator在打开这个xml的时候,做了事情,将xml文件变成了可视化的UI。如果我们通过可视化UI,给里面的增添改UI,然后QT Creator会将我们的操作变成xml文件。

验证QT Creator 将开发者可视化UI的操作变成xml实验:

之前界面和xml是这样:

我们往界面上通过可视化UI 添加一个 qpushbutton,保存后,可以看到xml文件多了一些东西

2. 那么这个 ui->setupUi(this)是干啥的呢?

我们按照以往的经验,在 ui->setupUi(this) 这一行上,按住ctrl+鼠标左键,看一下这一行代码跳转到哪里?--结果跳出来error,

这个error的意思是:我们找不到ui_mainwindows.h这个文件。或者没有权限打开这个文件。该文件是在这个目录下:

D:\code_qt\build-004qtUIstudy-Desktop_Qt_5_14_2_MinGW_32_bit-Debug\ui_mainwindow.h

那我们在磁盘里面找一下这个文件。发现确实没有这个文件。

我们再来看一下给出的error信息 路径是在

D:\code_qt\build-004qtUIstudy-Desktop_Qt_5_14_2_MinGW_32_bit-Debug\ui_mainwindow.h

这时候就想到了,这个应该是 项目build 之后生成的吧,于是查看了一下该项目的配置,果然是在D:\code_qt\build-004qtUIstudy-Desktop_Qt_5_14_2_MinGW_32_bit-Debug下面,也就是我们需要构建之后,才会生成 ui_mainwindow.h这个文件。

构建此项目

构建完成后,发现就生成了这个目录了。

在QT Creator 中 打开ui_mainwindow.h文件查看,还是ctrl+鼠标左键打开。为什么不用UE直接打开呢?因为在 QT Creator 中打开代码有关联性,方便查看。我们终于看到了熟悉的画面,和我们不使用general form时候的代码。

二 使用general form 后,QT 帮我们到底做了什么 的回答

1.QT Creator 提供了可视化的UI,方便开发者增删改UI,

2.改动的UI,QTCreator 会变成本质上是xml的 xxx.ui文件

3.然后QT 会在build 的过程中,将 xxx.ui文件变成ui_xxx.h文件。而这个 ui_xxx.h 文件并不是.h文件,实际上也含有.cpp的内容。

总结

                通过QT build 的过程

xxx.ui--------------------------------------> 变成 最终的 ui_xxx.h 文件

在代码中 通过 ui->setupUi(this); 这一行代码 加载 ui_xxx.h,完成 UI的创建。

好处1:

开发者可以通过可视化UI ,实现自己想要的UI界面。QT 帮忙转换成代码,最终通过ui->setupUi(this)加载这些代码生成UI。

 好处2:

开发者可以通过 查看这些可视化UI的最终代码,学习在代码层面实现,而不是借助可视化UI工具。

另一个问题:既然QT给了我们可视化UI的界面,为什么还要在第一章学习用代码生成UI呢?这是因为两个原因:1是在实际工作用,用代码生成UI的部分也不少。作为开发者首先就要要弄清楚这个原理。2是因为我们在后面学习到深度定制某一个UI控件的时候(假设我们这里的需求是自己开发一个button,自己的这个button 不能接受鼠标的点击事件,),这就需要我们自己create mybutton,并重写 mybutton的click事件,或者直接屏蔽click事件,这些的基础都是自己创建UI并。如果这块暂时想不明白也没有关系,学到后面知识就了解了。

三。 QT控件学习

实际上就是学习如下图的所有,但是有些UI不常用,有些UI,常用的部分,会在标题前面加上红色的"常用"两个字

四 ,Layouts 部分详解

1.垂直布局Vertical Layout 对应类为(QVBoxLayout)

学习思路是这样的,我们先在UI上拖拽一个 Vertical Layout 进去,然后给 Vertical Layout里面加上两个button。弄好UI后,保存一下,然后 使用 QT 的 "构建",最后看QT 生成的源码 ui_xxx.h

结合源码 和 QT api助手,学习垂直布局的常用写法,以及参数。

1.1拖入UI后的效果

1.2 构建

1.3 结合 QT-API助手 和  QT生成代码 学习

代码位置ui_mainwindow.h

D:\code_qt\build-004qtUIstudy-Desktop_Qt_5_14_2_MinGW_32_bit-Debug\ui_mainwindow.h

全部代码:
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.14.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>QT_BEGIN_NAMESPACEclass Ui_MainWindow
{
public:QAction *actionsave;QWidget *centralwidget;QWidget *verticalLayoutWidget;QVBoxLayout *verticalLayout;QPushButton *pushButton;QPushButton *pushButton_2;QMenuBar *menubar;QStatusBar *statusbar;void setupUi(QMainWindow *MainWindow){if (MainWindow->objectName().isEmpty())MainWindow->setObjectName(QString::fromUtf8("MainWindow"));MainWindow->resize(888, 666);actionsave = new QAction(MainWindow);actionsave->setObjectName(QString::fromUtf8("actionsave"));centralwidget = new QWidget(MainWindow);centralwidget->setObjectName(QString::fromUtf8("centralwidget"));verticalLayoutWidget = new QWidget(centralwidget);verticalLayoutWidget->setObjectName(QString::fromUtf8("verticalLayoutWidget"));verticalLayoutWidget->setGeometry(QRect(70, 60, 241, 191));verticalLayout = new QVBoxLayout(verticalLayoutWidget);verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));verticalLayout->setContentsMargins(0, 0, 0, 0);pushButton = new QPushButton(verticalLayoutWidget);pushButton->setObjectName(QString::fromUtf8("pushButton"));verticalLayout->addWidget(pushButton);pushButton_2 = new QPushButton(verticalLayoutWidget);pushButton_2->setObjectName(QString::fromUtf8("pushButton_2"));verticalLayout->addWidget(pushButton_2);MainWindow->setCentralWidget(centralwidget);menubar = new QMenuBar(MainWindow);menubar->setObjectName(QString::fromUtf8("menubar"));menubar->setGeometry(QRect(0, 0, 888, 21));MainWindow->setMenuBar(menubar);statusbar = new QStatusBar(MainWindow);statusbar->setObjectName(QString::fromUtf8("statusbar"));MainWindow->setStatusBar(statusbar);retranslateUi(MainWindow);QMetaObject::connectSlotsByName(MainWindow);} // setupUivoid retranslateUi(QMainWindow *MainWindow){MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));actionsave->setText(QCoreApplication::translate("MainWindow", "save", nullptr));pushButton->setText(QCoreApplication::translate("MainWindow", "\346\214\211\351\222\2561", nullptr));pushButton_2->setText(QCoreApplication::translate("MainWindow", "\346\214\211\351\222\2562", nullptr));} // retranslateUi};namespace Ui {class MainWindow: public Ui_MainWindow {};
} // namespace UiQT_END_NAMESPACE#endif // UI_MAINWINDOW_H

关键代码:

结论(重点):

1.我们拖拽的垂直布局Vertical Layout 实际上会做两件事情

        第一,生成一个新widget,该新的widget 的主控件是 centralwidget。

        第二,然后基于这个新的widget创建QVBoxLayout

2. 最后的两个button 也是基于 新widget 创建的。

也就是说,button的生命周期依存于 新的widget

3. 但是UI上的显示在layout上 --------通过 layout->addwidget(pushbutton) 实现。

4.layout在构造方法中的第一个参数,表示了这个layout是那个widget的layout。

除了这个构造方法外,QT api 助手中给了setLayout方法

      QWidget *window = new QWidget;QPushButton *button1 = new QPushButton("One");QPushButton *button2 = new QPushButton("Two");QPushButton *button3 = new QPushButton("Three");QPushButton *button4 = new QPushButton("Four");QPushButton *button5 = new QPushButton("Five");QHBoxLayout *layout = new QHBoxLayout;layout->addWidget(button1);layout->addWidget(button2);layout->addWidget(button3);layout->addWidget(button4);layout->addWidget(button5);window->setLayout(layout);window->show();

1.4 自己写代码验证。

这里创建一个 QT设计师界面类,写代码完成我们的代码验证

这里选择main window 和 widget其实都是可以的,反正都是学习用的

在main.cpp中调用的时候,改动代码如下:新建一个StudyMainWindow实例,然后show。

也就是说:我们在main函数中显示自己写的 studymainwindow。

int main(int argc, char *argv[])
{QApplication a(argc, argv);
//    MainWindow w;
//    w.show();StudyMainWindow sm;sm.show();return a.exec();
}

在studymainwindow.ui中什么也不干。

然后在studymainwindow 的构造函数中写代码 模拟前面我们在UI中的Vertical Layout的写法,这样就能验证之前的想法了。

也就是说:当前代码中是通过如下的方法加载UI的:

        1.StudyMainWindow的构造方法中通过 ui->setupUi(this);加载一部分UI

        2.StudyMainWindow的构造方法中ui->setupUi(this)方法后,通过自己写的代码加载一部分UI

先来看一下 ui->setupUi(this);中干了啥?

        弄了一个QMenuBar,弄了一个QWidget(该widget就是centralwidget),弄了一个QStatusBar

        StudyMainWindow->resize(800, 600);menubar = new QMenuBar(StudyMainWindow);menubar->setObjectName(QString::fromUtf8("menubar"));StudyMainWindow->setMenuBar(menubar);centralwidget = new QWidget(StudyMainWindow);centralwidget->setObjectName(QString::fromUtf8("centralwidget"));StudyMainWindow->setCentralWidget(centralwidget);statusbar = new QStatusBar(StudyMainWindow);statusbar->setObjectName(QString::fromUtf8("statusbar"));StudyMainWindow->setStatusBar(statusbar);

自己写的代码如下:

StudyMainWindow::StudyMainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::StudyMainWindow)
{ui->setupUi(this);//在 ui->setupUi(this)后,我们写自己想要验证部分的代码//1.创建新的widget,注意这里给定参数是 ui中的centralwidget。那么这个newwidget的大小就和centralwidget的大小一致了//1.1 我们打印一下 ui->centralwidget 的大小,打印结果是 width = 100, height = 30,从studymainwindows.ui上来看,我们并没有主动的设置centralwidget的大小/*那么谁设定的呢?进而查看了 QT帮我们生成的ui_mainstudymainwindow.h文件里面的写法,也只有如下的两句centralwidget = new QWidget(StudyMainWindow);centralwidget->setObjectName(QString::fromUtf8("centralwidget"));那么怀疑的对象只能是在QWidget.cpp中做了设置大小的事情,于是查看qwiget.cpp,发现如下代码大约在qwidget.cpp 的1046行data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,640,480);也就是说,你new 的qwidget,如果有父控件,则默认给100,30的大小,如果没有父控件,则给出640,480的控件这意味着啥?默认mainwindow的 主控件centralwidget的大小就是100,30的大小的,如需要,可以自己改动。*/qDebug()<<this->ui->centralwidget->width(); //这个值是100qDebug()<<this->ui->centralwidget->height();//这个值是30QWidget *newwidget = new QWidget(ui->centralwidget);//由于centralwidget是100,30的,那么newwidget应该也newwidget->setGeometry(0,0,500,600);//new 一个 QVBoxLayout出来,参数为刚才创建的newwidget,这样 QVBoxLayout 就是newwidget的layout,如果不设置参数,则要通过 newwidget.setLayout(vlayout) 方法设置的newwidget的layout就是vlayout.QVBoxLayout *vlayout = new QVBoxLayout(newwidget);QPushButton *button1 = new QPushButton(newwidget);button1->setText("aaa");QPushButton *button2 = new QPushButton(newwidget);button2->setText("bbb");vlayout->addWidget(button1);vlayout->addWidget(button2);
}

创建layout的时候如果不加参数的写法

StudyMainWindow::StudyMainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::StudyMainWindow)
{ui->setupUi(this);QWidget *newwidget = new QWidget(ui->centralwidget);newwidget->setGeometry(0,0,500,600);QHBoxLayout *hlayout = new QHBoxLayout();QPushButton *button1 = new QPushButton();button1->setText("ccc");QPushButton *button2 = new QPushButton();button2->setText("ddd");hlayout->addWidget(button1);hlayout->addWidget(button2);newwidget->setLayout(hlayout);}

1.5 Vertical Layout其他属性和UI对照图,以及代码的写法

我们弄一个 Vertical Layout,然后给 Vertical Layout中加两个button。

思路是这样的:改一下红色框框的属性,看看改动后 在UI层面的显示,以及生成的代码主要使用的api,然后再结合 QT api 助手学习

1.5.0. layoutName:控件的名称

1.5.1 改动layoutLeftMargin,layoutTopMargin,layoutLeftMargin,layoutBottomMargin
layoutLeftMargin:控件的左边距;比如我们设置这个值为20,可以看到内部的button距离左侧的边距有了变化UI

QT生成的代码:

verticalLayout->setContentsMargins(20, 40, 60, 80);

QT api 助手中的api 说明:

void QLayout::setContentsMargins(int left, int top, int right, int bottom)

Sets the left, top, right, and bottom margins to use around the layout.

By default, QLayout uses the values provided by the style. On most platforms, the margin is 11 pixels in all directions.

This function was introduced in Qt 4.3.

1.5.2 改动layoutspacing的值-layoutSpacing:控件间的间距,效果如图

UI

QT生成的代码:

verticalLayout->setSpacing(70);

QT api 助手中的api 说明:

void QBoxLayout::setSpacing(int spacing)
Reimplements QLayout::setSpacing(). Sets the spacing property to spacing.

1.5.3 layoutStretch:控制各个控件所占的比例,列表中的每个整数表示对应控件的伸缩因子,列表长度应与布局中的控件数量相等,伸缩因子越大,控件在布局中所占的空间就越大,但是在QBoxLayout中好像不起作用。

1.5.4 layoutSizeConstraint:控件在适应不同布局大小时,子控件的大小和位置如何变化

  • SetDefaultConstraint:使用默认的尺寸,布局没有特定的约束
  • SetNoConstraint:布局没有特定的尺寸策略,保持用户设定的已有属性
  • SetMinimumSize:布局和其子控件的尺寸至少为设定的最小值,可以随着窗口的增大而增大
  • SetFixedSize:控件大小为固定值,不会随着布局大小的变化而变化
  • SetMaximumSize:限制控件的最大尺寸,可以随着窗口缩小而缩小
  • SetMinAndMaxSize:布局和其子控件的尺寸被限制在设定的最小值和最大值之间

2.水平布局Horizontal Layout 对应类为(QHBoxLayout

3.网络布局Grid Layout 对应类为 (QGridLayout)

4.表格布局Form Layout 对应类为  (QFormLayout)

五. spacers部分详解

Qt6教程之二(2) Spacers_qt spacer-CSDN博客

六 Buttons

七 Item Views

八 Item Widgets

九 Containers

十 Input Widgets

十一 Dispaly Widgets

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39292.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Haption力反馈遥操作机器人:6自由度高精度技术,定义远程操作新标准

Haption在力反馈遥操作机器人技术领域展现了强大的创新能力。其核心技术——力反馈技术&#xff0c;通过提供高度逼真的触觉反馈&#xff0c;显著提升了远程操作的精确性与用户体验。这种技术在工业、医疗等高要求场景中表现出色&#xff0c;同时也为科研和教育领域提供了有力支…

魔塔社区的torch_empty错误问题的解决办法

前言 我在运行魔塔社区&#xff08;modelscope&#xff09;的ZhipuAI/chatglm3-6b模型&#xff08;智谱&#xff09;的实例程序的时候&#xff0c;碰到了一个奇怪的错误&#xff08;torch.empty&#xff09;&#xff0c;我尝试解决了一下。 &#xff08;当前采用的Python版本…

全面了解 Cookies、Session 和 Token

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

51c自动驾驶~合集26

我自己的原文哦~ https://blog.51cto.com/whaosoft/11968755 #大模型/Sora/世界模型之间是什么关系 1 什么是大模型 人工智能大模型&#xff08;Artificial Intelligence Large Model&#xff0c;简称AI大模型&#xff09;是指具有庞大的参数规模和复杂程度的机器学习模…

分布式环境下的重复请求防护:非Redis锁替代方案全解析

目录 引言 方案一&#xff1a;前端防护策略 方案二&#xff1a;后端协同控制 方案三&#xff1a;流量控制与过滤 滑动窗口限流 布隆过滤器 方案四&#xff1a;基于框架的实践方案 多层防护策略与最佳实践 总结 引言 在Web应用开发中&#xff0c;防止用户重复点…

4.1 C#获取目录的3个方法的区别

C#中常用有如下3个获取目录的方式如下 1.Directory.GetCurrentDirectory():获取当前工作目录&#xff0c;工作目录可能被用户或其他代码修改。尽量少用。&#xff08;似乎只要在运行中使用另存为或者打开某个文件夹&#xff0c;当前工作目录就修改&#xff09; 2.Application…

【漏洞复现】Next.js中间件权限绕过漏洞 CVE-2025-29927

什么是Next.js&#xff1f; Next.js 是由 Vercel 开发的基于 React 的现代 Web 应用框架&#xff0c;具备前后端一体的开发能力&#xff0c;广泛用于开发 Server-side Rendering (SSR) 和静态站点生成&#xff08;SSG&#xff09;项目。Next.js 支持传统的 Node.js 模式和基于边…

MCU-芯片时钟与总线和定时器关系,举例QSPI

时钟源&#xff1a; 时钟源为系统时钟提供原始频率信号&#xff0c;系统时钟则通过&#xff08;分频、倍频、选择器&#xff09;成为整个芯片的“主时钟”&#xff0c;驱动 CPU 内核、总线&#xff08;AHB、APB&#xff09;及外设的运行。 内部时钟源&#xff1a; HSI&#x…

使用 ByteDance 的 UI-TARS Desktop 探索 AI 驱动的 GUI 自动化新前沿

文章目录 UI-TARS Desktop 是什么&#xff1f;技术亮点应用场景如何快速上手&#xff1f;与其他技术的对比未来展望结语 随着人工智能技术的快速发展&#xff0c;AI 正在从单纯的文本生成和图像识别迈向更复杂的交互场景。ByteDance 近期推出的 UI-TARS Desktop&#xff08;基于…

DockerFile制作镜像(Dockerfile Creates an Image)

DockerFile制作镜像 hub.docker.com 搜索到的 Redis官方镜像&#xff0c;提示我们可以创建自己的 DockerFile 来添加 redis.conf 文件&#xff1a; 于是&#xff0c;我准备进行首次 DockerFile 的制作尝试。 一、准备工作 1.1 下载 redis.conf 我的方案是从 GitHub 上下载 …

C++List模拟实现|细节|难点|易错点|全面解析|类型转换|

目录 1.模拟代码全部 2.四大块代码理解 1.最底层&#xff1a;ListNode部分 2.第二层&#xff1a;ListIterator部分 3.第三层&#xff1a;ReserveListIterator部分 4最终层&#xff1a;List 1.模拟代码全部 using namespace std; template<class T> struct ListNode …

如何让自动驾驶汽车“看清”世界?坐标映射与数据融合概述

在自动驾驶领域,多传感器融合技术是实现车辆环境感知和决策控制的关键。其中,坐标系映射和对应是多传感器融合的重要环节,它涉及到不同传感器数据在统一坐标系下的转换和匹配,以实现对车辆周围环境的准确感知。本文将介绍多传感器融合中坐标系映射和对应的数学基础和实际应…

鸿蒙开发之背景图片的使用

在鸿蒙开发中&#xff0c;设置背景图片是提升应用界面视觉效果的重要一环。以下是关于鸿蒙开发中背景图片使用的详细方法&#xff1a; 一、通过XML布局文件设置背景图片 1.使用Image组件设置背景图片 在XML布局文件中&#xff0c;可以使用Image组件来设置背景图片。通过ohos…

如何在 HTML 中创建一个有序列表和无序列表,它们的语义有何不同?

大白话如何在 HTML 中创建一个有序列表和无序列表&#xff0c;它们的语义有何不同&#xff1f; 1. HTML 中有序列表和无序列表的基本概念 在 HTML 里&#xff0c;列表是一种用来组织信息的方式。有序列表就是带有编号的列表&#xff0c;它可以让内容按照一定的顺序呈现&#…

c++malloc出来的对象调用构造-------定位new

前言:之前在搓高并发内存池的时候就在想,类对象不能调用自身的构造函数,那直接申请内存出来的类对象岂不是很难受,然后我这两天仔细研究了一下,发现其实构造函数也可以显示去调用,而且含不限量,故做此文 在c中一个类对象不能直接调用自身的构造 class A { public:A() {cout &l…

ElementUI时间选择、日期选择

如大家所发现的&#xff0c;由于ElementUI 时间选择器&#xff0c;日期选择器&#xff0c;时间日期选择器点击清除按钮时&#xff0c;v-model 所绑定的属性值会变成 null&#xff0c;所以当使用 ElementUI 时间选择器&#xff0c;日期选择器&#xff0c;时间日期选择器 时&…

一篇文章入门Python Flask框架前后端数据库开发实践(pycharm在anaconda环境下)

Python Flask 是一个轻量级的 Web 应用框架&#xff0c;也被称为微框架。它以简洁、灵活和易于上手的特点而受到开发者的喜爱。 核心特点 轻量级&#xff1a;Flask 核心代码简洁&#xff0c;仅包含 Web 开发的基本功能&#xff0c;不强制使用特定的数据库、模板引擎等&#xf…

ctfshow WEB web2

1.查当前数据库名称 or 11 union select 1,database(),3 limit 1,2;#-- 得到数据库名称web2 2.查看数据库表的数量 or 11 union select 1,(select count(*) from information_schema.tables where table_schema web2),3 limit 1,2;#-- 得到数据库表数量为2 3.查表的名字 第…

【Git】--- 分支管理

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; Git 本篇博客我们来介绍Git的一个重要功能之一 ---- 分支。我们将讲解关于分支的各种操作&#xff0c;以及如何帮助我们进行开发。 &#x1f3e0; 理解分支…

系统思考与心智模式

“问题不是出在我们做了多少&#xff0c;而是出在我们做了什么。” — 赫尔曼凯恩 “一分耕耘一分收获”&#xff0c;这似乎是我们脑海中根深蒂固的心智模式。今天&#xff0c;我在一家餐厅用餐&#xff0c;店员告诉我&#xff0c;打卡收藏可以获得一份小食。没过多久&#xf…