Qt C++ 工具箱

从零开始的Qt开发之路

里面大概会写一些和Qt相关的内容,也不说是从0开始,感觉Qt做东西和用 C#也差不了很多?也许吧,总之慢慢来,一步一个脚印,直到给它拿下。

2022.5.13

关于ifdef预编译的问题

一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。

条件编译命令最常见的形式为:

#ifdef 标识符
程序段1
#else
程序段2
#endif

往往可以用于一些公司的发布版本代码的修改,比如我想这个版本和那个版本,通过一些参数或者变量来实现,这就需要最好就通过ifdef来实现,这样可以省很多编译资源,而不用用户全部编译完成之后再进行相应的比对。这些指令只检查使用 #define 定义的标识符是否存在,而不检查在 C 或 C++ 源代码中声明的标识符。

C++中#if #ifdef 的作用

2022.5.12

template 模板

有时候我们可能会写一大堆同名函数,这个时候就需要用到template函数模板

比如我们常用的swap交换两个数字的函数,交换数据的双方可能是int,double,float,string等等,总不能同名函数一直这么写下去吧,所以template应运而生。

例如:

void swap(int&a , int& b) {

int temp = a;

a = b;

b = temp;

}

首先我们把函数模板的声明形式摆在这:

template <class identifier> function_declaration;
template <typename identifier> function_declaration;

就比如前面提到的swap函数,我们来给它指定一个模板

//method.h
template<typename T> void swap(T& t1, T& t2); #include "method.cpp" template<typename T> void swap(T& t1, T& t2) {
T tmpT;
tmpT = t1;
t1 = t2;
t2 = tmpT;
}

这样就是一个模板的声明和定义了,那模板该如何进行实例化呢?

范例:

int num1 = 1, num2 = 2;
swap<int>(num1, num2);
printf("num1:%d, num2:%d\n", num1, num2);

尖括号中可以写一些需要返回的数据类型,然后直接向函数中输入已被定义的参数即可。

类模板

考虑我们写一个简单的栈的类,这个栈可以支持int类型,long类型,string类型等等,不利用类模板,我们就要写三个以上的stack类,其中代码基本一样,通过类模板,我们可以定义一个简单的栈模板,再根据需要实例化为int栈,long栈,string栈。

//statck.h
template <class T> class Stack {
public:
Stack();
~Stack();
void push(T t);
T pop();
bool isEmpty();
private:
T *m_pT;
int m_maxSize;
int m_size;
}; //stack.cpp
template <class T> Stack<T>::Stack(){
m_maxSize = 100;
m_size = 0;
m_pT = new T[m_maxSize];
}
template <class T> Stack<T>::~Stack() {
delete [] m_pT ;
} template <class T> void Stack<T>::push(T t) {
m_size++;
m_pT[m_size - 1] = t; }
template <class T> T Stack<T>::pop() {
T t = m_pT[m_size - 1];
m_size--;
return t;
}
template <class T> bool Stack<T>::isEmpty() {
return m_size == 0;
}

至于其他的,包括模板参数,模板专门化等,详情看文章C++模板template用法总结

C++回调函数概要

可以举个实例来看看

#include <iostream>

class ProgramA {
public:
void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); } static void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }
}; class ProgramB {
public:
void FunB1(void (*callback)()) {
printf("I'am ProgramB.FunB1() and be called..\n");
callback();
}
}; int main(int argc, char **argv) {
ProgramA PA;
PA.FunA1(); ProgramB PB;
PB.FunB1(ProgramA::FunA2);
}

上述代码中,也就是说,在一个函数里面写一个typedef (*callback) 则代表向这个函数里面传入了一个 函数的指针,然后就可以在这个函数里面 调用这个函数

比如上面这个FunB1里面,传入一个callback()的区域函数指针,然后在函数体内可以调用这个callback()函数

在实际调用中,我们向FunB1中传入Program类中FunA2函数进去,然后再FunB1的函数实现中,实际上调用的就是FunA2函数了

结果如下:

I'am ProgramB.FunA1() and be called..
I'am ProgramB.FunB1() and be called..
I'am ProgramB.FunA2() and be called..

要注意一些问题,就是回调函数在类内、类外、静态函数、非静态函数之间的调用关系,详情见下方文章

关于C++ 回调函数(callback) 精简且实用

