Qt的全面学习笔记【持续更新】

17 篇文章 13 订阅

目录大纲

本人会些Java、C++,速成做了Qt前端工程师,但是做项目时遇到很多不懂或问题,想在此分享于大家,也方便自己回顾;若有关于Qt问题,可评论提出,或许能帮些忙;若编写有误,也可评论,我会积极纠正的,提前道声谢谢~

认识Qt

  • 1991年由Qt Company(原公司名:奇趣科技)开发的跨平台C++ 图形用户界面GUI应用程序开发框架——Qt。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。
    Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些宏,Qt很容易扩展,并且允许真正地组件编程。
  • 1996年进入商业领域,成为全世界范围内数千种成功的应用程序的基础。它也是目前流行的Linux桌面环境(KDE)的基础,KDE是Linux发行版的主要一个标准组件。
  • 2008年,奇趣科技被诺基亚公司收购,Qt也因此成为诺基亚旗下的编程语言工具。
  • 2012年,Qt被Digia(芬兰IT服务公司)收购。
  • 2014年,Digia宣布成立“The Qt Company”全资子公司,以进一步推动Qt产品的开发和市场扩张。
  • 2014年4月,跨平台集成开发环境Qt Creator 3.1.0正式发布,实现了对于iOS的完全支持,新增WinRT、Beautifier等插件,废弃了无Python接口的GDB调试支持,集成了基于Clang的C/C++代码模块,并对Android支持做出了调整,至此实现了全面支持iOSAndroidWP,它提供给应用程序开发者建立艺术级的图形用户界面所需的所有功能。基本上,Qt 同 X Window 上的 Motif,Openwin,GTK 等图形界面库和 Windows 平台上的 MFC,OWL,VCL,ATL 是同类型的东西。

学习网站

安装Qt

在Linux时

在Windows时

  • Win10系统安装Qt5.8.0,不会出现“缺少某dll文件”的问题。
  • 打开Qt软件,载入已有项目:
    • [提示译文:没有找到这个Qt Creator实例创建的 .user 设置文件。您以前是否在其他机器上使用过这个项目,或者使用过不同的使用路径?您是否仍然要加载设置文件“C:\Userslyanfa\Desktop\DialogDialog.pro.user”?]
      在这里插入图片描述
    • 按No后会跳转到这个窗口,要点击“Configure Project”按钮。
      在这里插入图片描述
      • 注:若刚安装Qt Creator,第一次载入项目最好点No,然后配置环境,到了第二次第三次第N次都可以按Yes,环境可自动配置成Qt5.8.0 MinGW 32bit。
    • 若按Yes,直接在“编辑”的“项目框”中出现对应项目。
      在这里插入图片描述
    • 无论是按Yes还是No,最终运行时,构件套件都是Qt5.8.0 MinGW 32bit配置。
      在这里插入图片描述
  • Win7系统中安装Qt,也许会出现这样的问题。
  • 如何安装Qt 5.8.0 +mingw
    在这里插入图片描述
    • 若你下载了VS2010或VS其他版本的软件,则你需要找上图的“1、”;
    • 若没有下载,只想下载Qt Creator,则找上图的“2、”;
    • 若找不到5.8.0版,那你不用麻烦了,直接进入下面的文档链接

安装或异常解决方案文档:

链接:https://pan.baidu.com/s/18a7CKGmvMTKwVK6fv7YEfg 提取码:xjjx

找到Qt5.8SetUp文件夹,下载之后,双击安装—》安装时一定要勾选Tools的MinGW选择(默认不勾选),否则后面项目运行会报错在这里插入图片描述—》安装时,可能会弹出警告

  1. Cannot find file: E:\Qt程序\day.pro. When executing step "qmake"的问题

  2. Error while building/deploying project untitled(永久解决办法)

  3. Qt Creator 报错:Error while building/deploying project helloworld (kit: Desktop Qt 5.6.2 MinGW 32bit) When executing step “qmake”【当我安装Qt5.8.0时未勾选Tools的MinGW环境配置,当我项目运行时,就会报这样的异常(当时环境配置是Qt默认环境),我使用过文章的“方法一”,似乎也不奏效,可能问题源头是“未配置MinGW”】
    在这里插入图片描述
    OrQt学习一: Qt 在 win7 的安装和环境配置【图的“1、”是方案二,图的“2、”是方案一】
    QT5.8.0+MSVC2015安装以及环境配置(不需要安装VS2015)【简单粗暴的讲解,当时只觉得唯有这个是有用的信息:跳转Qt官方Qt5.8.0版本的软件下载链接】

  4. [下面俩文章,我暂时未用过]
    QT creator 5.8.0/5.9+opencv2.4.13.6安装与配置方法
    QT5.12安装图文教程与安装成功后环境配置详细教程

32位系统与x86系统关系

参考:
32位系统为什么又叫x86系统呢?
Any CPU X86 X64区别

构建项目及设置配置

Qt右击上下文菜单的某些选项之间区别

创建主窗口、设置窗口居中、dialog与widget与mainWindow比较

设置QLabel文本居中

在这里插入图片描述
在这里插入图片描述

QLineEdit、QLabel的字体、大小、颜色

//设置输入文本框的文本为Timers格式字体、20大小、粗体
ui->lineEditText->setFont(QFont("Timers",20,QFont::Bold));

Or

QLineEdit  *lineEdit;
lineEdit->setFont(QFont("Timers",20,QFont::Bold));

在这里插入图片描述

//设置"无效的角度值!"字符串为Timers字体格式、9大小、红色的粗体
QPalette palette;
palette.setColor(QPalette::WindowText,Qt::red);//QLineEdit以及QLabel的文本颜色就用QPalette::WindowText
ui->lab->setText("无效的角度值!");
ui->lab->setFont(QFont("Timers",9,QFont::Bold));
ui->lab->setPalette(palette);

Or

QLabel *label;
label->setText("无效的角度值!");
label->setFont(QFont("Timers",9,QFont::Bold));//第一个参数设置字体格式,第二个参数设置字体大小,第三个参数设置字体粗体
label->setPalette(palette);

在这里插入图片描述

另一种:
QString Setting =tr("Language");
ui->label->setText(Setting);
Font.setPointSize(20);//设置字体大小
ui->label->setFont(Font);
Palette.setColor(QPalette::WindowText,Qt::white);//字体是白色的
ui->label->setPalette(Palette);

在这里插入图片描述

LineEdit的监视器
  • 再谈Qt Focus事件【安装EventFilter过滤器,起到了“监视离开文本框的焦点Focus的控制”作用,成功了】
//在构造函数中,set ui LineEdit filter过滤器
ui->lineEdit->installEventFilter(this);
-------------------------------------------------
#include <QKeyEvent>

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
     if (watched == ui->lineEdit)//首先判断控件(这里指 lineEdit)【判断是否是被事件过滤器过滤的对象】
     {
          if (event->type() == QEvent::FocusOut)// 这里指 lineEdit 控件的失去焦点事件
          {
              lEdit = ui->lineEdit->text();
              if("" != lEdit.trimmed())
              {
			      ......
              }
              else if("" == lEdit.trimmed())
              {
                  ui->lineEdit>setText("0");
              }
          }
          //该if语句,可忽略,作用:按了回车键,会做出指定反应
          if (event->type() == QEvent::KeyPress)
          {
              QKeyEvent * keyEvent = static_cast<QKeyEvent*>(event);
              if(keyEvent->key() == Qt::Key_Return)//更改文本框内的值,按“Enter”键执行位置模式指令
              {
                  int count;
                  double angle;
			      ......
              }
          }
     }
}

pro文件

pri文件

  • Qt中 .pro 文件和 .pri 文件简介
  • pri = “pro + include”;
  • 可以把 ×.pro 文件内的一部分内容单独放到一个 ×.pri 文件内,然后include到×.pro 文件中
  • 如:将×.pro 文件用上的"configure function build"分类,独立出分别放入configure.pri、function.pri、build.pri,接着在×.pro 文件中include即可
include( $${PWD}/../../。。。/examples/examples.pri )

PS:若多个pri文件,最好集成于一个example.pri中,而在pro文件中,include的example.pri即可(include括号里的路径中不能出现回车符或者空格,否则系统找不到对应的文件)
在这里插入图片描述
在这里插入图片描述

rc文件

Qt中加入C文件

Linux中的Qt软件:
1.将xxx.c拷贝到项目中(若有src文件夹,可放入其中)
2.如图所示,在Qt项目的源文件上鼠标右键,弹出“添加现有文件”
在这里插入图片描述
3.弹出“文件管理器”,选中项目目录下对应的xxx.c,再点击Open按钮即可
4.然后xxx.c导入成功了,如图所示,但这还不算结束
在这里插入图片描述

xxx.c大概内容:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>

typedef uint8_t __u8;
typedef int32_t __s32;
typedef uint16_t __u16;
......
struct ixxta {
	char read_write;
	__u8 command;
	int size;
	union ixta *data;
};
......
void xxxge(char *file)
{
	printf("%s ... r addr\n",file);
	printf("%s ... w addr val\n",file);
}
......
int ixxxta()
{
    const char *v = "ixxx-0";
    const char *v1 = "0x34";
    const char *v2 = "0xB9";
	......

    return 1;
}

