200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > C++ Qt学习笔记 (1) 简易计算器设计

C++ Qt学习笔记 (1) 简易计算器设计

时间:2023-07-02 00:08:02

相关推荐

C++  Qt学习笔记 (1)  简易计算器设计

最近开始学习c++ qt, 按照教材上的例程设计一个简易的桌面计算器:

Qt是一个基于C++语言的跨平台应用程序和UI开发框架,主要包含一个类库,和跨平台开发及国际化的工具,最初由挪威的Trolltech公司开发,后来被诺基亚收购,现在属于Digia公司。qt最大的特点是其跨平台的属性,同一份代码可以在不同平台上编译运行。qt中使用信号/槽机制来代替传统UI设计中的回调函数。

信号和槽是Qt中对象通信的一种方式,它代替了传统的GUI编程中利用回调函数传递消息的机制。回调函数的原理是:将处理函数传递到按钮控件中去,在用户点击按钮对象之后,按钮控件对象调用传进去的处理函数,这种将一个函数传进去,在将来某个时刻调用的方式称为回调。信号与槽机制:同样需要编写处理函数(称为槽函数),但是不需要将处理函数传递给控件,只需要将按钮的单击信号(如clicked(),这是Qt种已经比那些好的函数)和槽函数连接起来即可。使用更加方便,但是也带来了效率上的损耗。

QWidget是所有图像用户将界面的基类,QWidget包含所有界面共有的特征:1. 接受鼠标点击事件 2. 接受键盘事件 3. 区域渲染

同时,QWidget也可以包含其他的界面控件。

(由于目前没有找到好的Qt教材,所以只对Qt有一个简单的了解,后续会进行更加全面的学习)

1. 计算器界面设计:

这里界面设计采用了Qt designer, 在Qt Creator种新建项目,进入.ui文件。进行界面设计,如下图所示:

对界面中的控件进行命名,以及属性设置:

将计算器的按钮与相应的槽函数进行连接:

这里使用Qt中的connect方法,将按钮和相应的槽函数连接在一起:

connect(btn, SIGNAL(clicked()), this, SLOT(onDigitClicked()));

connect函数的形式如上所示:

在计算器设计中,采用的方式为,将数字按钮0~9连接到同一个槽函数中,将加减乘除连接到同一个槽函数中,将其它的按钮连接到对应的槽函数中,首先定义在widget.h文件中定义相应的槽函数:

private slots:void onDigitClicked();// 数字键按下对应的槽函数void onOperatorClicked(); // 运算符键按下对应的槽函数void onEqualBtnClicked(); // 按下运算键对应的槽函数void onDotBtnClicked(); // 按下小数点对应的槽函数void onClearBtnClicked(); // 清除按钮对应的槽函数void onClearAllBtnClicked(); // 清除所有按钮对应的槽函数void onSignBtnClicked(); // 正负号按键所对应的槽函数

定义函数connectSlots(),将连接槽函数的过程进行封装:

private:void connectSolts(); // 将数字键以及符号键连接到槽函数

实现connectSlots()函数:

void Widget::connectSolts(){// 链接槽函数// 将十个数字键连接到槽函数onDigitClicked();QPushButton *digit_btns[10] ={ui->btn_0,ui->btn_1,ui->btn_2,ui->btn_3,ui->btn_4,ui->btn_5,ui->btn_6,ui->btn_7,ui->btn_8,ui->btn_9};for(auto btn : digit_btns)//for(int i=0; i<10; i++){// 将按键连接到槽函数connect(btn, SIGNAL(clicked()), this, SLOT(onDigitClicked()));}// 对应的按钮为指针QPushButton *operatorBtn[4] ={ui->btn_add,ui->btn_subtract,ui->btn_multiply,ui->btn_divide};for(auto btn : operatorBtn)// for(int i=0; i<4; i++){connect(btn, SIGNAL(clicked()), this, SLOT(onOperatorClicked()));}connect(ui->btn_equal, SIGNAL(clicked()), this, SLOT(onEqualBtnClicked())); // 等号键按下connect(ui->btn_dot, SIGNAL(clicked()), this, SLOT(onDotBtnClicked())); // 小数点键安按下connect(ui->btn_clear, SIGNAL(clicked()), this, SLOT(onClearBtnClicked())); // 清除键按下connect(ui->btn_clear_all, SIGNAL(clicked()), this, SLOT(onClearAllBtnClicked())); // 清除所有 按钮connect(ui->btn_neg_pos, SIGNAL(clicked()),this, SLOT(onSignBtnClicked())); // 符号按键}

上面通过循环的方式,将相应的按钮与槽函数连接。相应槽函数的实现如下:

1. 数字键按下对应的槽函数:

void Widget::onDigitClicked(){// std::cout << "数字键按下" << std::endl;qDebug() << "digit key pressed" << endl;QPushButton *digitBtn = static_cast<QPushButton*>(sender()); // sender()表示信号的发送者QString value = digitBtn->text(); // 获取按钮的text属性// 判断按键if(ui->result->text() == "0" && value == "0") // 按键为0return;if(waitForOperator) // 等在操作数 状态为真{ui->result->setText(value);waitForOperator = false; // 此时不再需要等待操作数}else{ui->result->setText(ui->result->text() + value);}}

2. 运算符键按下对应的槽函数实现:

void Widget::onOperatorClicked(){// qDebug() << "operator key pressed" << endl;// 判断按下的运算符键QPushButton *clickedBtn = static_cast<QPushButton*>(sender()); // 将信号源转化为QpusuBytton指针QString value = clickedBtn->text();// 获取运算符// 此时的状态是按下了运算符,所以需要获取第一个运算数double operand = ui->result->text().toDouble();// 获取运算数if(pendingOperator.isEmpty()) // 运算符为空{result = operand;}else{if(!calculate(operand, value)){abortOperation();return;}ui->result->setText(QString::number(result));}// 更新运算符pendingOperator = value;waitForOperator = true; // 等待新的输入数字}

函数calculate(operand, value)用于获取运算符和操作数之后进行计算,具体的实现如下所示:

bool Widget::calculate(double operand, QString pendingOperator){if(pendingOperator == "+"){result += operand;// 加法运算}else if(pendingOperator == "-"){result -= operand;}else if(pendingOperator == "*"){result *= operand;}else{if(operand == 0){return false;}result /= operand;}return true;}

Qt中的键盘事件:

Qt中使用QKeyEvent来描述键盘事件,当键盘按下胡哦这松开的时候,键盘事件便会传递给拥有键盘输入焦点的控件,key()函数可以用来获取具体的按键值。在简易计算器设计中中加入键盘事件,使得在键盘上输入数据和在计算器上输入具有相同的效果,给按钮添加快捷键的方式主要有两种方法:

1. 重写键盘事件函数:

首先,在widget.h文件中,键盘事件函数必须定义为protected类型:

#include <QKeyEvent>

protected:void keyPressEvent(QKeyEvent* event);

键盘事件函数的定义:

(未解决的bug, emit ui->btn_0->clicked报错问题)

void Widget::keyPressEvent(QKeyEvent *event){switch (event->key()){case Qt::Key_0:emit ui->btn_0->clicked();break;case Qt::Key_1:emit ui->btn_1->clicked();break;case Qt::Key_2:emit ui->btn_2->clicked();break;case Qt::Key_3:emit ui->btn_3->clicked();break;case Qt::Key_4:emit ui->btn_4->clicked();break;case Qt::Key_5:emit ui->btn_5->clicked();break;case Qt::Key_6:emit ui->btn_6->clicked();break;case Qt::Key_7:emit ui->btn_7->clicked();break;case Qt::Key_8:emit ui->btn_8->clicked();break;case Qt::Key_9:emit ui->btn_9->clicked();break;case Qt::Key_Plus:emit ui->btn_add->clicked();break;case Qt::Key_Minus:emit ui->btn_subtract->clicked();break;case Qt::Key_Asterisk:emit ui->btn_multiply->clicked();break;case Qt::Key_Slash:emit ui->btn_divide->clicked();break;case Qt::Key_Enter:case Qt::Key_Equal:emit ui->btn_equal->clicked();break;case Qt::Key_Period:emit ui->btn_dot->clicked();break;case Qt::Key_M:emit ui->btn_neg_pos->clicked();break;case Qt::Key_Backspace:emit ui->btn_clear->clicked();break;default:break;}}

2. 通过按钮控件的setShortCut()函数

在widget.h中定义快捷键设置的函数setShortCut()

public:void setShortCut(); // 设计快捷键

void Widget::setShortCut(){Qt::Key key[18] = {Qt::Key_0, Qt::Key_1, Qt::Key_2,Qt::Key_3, Qt::Key_4, Qt::Key_5,Qt::Key_6, Qt::Key_7, Qt::Key_8,Qt::Key_9,Qt::Key_Plus, Qt::Key_Minus, Qt::Key_Asterisk, Qt::Key_Slash,Qt::Key_Enter, Qt::Key_Period, Qt::Key_Backspace, Qt::Key_M};QPushButton *btn[18] = {ui->btn_0, ui->btn_1, ui->btn_2,ui->btn_3, ui->btn_4, ui->btn_5,ui->btn_6, ui->btn_7, ui->btn_8,ui->btn_9,ui->btn_add, ui->btn_subtract, ui->btn_multiply, ui->btn_divide,ui->btn_equal, ui->btn_dot, ui->btn_clear, ui->btn_neg_pos};for(int i=0; i<18; i++){btn[i]->setShortcut(QKeySequence(key[i]));}ui->btn_clear_all->setShortcut(QKeySequence("Ctrl+Backspace"));}

Qt中的鼠标事件:

Qt中用一个对象表示一个事件(event), 继承自QEvent。QMouseEvent事件用来表示鼠标事件,它可以检测到当前哪个键被按下了,或者鼠标的当前位置。QWheelEvent用来表示鼠标滚轮事件,用来获取滚轮的滑动方向和距离,共有5个鼠标事件处理函数,在.h文件中这些事件处理函数必须为protected类型,同时需要包含头文件<QMouseEvent><QwheelEvent>

mousePressEvent()

mouseReleaseEvent()

mouseDoubleClickedEvent()

mouseMoveEvent()

wheelEvent()

---------------------------------------------------------------------------------------------------------------

简易计算器完整代码:

widget.h文件

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QString>#include <QKeyEvent>namespace Ui {class Widget;}class Widget : public QWidget{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();private:Ui::Widget *ui;private:bool calculate(double operand, QString pendingOperator); // 做算数运算void abortOperation();// 结束运算void connectSolts(); // 将数字键以及符号键连接到槽函数QString pendingOperator; // 存储运算符double result; // 存储运算结果bool waitForOperator;// 标志位,是否等待操作数private slots:void onDigitClicked();// 数字键按下对应的槽函数void onOperatorClicked(); // 运算符键按下对应的槽函数void onEqualBtnClicked(); // 按下运算键对应的槽函数void onDotBtnClicked(); // 按下小数点对应的槽函数void onClearBtnClicked(); // 清除按钮对应的槽函数void onClearAllBtnClicked(); // 清除所有按钮对应的槽函数void onSignBtnClicked(); // 正负号按键所对应的槽函数public:void setShortCut(); // 设计快捷键//protected:// void keyPressEvent(QKeyEvent* event);};#endif // WIDGET_H

widget.cpp文件:

#include "widget.h"#include "ui_widget.h"#include <QString>#include <QLayout>#include <QMessageBox>#include <iostream>#include <QDebug>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget){ui->setupUi(this);waitForOperator = true; // 初始状态等待操作数result = 0.0; // 初始状态结果为0ui->result->setText("0");connectSolts(); // 连接所有的按键与对应的槽函数setShortCut();}Widget::~Widget(){delete ui;}bool Widget::calculate(double operand, QString pendingOperator){if(pendingOperator == "+"){result += operand;// 加法运算}else if(pendingOperator == "-"){result -= operand;}else if(pendingOperator == "*"){result *= operand;}else{if(operand == 0){return false;}result /= operand;}return true;}void Widget::abortOperation(){// 终止运算,清除数据,输出错误信息result = 0;pendingOperator.clear();// 清除运算符ui->result->setText("0");// 清除显示结果waitForOperator = true; // 等待一个操作数输入QMessageBox::warning(this, "运算错误", "除数不能为零");}void Widget::connectSolts(){// 链接槽函数// 将十个数字键连接到槽函数onDigitClicked();QPushButton *digit_btns[10] ={ui->btn_0,ui->btn_1,ui->btn_2,ui->btn_3,ui->btn_4,ui->btn_5,ui->btn_6,ui->btn_7,ui->btn_8,ui->btn_9};for(auto btn : digit_btns)//for(int i=0; i<10; i++){// 将按键连接到槽函数connect(btn, SIGNAL(clicked()), this, SLOT(onDigitClicked()));}QPushButton *operatorBtn[4] ={ui->btn_add,ui->btn_subtract,ui->btn_multiply,ui->btn_divide};for(auto btn : operatorBtn)// for(int i=0; i<4; i++){connect(btn, SIGNAL(clicked()), this, SLOT(onOperatorClicked()));}connect(ui->btn_equal, SIGNAL(clicked()), this, SLOT(onEqualBtnClicked())); // 等号键按下connect(ui->btn_dot, SIGNAL(clicked()), this, SLOT(onDotBtnClicked())); // 小数点键安按下connect(ui->btn_clear, SIGNAL(clicked()), this, SLOT(onClearBtnClicked())); // 清除键按下connect(ui->btn_clear_all, SIGNAL(clicked()), this, SLOT(onClearAllBtnClicked())); // 清除所有 按钮connect(ui->btn_neg_pos, SIGNAL(clicked()),this, SLOT(onSignBtnClicked())); // 符号按键}void Widget::onDigitClicked(){// std::cout << "数字键按下" << std::endl;qDebug() << "digit key pressed" << endl;QPushButton *digitBtn = static_cast<QPushButton*>(sender()); // sender()表示信号的发送者QString value = digitBtn->text(); // 获取按钮的text属性// 判断按键if(ui->result->text() == "0" && value == "0") // 按键为0return;if(waitForOperator) // 等在操作数 状态为真{ui->result->setText(value);waitForOperator = false; // 此时不再需要等待操作数}else{ui->result->setText(ui->result->text() + value);}}void Widget::onOperatorClicked(){// qDebug() << "operator key pressed" << endl;// 判断按下的运算符键QPushButton *clickedBtn = static_cast<QPushButton*>(sender()); // 将信号源转化为QpusuBytton指针QString value = clickedBtn->text();// 获取运算符// 此时的状态是按下了运算符,所以需要获取第一个运算数double operand = ui->result->text().toDouble();// 获取运算数if(pendingOperator.isEmpty()) // 运算符为空{result = operand;}else{if(!calculate(operand, value)){abortOperation();return;}ui->result->setText(QString::number(result));}// 更新运算符pendingOperator = value;waitForOperator = true; // 等待新的输入数字}void Widget::onEqualBtnClicked(){// 等号键按下,需要计算最终的结果double operand = ui->result->text().toDouble(); // 获取运算数if(pendingOperator.isEmpty()) // 没有输入加减乘除运算符,直接按了等号{return;}if(!calculate(operand, pendingOperator)){abortOperation();return;}ui->result->setText(QString::number(result));waitForOperator = true;result = 0.0;pendingOperator.clear();}void Widget::onDotBtnClicked(){if(waitForOperator){ui->result->setText("0");}if(ui->result->text().contains(".")){// no operation}else{ui->result->setText(ui->result->text() + ".");}waitForOperator = false; // 当前数字的输入还未结束}void Widget::onClearBtnClicked(){ui->result->setText("0");// 输入的数字清零waitForOperator = true; // 重新输入}void Widget::onClearAllBtnClicked(){ui->result->setText("0");waitForOperator = true;result = 0.0;pendingOperator.clear();}void Widget::onSignBtnClicked(){QString text = ui->result->text();double value = text.toDouble();if(value > 0){text.prepend("-");}else{text.remove(0, 1);}ui->result->setText(text);}void Widget::setShortCut(){Qt::Key key[18] = {Qt::Key_0, Qt::Key_1, Qt::Key_2,Qt::Key_3, Qt::Key_4, Qt::Key_5,Qt::Key_6, Qt::Key_7, Qt::Key_8,Qt::Key_9,Qt::Key_Plus, Qt::Key_Minus, Qt::Key_Asterisk, Qt::Key_Slash,Qt::Key_Enter, Qt::Key_Period, Qt::Key_Backspace, Qt::Key_M};QPushButton *btn[18] = {ui->btn_0, ui->btn_1, ui->btn_2,ui->btn_3, ui->btn_4, ui->btn_5,ui->btn_6, ui->btn_7, ui->btn_8,ui->btn_9,ui->btn_add, ui->btn_subtract, ui->btn_multiply, ui->btn_divide,ui->btn_equal, ui->btn_dot, ui->btn_clear, ui->btn_neg_pos};for(int i=0; i<18; i++){btn[i]->setShortcut(QKeySequence(key[i]));}ui->btn_clear_all->setShortcut(QKeySequence("Ctrl+Backspace"));}/*void Widget::keyPressEvent(QKeyEvent *event){switch (event->key()){case Qt::Key_0:emit ui->btn_0->clicked();break;case Qt::Key_1:emit ui->btn_1->clicked();break;case Qt::Key_2:emit ui->btn_2->clicked();break;case Qt::Key_3:emit ui->btn_3->clicked();break;case Qt::Key_4:emit ui->btn_4->clicked();break;case Qt::Key_5:emit ui->btn_5->clicked();break;case Qt::Key_6:emit ui->btn_6->clicked();break;case Qt::Key_7:emit ui->btn_7->clicked();break;case Qt::Key_8:emit ui->btn_8->clicked();break;case Qt::Key_9:emit ui->btn_9->clicked();break;case Qt::Key_Plus:emit ui->btn_add->clicked();break;case Qt::Key_Minus:emit ui->btn_subtract->clicked();break;case Qt::Key_Asterisk:emit ui->btn_multiply->clicked();break;case Qt::Key_Slash:emit ui->btn_divide->clicked();break;case Qt::Key_Enter:case Qt::Key_Equal:emit ui->btn_equal->clicked();break;case Qt::Key_Period:emit ui->btn_dot->clicked();break;case Qt::Key_M:emit ui->btn_neg_pos->clicked();break;case Qt::Key_Backspace:emit ui->btn_clear->clicked();break;default:break;}}*/

后续还会对简易计算器进行改进。。。(未完待续)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。