这里简单摘抄一下:为了避免 static 函数不能访问非static 成员变量或函数,会严重限制回调函数可以实现的功能。而且在programB中FunB1还使用 programA的类型,也就我预先还要知道回调函数所属的类定义,当programB想独立封装时就不好用了。

一个比较常用的方法就是:可以把非static的回调函数 包装为另一个static函数,这种方式也是一种应用比较广的方法。

#include <iostream>

class ProgramA {
public:
void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); } void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); } static void FunA2Wrapper(void *context) {
printf("I'am ProgramA.FunA2Wrapper() and be called..\n");
((ProgramA *)context)->FunA2(); // 此处调用的FunA2()是context的函数, 不是this->FunA2()
}
}; class ProgramB {
public:
void FunB1(void (ProgramA::*callback)(), void *context) {
printf("I'am ProgramB.FunB1() and be called..\n");
((ProgramA *)context->*callback)();
} void FunB2(void (*callback)(void *), void *context) {
printf("I'am ProgramB.FunB2() and be called..\n");
callback(context);
}
}; int main(int argc, char **argv) {
ProgramA PA;
PA.FunA1(); ProgramB PB;
PB.FunB1(&ProgramA::FunA2, &PA); // 此处都要加& printf("\n");
PB.FunB2(ProgramA::FunA2Wrapper, &PA);
}

但是C++其实有自带的转换宏,不需要程序员去这样写方法,太麻烦,而且也没什么含义。

std::funtion和std::bind的使用

std::funtion和std::bind可以登场了。

std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、函数指针、以及其它函数对象等[1]。

std::bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的[2]。

这里直接上代码,看std::funtion和std::bind如何在回调中使用。

#include <iostream>

#include <functional> // fucntion/bind

class ProgramA {
public:
void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); } void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); } static void FunA3() { printf("I'am ProgramA.FunA3() and be called..\n"); }
}; class ProgramB {
typedef std::function<void ()> CallbackFun;
public:
void FunB1(CallbackFun callback) {
printf("I'am ProgramB.FunB2() and be called..\n");
callback();
}
}; void normFun() { printf("I'am normFun() and be called..\n"); } int main(int argc, char **argv) {
ProgramA PA;
PA.FunA1(); printf("\n");
ProgramB PB;
PB.FunB1(normFun);
printf("\n");
PB.FunB1(ProgramA::FunA3);
printf("\n");
PB.FunB1(std::bind(&ProgramA::FunA2, &PA));
}

std::funtion支持直接传入函数地址,或者通过std::bind指定。

简而言之,std::funtion是定义函数类型(输入、输出),std::bind是绑定特定的函数(具体的要调用的函数)。

相比于wrapper方法,这个方式要更直接、简洁很多。

Qt 服务端中 设置心跳断连的实例

Qt实现简易心跳包机制

2022.5.11

int char*、string 和char

直接用(int)进行强制转换可能会导致一些不可预料的错误,需要使用到atoi函数C++:string类型、char *类型,int类型之间的转换:atoi(),stoi(),c_str()

2022.5.10

定义问题

注意,千万注意

已经定义过的关键字,就不要再定义了

比如

char* serverip = "0";
int port = 4443;
char* otherUserName = "0";
char* otherUserSeat = "0";
char* currentUserName = "0";
char* currentUserSeat = "0"; if (true) {
char* serverip = "192.168.110.122";
char* port = 4443;
char* otherUserName = "11";
char* otherUserSeat = "s1";
char* currentUserName = "22";
char* currentUserSeat = "s2";
char* qDebug() << "true";
}

这可能会导致一些问题,使得程序无法进入到这个分支里面去,出现严重错误!!!

注意格式转换问题

如果你拿到一个QString类型,先转到char* 再转回QString,可能会缺失一部分内容,导致报错

这个websoup什么的exe,如果你给定的ip 连接错误或者连接失败,会持续的更换线程ID,同时会不停地更换输入法,导致使用失败

睡眠真的很重要

关于我在多屏幕之间的坐标转换这个问题上犯了蠢,geometry这个方法设定窗体坐标位置,注意是 x y w h

所以第一个参数不应该带有主桌面的x坐标,因为主窗体第一个坐标永远是0 , 0 !我之前想了半天这个问题,为什么我锁定了主屏幕,结果窗口出现在副屏幕上

this->setGeometry(screenRect.x() - wholeFrm.width, screenRect.y(), wholeFrm.width, wholeFrm.height);