5.要建同名的xxx.h,在里面定义xxx.c声明了的函数,如图所示:
在这里插入图片描述

xxx.h大概内容:

typedef uint8_t __u8;
typedef int32_t __s32;
typedef uint16_t __u16;

extern "C"
{
	void xxxge(char *file);
	......
	int ixxxta();
}

6.最后,若在xxx类(如:mainWindow)中要调用,可直接include,然后在xxx.cpp(如:mainWindow.cpp),可以根据个人想法直接调用“xxxge”、“ixxxta”等函数
在这里插入图片描述

cpp文件改c文件

添加文件

添加资源,在资源里添加并使用图片

qrc文件

在已有的项目中分别添加头文件、源文件 与 使用.h文件

多个UI界面的联系

QML

qmlscene、qmlviewer

  • qmlscene与qmlviewer【qmlscene是Qt5以上版本使用的查看QML文件效果的工具,qmlviewer是Qt4的QML查看器】

qmake

与Cmake、Qbs 区别

为什么会这么问,在创建Qt Quick项目的时候遇到了,心有疑惑则需立即解答:
在这里插入图片描述

Cmake搭配编译器

可以是MSVC2015/2017的,但可能出现“感叹号在这里插入图片描述”,所以可改用MinGW编译器

推荐Qt转Cmake工具

QSS

推荐QSS Editor辅助工具

Qt翻译语言家——Linguist

推荐翻译工具digital translate

为什么main()函数总是有"return a.exec"

  • 关于qt的主程序调用exec()
  • a.exec()的作用,该怎么解决
    [译文: 第一行:进入主事件循环并等待,直到调用exit()。返回设置为exit()的值(如果通过quit()调用exit(),则返回0)。
    第二行:需要调用此函数来启动事件处理。主事件循环从窗口系统接收事件,并将这些事件分派给应用程序小部件。
    第三行:要使应用程序执行空闲处理(即在没有挂起事件时执行特殊函数),请使用超时为0的QTimer。使用processEvents()可以实现更高级的空闲处理方案。
    第四行:我们建议您将清理代码连接到aboutToQuit()信号,而不是将其放在应用程序的main()函数中,因为在某些平台上,QCoreApplication::exec()调用可能不会返回。例如,在Windows上,当用户注销时,系统在Qt关闭所有顶级窗口后终止进程。因此,在QCoreApplication::exec()调用之后,不能保证应用程序有时间退出事件循环并在main()函数结束时执行代码
    "引用"栏的译文: 汇编代码:
    进入主事件循环并等待,直到调用exit()。返回设置为exit()的值(如果通过quit()调用exit(),则返回0)。
    有必要把这个函数称为…]
  • Qt exec()做了什么
  • qt: exec()的用法,accept()和accepted的概念

myDlg.exec()==QDialog::Accepted

  • my1.exec()==QDialog::Accepted
    • exec():显示模式对话框【不关闭此对话框,不能执行别的操作】
    • my1是一个对话框或下拉框,当调用exec方法时,弹出‘框’,等待用户响应,用户可能点击确定或选择xxx项,那么exec返回QDialog::Accepted值(int类型),如果点击取消或不选择点击框外范围,则返回QDialog::Rejected(int类型)
    • 这句话是通过返回值来确定用户的响应结果。
    • 一般作为if语句的条件

模态与非模态的区别

模态对话框

  • 模态窗体一般指:在其没有被关闭之前,用户不能与同一个应用程序的其他窗口进行交互,直到该对话框关闭。

非模态对话框

  • 非模态窗体是指:当被打开时,用户既可选择和该对话框进行交互,也可以选择同应用程序的其他窗口交互。

show()与exec()的区别

show()

  • 可以显示非模式也可以显示模式对话框。
  • 当设置modal为true时,显示模式对话框;若false(默认值)则显示非模式。
MyDialog myDlg;
myDlg.setModal(true);    myDlg.show();//模态

myDlg.setModal(false);或者myDlg.setModal();    myDlg.show();//非模态   

exec()

  • 显示模式对话框。
myDlg.exec();

同中不同:模式对话框的显示不同

  • show()
    • 显示的模态对话框并非真正意义上的模态,虽然在对话框弹出的时候,程序的其它操作(按钮、窗口切换等)都失效了;但是程序仍然在调用对话框之后,继续执行后面的代码。但这样,就不会得到窗口的返回值。
  • exec()
    • 在调用之后,程序就被锁定在原地。等待窗口的关闭。

顺便提下:C语言的main函数为什么要返回0?

int main(int argc, char *argv[]){}

include <xxx.h> 与 include “xxx.h” 的区别

#ifndef XXX_H #define XXX_H … #endif

之间的关系与区别

#ifndef 本文件的头文件名全大写XXX_H    
#define 本文件的头文件名全大写XXX_H 
........某内容.......   
#endif 

延伸

#ifdef…#else…#endif与#ifndef…#else…#endif

#if defined…#endif

#if…#elif…#else…#endif与if…else if…else

区别
\#ifif
名称条件编译条件语句
介绍是C语言中预处理部分的内容,它是编译器编译代码时最先处理的部分是 C 语言中的关键字,它根据表达式的计算结果来觉定执行那个语句,它里面的每个分支都编译了的
简单说根据 宏条件 选择性地编译语句,它是编译器在编译代码时完成的根据条件表达式选择性地执行语句,它是在程序运行时进行的
代码qb-01区代码qb-02区代码
意思如果宏条件符合,编译器就编译这段代码,否则,编译器就忽略这段代码而不编译做A条件判断
什么时候用如果你的条件在程序编译前就已经确定了,那就用#if如果条件需要在程序运行过程中才能判断,则用if

qb-01:

#define  A 0  //把A定义为0
#if (A > 1)
         printf("A > 1");  //编译器没有编译该语句,该语句不生成汇编代码
#elif (A == 1)
         printf("A == 1"); //编译器没有编译该语句,该语句不生成汇编代码
#else
         printf("A < 1");   //编译器编译了这段代码,且生成了汇编代码,执行该语句
#endif

qb-02:

#define A 0 
if (A > 1) 
     printf("A > 1");   //编译器编译该语句,但因为A == 0 未执行 
else if(A == 1) 
   printf("A == 1");  //编译器编译该语句,但因为A == 0 未执行 
else
   printf("A < 1");  //编译器编译该语句,因为A == 0 故执行

