使用ROS2 + Qt编写一个简易计算器
先看结果
一、搭建ROS框架
创建工作空间
mkdir -p calculate_qt_ws/src
创建功能包
cd calculate_qt_ws/src/
ros2 pkg create calculator_qt
二、编写头文件
c_cpp_properties.json
{"configurations": [{"name": "Linux","includePath": ["${workspaceFolder}/**","/usr/include/x86_64-linux-gnu/qt5/**"],"defines": [],"compilerPath": "/usr/bin/gcc","cStandard": "c17","cppStandard": "gnu++17","intelliSenseMode": "linux-gcc-x64"}],"version": 4
}
calculator.hpp
#ifndef CALCULATOR_HPP
#define CALCULATOR_HPP#include <QApplication>
#include <QLabel>
#include <QPushButton>
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QString>
#include <iostream>
#include <regex>
#include <cmath>
#include <stdlib.h>class Calculator : public QWidget
{Q_OBJECT
private:std::string result_string;std::regex expression_pattern;std::regex clear_pattern;QLabel result_label;QPushButtonbutton_0,button_1,button_2,button_3,button_4,button_5,button_6,button_7,button_8,button_9,add_button,sub_button,mul_button,div_button,equal_button,delete_button;QGridLayout glayout;QVBoxLayout vlayout;QHBoxLayout hlayout;public:Calculator(QWidget *parent = nullptr);void put_text();void calculateExpression();
};#endif // CALCULATOR_HPP
三、编写源文件
calculator.cpp
#include "calculator_qt/calculator.hpp"Calculator::Calculator(QWidget *parent): QWidget(parent),result_label("",this),button_0("0",this),button_1("1",this),button_2("2",this),button_3("3",this),button_4("4",this),button_5("5",this),button_6("6",this),button_7("7",this),button_8("8",this),button_9("9",this),add_button("+",this),sub_button("-",this),mul_button("*",this),div_button("/",this),equal_button("=",this),delete_button("cls",this)
{//结果字符串result_string = "";//正则匹配表达式expression_pattern = std::regex(R"(^([-]?\d+)([/*+-])([-]?\d+)$)"); //匹配表达式 加入括号分组clear_pattern = std::regex(R"(^([-]?\d+)([/*+-])?([-]?\d+)?$)"); //判断表达式 //窗口属性setWindowTitle("简易计算器");resize(400, 100);//交互框美化result_label.setMinimumWidth(200);result_label.setAlignment(Qt::AlignRight);result_label.setStyleSheet("border: 1px solid #ccc; padding: 5px; font-size: 16px;");//按钮链接connect(&button_0,&QPushButton::clicked,[&](){put_text(button_0);});connect(&button_1,&QPushButton::clicked,[&](){put_text(button_1);});connect(&button_2,&QPushButton::clicked,[&](){put_text(button_2);});connect(&button_3,&QPushButton::clicked,[&](){put_text(button_3);});connect(&button_4,&QPushButton::clicked,[&](){put_text(button_4);});connect(&button_5,&QPushButton::clicked,[&](){put_text(button_5);});connect(&button_6,&QPushButton::clicked,[&](){put_text(button_6);});connect(&button_7,&QPushButton::clicked,[&](){put_text(button_7);});connect(&button_8,&QPushButton::clicked,[&](){put_text(button_8);});connect(&button_9,&QPushButton::clicked,[&](){put_text(button_9);});connect(&add_button,&QPushButton::clicked,[&](){put_text(add_button);});connect(&sub_button,&QPushButton::clicked,[&](){put_text(sub_button);});connect(&mul_button,&QPushButton::clicked,[&](){put_text(mul_button);});connect(&div_button,&QPushButton::clicked,[&](){put_text(div_button);});connect(&equal_button,&QPushButton::clicked,[&](){calculateExpression();});connect(&delete_button,&QPushButton::clicked,[&](){result_label.setText("");});//布局配置 先配置九宫格按钮布局glayout.addWidget(&button_1, 0, 0);glayout.addWidget(&button_1, 0, 0);glayout.addWidget(&button_2, 0, 1);glayout.addWidget(&button_3, 0, 2);glayout.addWidget(&button_4, 1, 0);glayout.addWidget(&button_5, 1, 1);glayout.addWidget(&button_6, 1, 2);glayout.addWidget(&button_7, 2, 0);glayout.addWidget(&button_8, 2, 1);glayout.addWidget(&button_9, 2, 2);//按照小键盘布局,0跨多列,因为没有 . 所以跨三列glayout.addWidget(&button_0, 3, 0, 1, 3);//第四列填充符号按钮glayout.addWidget(&add_button, 0, 3);glayout.addWidget(&sub_button, 1, 3);glayout.addWidget(&mul_button, 2, 3);glayout.addWidget(&div_button, 3, 3);//配置水平布局,将结果框和‘=’按钮‘cls’按钮放置同一个布局中hlayout.addWidget(&result_label);hlayout.addWidget(&equal_button);hlayout.addWidget(&delete_button);//配置垂直布局,将水平布局和网格布局放置同一个垂直布局中vlayout.addLayout(&hlayout); //先水平vlayout.addLayout(&glayout); //后网格setLayout(&vlayout); //让整个类(窗口)的布局使用垂直布局}void Calculator::put_text(QPushButton & button)
{//通过正则判断当前输入是否为数字和指定的运算符号if(!std::regex_match(result_string, clear_pattern)) {result_string = "";}result_string += button.text().toStdString(); //如果是,则将按钮标签加入交互框//将内容添加到交互框中result_label.setText(QString::fromStdString(result_string));
}void Calculator::calculateExpression()
{ std::smatch match;if (std::regex_search(result_string, match, expression_pattern)){int num1 = std::atoi(match[1].str().c_str());int num2 = std::atoi(match[3].str().c_str());std::string op = match[2].str();switch(op[0]){case '+':result_string = std::to_string(num1 + num2);break;case '-':result_string = std::to_string(num1 - num2);break;case '*':result_string = std::to_string(num1 * num2);break;case '/':if (num2 == 0){result_label.setText(QString::fromStdString("除数不为0!"));return;}result_string = std::to_string(num1 / num2);break;default:result_string = "不支持运算符!";break;}}else{result_string = "表达式错误!";}result_label.setText(QString::fromStdString(result_string));return;}// main.cpp
int main(int argc, char *argv[])
{QApplication app(argc,argv);Calculator calculator;calculator.show();return app.exec();}
四、编写CMakeLists
cmake_minimum_required(VERSION 3.8)
project(calculator_qt)if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic)
endif()# find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)#########################################################################查找Qt5 库,注意大小写
find_package(Qt5 REQUIRED COMPONENTS Widgets)
#生产moc文件
qt5_wrap_cpp(MOC_SOURCES include/calculator_qt/calculator.hpp)#包含头文件 calculator.hpp
include_directories(include
)#生成执行文件
add_executable(calculator"src/calculator.cpp"${MOC_SOURCES}
)#链接Qt5库
target_link_libraries(calculatorQt5::Widgets
)
#安装
install(TARGETS calculatorDESTINATION lib/${PROJECT_NAME}
)########################################################################if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)# the following line skips the linter which checks for copyrights# comment the line when a copyright and license is added to all source filesset(ament_cmake_copyright_FOUND TRUE)# the following line skips cpplint (only works in a git repo)# comment the line when this package is in a git repo and when# a copyright and license is added to all source filesset(ament_cmake_cpplint_FOUND TRUE)ament_lint_auto_find_test_dependencies()
endif()ament_package()
五、编译运行
在ws目录下执行
colcon build
结果:
iise@iise-virtual-machine:~/workspace/calculate_qt_ws$ colcon build
Starting >>> calculator_qt
Finished <<< calculator_qt [9.23s] Summary: 1 package finished [9.58s]
然后执行即可
source install/setup.bash
ros2 run calculator_qt calculator