这显然是错误的,因为screenRect.x() = 0 ,所以该窗体永远只会显示到主屏幕的左边去!\

正确做法范例:

//获取主屏幕索引
int mainScreenID = desktop->primaryScreen();
//获得主屏幕宽高
QRect screenRect = desktop->screenGeometry(mainScreenID);
//将窗体挪到对应位置去
this->setGeometry(screenRect.width() - wholeFrm.width, screenRect.y(), wholeFrm.width, wholeFrm.height);

在Qt下处理多屏幕程序方案

2022.5.9

在VS中 Qt的release模式下进行调试

C++ Release下进行调试

报错 This application failed to start because it could not find or load the Qt platform plugin"windows" in ""

缺少了platforms的支持,找到msvc文件夹中的platforms文件夹,粘贴到 Release文件夹中就行了

VS工程中常用路径宏定义表示$(SolutionDir) $(ProjectDir) $(ProjectName) $(Configuration)

一个关于VS工程中常用路径宏定义表示的说明 VS工程中常用路径宏定义表示$(SolutionDir) $(ProjectDir) $(ProjectName) $(Configuration) (good解释的很清楚)

关于TestDemo中给定的默认的引用路径为:$(SolutionDir)$(Configuration)\LBD_VideoMeeting.lib;%(AdditionalDependencies)

关于如何向c++编译生成的exe中设定参数这回事

一般是通过命令行,具体如何实现请参考

详情请参考:C/C++生成的exe文件如何传参数到main中

关于如何在qt中添加点击事件

博客 Qt QLable 响应单击点击事件 中写的比较清楚了,注意一点就是,eventFilter是继承过来的方法,所以不能直接取用,需要添加一个override参数,例如:

public slots:
bool eventFilter(QObject *, QEvent *) override;

2022.5.7

一个关于如何将widget变成一个像商用软件那样 不可拖拽大小、没有开启、关闭等按钮的固定窗口Qt::FramelessWindowHint无边框化,移动,大小调整插入此业务代码的时候需要注意到就是,这个Direction不是Qt自带的,而是一个Enum,需要注意以下这个点

一些和窗口控件有关的、选中标红的方案:QT的基本控件的焦点定位及切换

2022.5.6

将窗口设置为全屏化

将指定句柄窗口设置为全屏化的方案

但是qt里应该有自带的,我稍微研究下

qt中 按钮状态的切换

可以设置一下按钮按下去就陷下去,再按一下回弹的方法,就是哪个clicked(bool)方法,调用案例如下:

首先在ui初始化的时候需要对按钮进行设置:ui.btn_Audio->setCheckable(true);

void LBD_VideoMeeting_SingalMeet::on_btn_Audio_clicked(bool isSilent)
{
if (isSilent) {
qDebug() << "isSilent turns into TURE" << endl;
}
else {
qDebug() << "isSilent turns into FALSE" << endl;
}
}

2022.5.6

第一个项目,可视化对讲 关于窗口句柄,其实理解上是没有问题的,为什么5.5找了一天问题呢?其实不是我自己的问题,是Release里面少了个exe文件,但是我并不知道这回事。其中关于访问网络有两个文件时必须的,一个是MediasoupWebSocket.exe,另一个是CLBDVideoMeeting.ini,这两个文件是被LBD_ViedeoMeeting引用了的,但是这里并未提及。

获得

2022.5.5

将句柄转成int类型,示例:QString var = QString("%1%2%3").arg("param1").arg(QString::fromLocal8bit(char*串)).arg("param2");

因为陶工给的lib是Release版的,所以这里我们也可以用Release版打开,但是这里有个问题,就是在vs中打开一个qt的工程文件,打开debug版是没有问题的,但是release版不行,原因是生成Release版的时候,它并没能正常的生成一个plugins文件,少了dll所以会报错。

解决方案见QT-This application failed to start because it could not find or load the Qt platform plugin "windows"

※ 重要内容

如何在QT中获得窗口&控件的句柄:获得窗口句柄

