一、Qt初尝试,做一个QT计算器《QT 入门到实战》

2022-12-10 15:22:56 浏览数 (1)

学习目标

  • 了解 qt 的基本信息
  • 了解 qt 的下载及安装
  • 了解创建一个基本 qt 项目的流程
  • 了解信号与槽
  • 通过示例了解信号与槽的设置与编写
  • 了解控件添加的方式
  • 了解控件如何使用代码获取其文本
  • 了解控件如何使用代码设置其文本
  • 使用 connect 自定义信号与槽
  • 了解使用样式修饰控件外观
  • 了解使用代码清空控件文本
  • 学习使用Qt 编写一个四则算术计算器

注:本章中使用的一些方法方法是为了简单的了解一下概念性质,例如在多个槽函数时使用的方法并不是简便的,简便的方法在之后的学习中将会进行讲解。

一、简单了解 Qt 及下载安装

1.1 简单了解 Qt

qt 是 C 的图形用户工具,是一个跨平台的用户界面解决方案;Qt 几乎支持所有的系统平台,并且是面向对象的。

Qt 的跨平台是非常强大的,例如可支持 win下的 XP、Vista、Win7/8/10 等 Windows 系统,并且对于Linux 下 X11、HP-UX、BSD/OS 又或是 嵌入式 Linux 平台 等都是支持的,甚至是 Mac 平台也支持。

1.2 Qt 下载及安装

Qt 分为商业版以及开源版,在此我们使用开源版本,开源版本是免费的。

Qt 开源版本的下载链接为 https://www.qt.io/download,打开链接中,往下滑动页面,找到开源版本下载板块:

点击后,将会跳转到一个页面,往下拉页面,点击下载 qt 二进制在线安装:

之后将会跳转到一个页面,并且会根据你的系统推荐你使用某个版本:

最后点击 Download 即可下载,安装步骤操作简单不再赘述,以上介绍开源版下载方式是因为部分同学认为Qt 是收费的,所以在此介绍开源版的下载方法(可能由于时间问题网页更新会导致下载“路径”不同)。

1.3 项目示例

Qt 作为一款优秀的 GUI 解决方案许多经典流行的应用使用了 Qt 进行开发,例如 WPS:

谷歌地球:

VirtualBox 虚拟机:

Linux 桌面系统等。

二、Qt Creator 界面介绍 及 第一个Qt 程序创建

2.1 简单的第一个 qt 程序

Qt 界面中自带了很多项目示例,可以通过 查看 Qt 示例学习经典项目的开发:

Qt 自带了教程,查看教程可以观看资料,不过是英文的,有英文能力的同学推荐阅读:

点击创建项目将会弹出一个窗口,选择对应的模板将会可以创建不同的项目:

在以上所选择的模板中最右侧是对应的模板介绍:

该模板是创建一个桌面 Qt 程序,以及包含了一个用于设计的 Qt 窗口。

点击选择可以进入下一步,在下一步窗口中选择项目名称以及对应项目存放的位置:

在此需要注意,名称和路径不能有中文,接着一直下一步,知道出现语言选择时在此你可以选择中文:

接着一直下一步进行操作即可,完成后将会弹出所创建的项目的基本内容:

接着,点击运行将会出现一个 空窗口:

三、信号与槽

3.1 信号与槽的基本示例

信号在 Qt 中指的是一个事件,例如当你点击一个按钮时会触发点击的事件,也就是信号,触发完毕后你需要某一个“动作”对其作出响应,或者说当收到信号后将会执行一些动作,而这个动作则是槽,又或者说是一个对信号响应的代码块。

此时我们可以通过一个例子来简单的理解一下信号与槽的概念,点击创建项目,最后创建一个 Qt Widgets 的 App 应用:

随后指定文件目录后一直点击下一步即可:

接下来点击 mainwindow.ui 文件:

点击之后将会出现一个设计窗口:

这个窗口如图所示,左侧是对应的基本空间区域,右侧是对应的设计窗口。我们可以通过拖拽左侧的控件到右侧的设计窗口之上,使当前 window 添加对应的控件,例如:

此时可以点击整个 Qt creator 左下角的运行按钮对整个项目编译运行:

运行之后,将会出现一个窗体程序,这个窗体程序在界面之上有一个 pushbutton:

为了实现信号与槽这个概念,我们可以再拖拽一个 edit 控件到窗体之上,由于一个 edit 是一个可编辑的控件,那么必然是输入 input Widgets,我们在 input Widgets 控件之下可以找到对应的 line Edit:

此时拖拽这个控件到窗体之上:

接着我们开始试验信号与槽。我们右键 PushButton,将会出现跳转到槽的选择项:

此时将会出现一个信号选择框,我们可以选择在什么情况下触发这个槽函数:

在这里选择 clicked 指在点击时触发这个槽函数。选择完毕后, qt creator 将会跳转窗口到一个编辑页,此时编辑页中出现的 on_pushButton_clicked 则是点击 pushButton 按钮后将会跳转到的槽函数:

那此时我们该在这里编写什么代码呢?此时我们可以编写一些动作,例如直接将当前按钮的文本改变成 lineEdit 空间所输入的文本,那么就可以很好的演示当点击按钮后执行代码后界面所产生的反应。

此时我们可以编写代码:

代码语言:javascript复制
void MainWindow::on_pushButton_clicked(){
    QString inputText=ui->lineEdit->text();
    ui->pushButton->setText(inputText);
}

其中 QString inputText=ui->lineEdit->text(); 表示新建一个 QString 类型的 inputText 变量用来获取对应输入框所输入的内容;获取输入框需要指定到窗口上的某个空间,我们需要通过 ui 进行获取,ui-> 指 ui 上的某个空间,由于在窗体上的输入框名称默认为 lineEdit 所以直接写成 lineEdit 即可,查看 控件名称 直接点击控件后可在 Qt creator 右上角进行查看:

此时代码为 ui->lineEdit 表示指定到了某个元素,而最后的 ->text() 则表示获取当前控件的文本内容,获取到文本内容后存储到 QString 类型的 inputText 变量即可。

此时已经获取到了对应的输入框内容,那么接下来需要把对应输入框的文本设置到 pushButton 之上即可,设置一个控件的文本也需要使用 ui 指定到某一个控件,那么获取 PushButton 控件代码则是 ui->pushButton,那么设置文本则是 setText 方法,在 setText 方法中传入对应的文本值即可,所以最终代码写成 ui->pushButton->setText(inputText);,当然你可以直接写成 ui->pushButton->setText(ui->lineEdit->text());

此时完成了代码编写后,我们可以运行程序,运行成功将会出现一个窗体界面,此时在窗体界面中输入 233:

接着点击 PushButton 按钮,点击后 PushButton 按钮的文本将会改变成你所输入的值:

3.2 自定义信号与槽

信号与槽不止可以通过默认方式进行生成和编写,还可以通过自定义的方式自定义信号与指定处理的槽函数。

我们自定义的信号与槽是通过 connect 函数进行设置,例如如下代码:

代码语言:javascript复制
connect(ui->lineEdit,SIGNAL(returnPressed()),this,SLOT(on_pushButton_clicked()));

以上代码中 connect 函数接收的第一参数为你需要指定信号与槽的控件,第二个参数则是表示发送什么信号,就像我们在设计窗口中右键某一个控件,随后通过鼠标点击指定对应的信号;在这里 SIGNAL(returnPressed()) 中 SIGNAL 表示是一个宏函数,需要传入对应的事件,其 returnPressed 则表示是 enter 按下确认的事件,接下来的 this 则是表示当前类处理这个信号,最后一个则是槽,SLOT 需要传入对应处理信号的函数即可。

由于自定义信号与槽的方式有很多种,在这里先简单讲解一种,之后其他的处理方式将会补充讲解。

最后我们点击运行,随后在 lineEdit 中输入对应的文本,enter 键后按钮也会发生其文本的改变:

四、实现简单四则计算器

4.1 界面设计

在这一节中,我们使用 qt 制作一个简单的四则运算器,学习一下界面创建与修饰。

首先创建好项目,其次打开 ui 文件,进入到设计窗口之中:

在一个计算机中,数字的按键是必不可少的,我们拖动对应的按钮到设计窗口之上,最后点击按钮,在右下角的属性设置之上改变其宽高:

接着我们更改文本后,按住键盘 ctrl 拖动控件,将会直接复制出一个新的控件:

接着我们拖动出多个对应的按钮,并且更改其文本:

此时我们发现这些按钮的排列并不整齐,我们可以选中所有的按钮,接着点击设计窗口顶部的栅格布局:

点击之后整个按钮将会自动进行规整的排列。

接着,我们点击右上角,给每一个按钮起名,方便我们接下来的调用:

接着我们添加两个 eidt 到窗口之上,并且设置号大小和位置:

当然也要更好对应的控件名,一个用于显示公式,还有一个用于显示最终的计算结果:

接着设置整个窗体大小的宽高:

设置完毕后我们可以给这些控件对应的样式。

4.2 添加样式

首先我们可以给这些控件设置边框为 none 去掉对应的边框,主要是把 edit 的边框去掉使其较为美观。右键在右上角的对象树上,选择改变样式:

接着在弹出来的样式表上添加样式修饰:

代码语言:javascript复制
*{
    border:none;
	background-color: rgb(234, 234, 234);
}

其中 * 表示给所有的对象设置样式,其样式编写在 * 之后的花括号之中,border 设置为 none 表示边框为 none 则表示不需要边框,background-color 表示设置对应的背景色,用 rgb 色进行设置。输入完毕后点击应用,当前的窗体如下:

接着我们可以设置对应的 按钮样式,例如设置 QPushButton 的背景色以及对应的字体大小、是否加粗以及字体,可以使用以下样式:

代码语言:javascript复制
QPushButton{
	background-color: rgb(255, 255, 255);
	font:bold 11pt '微软雅黑';
}

font:bold 11pt '微软雅黑'; 表示设置字体,bold 表示字体加粗,11pt 表示字体的大小、最后则是对应的字体。

若此时我想对应的设置乘号、除号、加号、减号这些运算符号的不同,则可以通过样式指定控件设置不一样的样式,例如:

代码语言:javascript复制
QPushButton#add,#subtraction,#division,#multiplication{
	background-color: rgb(56, 208, 203);
}

此时设置样式则需要先指定某个类型的组件,随后使用 # 在末尾街上控件名称,随后逗号分隔即可指定某个控件设置样式。

此时运行程序,我们发现鼠标移动到某个按钮上时没有任何反应,若想使按钮有反应则需要对应的设置 hover 时按钮的样式,hover 则是指对应的鼠标悬浮上去后,按钮发生的改变,设置这个样式很简单,只需要指定某个类型的控件后,在其后使用一个冒号 :hover 即可指定一个样式,例如:

代码语言:javascript复制
QPushButton:hover{
	background-color: rgb(221, 221, 221);
	border:1px solid rgb(185, 185, 185);
}

此样式表示当鼠标移动上去后改变其对应的背景色以及边框颜色,此时鼠标移动上去将会使按钮有反应,并不会过于死板。

此时效果如下:

但此时我们发现,设置过指定控件的样式例如加减乘除并没有移动上去后发生样式改变,这时需要再针对这些控件设置一下 hover 样式:

代码语言:javascript复制
QPushButton#add:hover,#subtraction:hover,#division:hover,#multiplication:hover{
	background-color: rgb(221, 221, 221);
	border:1px solid rgb(185, 185, 185);
}

效果如下:

4.3 功能设计

设计功能我们需要设置一个全局变量用于记录通过按钮生成的四则运算公式,在此我们设置在头文件之中:

接着我们给每个按钮手动设置一个槽函数:

首先我们设置数字 7 按钮的槽函数:

代码语言:javascript复制
void MainWindow::on_btn7_clicked()
{
    expression ="7";
    ui->show->setText(expression);
}

在这个槽函数中设置 expression 全局变量记录用户输入了7,随后设置 show edit 的文本为 expression;既然 expression 是用于对应的记录公式,那么我们就可以把所有的数字都设置类似于数字 7 的形式往 expression 中添加对应的拼接,并且加减乘除法按钮也要完成该操作:

最后运行一下程序,发现输入点击对应按钮后将会出现对应的公式:

但是我们发现由于是 eidt 对象,可以用户输入,我们可以设置其 edit 的属性 readonly 为 true 即可:

也可以设置对应的水平对齐为右:

最后我们得到了这个公式,我们只需要通过计算器代码即可求出对应值,由于这是 C/C 的内容在此就不再赘述,我们此时直接右键等于号,设置其槽函数,并且赋值以下代码即可(代码来源于网络):

代码语言:javascript复制
 QStack <int> OPND;  // Operand stack
 QStack <char> OPTR;  // Operator stack
 OPTR.push('#');//
 char ss[2]="#";//尾部有
 char s[maxn];

 char path[50];
 QString str = expression;
 QByteArray ba = str.toLocal8Bit();
 memcpy(s,ba.data(),ba.size() 1);//加1是为了最后的终结符,否则转换回来的时候不知道什么时候截止

 QString str2;
 str2 = QString::fromLocal8Bit(s);


 strcat(s,ss);// 运算式尾部加 "#"--结束运算符
 char c=s[0];
 int k=1;
 while(c!='#'||OPTR.top()!='#'){  //表达式未读完或者运算未完
     int y=0;
     if(c>='0'&&c<='9'){
         while(c>='0'&&c<='9'){  // 读入连续的数字
             y=y*10 (c-'0');
             c=s[k  ];
         }
         OPND.push(y);  // 把读进的数字入数字栈
     }
     else{
         switch(Procede(OPTR.top(),c))
         {
             case'<':  //栈顶元素优先权低
                 OPTR.push(c);
                 c=s[k  ];
                 break;
             case'=':
                 OPTR.pop();  // 脱括号
                 c=s[k  ];  // 读入下一个字符
                 break;
             case'>':  //退栈并将运算结果入栈
                 char x=OPTR.top();OPTR.pop();
                 int m=OPND.top();OPND.pop();
                 int n=OPND.top();OPND.pop();
                 OPND.push(Operate(m,n,x));
                 break;
         }
     }
 }

 ui->res->setText(QString::number(OPND.top()));

当然,你直接复制这个代码将会报错,此时需要再复制几个函数以及添加头文件,先复制几个函数:

代码语言:javascript复制
const int maxn=110;
char priority[7][7]={
    {'>','>','<','<','<','>','>'},
    {'>','>','<','<','<','>','>'},
    {'>','>','>','>','<','>','>'},
    {'>','>','>','>','<','>','>'},
    {'<','<','<','<','<','=','0'},   // 此行"("=")"表示左右括号相遇,括号内运算已完成
    {'>','>','>','>','0','>','>'},
    {'<','<','<','<','<','0','='}    // "=" 表示整个表达式求值完毕
    };                               //  "0"表示不可能出现这种情况 ( 语法错误 )

//Precede 用于判断运算符栈栈顶运算符 a1 与读入运算符 a2 之间的优先关系函数
char Procede(char a,char b){   // 建立 pre[][] 到 运算符间的映射关系
    int i,j;
    switch(a){
        case' ':i=0;break;
        case'-':i=1;break;
        case'*':i=2;break;
        case'/':i=3;break;
        case'(':i=4;break;
        case')':i=5;break;
        case'#':i=6;break;   // # 是表达式的结束符
    }
    switch(b){
        case' ':j=0;break;
        case'-':j=1;break;
        case'*':j=2;break;
        case'/':j=3;break;
        case'(':j=4;break;
        case')':j=5;break;
        case'#':j=6;break;
    }
    return priority[i][j];
}

int Operate(int m,int n,char x){
    if(x==' ')
    return m n;
    if(x=='-')
    return n-m;
    if(x=='*')
    return m*n;
    if(x=='/')
    return n/m;
}

随后需要对应的添加一个头文件 QStack:

代码语言:javascript复制
#include <QStack>

最后若你的命名跟我的不符,你需要修改字符串转字符数组时的公式变量命名:

以及最后显示值时指定改变某个控件:

最终结果如下:

总结

本章节主要介绍了 qt 的一些基本信息,并且使用 qt 创建一个基本的项目,了解 qt 项目创建的基本流程;在此基础上学习了信号与槽,并且使用了对应的小示例改变了按钮的文本,在基础信号与槽的基础上,通过 connect 实现了自定义的信号与槽指定,完成了使用键盘响应对应的槽函数;最后通过学习如何制作一个简单的四则运算程序,在其中了解了 UI 界面的布局制作、限制其大小、以及设置对应的样式,最终也实现了对应的按钮及计算。

0 人点赞