~MainWindow()

  • Qt程序报error: undefined reference to `MainWindow::~MainWindow()’
    • 析构函数(Destructor)也是一种特殊的成员函数,没有返回值,不需要程序员显式调用(程序员也没法显式调用),而是在销毁对象时自动执行。
    • 构造函数的名字和类名相同,而析构函数的名字是在类名前面加一个~符号。
    • 函数名是标识符的一种,原则上标识符的命名中不允许出现~符号,在析构函数的名字中出现的~可以认为是一种特殊情况,目的是为了和构造函数的名字加以对比和区分。
    • 析构函数没有参数,不能被重载,因此一个类只能有一个析构函数。如果用户没有定义,编译器会自动生成一个默认的析构函数。
    • 析构函数里的delete,销毁组件、部件缓存,减少内存或释放内存,防止内存泄漏。
      在这里插入图片描述
      在这里插入图片描述

~QString()

  • QString类
  • QString::~QString ()
    • 表示:销毁这个字符串并且如果这是 这个字符串 的最后一个复制,就释放“真实的”字符串。

QString

QString::replace()

  • 原型: 常用:QString &replace(int i, int len, const QString &after);
  • 头文件:qstring.h
  • 说明:第一个参数:字符下标,从0开始;第二个参数:替换字符串长度;第三个参数:替换成xxx字符串,&after就是xxx。函数表示:替换 i下标往后len个字符的位置为xxx字符串。
  • 注:除了这个函数,还有几个“重载”函数,如图所示:
    在这里插入图片描述
    参考:C++ string中的replace函数详解
QByteArray::replace()
  • 头文件:qstring.h
  • 常用的话,可能是第一个replace函数,如图所示:
    在这里插入图片描述
  • 我调用QByteArray的replace(),出现了些许问题:
    在这里插入图片描述
    • 分析:
      • 很明显,该replace()是QString::replace(int i, int len, QChar after),不是QByteArray::replace();
      • 并且直接赋字符值,系统会把它识别成char类型,而不是QChar类型;
      • 但是,报错中表示:replace()函数第三个参数是char类型,且不能将char直接赋值于char
      • 我就懵了,不是QString::replace(int i, int len, QChar after);难道是QString::replace(int i, int len, const QChar *s, int slen);或者QString::replace(int i, int len, const QString &after); ???
    • 解决:
      • QByteArray本来就是字节数组,可以对某个字符或者某下标的数组进行更改,所以根本就不需要QByteArray::replace(),而是直接:
int value = 4;//二进制为0100
QString convertedValue = QString("%1").arg(value,4,2,QLatin1Char('0')).toUpper();
QByteArray ba = convertedValue.toLatin1();
ba[2] = 1;//ba == 0110;

QString::number()

  • 原型: 常用:static QString number(int value, int base=10);【若base值未赋值,默认为10】
  • 说明:十进制整型value值转成十进制字符串
    在这里插入图片描述
可以用于“int类型转成QString类型”
int val = 6;
QString str =  QString::number(val);

在这里插入图片描述
在这里插入图片描述

错误:QString str = new QString()new QString 或 new QString("43");
否则,报错:"错误:从'QString*'转换为请求的非标量类型'QString'"

正确:QString str = "";或QString str;

在这里插入图片描述

非标量与标量类型

参考:
《SQL与关系数据库理论——如何编写健壮的SQL代码》一一2.5 标量类型vs.非标量类型
错误:转换为非标量类型(Error: Conversion to non-scalar type)
错误:从“基本类型”转换为请求的非标量类型“NamedType <基本类型>”

共用体 结构体 枚举的特点与区别

参考:
结构体,共用体和枚举类型的基本特点及区别

QString::at ( uint i )

  • 原型:QChar QString::at ( uint i ) const
  • 返回在索引i处的字符,或者如果i超过字符串的长度返回0。
const QString string( "abcdefgh" );
QChar ch = string.at( 4 );// 打印ch == 'e'

QString str = "After finishing the homework,she does her housework~";
qDebug() << "str[2] = " << str.at(2);//打印:str[2] =  't'

QString::arg()

1.
QString m = tr("%1:%2:%3").arg("12").arg("60").arg("60");
//结果是m = "12:60:60"

2.
QString QString::arg(int a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char( ' ' )) const
[在QString头文件:inline QString QString::arg(int a, int fieldWidth, int base, QChar fillChar) const]
分析:
第一个参数是要填充的数字(一定是十进制,若二进制数值传入,也会被认为是"十进制"数值),
第二个参数为最小宽度,
第三个参数为进制,
第四个参数为当原始数字长度不足最小宽度时用于填充的字符
如:
QString text = QString("%1:%2")
               .arg(123, 5, 10, QChar('0'))
               .arg(456, 5, 10, QChar('0'));
//结果是text = "00123:00456"

从QString头文件看出:一个arg()函数最多实现九个参数;
在这里插入图片描述
若一定要实现九个以上的参数值呢,可以这样:
在这里插入图片描述

QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11")
        .arg("1","2","3","4","w","6","7","8","9").arg("a","b");
//结果是:"1 2 3 4 5 6 7 8 9 a b"
16进制转2进制

QString的isEmpty与isNull

  • QString的isEmpty与isNull区别
  • Qt: QString::isEmpty()与QString::isNull()区别
    • isEmpty()如果字符串没有字符,则返回true;否则返回false。
    • isNull() 如果字符串是无效的,则返回true;否则返回false。
    • 区别:
      (1)由于历史原因,Qt对无效字符串和空字符串进行了区分。对于大多数应用程序,重要的是字符串是否包含任何数据,这可以使用isEmpty()函数来确定;
      (2)无效的字符串指的是QString没有初始化,这也是isEmpty与isNull的区别;
      (3)无论QString有没有初始化,QString()与QString(“”)的isEmpty都为真,而QString()的会被判定为无效字符串。
isEmpty与isNull的基本区别
     QString().isEmpty();            // returns true
     QString("").isEmpty();          // returns true
     QString("x").isEmpty();         // returns false
     QString("abc").isEmpty();       // returns false

     QString().isNull();             // returns true
     QString("").isNull();           // returns false
     QString("abc").isNull();        // returns false

toInt()

    QString str1("F");
    int i1 = str1.toInt(0,16);
    qDebug() << i1 << " = i1~~~";

std::string与QString

:

int data = 123;
QString convertedValue = QString("%1").arg(data,16,2,QLatin1Char('0')).toUpper();
//arg()函数在上面已说明,int类型的data转QString类型,而toUpper()函数:把小写字母转换为大写字母。

QByteArray ba = convertedValue.toLatin1();//将QString转QByteArray类型
ba[15] = '1';//可以直接更改QByteArray某index的字符
std::string str = ba.toStdString();
//QByteArray的toStdString()专门从QByteArray转成std::string类型

/*            该语句就是你们要找的!!!         */
QString convertedValue1 = QString::fromStdString(str);
//利用QString的fromStdString函数,将std::string类型转成QString类型

或者

QString qstr = QString::number(123);//int类型的数据转QString类型  
string s = qstr.toStdString();//除了QByteArray有toStdString(),QString也有
QString qstr2 = QString::fromStdString(s);//将std::string类型转成QString类型

延伸

atoi()和itoa()
atoi()
stoi()

参考:

该函数,在 进制间的转换 方面中,起到很大作用:
C++中二进制、字符串、十六进制、十进制之间的转换
c++ 二进制字符串转成10进制数

itoa()
  • Linux编程:11 itoa函数未定义标识符
  • C错误:对’_itoa’的未定义引用
  • 原型:char *itoa( int或者long value, char *string,int radix);
  • 所属头文件:stdlib.h【Windows系统的Qt才有,不是一个标准的c函数】
  • 作用:将整数value 转换成字符串存入string 指向的内存空间 ,radix 为转换时所用基数(保存到字符串中的数据的进制基数)。
  • 说明:value:要转换的数据。string:目标字符串的地址。radix:转换后的进制数,可以是10进制、16进制等,范围必须在 2-36。

setCodecForTr()与setCodecForCStrings() 、setCodecForLocale()

函数描述
QTextCodec::setCodecForCStrings(textc)主要用在用字符常量或者QByteArray构造QString对象时使用的默认编码方式。
QTextCodec::setCodecForTr(textc)这个函数的作用是设置传给tr函数时的默认字串编码。
QTextCodec::setCodecForLocale(textc)这个函数主要用于设置和对本地文件系统读写时候的默认编码格式。

tr() string和QString乱码的解决

QString拼接数值或字符串

setText() setPlainText()

Qt中获取当前路径

QByteArray

QString convertedValue = QString("%1").arg(data,16,2,QLatin1Char('0')).toUpper();
//arg()函数在上面已说明,int类型的data转QString类型,而toUpper()函数:把小写字母转换为大写字母。

QByteArray ba = convertedValue.toLatin1();//将QString转QByteArray类型
ba[15] = '1';//可以直接更改QByteArray某index的字符
std::string str = ba.toStdString();
//QByteArray的toStdString()专门从QByteArray转成std::string类型

QWdiget

QWidget *parent = 0

setStyleSheet(“QLabel{border:5px solid rgb (0x00,0xff,0x00,0x00);}”)

	QWidget *m_statusInd = new QWidget;
    m_statusInd->setFixedSize( 16, 16 );  
    m_statusInd->setStyleSheet("background-color: red");
    //使用部件Widget的setStyleSheet函数

在这里插入图片描述

Qt::FocusPolicy

属性表示的十六进制描述
Qt::TabFocus0x1接受Tab键焦点
Qt::ClickFocus0x2接受鼠标单击做焦点
Qt::StrongFocusTabFocus or ClickFocus or 0x8接受Tab键和鼠标单击做焦点
Qt::WheelFocusStrongFocus or 0x4滑轮作为焦点选中事件
Qt::NoFocus0不接受焦点
#include <QLineEdit>//若头文件没有继承QWidget,就要加上这个

QLineEdit *edit = new QLineEdit;
edit->setFocusPolicy(Qt::StrongFocus);//默认使用Qt::StrongFocus属性

设置标题栏与图标

    this->setWindowTitle("Qt系统");
    this->setWindowIcon(QIcon(":/img/logo.png"));

在这里插入图片描述

QListWidget

QLayout

addLayout与addWidget

layout布局

QComboBox

addItem()

  • 原型:常用:inline void addItem(const QString &text, const QVariant &userData = QVariant());
    • 说明:添加一个下拉选项 在这里插入图片描述
      在这里插入图片描述
    for(int i=0; i<8; i++)
        ui->cmbCode->addItem(QString::number(i));

在这里插入图片描述

QSpinBox

  • Qt 之 QSpinBox 和 QDoubleSpinBox
    • QSpinBox旨在处理整数和离散值(例如:月份名称)。如图所示:图-1
    • QDoubleSpinBox则用于处理浮点值。如图所示:图-2
    • 他们之间的区别就是处理数据的类型不同,其他功能都基本相同。
      图-1在这里插入图片描述
      图-2在这里插入图片描述

setEnabled()

  • 原型:void setEnabled(bool);
  • 所在文件:qwidget.h
  • 这个"选值框"是否启用setEnabled():
    • 设置成true时,相当于激活了框,框的状态不再是死的,而是会对触摸或者点击产生反应,并且可以响应一些触发事件。
    • 而设置成false时,框呈灰色的,无论是否可点击(即使将setClickable()设置成true),都无法响应任何触发事件。如图所示:图-1
      图-1在这里插入图片描述

QThread

sleep()

Windows下

#include <QDebug>      //qDebug()要求的
#include <QTimer>      //QTimer要求的
#include <synchapi.h>  //Sleep()要求的

    QTimer *ti = new QTimer(this);
    ti->start(1000);
    qDebug() << "Start to sleep 10 seconds~~";
    QThread::sleep(10);
    qDebug() << "End to sleep 10 seconds But start to Sleep 15 seconds~~";
    Sleep(15000);
    qDebug() << "End to Sleep 15 seconds~~";

在这里插入图片描述
在这里插入图片描述

Linux下

QMath

pow()

运用:
二进制字符串转为十进制数值

QString val = "0000000010001100";
QByteArray ba = val.toLatin1();
int nVal = 0;
for(int i = 15;i>=0;i--)
{
	if(ba[i] == '1')
    {
		int t = 15-i;
		nVal += pow(2, t);//2的t次幂
	}
}

QDebug

  • qDebug用法总结
  • qDebug 的使用
  • qDebug的用法
    • 经常用到:重定向操作符(<<)
    • 头文件:#include “qdebug.h” 或者 #include <QtDebug> 或者#include <QDebug>[因为编辑器原因,将英文半角尖括号符号用了全角的尖括号]
      在这里插入图片描述
      在这里插入图片描述
	QString chin = "中文繁体";
    qDebug() << chin.toStdString().c_str();

    char da = 'a';
    qDebug("%04x",da);

    qDebug()<<  "MainWindow : Init Completed ";

    qDebug() << "Hello" << 123;

    qDebug() << QString("Hello") << QPoint(10, 10);

    int num = 20;
    char str[20]="hello world";
    qDebug("如果只写在括号里,是不需要QDebug头文件的 %d %s", num, str);

QSettings

QSettings st = new QSettings("qModMaster.ini",QSettings::IniFormat);
//IniFormat存储格式:'读写配置ini文件'可以储存一些系列配置,即将设置存储在INI文件中。

QStandardItem

  • QStandardItem_Qt文档
  • QRowTable表格控件(三)-效率优化之-合理使用QStandardItem
  • 是一个数据结构,它可以存储一个cell单元格的各种信息,比如文本、图标、是否可选、字体、别景色、前景色等等。并且QStandardItem可以有孩子和兄弟,它是为model提供数据存储的节点。
  • 使用该类:#include “qstandarditemmodel.h” 或者 #include <QStandardItem>
  • 可能用上的void setEditable(bool editable);
    • 说明:若editable为true,设置表格某列的某项可编辑,若为false,则不可编辑。

QAbstractItemModel

QStandardItemModel

  • Qt QStandardItemModel用法(超级详细)
  • QListView,QTreeView和 QStandardItemModel的简单使用
  • 【QT】模型与视图,QStandardItemModel and QTreeView
  • Qt 常用类——QStandardItemModel
    • 是标准的基于项数据的数据模型,以类似于二维数组的形式管理内部数据,适合于处理表格型数据,其显示一般采用 QTableView。
    • 是标准的以项数据(item data)为基础的标准数据模型类,通常与 QTableView 组合成 Model/View 结构,实现通用的二维数据的管理功能。
    • 使用该类:#include “qstandarditemmodel.h” 或者 #include <QStandardItem>
    • 为什么QStandardItemModel和QStandardItem,引入同样的头文件?
      • 因为在qstandarditemmodel.h头文件中,定义声明了“class QStandardItemModel”、“class Q_GUI_EXPORT QStandardItem”。
    • 继承了QAbstractItemModel类 在这里插入图片描述
    • 构造函数原型:QStandardItemModel(int rows, int columns, QObject *parent = Q_NULLPTR);
      • 说明:声明数据模型(表格)有rows+1(说明row是某行的下标)行、columns列,基类是Q_NULLPTR2
      • 注:Q_NULLPTR表示该类(此处指QStandardItemModel)不作为顶层容器。
    • 可能用上的QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
      • 说明:取下标为row的行及第column+1列的QModelIndex()父类类型的值作为index索引值。
    • 可能用上的void setItem(int row, int column, QStandardItem *item);
      • 说明:row与column从0开始,设置row+1这么多行column+1这么多列的项(一项项组合起来成一个表格)。
//在头文件的类外定义声明
static const int AddressColumn=0;
static const int ValueColumn=1;

//在cpp中的类的函数中定义声明
int m_startAddress = 2;//设置开始的索引号从2开始
int m_noOfItems = 4;//读取指定表格的两列四行(或者指四项[是"键-值"————“addressItem-valueItem”的形式])

for (int row = 0; row < m_noOfItems ; row++) 
{
	//将int类型转QString类型赋值于QStandardItem的addressItem变量
	QStandardItem *addressItem = new QStandardItem(QString::number(m_startAddress+row));
    model->setItem(row, AddressColumn, addressItem);//设置addressItem放在    row从0开始遍历的对应行  及   索引号为0的列  中(即,addressItem放在每行的第一列)
    addressItem->setEditable(false);//设置addressItem项不可编辑,不可双击或点击触发编辑事件
    QStandardItem *valueItem = new QStandardItem("-");//设置valueItem的值为字符"-"
    model->setItem(row, ValueColumn, valueItem);//让valueItem放在每行的第二列
    //valueItem->setEditable(valueIsEditable);//若为false,调用这个函数的控件不能被编辑,如果设为true或者不调用这个函数,则控件可以编辑。
}
延伸:C++11中可使用nullptr替代Q_NULLPTR
  • nullptr3表示对象句柄、内部指针或本机指针类型不指向对象(即,空指针)。nullptr空指针常数可以转换为任意类型的指针类型。
  • 如图所示:(Windows的Qt中找到的)
    在这里插入图片描述
区别
  • 宏Q_NULLPTR向读代码的人说明了意图,而nullptr向编译器说明意图。Q_NULLPTR没有提供类型安全,仅仅是“装饰”作用的。若软件兼容或支持C++11,宏Q_NULLPTR会自动扩展为nullptr。如果编译器不支持c++11,它将被替换为NULL(被替换为0)。
    • 什么时候用Q_NULLPTR?
      Johannes Matokic解答的译文:实际上Q_NULLPTR只有一个目的:允许使用nullptr而不丧失对不支持c++ 11/ c++ 0x的编译器的支持,因为直接使用nullptr会导致这种设置中的错误。其不利之处在于,与nullptr相比,回退到NULL(或旧Qt版本中的0)可能会导致意外的运行时行为,并限制所支持的用例。在极少数情况下,你的目标是不兼容c++ 11的编译器,使用Q_NULLPTR,但是要确保在禁用c++ 11特性时代码能够正常工作。在所有其他情况下,nullptr是更好的选择,因为它会导致编译错误,而不是与遗留编译器一起使用时出现错误的运行时行为。Qt 5.7,后来取消了编译不使用c++ 11的支持,所以如果依赖于这些版本,就不需要Q_NULLPTR。还有其他一些特性,如qMove或Q_DECL_OVERRIDE,它们在支持编译器时提供了更好的语义,而不会破坏旧编译器上的编译。
      Martin Hennings解答的译文:使用Q_NULLPTR来保持编译器的独立性。如果您现在决定使用nullptr,那么您的代码将无法使用较旧的c++98编译器进行编译。如果决定使用NULL,就会失去c++11类型安全性,即使在当前编译器中可用。出于同样的原因,存在qMove(x)等宏以及相应的定义Q_COMPILER_RVALUE_REFS。】
setData()
  • 项目中经常使用该函数,在qstandarditemmodel.h中:
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
  • 将项目在索引index处的角色role数据设置为值value。
    • 如果成功返回true;否则返回false。
    • 如果数据设置成功,则应该发出dataChanged()信号。
    • 基类实现返回false。这个函数和data()必须为可编辑的模型重新实现
static const int ValueColumn=1;//在头文件的类外定义声明

//在cpp中的类的函数中定义声明
QStandardItemModel *model = new  QStandardItemModel(0,2,this);
//以代码所在的该类为基类,初始化:一行两列的表格;第一参数,指的是行下标index;第二参数,指的是表格的每行有几列。

for (int i = 0; i < m_noOfItems; i++)
{
        QModelIndex index = model->index(i, ValueColumn, QModelIndex());
        //取下标为i,第valueColumn列的QModelIndex类型的索引号
        
        //qDebug() << index << " = index!";
        //若i=0,打印QModelIndex(0,1,0x18da0380,QStandardItemModel(0x18d29be8))  = index!
        
        model->setData(index,"N/A",Qt::DisplayRole);
        //将索引号index行列要显示出来(DisplayRole角色属性)的值设置为"N/A",
}
data()
  • 用了setData(),怎么少的了用data()函数?
  • 在qstandarditemmodel.h中,原型:QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
  • 说明:返回由索引index(表格的行索引号从0开始)引用的项的给定角色role(默认为Qt::DisplayRole)下存储的数据。

QTableView

  • 若只使用QStandardItemModel,会遇到个表格问题,将十进制转16位的二进制后,表格的列不能自动调整大小!
    在这里插入图片描述
  • 此时,使用QTableView再好不过了!
//根据内容自动调整所有列的列宽
//设置表格的列与内容相匹配
ui->tblView->resizeColumnsToContents();
//我将放在mainWindow.cpp的某函数中,起作用了呀!
//【若你的未起作用,可以看看第三篇文章,或许对你有帮助】
QTableWidget

QTreeView

参考:

QTreeWidget

参考:

继承了QTreeView类:
在这里插入图片描述

QItemSelectionModel

QMessageBox

  • 消息对话框,用于显示提示、警告、错误等信息,或进行确认选择。
  • Qt 5种标准对话框及使用方法详解【其中一种就是QMessageBox】
  • qt5信息提示框QMessageBox用法QMessageBox用法
  • 原型:static StandardButton critical(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton);
  • 说明:被用于保留严重错误。弹出警告(有红×的图标)窗口,第一参数表示父类是this(MainWindow该类),这样的话将窗口弹在父类“主窗口”的前面居中位置,而且窗口是模式的,第二参数是窗口的标题,第三参数是窗口弹出的内容,第四参数表示未赋值的话,默认(缺省)按钮的文本为OK,第五参数是缺省选择的按钮,缺省表示没有选择(该参数没什么用)。
    在这里插入图片描述
//弹出窗口最多有三个按钮,超三个就会报错!
QMessageBox::critical(this, "Request failed","Add items to Registers Table.","Ready","Cancel","Close");
//设置三个或者两个按钮后,右上角的红×都是失效的!
//默认第一个按钮亮起蓝色框,按钮文本可以用中文表示

//只有设置一个按钮或者使用默认按钮OK的时候,右上角的红×才是有效的!
QMessageBox::critical(this, "Request failed","Add items to Registers Table.","Ready");

在这里插入图片描述
在这里插入图片描述

QString errorDetails = "404";
第三参数可以是:(拼接的字符串)
QString("An internal error occurred. Please ") +
"call technical support at 123456789 and report\n"+
"these numbers:\n\n" + errorDetails +
"\n\n<Application> will now exit."

e.g:
msg001:
在这里插入图片描述
msg002:
在这里插入图片描述

msg001:QMessageBox::warning(this,"Information",tr("文本框内容不许为空!!!"));
msg002:QMessageBox::information(this,"Information",tr("connection ok"));

critical() 与 Critical

  • 都在qmessagebox.h中定义。
  • QMessageBox::Critical用来显示Critical图标。而QMessageBox::critical()函数应用于保留严重错误。
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

QPushButton

setChecked()

  • 原型:void setChecked(bool);
  • 所在文件:qabstractbutton.h
  • 说明:设置选中状况。会影响click、toggled触发事件的bool值。
  • 实操情景:若设置true,就一直是选中状态(怎么点,都是蓝色按钮),不可变换按钮文本,触发不了toggled事件,但能触发clicked事件。
  • QCheckBox也有该函数,选中是“勾选复选框”状态。
    在这里插入图片描述

isChecked()

  • 原型:void setChecked(bool);
  • 所在文件:qabstractbutton.h
  • 说明:提示按钮是否已经标记、已选中;返回按钮的状态,已选中:返回值为True;未选中:返回False。大多用于“判断”。

setCheckable()

  • 原型:void setCheckable(bool);
  • 所在文件:qabstractbutton.h
  • 说明:设置按钮是否能够被选中;若设置为true,表示能选中该按钮,但出现选中变蓝再选中变米白色的情况,不是这个函数控制的,而是setChecked函数控制,默认点一次,setChecked(true)变蓝,反之亦然。
  • 实操情景:如果设置True,则表示按钮将保持已点击(变蓝色)和释放状态,只要再点一次,按钮可从蓝色变正常色;若为false,按钮不可点击。
ui->btTest->setCheckable(false);//表示btTest按钮不可选中,特征:呈灰色,不可点击

在这里插入图片描述

绘图类

QPixmap、QImage、QBitmap、QPicture

QIcon或QLable缩放 QPixmap的自适应

QPainter 及其使用

QPalette调色板

setAutoFillBackground

const

virtual

moc,Q_OBJECT

  • 官方解释:Q_OBJECT宏必须出现在类定义的私有部分中,该类定义声明自己的信号和插槽,或者使用Qt的元对象系统提供的其他服务
  • mocOrmoc
  • Q_OBJECT宏的作用
  • QT中添加Q_OBJECT出现的问题【多重继承时QObject一定要放在最前面】
    • [该文章的译文:刚收到这个错误消息而编译一个小类,它来源于QTreeWidgetItem:错误C2039:“staticMetaObject”:不是’QTreeWidgetItem’的成员。这就是说QTreeWidgetItem不是从QObject继承的,这意味着您自己的单继承类也不是从QObject继承的。继承QObject是使用Q_OBJECT宏的先决条件之一,如果您和我一样,您可以自动地将Q_OBJECT宏插入到任何与Qt GUI相关的类中。如果您没有在子类中使用任何元对象,例如信号/插槽或属性,那么只需取出Q_OBJECT宏。如果您需要使用信号和插槽,您还需要使您的子类从QObject中多次继承。如果您采用这种方法,请记住,多重继承要求QObject位于第一,否则您将得到与上面相同的错误,或者类似于您的类从moc的两个QObject子类继承]

emit,signal,slot

emit

  • 发出信号(A类信号函数)
  • 连接信号(A类信号函数)与槽(B类或本类槽函数)
  • emit也可以向一个已定义的信号函数提供参数
  • emit无非就是告诉编译器编译的时候A类信号函数 的定义实现在另一个地方(A类),从B类的connect方式中可以找到。
A类:
.h里:
Q_SIGNALS:
	void SShowB();
.cpp里:
按键释放事件函数里:
switch (event->key()){
	case Qt::Key_M:{
		hide();//隐藏当前或A类窗口
		emit SShowB();
	}
}
B类:
.h里:
private:
	A a;
	B b;
public slots:
	void SlotShowThisWindow();
.cpp里:
在构造函数里:
connect(&a,SIGNAL(SShowB()),this,SLOT(SlotShowThisWindow()));//显示当前窗口
声明SlotsShowB函数:
void SlotShowThisWindow(){ 
	show(); //显示当前或B类窗口
}

信号与槽的连接关系 sender()函数

Q_SLOTS Q_SIGNALS namespace

Q_PROPERTY

Q_UNUSED

Qsrand与Qrand

如:【Qt获取随机数qsrand和qrand

比如使用QT获取0-10之间的随机数
 
#include <ctime>
 
//这里以时间为种子
qsrand((quint32)time(0));
int res  = 0+qrand()%10;

这两句不太明白什么意思

qsrand(QTime::currentTime().msec()); //取时间作为产生随机数的种子
timer->start(qrand()%5000+1000);//qrand()%5000+1000是产生一个在 1000-6000间的数,timer->start()是根据上述产生的数值来启动定时器

QRectF QRect

QPoint与QPointF

QSize

QRect QSize QPoint 的使用

数学计算函数

QRegExp

#include <QRegExp>

bool MainWindow::validate(QString str)
{
QString regexStr("^(-?\\d+)|(-?\\d+)(\\.\\d+)$");//Qt匹配正数、负数、浮点数;若结尾是.或-【若出现正负数、浮点数以外的值】,match==false
QRegExp regex(regexStr);//QRegExp regex = new QRegExp(regexStr);会报错
bool match = regex.exactMatch(str);//检查传进来的str字符串是否符合指定的正则表达式,符合为true,反之亦然
if (match)
  return true;
else
  return false;
}

QString arg1 = "-32.3";
bool a = validate(arg1.trimmed());
//打印 a==true
QString arg2 = "。";
bool b = validate(arg2.trimmed());
//打印 b==false

QFile常用函数及使用

QDir

mkpath和mkdir的区别

过滤器Filter

跟QDir有关
QStringList filter;
filter << "*.jpg" << "*.h264";
dir2.setNameFilters(filter);

代码实现创建文件夹功能

代码实现删除文件夹

Dialog

FileDialog

容器类

在学习STL风格迭代器的两种分类(“QMap与QHash”)时,要接触的知识点【时间复杂度为主】

explicit与implicit

globalPos()与pos()

函数描述
globalPos()给出的坐标信息是相对于桌面的,即以桌面左上角为原点。
pos()是相对于窗口的,以窗口左上角为原点(去除边框)。

TextEdit

typedef

qreal

键盘事件

键盘事件之回车事件Qt::Key_Return与Qt::Key_Enter

界面刷新

解决乱码

线程

异常/问题

“collect 2:error :ld returned 1 exit status”

编写串口软件出现的异常

D:…\mainwindow.cpp:20: error: undefined reference to `SPComm::isOpen() const’

  • 说明SPComm类的isOPen()函数没有定义
    • 解决:在cpp里写入即可:
bool SPComm::isOpen() const
{
    if(m_serialPort->isOpen())
        return true;
    else
        return false;
}

在这里插入图片描述

D:…\debug\spcomm.o: -1: In function `ZN6SPCommC2EP7QObject’:

在这里插入图片描述

  • 解决:在pro文件加上"QT += serialport"

“munmap_chunk(): invalid pointer”

“error: ‘tr’ was not declared in this scope”——“tr”未在此作用域中声明

“: -1: error: 没有规则可以创建“mainwindow.o”需要的目标“…/qt_battery/ui_mainwindow.h”

  • 报错来源:
    在qt_battery项目目录下打开终端进行qmake和make编译,生成了项目的Makefile、.exe文件、moc_xxx.cpp文件、xxx.o、moc_xxx.o文件,之后做某些操作(身为小白的我,没有习惯在终端指定项目目录下编译,但这个‘所谓的某些操作’之前必须要先编译),完成后,我在终端执行“make clean”指令,将.o文件清空,并将剩下的文件(除了xxx.cpp xxx.h xxx.pro)放入回收站,然后在Qt中调试模式运行qt_battery程序调试按钮,在控制台中出现该异常了
  • 解决:
    缺什么给什么,编译过的项目,就不能像“没在终端编译过,没生成.o文件,也可直接在Qt软件中调试运行,程序能照常运行”的项目了,必须“qmake和make编译”产生Makefile、.exe文件、moc_xxx.cpp文件、xxx.o、moc_xxx.o文件之后,才去Qt软件中调试运行。
    在这里插入图片描述
  • 若项目简单,没有“界面文件”(就不会在某.cpp中加入" #include “ui_mainwindow.h” "),则不会报这个错。

“Project ERROR: Unknown module(s) in QT: declarative”

  • 接触的这个项目是从别人那拷贝的,因为环境配置(有人另称为交叉工具链【我虚拟机Linux里的Qt使用的是GCC编译器套件】)不同,弹出了这异常,导致不能正常执行该程序(下面第三张图,按钮呈灰色,表示不能运行程序)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • QT中的未知模块:声明性的/Unknown module(s) in QT: declarative在这里插入图片描述
    【可参考:QtDeclarative module
    在这里插入图片描述
    以上都没有说怎么解决,我就自个找找看:在xxx.pro文件中将"QT += declarative"代码注释(加“#”表示注释),就不会出现该异常,但有新的异常出现了。。。在这里插入图片描述

  • 补充:

    一个异常解决了之后还有新的异常,可能存在某些原因:项目涉及底层程序或某些驱动程序,不好注释更改,又或者富有复杂性、移植性不高,不易配置相应的库或环境配置。。。但是“办法总比问题多”,吼~嘎油!
    GCC:GCC(GNU编译器套件)常用简要介绍、GCC编译器(Linux gcc命令)30分钟入门教程

“ error: ‘class Ui::MainWindow’ has no member named ‘timerLabel’ ui->timer ”

  • 有人这么解决的:C语言,C++编译遇到问题:has no member named ''XXX‘
  • 而我的解决方式:
    • 分析:“异常的意思是:主窗口的ui界面没有timerLabel标签控件”,
    • 找问题:“QLabel控件有名字为timerLabel的!”,
    • 解决:在对应项目文件夹下----》在空白处右击鼠标弹出菜单----》选择打开终端,编译一遍:“qmake”、 “make clean”、 “make”(接着我关闭项目,重新载入项目【若编译之后运行还是出现了异常,则多做这个步骤】),然后运行,异常解决了
  • 补充:

“deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] char *i2c_device = “/dev/stm32_control”;”

“QObject::connect: No such slot QLabel::valueChange2() in …/batteryDisplay/m。。。”(即:“QObject::connect: No such slot Xxx…”)

“/qopengl.h:140: error: GL/gl.h:没有那个文件或目录”

“error:forward declaration of class”

“Project ERROR: Unknown module(s) in QT: opengl”

“: -1: warning: TARGET is empty”

在这里插入图片描述

“Signal received The inferior stopped because it received a signal from the operatina system.”

  • 异常译文:下级停止,因为它收到了来自操作系统的信号。

Signal name : SIGSEGV Signal meaning : Segmentation fault"

“libpng warning: iCCP: known incorrect sRGB profile”

C:…\项目名2.0.0.20161005\forms\about.cpp: -1: warning: C4819(编码问题)

“glibc detected”

“QT5丢失Qt5Cored.dll”

我会遇到这个问题,是因为:
“将Debug或Release目录下的.exe文件 直接移至其他电脑,双击运行”,然后里面弹出这个“警告框:丢失Qt5Cored.dll”。
解决:打包发布exe【请看Qt——Windows端打包发布文章,即刻解决】
在这里插入图片描述

error: cast from ‘disp_color*’ to ‘unsigned int’ loses precision [-fperm

其实就是使用类型不当的问题,要么强制转换,要么改用同样的类型:

error: ‘::ioctl’ has not been declared

APPCRASH 故障模块名称: ntdll.dll

安装VS时KERNELBASE.dll出故障了

注:因Qt项目需求,需安装VS、VC,其中遇到了问题,就此做个笔记。

可能因为VS2015安装包有问题,安装完VS2015,双击图标后,弹出该窗口,解决:
将VS全部卸载(卸干净),下载新的完整的VS安装包,安装之后,双击图标,不会再出现该窗口!

推荐参考:VS2015、VSCode安装(卸载vs导致MVSVCP140.dll缺失的解决;VSCode:han汉hua化、改变字体大小、改变背景色、解决乱码、打开PDF等文件)

在这里插入图片描述

快捷键

  • 当使用Qt时,快捷键的使用是必不可少的,而且提高不少的工作效率呢~

常用

快捷键意义备注
Ctrl+X剪切选中范围
Ctrl+V粘贴
Ctrl+C复制
Ctrl+O打开文件
Ctrl+S保存修改内容
Ctrl+N弹出“新建项目”窗口
Ctrl+↑滚动条向上(Ctrl+↓作用与之类似)
Ctrl+←焦点在的那行,若在单词或词组后,会出现在单词或词组的前面(Ctrl+→作用与之类似)
Ctrl+/在选中部分区域的头和尾加上"/* */“,在选中整个函数代码或语句块代码的每行前面加上”//“注释符号,若没有选中区域,在光标所在的行加上”//“,若已经有"注释符号”,快捷键之后会取消"注释符号"
Ctrl+Z撤回[向前撤回]
Ctrl+Shift+Z重写[向后重写]一般用Ctrl+Y表示向后撤回,但Ctrl+Y好像不是重写作用,反正按了没有反应
Ctrl+Shift+V将剪切板弹出,选择拷贝的文本粘贴到当前文本中如图:kj-20
Ctrl+回车Enter光标只要在该行(无论是代码前还是代码中或尾),快捷键之后,该行的下一行出现空行,光标出现在空行中
Shift+回车Enter光标在整行代码前面,快捷键之后在该行的上一行会插入空行,但光标还在该行代码前面其实与回车Enter效果一样
Shift+Ctrl+回车Enter光标则与上面的相反了,只要在该行(无论是代码前还是代码中或尾),快捷键之后,该行的上一行出现空行,光标出现在空行中
Shift+’在选中区域的头与尾加上双引号""注意:一定在英文输入的双引号才有这样的快捷键效果
Tab若未选中代码,光标在代码中,相当于“空格”的作用,会在光标前空一格或两格或四格;光标在代码最前面,会在光标前空四格 ,整行代码往后走。若选中代码,整体都会向后走,每行代码最前多四格空格Shift+Tab是其反向操作
Shift+Tab若未选中代码,光标在代码中,会将光标前的空格清除;光标在代码最前,会将光标的该行向前减少四个空格。若选中代码,整体会向前走,每行代码减少四个空格与Tab是反方向的作用
Ctrl+Tab当前窗口与前一个窗口的跳转
Ctrl+H选中某部分改过的代码,按快捷后,会打开Diff窗口,比较选中代码范围或文件的差异如图:kj-01(红色部分是改之前的代码,绿色部分是已改的代码)
Ctrl+F若未选中单词,会自动捕捉光标附近的单词,若选中整个语句,会出现淡蓝色背景的框 框住选中的语句,弹出Find小窗口进行查找如图:kj-02(第一张图,选中的值有重复的,呈黄色,第二张图,选中范围,有重复的背景呈黄色,无重复的呈淡蓝色背景)
Ctrl+A选中当前文件的所有内容
Ctrl+B对当前项目所有文件进行“遍历编译检查”,系统查看是否存在问题,若存在问题,会在问题控制台呈现。若有代码修改未及时保存,它会弹出提示“以下文件有未保存的修改【如图:kj-16】”如图:kj-03
Alt+D弹出调试菜单的子菜单项如图:kj-04
Alt+E弹出编辑菜单的子菜单项如图:kj-05
Alt+F弹出文件菜单的子菜单项如图:kj-06
Alt+B弹出构建菜单的子菜单项如图:kj-07
Ctrl+T弹出运行项目的构建项如图:kj-08
Alt+T弹出工具菜单的子菜单下如图:kj-09
Alt+W弹出控件菜单的子菜单下如图:kj-10
Alt+H弹出帮助菜单的子菜单下如图:kj-11
Ctrl+I选中部分代码,相当于做了一次“Shift+Tab”操作,按了一次,对同样代码按第二次第三次都不会有反应的
Ctrl+J若未选中代码,按了快捷键,将光标所在行与下一行之间的空格清除;若选中部分代码,按快捷键后,会将代码中的所有的空格清除,只留下有意义的空格,变成简化的代码行如图:kj-12(第一张是按键前,第二张是选择范围按键后)
Ctrl+K打开项目文件搜索栏,可以进行文件名的搜索如图:kj-13(第一张是按键后,立马弹出的样子;第二张是进行搜索的样子)
Ctrl+L好像没什么用,光标出现在代码中(可选中代码,也可不选择代码),按这个快捷键,文件搜索栏会出现“l <line>:<column>”(因为该编辑器问题,将半角的英文"<>"改用全角的尖括号);若光标不在代码中,而是选中某个文件或文件夹,按键后并没有反应如图:kj-14
Ctrl+M在光标所在行(无论有没有选中代码),按一次快捷键,会在行数标志旁加“书签”图标;再按一次,取消“书签”图标如图:kj-15
Ctrl+Q退出Qt窗口(关闭Qt软件)。若你不小心按到,而且刚刚修改的代码未保存,它会弹出提示“以下文件有未保存的修改”如图:kj-16
Ctrl+R按键后,对【如图:kj-17】的红圈圈起的已选中的项目重新构建,相当于“Release(Run)”运行发布操作。若有代码修改未及时保存,它会弹出提示“以下文件有未保存的修改【如图:kj-16】”
Ctrl+U若未选中代码范围,光标在某单词“前、中、后”,会自动选中单词;关闭在标点符号或标号 “前、中、后”(反正光标不在单词旁),会自动选中标号的 该行 / 整段语句块 / 整段语句
Ctrl+W将当前文件关闭
F1Windows端Qt中:若选中某函数后按键,会在最右边扩展出“帮助”栏,其中是对应的函数解释,如图所示:18-01图一;若无选中,操作变得无意义,扩展的“帮助”栏:显示“没有可用文档”,如图所示:18-02图二;Linux端Qt中:若选中某函数按键,直接跳转“帮助”项的窗口,查看对应函数解释如图:kj-18
F2若选中“函数名”或"类名",按键后跳到对应的“.h”头文件;若选中“变量名”,按键后跳至“定义”之处;若选中“控件名”,按键后跳至“ui_mainwindow.h”头文件
Ctrl+Space空格在未写完的函数名末端(或中部)按快捷键后,会弹出相关函数名;在未写完的变量名末端(或中部)按快捷键后,会弹出相关变量名如图:kj-19

kj-01:
在这里插入图片描述
kj-02:
在这里插入图片描述
在这里插入图片描述
kj-03:
在这里插入图片描述
kj-04:
在这里插入图片描述
kj-05:
在这里插入图片描述
kj-06:
在这里插入图片描述
kj-07:
在这里插入图片描述
kj-08:
在这里插入图片描述
kj-09:
在这里插入图片描述
kj-10:
在这里插入图片描述
kj-11:
在这里插入图片描述
kj-12:
在这里插入图片描述
在这里插入图片描述
kj-13:
在这里插入图片描述
在这里插入图片描述
kj-14:
在这里插入图片描述
kj-15:
在这里插入图片描述
kj-16:
在这里插入图片描述
kj-17:
在这里插入图片描述
kj-18:
18-01图一:
在这里插入图片描述
18-02图二:
在这里插入图片描述
kj-19:
在这里插入图片描述
kj-20:
在这里插入图片描述

参考

Linux中命令

  • 我这边:命令大多在“ Tera Term【是支持UTF-8协议的开源自由软件终端仿真器,是串口调试工具】 ”软件上输入,连接开发板与虚拟机VWM里的Linux,做桥梁搭建连接
  • 有个快捷键必须知道:
    • Tab键
      • 输入文件名或项目名的开头字母,按Tab键,会自动匹配开头字母相同的名称
      • 若有多个前几个字母都相同的名称,则要多写些字母,最好具有唯一性,这样匹配度更高:
      有i2c_abcd,i2c_bcde,i2c_cdef三个文件,
      则输入“i2c_a”之后按Tab键,自动匹配i2c_abcd名字;
      若输入"i2c_"之后按Tab键,不会匹配任何名字;
      若输入"i"之后按Tab键,自动匹配i2c_相同部分。
      PS:若跳转某目录,输入目录名时,按Tab键,可能会根据“已输入的字母开头”找到相同字母开头相同的名字,可能没有一点反应。
      

常用

Linux指令意义备注
cp -R或-r或忽略 Test或/test/Test /home或/home/或/home/Test2复制本目录下的Test文件或test目录下的Test文件至home目录下 或 home目录下并改名为Test2文件(可以指定Test文件是哪个目录下的某文件,自动新建或覆盖)。Test、Test2:文件名;test:目录名;home:把复制的文件放入指定目录的目录名 ;“-R"或”-r"可忽略、也可二选一。Linux-001至003
cd /进入根目录,最上级目录。
cd . .进入本目录的上级目录。点点之间不可出现空格。
cd test 或 cd /test/ 或 cd /test 或 cd /test/test1/test2进入本目录的test目录 或 根目录下的test目录或 根目录下的test的test1的test2目录。
mkdir Test 或 mkdir /home/Test在本目录创建新文件夹或在根目录下的home目录里新建文件夹。目录名不可与同级文件或文件夹重名。Linux-004
touch Test 或 touch Test.ini 或 touch Test.txt 或 touch /home/Test 或 touch home/Test 或touch /home/test1/test2/Test 或 touch /udisk/yuv6 /udisk/yuv7在本目录下新建Test或Test.ini或Test.txt普通文本文件 或者 在根目录下的home目录里新建Test文件 或者 在根目录下的home的test1的test2目录下新建Test文本文件 或者 在根目录的udisk目录里新建yuv6和yuv7两个文件。若touch home/Test新建时出现提示:touch: home/Test: No such file or directory则改用“touch /home/Test”命令,因为本目录没有叫home的目录。若同时新建多个文件,就以空格相隔。Linux-005
rm -f /home/Test 或 rm yuv7 yuv3删除home文件夹下的Test文件 或者 删除本目录的yuv7和yuv3文件若文件是有后缀的,在指令中的文件名部分就要补上后缀名;-f可忽略。Linux-006
rm -rf /home/test删除home文件夹下的test文件夹;若test目录含文件和文件夹的话,则作用是:删除test文件夹及其含有的文件或文件夹。r是递归处理,f是强制删除;一旦删除了一个文件,就无法再恢复它。Linux-007
rm *.ini *.jpg删除当前目录的所有.ini和.jpg后缀的文件
more mxx.ini将文件从第一行开始,根据输出窗口的大小,适当的输出文件内容,只能向后翻(怎么翻页在文章中有表述,但没实操过)。若文件是有后缀的,在输入指令时文件名要补上后缀名。Linux-008
less mxx.ini 或 less passwd可以向前或向后翻看文件(退出查看,按“Q或q”键),less的用法比起more又更加有弹性。若文件是有后缀的,在输入指令时文件名要补上后缀名。Linux-008
ps查看当前所有进程。Linux-009
ls查看当前目录的所有文件、文件夹,结果显示一般为:文件或文件夹的名字和图片视频的名字加后缀名。
killall pinchzoom或其他程序名称关闭正在运行的名为pinchzoom的程序(一般开发板开机默认运行pinchzoom程序[在背景图——奶酪上有一群老鼠乱跑];若要进行其他程序,最好用该命令强制关闭之后才去运行指定的程序)。Linux-010
kill -9 1444或进程号PID或1444 1445关闭指定进程号的进程,必须指定进程号PID;否则,如图所示:Linux-011。Linux-012
./T3QQ(在开发板上)运行当前目录/当前文件夹下T3QQ程序,若要退出程序,一般用“Ctrl+C”快捷键就可以关闭当前程序。
./T3QW &(在开发板上)的后台执行,补:一般使用Ctrl+C可以退出程序,但,在放入后台执行的情况下,想完全关闭程序,只能kill或killall进程,才能真正的关闭程序。Linux-013
ifconfig查看网络IP地址(必须有网,结果会出现eth1或eth0、lo;若无网,只存在lo:127.0.0.1,但对于仿真工作来说这是无意义)。
ifconfig eth1 192.168.XXX.XXX修改eth1的ip地址为’192.168.XXX.XXX’。
reboot重启。
vi 文件名(如:xxx/xx.ini)查阅文件内容,按"小写i或大写I",可编辑文件内容,即进入编辑模式,**按"Esc"表示退出编辑模式(若没有进入编辑模式,则为无效按键指令),按(必须是英文符号)“:q!“表示不保存并结束查看,与按”:wq”**表示保存并结束查看。vim指令也是这样,若输入之后,出现如图所示:Linux-015这样的情况,换成vi命令即可(哪个简单哪个来嘛~)。Linux-016
init 0在终端输入该指令,表示停机或关机(千万不能将initdefault设置为0)。
init 6重启(千万不要把initdefault设置为6)。
init 1或2或3或4或5不经常用,但分别表示‘单用户模式,只root用户进行维护’ ‘多用户模式,不能使用NFS(Net File System)’ ‘完全多用户模式(标准的运行级别)’ ‘安全模式,一般不可用’ ‘图形化(即图形界面)’ 。
  • Linux 基础学习2linux中各种文件的颜色表示是什么意思?LINUX里各个颜色文件名代表什么LINUX文件名颜色代表意义
    • 绿色:代表可执行文件、可执行的程序(.jpg、.png、.c、.exe、.yuv等);紫色或蓝色:代表文件夹、目录;天空蓝色/浅蓝色:代表链接文件,主要是使用ln命令建立的文件,可以直接用cd xxx直接跳转查看目录;红色:代表压缩文件或者包文件; 白色:普通文件(.ini、.txt、.conf、.wac等)
      在这里插入图片描述
      在这里插入图片描述
  • Linux-001:
    home 与 mnt 是同级目录/文件夹;一个点’.‘表示当前目录,两个点’ . .'(中间不可出现空格)表示上级目录。当cp Test .时,会报提示,表示当前目录有Test的文件了,不可复制粘贴。
    Linux-001
  • Linux-002:
    cp -r . ./Test /home表示将本目录的上级目录下的Test文件复制到home目录下。
    Linux-002
  • Linux-003:
    查看了udis目录下无任何文件或文件夹,将mnt目录下的Test文件的内容复制到udisk目录下的Test2文件中。
    Linux-003
# cd /lib32/dhcpcd/
# ls
dhcpcd-hooks      dhcpcd-run-hooks
# cd /lib32/dhcpcd/dhcpcd-hooks/
# ls
01-test         02-dump         20-resolv.conf  30-hostname
# cd ..              				   ------[1]
# ls
dhcpcd-hooks      dhcpcd-run-hooks
# cd /lib32/dhcpcd/dhcpcd-hooks/
# cp ../dhcpcd-run-hooks /home/hooks   ------[2]
# cd ..
# ls
dhcpcd-hooks      dhcpcd-run-hooks
# cd /home
# ls								   ------[3]
Rear_Center.wav  T3QTDlg          hooks            i2c_axp22_test
#

  • Linux-004:
    到根目录的media的mmcblk0p1的DCIM目录,新建与DCIM同级的my2文件,若进入DCIM上级mmcblk0p1目录,创建目录my2,会弹出提示:不能创建目录my2,因为文件已存在。
    在这里插入图片描述
  • Linux-005:
    到根目录,查看文件,touch udisk/yuv7:在本目录的udisk目录里创建yuv7文件,进入udisk目录查看文件,只有touch /udisk/yuv8才能创建文件成功,因为udisk本目录没有udisk文件夹,只有yuv2目录,udisk是根目录下的目录,所以要加上“/”斜杠 。
    在这里插入图片描述
  • Linux-006:
    在根目录下的media的mmcblk0p1目录时,删除yuv6与yuv7文件,只有yuv6删除成功,因为“/ . . /udisk/yuv6”(最好是//udisk/yuv6,好理解)代表 根目录的udisk目录的yuv6文件;若在udisk目录,输入指令rm -f /…/udisk/yuv …/udisk/yuv8,两个文件删除成功,和 rm yuv7 yuv3 一样删除成功。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • Linux-007 :
  • Linux-008 :
    在这里插入图片描述
  • Linux-009:

在这里插入图片描述
在这里插入图片描述

  • Linux-010:
    图1:WriteOnlyTest程序在后台运行,图2:查看进程,图三:在进程结果中发现“WriteOnlyTest程序”正在运行,然后使用killall WriteOnlyTest指令关闭WriteOnlyTest程序,然后再用ps指令查看进程,判断是否关闭成功,图四:发现进程关闭成功了。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • Linux-011:
    在这里插入图片描述
  • Linux-012:
    图1:查看进程,图二:在进程结果中发现“WriteOnlyTest程序”正在运行,接着再运行一个WriteOnlyTest,看下是否独立运行,图三:发现两个同名程序独立且互不干扰的运行着,然后使用kill -9 1549 1555指令关闭两个程序名为WriteOnlyTest的进程,然后再用ps指令查看进程,判断是否关闭成功,图四:发现进程关闭成功了。在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • Linux-013:
    在这里插入图片描述
    在这里插入图片描述
  • Linux-015:
    在这里插入图片描述
  • Linux-016:
    在这里插入图片描述
    在这里插入图片描述

会用

Linux指令意义备注
devmem ADDRESS [WIDTH [VALUE]]应用层可以使用devmem工具访问物理地址,得到指定地址(寄存器)的数据;ADDRESS 是地址;WIDTH是结果的宽度,默认为32位,可以忽略;VALUE可以忽略,一般不使用。如:devmem 0x44e07134 32[busybox devmen表示查看devmen配置]LinuxCan-001
date查看硬件平台的系统时间
rtc查看硬件平台的系统时间、硬件时间、当地时间
uptime查看系统 运行了多长时间
du
sudo
  • LinuxCan-001:
    在这里插入图片描述

参考

Linux其他

自定义控件及其他Qt使用例子

Qwt仪表盘

同一小编的文章

QProcess

Mplayer

暂停功能

process->write("pause\n");//但是放入项目中,无效,不知道其他人是不是也这样

FFmpeg

  • 这个播放器与QProcess类无关,但是与Mplayer有关

暂停功能

获取CPU序号

参考:

读取某进程是否存在

PS:还没有代码实现实践

避免Too many open files异常

方法一:Qt项目调用的QProcess::execute()后要close()

#include <QProcess>#include <QtGui>

QProcess* myProcess = new QProcess(this);
QString strVal = "ls";//查看当前目录
myProcess->execute(valOutput);//执行指令
if(myProcess)
{
  myProcess->close();
  delete myProcess;
  myProcess = 0;
}

因为execute相当于start + waitForFinished,所以还可以这样:
myProcess->start(valOutput);//执行指令
myProcess->waitForFinished();
if(myProcess)
{
  myProcess->close();
  delete myProcess;
  myProcess = 0;
}

后者的话,还可以加行代码,作用是:读取指令的打印结果
QString strOutput = myProcess->readAllStandardOutput();

方法二:设置“open files”或“file descriptions”项从1024改为2048
【表示每个用户最大允许打开的文件数量是1024改为2048】
使用指令:ulimit -n 2048
在这里插入图片描述
在这里插入图片描述

参考:linux 打开文件数 too many open files 解决方法

Java,C++,C某些的比较

枚举

数据类型

C++ 与 Java 数据类型的区别

QTimer QTime QDateTime QDate 对应时间格式

其他

C语言的strtoul函数

const char *axpv1 = "0x34";
int dev_addr = strtoul(axpv1,NULL,0);

C语言的tcgetattr函数

C语言的ioctl函数

Qt Assistant

指针及运算符

  • 指针:是存放变量地址的;用来访问变量地址。

[]运算符

*、&运算符

酒店,404号房是黑白主题的房间,
	p就是404号,表示门牌指向的第四层的4号房(房间地址),
	*p就是让我们得知房间内容——黑白主题的窗帘桌子床,
	&p就是让我们得知门牌——404号。
a = 3;                     //将赋值为3    
c = &a;                    //把a的地址赋值于c
d = *c;                    //取出c存放a地址中的值,并赋值给d
printf("d = %d",d);        //打印d

输出为:     d = 3

++运算符运算顺序

序号指针运算顺序备注
1*p++先返回 *p的值,然后p再++。
2(*p)++先返回 *p的值,然后 *p的值再++。
3*(p++)先返回 *p的值,然后p再++。也就是说它和 *p++的运算顺序一样。
4++*p先将 *p的值++,然后再返回 *p的值。
5++(*p)先将 *p的值++,然后再返回 *p的值它和++ *p是一样的。
6*(++p)先将p的值++,然后再返回 * p的值它和 *++p是等价的。

1~3三组 是先返回 *p的值,区别就在于到底是p++还是 *p的值++。
4~6三组 是最后都是返回 *p的值,不同点在于是 *p先++还是p++。

运算符重载

成员运算符(.)和指针运算符(->)

Human Tom;
Human* p;
p = &Tom;
Tom.BirthDay = "1969“;
Tom.IntroduceSelf();
效果等价于:
p->BirthDay = "1969";
p->IntroduceSelf();

逻辑、移位运算符

打包发布

参考:
Qt——Windows端打包发布【讲解全面,因为是我写的!】

全志平台T3

typedef enum //定义枚举
{
	DISP_BT601  = 0, //用于标清视频
	DISP_BT709  = 1, //用于高清视频
	DISP_YCC    = 2, //用于图片
}disp_color_space;

按键消抖

注:好像不是Qt能控制的,这个需要按键硬件控制。

-按键消抖_百度百科

如何保证代码稳定性

注:其实这个问题,是一个码农一直研究的话题之一,重在经验积累。

架构设计文档

Qt调度器

Qt看门狗

Qt使用运动卡

延伸

Qt5串口收发数据(通信)

  • QSerialPort4

Qt5版本之前

动态变化的例子

挑战

随便看看


  1. Qt小传——从诞生到发展、繁荣Qt公司——全球百科Qt深入浅出(一) 从零开始写Qt应用Qt的版本历史 ↩︎

  2. Qt构造函数的参数:QObject *parent = Q_NULLPTR ↩︎

  3. nullptr和NULLNULL与nullptr ↩︎

  4. QSerialPort Class——Qt文档 ↩︎

  • 12
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
很抱歉,我没有找到关于"Qtcreate"的相关信息。请问您是指"Qt Creator"吗?Qt Creator是一个集成开发环境(IDE),用于开发Qt应用程序。它支持多种平台,包括iOS、Android和WinRT。通过Qt Creator,您可以编写和调试代码,并使用Qt的字符串类,如QString和QByteArray,来处理字符串。QString是Qt最常用的字符串类,而QByteArray适用于处理以'\0'结尾的传统字符串。QByteArray可以处理多字节编码的字符串,如UTF-8、GBK和Big5。在使用QByteArray时,程序员需要确定所使用的字符串编码格式。此外,QByteArray还使用了隐式共享机制来提高运行效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Qt Create 笔记 (一) 1.QString 2.QByteArray](https://blog.csdn.net/linbounconstraint/article/details/51497782)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Game Programming Using QT(PACKT,2016)](https://download.csdn.net/download/vanridin/9431499)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yvette_QIU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值