第一次开始进行Qt的界面开发,第一个项目:LBD_VideoMeetingTest,有个问题,就是运行会报错,提示无法解析的外部符号。注:目前为止遇到的所有无法解析外部符号的问题都是由无法调用起来.lib文件造成的,要多加注意这点。因为是隐式调用,而且lib文件的调用是直接设置到工程文件里面去的而不是通过#pragma调用,具体设置方式是 右键工程文件->属性->链接器->附加依赖项->输入具体的.lib文件路径(相对或者绝对都行)包含文件名,如$(SolutionDir)$(Configuration)\LBD_VideoMeeting.lib;%(AdditionalDependencies),这时就相当于用了一个#pragma声明引用了该.lib文件,使用对应的.h头文件,即可直接调用dll

2022.4.18

看到个挺全的教程文档,当个参考

qt教程

QString::Comapre 函数

之前遇到一个坑点就是关于QString::Compare函数,我以为这个函数是用作比对两个字符串是否相同的,但是并不是,它是用作两个字符串比大小的,具体实例如下:

QString::compare("ab","ab"); //值为0;

QString::compare(“ab”,“df"); //值为<0;

QString::compare("df","ab"); //值为>0;

反正很傻逼,我开始的时候怎么判都潘不对,如果要判断两个字符串是否相同,则需要用QString::compare(a,b) == 0;

qt绑定数据库 遇到的一些问题

首先向工具箱中添加两个实例,一个是如何在qt的tableView中展示数据库,一个是如何连接数据库

注意使用构造函数的时候你声明的定义,如果你自定义了构造函数,而且参数非缺省,则你在任何地方都不应该出现如QInser Inser;这种语句,否则可能会报错。

另外,就是在使用执行命令的query类的指令时,一定要进行初始化,比如QSqlQuery query = QSqlQuery(db)

2022.4.16 数据库?

就是有个问题,你这个数据库连接了对吧,你建立了一个query对象,他就可以执行你的代码吗?理论上说是你的query直接和你当前的databse绑定了,但是并不一定,最好是直接在建立之后进行一下初始化

比如: 在.h文化中初始化 QSqlQuery query = QSqlQuery(db);

然后在cpp中进行绑定 QSqlQuery query(db);

在执行中要注意一点,就是第一行并不是默认的,要先query.next()

举个例子

while(query.next())     //遍历数据库查找数据,先next,否则

{

    name = query.value(1).toString();

    sex = query.value(2).toString();

    stu_number = query.value(3).toString();

    qDebug() << name;

    qDebug() << sex;

    qDebug() << stu_number;

}

2022.4.15

Driver not loaded?

真草泥马了,这问题是真的傻逼,我的QT 可能跟我的 数据库mysql装的不是一个位数的,mysql是32位的,其实我的qt用的编译器也是32位的,但是系统却不是32位的可能,所以对mysql数据库的连接connector 不能直接用mysql给定的,具体原理我也不知道,总之网上的教程很多其实都没说到点子上,反正我自己的问题并没有解决,而在我一段时间的思考之后,我才意识到可能是我的connector也下错了,而是要下个32位的connector

因为我的mysql版本是5.5 , 所以这个connector的版本可以下个旧一点的,比如这个 Windows (x86, 32-bit), ZIP Archive 下个这个就行

QtDesigner 中 窗口没有工具栏?

因为Widgets类本身就是没有 工具栏 状态栏等等,也没法用Action,只有MainWindow类才继承了这些功能,如果需要用这些的话只能再新建一个MainWindow。

如果需要就新建一个MainWindow类,然后将Widget中所有组件复制过去这样

driver not loaded?

转移lib和dll 的方法都试过了,唯一的问题就是数据库和qt的版本之间不兼容,32位的数据库

然后数据库连接还是可能出错,不要用127.0.0.1做本地,按理说是没问题的,但还是报错

qt 中文报错?

如果是qt5以上版本,将

if _MSC_VER >= 1600

pragma execution_character_set("utf-8")

endif

插入对应msvc目录下的qglobal.h文件中即可解决。

来自博客 qt中文乱码解决方案

2022.4.14 路径取进程名 || 一些参数类型转换问题 ||QTimer 控件的问题

QTimer使用的问题

其实QTimer这个控件的使用方法和C#中的timer控件差别并不大,但是要注意,QTimer控件指向的方法一般是通过connect指向槽函数

我整晚遇到的问题就是,我的connect函数 触发的槽函数 没有在头文件中定义,它并不报错,但是触发器connect并不执行,这就是很傻逼的地方这次犯了,下次记得找回场子来

窗口模态打开的问题

qt中窗口有两种打开方式,一种是->show(),一种事->exec(),前者打开之后就无了,后者打开之后会锁定父窗口

其实在这里打开对话框之后就相当于事进入了一个while()循环,直到它关闭,为什么这么说呢?可以打个比方

int ret = dlgTableSize->exec(); //打开一个窗口,进入等到

if(ret == QDialog::Accepted) //如果点击窗口的确认,则触发此if

{

...

}

delete dlgTableSize; //用完记得清除窗口,直接delete就行,或者close

子窗口如何操作主窗口?

声明一个子窗口的方法:instance = new QWDialogLocate(this); //加一个this指针声明当前窗口是其子窗口的父窗口

可以通过一行语句获得父窗口对象:MainWindow parWind = (MainWindow)parentWidget();

这样就可以得到一个指向父窗口的指针

由路径取进程名:

/内存安全的版本/

char *get_filename(char *fullpath)

{

char *ptr = NULL;

int len = strlen(fullpath);

if (fullpath == NULL)

	return NULL;

ptr = fullpath + len;

while (ptr != fullpath && *ptr != '\') // 注1

	ptr--;

if (*ptr == '/')

	ptr++;

return ptr;

}

注1:注意一个问题,这里的*ptr != '/' 其实是有点问题的,因为常规给定的路径不会是这样,而是\ 两种斜杠不同,当然这都取决于你输入的路径如何

C++参数类型转换

其实c++写的dll哪里还需要什么类型转换啊?,主要是说一下在dll里面的类型转换

我这个Firewall代码本身的代码其实不是纯c++,而是c#和c++的混合编程,也就是说其内部有一个带string类型的接口,在托管C++代码中将char*类型转换成 System::String 类型的方法如下:

String^ apppath = System::Runtime::InteropServices::Marshal::PtrToStringAnsi((IntPtr)strAppPath);

源代码中其实是有一个自带const wchar_t*指针的接口,但是这个接口的问题就是:我们不可能要求外部调用者也用这样的类型,所以必须得转置一下。

System::String 转制 const wchar_t*类型的方法 如下:

wchar_t* chrAppPath = (wchar_t*)(Marshal::StringToHGlobalUni(strAppPath)).ToPointer();

详情见项目Firewall.dll 带demo

2022.4.13 C#和QT链接之后的一些问题 || 关于链接库

C#和QT之间链接出现的一些问题

首先一个问题就是我在c#中使用的dataset类型,在c++中是不存在的,所以我如果是在c#中写的那些函数需要返回一个dataset的话,那这个方法其实是不可用捏。

然后说说托管的事,如果你想要从dll中引出一个类,那么你就需要在这个c++的项目中声明一个托管的类来承载这个类中的内容,需要用到ref关键字

比如:ref class Dataoperator 然后如果需要声明一个数值类型比如int bool等,则可以直接如System::Boolean blnToolBroadcastFlagA; 这样声明,如果你需要声明的是一个类,那么则需要在其后加上一个,如:System::String strPath;

另外注意,如果你是托管类中的声明,如果只有声明接口但是却没有写任何实现,则会报错LNK2020 无法解析xxx,这是个很坑的点,因为并没有很明确的写清楚错误原因。

格式转换的问题

现在我这个c#转c++/clr 已经成功了,现在要做的就是把c++打包成一个纯c++的dll,做法不难,但需要进行对接,这时候格式就需要进行转换。

就拿我之前写的防火墙距离,比如我现在有一个方法bool CFirewall::AddApplication(System::String^ strAppPath, System::String^ strAppName) 我现在需要将其打包成一个纯c++的接口,我该怎么做?

首先我们可以先写一个接口类,我就称其为Caller.cpp,在其中写一个对外的接口DLL_FIREWALL bool AddApp(char* strAppPath, char* strAppName) (DLL_FIREWALL 是一个宏,你知道是extern "C" _declspec (dllexport)就可以了)

DLL_FIREWALL bool AddApp(char* strAppPath, char* strAppName) //接收的参数是char*类型

{

System::String^ apppath = gcnew System::String(strAppPath); //将char*类型通过构造函数转换成System::String类型

System::String^ appname = gcnew System::String(strAppName);

CFirewall cfer;

bool isok = cfer.AddApplication(apppath, appname); //然后再调用其函数即可

if (isok) {

	printf("应用已成功添加");

}

else {

	printf("应用添加失败");

}

getchar();

return true;

}

c#转c++遇到的一些问题

之前我觉得可能c++中不好使用C#的类,但是其实我错了,还是能有好办法的只是我懂得太少了,现在我在这里简单写一下步骤和我踩过的坑。

1.首先需要一个c#的项目和c++的项目

注意这个c#的项目必须是类库,而且这个c++的项目必须是clr空项目(当然你要是那种普通的c++项目也行,但是那个/clr的设置会是你过不去的坎)。注意,这里让你建立的clr空项目并不是让你直接用的,因为它/clr并不是一个qt兼容的设置所以这个c++项目只能做一个中间态的兼容类,到时候转换成 c++的dll,再让qt去调用。

2.建好项目之后,需要修改两个设置

3.修改完两个设置之后,就可以开始写了,需要在头文件中输入

using "D:\Workshop\ClassLibrary1\Debug\ClassLibrary1.dll"

对其进行引用

在源文件中 使用其命名空间 如 using namespace LeventureDesign;

然后实例化一个类即可

LeventureDesign::PublicClass^ pc = gcnew LeventureDesign::PublicClass();

注意由于这个是托管类,需要^符号进行标注

4.使用

这个类应该就可以使用了,不管是静态方法还是类方法,都是可以用的了。

2022.4.12 .ui文件打开失败 || 文件操作 || 导入数据库功能

数据库功能

就在qt中使用数据库功能需要在.pro文件内添加一个QT+=sql的参数,但是我在vs里没有找到添加这个参数的接口,我一开始以为是默认添加的,其实不是,是在创建项目的时候就添加上了,如果后期想要加上,则需要添加参数,具体步骤:VS"Qt"菜单-"Qt Project Settings"-"Qt Modules"-勾选SQL library

.ui文件打开失败:

右键.ui文件->打开方式->添加.. ->找到msvc2015\Bin目录下的desinger.exe 确定->将其设为默认,再打开,就可以用了

文件操作:

写在前面,因为在qt中编码多数是有问题的,所以需要解决一下Unicode的识别问题,在main函数下写上:

QTextCodec *codec = QTextCodec::codecForName("UTF-8");

QTextCodec::setCodecForLocale(codec);

一般再QT中操作文件需要先实例化一个QFile对象,比如我现在可以写一个方法:

bool QtFirst::openTextByIODevice(const QString & aFileName)

{

QFile aFile(aFileName);

if (!aFile.exists()) //假如文件不存在

{

	return false;

}

if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text)) { //如果打开方式不是只读或是文本文件

	return false;

}

aFile.close();//关闭文件

return true;

}

放置一个按钮pushButton,点击后可以选择文件,并调用上面这个方法

void QtFirst::on_pushButton_clicked() { //注意,如果需要一个点击的槽函数,可以以on_控件名称_clicked()的形式写一个函数,这样就点击会触发该槽函数了

QString curPath = QDir::currentPath();

QString dlgTitle = "打开一个文件";

QString filter = "文本文件(*.txt *.docx *.doc);;所有文件(*.*)";

//通过这个getOpenFileName方法打开一个选择文件的窗口,输入的参数有父窗口指针this,窗口标题dlgtitle,一个默认目录,和一个筛选器,选择特定的文件格式

QString aFileName = QFileDialog::getOpenFileName(this, dlgTitle, curPath, filter); 

if (aFileName.isEmpty()) {

	return;

}

ui->textEditDevice->setPlainText(aFile.readAll()); //读取这个文件aFile,并将其中的内容写入这个textEdit中去

openTextByIODevice(aFileName);

}

以上就是打开一个文件的方法,主要是先通过getOpenFileName方法操作一个选择文件的窗体,然后返回一个文件路径,然后再操作其文件。

至于保存文件,则同样的,与上面的不同的是,打开文件的窗口控件变成了getSaveFileName,读取也变成了readall也变成了写入write

注意,写入时不能直接写入QString,要将QString转换成QByteArray,比如QString str = ui->textEdit->toPlainText(); QByteArray strBytes=str.toUtf8();

这样才能写入一个文件aFile.write(strBytes,strBytes.length());

2022.4.11 简单说下vs+qt的配置问题

说实在的,qt自带的那个creator倒也不是不能用,就是单纯的不好用,所以一般的来说,我们会把这个qt绑定在vs上使用,一个是vs的在作为编译器这方面远远比qt creator好用

首先说下qt的版本,我这里用的qt版本是5.10.1版本,vs在工作端用的是vs2015,在学生端采用的是vs2019,但是基本上差不了很远,这里简单说说2015端的配置方法

第一步,安装好qt和vs。可以确认一下是否可以新建项目什么的,确认无误之后可以开始进一步的操作

第二步,安装插件。如果是在vs2015,则可以在工具->扩展与更新->联机 中 搜索qt,第一个就是了

第三步,选择版本。在上方工具栏中出现了一个QT VS Tools,点击之后有一个QT Versions,进入之后进入Qt->Versions->add new Qt version 找到qt的安装目录,转到msvc2015->bin目录下的 qmake.exe

第四步,新建一个项目。现在应该已经可以新建一个项目了,但是还没法运行,因为会提示缺少库文件。这个时候就需要右键项目->属性->vc++目录->常规->包含目录 添加一个msvc2015\include

第五步,到这里应该差不多就可以了,但是还要注意一点,就是QT VS Tools->General->Qt/MSBuild->Path to Qt/MSBuild files 这条,默认可能是空,需要自己填,我这里填的是C:\Users\Administrator\AppData\Local\QtMsBuild,具体情况具体分析

2022.4.10

中间休了两天,实在是上班上的头都有点晕了。

从文件操作开始,到摄像头控件的使用

通常这个 receiver需要代表的是一个窗口类,而不是某个特定的控件

比如我们写一个函数,它的作用是让一个label的text变成正宗大肥猪

方法就这么写:

void MainWindow::textChange(){

ui->label->setText(" 正宗大肥猪 ");

}

而我们的connect就需要这么写:

connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(textChange()));

就写在mainwindow.cpp中,当然直接卸载mainwindow.h中也是可以的

另外有个问题,就是这个qt连接vs,我现在还没搞明白,主要是创建了一个新的项目之后,没有哪个ui.h文件,我也不知道为什么

2022.4.8

从零开始,Qt开发

第一步,部署Qt环境

因为公司用的是vs,而我前面的老哥用的是qt5.10,所以我也用qt5.10

安装方案如下:(VS2015 - Qt5.10)[https://www.likecs.com/show-204623088.html]

我用的是戴工老哥的安装包,按照博客中的方法安装,插件没法很好地兼容,会提示有的文件不存在,所以我选择了使用另外一个插件,就可以使用了

在qt中可以直接在ui设计界面设定一个connect

先说下什么是信号与槽,其实直白点说就是触发器和接收器,翻译问题让这两个令人有点难以理解

信号:Signal,槽:Slots

不知道谁翻译的,确实难懂

总之说下普遍的连接方法吧:

QObject:connect(sender,SIGAL(signal()),receiver,SLOT(slot());

这个QObject:: 可以省略,就是connect(sender,SIGAL(signal()),receiver,SLOT(slot());

Qt从实习到搬砖的更多相关文章

  1. 如何使用银联卡充值美元到BTC-E以及比特币搬砖教程

    1,名词解释 搬砖:就是在价格低的平台买入比特币,然后转移到价格高的平台卖出, 一般而言,BTC-E是国外三大比特币交易所中比特币单价最低的一个站,因为其需要用美元充值,相对不方便.之前国内比特币价格 ...

  2. 网络搬砖是件苦力活 CMS推荐GHOS博客程序

    搬砖不是技术活,而是苦力(bi)活,富有技术含量的苦力活说不定就是一门可以持续的生意. 我们不生产内容,我们只是互联网的内容搬运工,这是大部分不具备原创能力个人站长的心声.虽然原创能力不够,但是服务目 ...

  3. 【NOI2019模拟】搬砖

    [NOI2019模拟]搬砖 Description 小火车很穷,只好去搬砖了. 小火车被工头要求搭建\(n\)座塔,第i个高度为\(H_i\),也就是由\(H_i\)块砖头组成.每次小火车可以携带至多 ...

  4. Software-Defined Networking之搬砖的故事

    在很久很久以前,有一个村子. 村里的每一户,都有一个男人和一个女人. 每一户,都以搬砖为生. 从不同的地方,搬到不同的地方. 男人负责搬砖,女人负责告诉男人往哪搬. 每个家庭,都服从村委会的指挥. 村 ...

  5. PS官方正式中文版(搬砖分享)

    https://pan.baidu.com/s/1c3IdQq0 PS官方正式中文版(搬砖分享) 注意事项: 1.安装开始前请先断网,在成功破解激活前请全程断网: 2.安装完成后先试运行软件一次,然后 ...

  6. 中国用户通过rchange用银联充值到PerfectMoney再给BTC-E充值进行搬砖的方法

    最近迷上了比特币这个疯狂的东西,相信很多技术人员都感兴趣. 比特币.莱特币钱包下载和把数据迁移到C盘以外其他盘的方法. 莱特币和山寨币的原理跟比特币基本上一样,可以参考这个方法进行,莱特币的钱包数据迁 ...

  7. NOJ——1656搬砖(DP)

    [1656] 搬砖 时间限制: 2000 ms 内存限制: 65535 K 问题描述 开学了,万恶的大二学长们又要领着大一的鲜肉们一起敲代码搬砖了,这不,著名的杨神拿着n块砖头,当然他把这n块砖头的重 ...

  8. 比特币搬砖对冲策略Python源码

    策略复制地址:https://www.fmz.com/strategy/21023 策略原理 比特币搬砖策略是入门程序化交易的基础策略.原理简单,是新手尝试程序化的好选择,在其黄金时期,比特币搬砖也带 ...

  9. 搬砖--杭电校赛(dfs)

    搬砖 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submissi ...

  10. Android老司机搬砖小技巧

    作为一名Android世界的搬运工,每天搬砖已经够苦够累了,走在坑坑洼洼的道路一不小心就掉坑里了. SDK常用工具类 Android SDK中本身就拥有很多轮子,熟悉这些轮子,可以提高我们的搬砖效率. ...

随机推荐

  1. Linux 宝塔部署 ASP.NET Core 应用

    第一步,发步应用 我这是一个API 应用和 MVC 应用 设置,服务器上要运行的端口 API 端口5000 MVC 端口5001 打包文件夹,发步 1.桌面新建俩个文件夹 2.右键项目发步,选中iis ...

  2. SpringBoot课程学习(三)

    一.YAML格式的基本语法 (1)格式: 大小写敏感 数据值前边必须有空格,作为分隔符 使用缩进表示层级关系 缩进时不允许使用Tab键,只允许使用空格(各个系统 Tab对应的 空格数目可能不同,导致层 ...

  3. Python全栈工程师之从网页搭建入门到Flask全栈项目实战(1) - ES6标准入门和Flex布局

    1.简述 1.什么是ES6?ES6, 全称 ECMAScript 6.0,是 JavaScript 的下一个版本标准,2015年6月份发版.ES6的主要目的是为了解决 ES5 的先天不足. 2.了解E ...

  4. IDEA生成带参数和返回值注释

    步骤说明 打开IDEA进入点击左上角 - 文件 - 设置 - 编辑器 - 活动模板 新建活动模板 填写模板文本 编辑变量 添加变量表达式 设置模板使用范围-设置全部范围应用-或者设置只在Java代码中 ...

  5. 5.ElasticSearch系列之文档的基本操作

    1. 文档写入 # create document. 自动生成 _id POST users/_doc { "user" : "shenjian", " ...

  6. 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍

    微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍 一.为什么会有 API Gateway 网关 随着微服务架构的流行,很多公司把原有的单 ...

  7. java集合框架复习----(2)List

    文章目录 三.List集合 listIterator:迭代器 List实现类 1.泛型类 2.泛型接口 三.List集合 特点 有序,打印输出的顺序和添加时的顺序一致(不会帮你自动排序) 有下标,可以 ...

  8. 0025:2011年NOIp普及组真题——瑞士轮题解

    题目链接:https://www.luogu.com.cn/problem/P1309 如果是新手可能马上会想到sort排序,每比一次就排一次,但是这样的时间复杂度有点高,只有60分: 这是因为每次比 ...

  9. 更改DataFrame列顺序

    使用pandas进行数据分析的时候,有时会由于各种需求添加了一些列.可是列的顺序并不能符合自己的期望.这个时候就需要对于列的顺序进行调整. import numpy as np import pand ...

  10. 学习笔记之——C语言 函数

    采用函数的原因: 随着程序规模的变大,产生了以下问题: --main函数变得相当冗杂 --程序复杂度不断提高 --代码前后关联度提高,修改代码往往牵一发而动全身 --变量使用过多,命名都成了问题 -- ...