rviz添加qt插件

news2024/11/24 21:02:24

一、增加rviz plugin插件

资料:http://admin.guyuehome.com/42336
https://blog.51cto.com/u_13625033/6126970

  • 这部分代码只是将上面两个链接中的代码整合在了一起,整合在一起后可以更好的理解其中的关系

1、创建软件包

catkin_create_pkg rviz_teleop_commander roscpp rviz std_msgs

在这里插入图片描述

2、创建​plugin_description.xml​​文件

  • 最后只是生成了一个动态库so文件,一个库里可以有多个插件,所以只有一个library
<library path="lib/librviz_teleop_commander">
    <class name="rviz_teleop_commander/TeleopPanel"
           type="rviz_teleop_commander::TeleopPanel"
           base_class_type="rviz::Panel">
        <description>
            A panel widget allowing simple diff-drive style robot base control.
        </description>
    </class>
    <class name="rviz_teleop_commander/cmd_control"
           type="rviz_teleop_commander::cmd_control"
           base_class_type="rviz::Panel">
        <description>
            A panel widget allowing simple diff-drive style robot base control.
        </description>
    </class>
</library>

3、处理package.xml文件

  • 这部分不需要改太多,只在最后增加一个export即可
<?xml version="1.0"?>
<package format="2">
  <name>rviz_teleop_commander</name>
  <version>0.0.0</version>
  <description>The rviz_teleop_commander package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
  <maintainer email="wangyuanhao@todo.todo">wangyuanhao</maintainer>


  <!-- One license tag required, multiple allowed, one license per tag -->
  <!-- Commonly used license strings: -->
  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  <license>TODO</license>


  <!-- Url tags are optional, but multiple are allowed, one per tag -->
  <!-- Optional attribute type can be: website, bugtracker, or repository -->
  <!-- Example: -->
  <!-- <url type="website">http://wiki.ros.org/rviz_teleop_commander</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="jane.doe@example.com">Jane Doe</author> -->


  <!-- The *depend tags are used to specify dependencies -->
  <!-- Dependencies can be catkin packages or system dependencies -->
  <!-- Examples: -->
  <!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
  <!--   <depend>roscpp</depend> -->
  <!--   Note that this is equivalent to the following: -->
  <!--   <build_depend>roscpp</build_depend> -->
  <!--   <exec_depend>roscpp</exec_depend> -->
  <!-- Use build_depend for packages you need at compile time: -->
  <!--   <build_depend>message_generation</build_depend> -->
  <!-- Use build_export_depend for packages you need in order to build against this package: -->
  <!--   <build_export_depend>message_generation</build_export_depend> -->
  <!-- Use buildtool_depend for build tool packages: -->
  <!--   <buildtool_depend>catkin</buildtool_depend> -->
  <!-- Use exec_depend for packages you need at runtime: -->
  <!--   <exec_depend>message_runtime</exec_depend> -->
  <!-- Use test_depend for packages you need only for testing: -->
  <!--   <test_depend>gtest</test_depend> -->
  <!-- Use doc_depend for packages you need only for building documentation: -->
  <!--   <doc_depend>doxygen</doc_depend> -->
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rviz</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rviz</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rviz</exec_depend>
  <exec_depend>std_msgs</exec_depend>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->
      <rviz plugin="${prefix}/plugin_description.xml"/>
  </export>


  
</package>

4、处理CMakeLists.txt文件

cmake_minimum_required(VERSION 3.0.2)
project(rviz_teleop_commander)

## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rviz
  std_msgs
)

###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES rviz_teleop_commander
#  CATKIN_DEPENDS roscpp rviz std_msgs
#  DEPENDS system_lib
)

###########
## Build ##
###########

## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
  ${catkin_INCLUDE_DIRS}
)


####################################################################################
####################################################################################
## 找到相关的库
find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
set(QT_LIBRARIES Qt5::Widgets)

## I prefer the Qt signals and slots to avoid defining "emit", "slots",
## etc because they can conflict with boost signals, so define QT_NO_KEYWORDS here.
add_definitions(-DQT_NO_KEYWORDS)

## Here we specify which header files need to be run through "moc", Qt's meta-object compiler.
## 指定需要qt元编译的头文件
qt5_wrap_cpp(MOC_FILES
  src/teleop_pad.h
  src/cmd_control.h
  )

## 定义SOURCE_FILES_1变量
message(MOC_FILES " ${MOC_FILES}")
set(SOURCE_FILES_1
  src/teleop_pad.cpp 
  src/cmd_control.cpp 
  ${MOC_FILES}
)

## 生成库文件,定义库的名字与项目名字一样
add_library(${PROJECT_NAME} ${SOURCE_FILES_1})    
## 连接qt和ros的库到目标库
target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${catkin_LIBRARIES})    

## Install rules 复制文件到指定位置
install(TARGETS ${PROJECT_NAME}
  ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)


install(FILES plugin_description.xml
  DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})

5、编写代码

teleop_pad.h

#ifndef TELEOP_PAD_H
#define TELEOP_PAD_H

//所需要包含的头文件
#ifndef Q_MOC_RUN
#include <ros/ros.h>
#include <ros/console.h>
#include <rviz/panel.h>   //plugin基类的头文件
#endif

class QLineEdit;

namespace rviz_teleop_commander
{
// 所有的plugin都必须是rviz::Panel的子类
class TeleopPanel: public rviz::Panel
{
// 后边需要用到Qt的信号和槽,都是QObject的子类,所以需要声明Q_OBJECT宏
Q_OBJECT
public:
    // 构造函数,在类中会用到QWidget的实例来实现GUI界面,这里先初始化为0即可
    TeleopPanel( QWidget* parent = 0 );

    // 重载rviz::Panel积累中的函数,用于保存、加载配置文件中的数据,在我们这个plugin
    // 中,数据就是topic的名称
    virtual void load( const rviz::Config& config );
    virtual void save( rviz::Config config ) const;

// 公共槽.
public Q_SLOTS:
    // 当用户输入topic的命名并按下回车后,回调用此槽来创建一个相应名称的topic publisher
    void setTopic( const QString& topic );

// 内部槽.
protected Q_SLOTS:
    void sendVel();                 // 发布当前的速度值
    void update_Linear_Velocity();  // 根据用户的输入更新线速度值
    void update_Angular_Velocity(); // 根据用户的输入更新角速度值
    void updateTopic();             // 根据用户的输入更新topic name

// 内部变量.
protected:
    // topic name输入框
    QLineEdit* output_topic_editor_;
    QString output_topic_;

    // 线速度值输入框
    QLineEdit* output_topic_editor_1;
    QString output_topic_1;

    // 角速度值输入框
    QLineEdit* output_topic_editor_2;
    QString output_topic_2;

    // ROS的publisher,用来发布速度topic
    ros::Publisher velocity_publisher_;

    // ROS节点句柄
    ros::NodeHandle nh_;

    // 当前保存的线速度和角速度值
    float linear_velocity_;
    float angular_velocity_;
};

} // end namespace rviz_teleop_commander

#endif // TELEOP_PANEL_H

teleop_pad.cpp

#include <stdio.h>

#include <QPainter>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTimer>

#include <geometry_msgs/Twist.h>
#include <QDebug>

#include "teleop_pad.h"

namespace rviz_teleop_commander
{

// 构造函数,初始化变量
TeleopPanel::TeleopPanel( QWidget* parent )
  : rviz::Panel( parent )
  , linear_velocity_( 0 )
  , angular_velocity_( 0 )
{
    // 创建一个输入topic命名的窗口
    QVBoxLayout* topic_layout = new QVBoxLayout;
    topic_layout->addWidget( new QLabel( "Teleop Topic:" ));
    output_topic_editor_ = new QLineEdit;
    topic_layout->addWidget( output_topic_editor_ );

    // 创建一个输入线速度的窗口
    topic_layout->addWidget( new QLabel( "Linear Velocity:" ));
    output_topic_editor_1 = new QLineEdit;
    topic_layout->addWidget( output_topic_editor_1 );

    // 创建一个输入角速度的窗口
    topic_layout->addWidget( new QLabel( "Angular Velocity:" ));
    output_topic_editor_2 = new QLineEdit;
    topic_layout->addWidget( output_topic_editor_2 );

    QHBoxLayout* layout = new QHBoxLayout;
    layout->addLayout( topic_layout );
    setLayout( layout );

    // 创建一个定时器,用来定时发布消息
    QTimer* output_timer = new QTimer( this );

    // 设置信号与槽的连接
    // 输入topic命名,回车后,调用updateTopic()
    connect( output_topic_editor_, SIGNAL( editingFinished() ), this, SLOT( updateTopic() ));    
    // 输入线速度值,回车后,调用update_Linear_Velocity()    
    connect( output_topic_editor_1, SIGNAL( editingFinished() ), this, SLOT( update_Linear_Velocity() )); 
    // 输入角速度值,回车后,调用update_Angular_Velocity()
    connect( output_topic_editor_2, SIGNAL( editingFinished() ), this, SLOT( update_Angular_Velocity() ));

    // 设置定时器的回调函数,按周期调用sendVel()
    connect( output_timer, SIGNAL( timeout() ), this, SLOT( sendVel() ));

    // 设置定时器的周期,100ms
    output_timer->start( 100 );
}

// 更新线速度值
void TeleopPanel::update_Linear_Velocity()
{
    // 获取输入框内的数据
    QString temp_string = output_topic_editor_1->text();
    
    // 将字符串转换成浮点数
    float lin = temp_string.toFloat();  
    
    // 保存当前的输入值
    linear_velocity_ = lin;
}

// 更新角速度值
void TeleopPanel::update_Angular_Velocity()
{
    QString temp_string = output_topic_editor_2->text();
    float ang = temp_string.toFloat() ;  
    angular_velocity_ = ang;
}

// 更新topic命名
void TeleopPanel::updateTopic()
{
    setTopic( output_topic_editor_->text() );
}

// 设置topic命名
void TeleopPanel::setTopic( const QString& new_topic )
{
    // 检查topic是否发生改变.
    if( new_topic != output_topic_ )
    {
        output_topic_ = new_topic;

        // 如果命名为空,不发布任何信息
        if( output_topic_ == "" )
        {
            velocity_publisher_.shutdown();
        }
        // 否则,初始化publisher
        else
        {
            velocity_publisher_ = nh_.advertise<geometry_msgs::Twist>( output_topic_.toStdString(), 1 );
        }

        Q_EMIT configChanged();
    }
}

// 发布消息
void TeleopPanel::sendVel()
{
    if( ros::ok() && velocity_publisher_ )
    {
        geometry_msgs::Twist msg;
        msg.linear.x = linear_velocity_;
        msg.linear.y = 0;
        msg.linear.z = 0;
        msg.angular.x = 0;
        msg.angular.y = 0;
        msg.angular.z = angular_velocity_;
        velocity_publisher_.publish( msg );
    }
}

// 重载父类的功能
void TeleopPanel::save( rviz::Config config ) const
{
    rviz::Panel::save( config );
    config.mapSetValue( "Topic", output_topic_ );
}

// 重载父类的功能,加载配置数据
void TeleopPanel::load( const rviz::Config& config )
{
    rviz::Panel::load( config );
    QString topic;
    if( config.mapGetString( "Topic", &topic ))
    {
        output_topic_editor_->setText( topic );
        updateTopic();
    }
}

} // end namespace rviz_teleop_commander

// 声明此类是一个rviz的插件
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(rviz_teleop_commander::TeleopPanel,rviz::Panel )
// END_TUTORIAL

cmd_control.h

#ifndef CMD_CONTROL_H
#define CMD_CONTROL_H

#include <stdio.h>

//所需要包含的头文件
#include <ros/ros.h>
#include <ros/console.h>
#include <rviz/panel.h>   //plugin基类的头文件


#include <QPainter>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTimer>
#include <QPushButton>
#include <geometry_msgs/Twist.h>
#include <QDebug>
#include <QCheckBox>
#include <QSlider>
namespace rviz_teleop_commander {
class cmd_control:public rviz::Panel
{
    Q_OBJECT
public:
    // 构造函数,在类中会用到QWidget的实例来实现GUI界面,这里先初始化为0即可
    cmd_control(QWidget* parent=0);
    // 重载rviz::Panel积累中的函数,用于保存、加载配置文件中的数据,在我们这个plugin中,数据就是topic的名称
//    virtual void load( const rviz::Config& config );
    virtual void save( rviz::Config config ) const;
    void move_base(char k,float speed_linear,float speed_trun);
public Q_SLOTS:
    void slot_cmd_control();
    void on_Slider_raw_valueChanged(int);
    // 内部变量.
protected:
    QPushButton* pushButton_i;
    QPushButton* pushButton_u;
    QPushButton* pushButton_o;
    QPushButton* pushButton_j;
    QPushButton* pushButton_l;
    QPushButton* pushButton_m;
    QPushButton* pushButton_back;
    QPushButton* pushButton_backr;

    QCheckBox* is_all_check;

    QSlider* yaw_slider;
    QSlider* linera_slider;
    // ROS的publisher,用来发布速度topic
    ros::Publisher velocity_publisher_;
    QString output_topic_="cmd_vel";

    // The ROS node handle.
    ros::NodeHandle nh_;

    // 当前保存的线速度和角速度值
    float linear_velocity_;
    float angular_velocity_;

};
}

#endif // CMD_CONTROL_H

cmd_control.cpp

#include "cmd_control.h"
#include <stdio.h>

#include <QPainter>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTimer>

#include <geometry_msgs/Twist.h>
#include <QDebug>

namespace rviz_teleop_commander {
cmd_control::cmd_control(QWidget* parent)
    :rviz::Panel (parent)
{


    //初始化ui
 QVBoxLayout *mainlayout=new QVBoxLayout;
 pushButton_i=new QPushButton;
 pushButton_i->setText("i");
 //快捷键
 pushButton_i->setShortcut(QKeySequence(QLatin1String("i")));
 pushButton_i->setStyleSheet("QPushButton#pushButton_i:pressed{background-color:rgb(239, 41, 41)}");
 pushButton_u=new QPushButton;
 //快捷键
 pushButton_u->setShortcut(QKeySequence(QLatin1String("u")));
 pushButton_u->setText("u");
 pushButton_u->setStyleSheet("QPushButton#pushButton_i:pressed{background-color:rgb(239, 41, 41)}");
 pushButton_o=new QPushButton;
 //快捷键
 pushButton_o->setShortcut(QKeySequence(QLatin1String("o")));
 pushButton_o->setText("o");
 pushButton_o->setStyleSheet("QPushButton#pushButton_i:pressed{background-color:rgb(239, 41, 41)}");
 QHBoxLayout *first=new QHBoxLayout;
 first->addWidget(pushButton_u);
 first->addWidget(pushButton_i);
 first->addWidget(pushButton_o);
 mainlayout->addLayout(first);

 pushButton_j=new QPushButton;
 pushButton_j->setText("j");
 //快捷键
 pushButton_j->setShortcut(QKeySequence(QLatin1String("j")));
 pushButton_j->setStyleSheet("QPushButton#pushButton_i:pressed{background-color:rgb(239, 41, 41)}");
 is_all_check=new QCheckBox;
 is_all_check->setText("使用全向轮模式");
 //快捷键
 is_all_check->setShortcut(QKeySequence(QLatin1String("k")));
 pushButton_l=new QPushButton;
 pushButton_l->setText("l");
 //快捷键
 pushButton_l->setShortcut(QKeySequence(QLatin1String("l")));
 pushButton_l->setStyleSheet("QPushButton#pushButton_i:pressed{background-color:rgb(239, 41, 41)}");
 QHBoxLayout *second=new QHBoxLayout;
 second->addWidget(pushButton_j);
 second->addWidget(is_all_check);
 second->addWidget(pushButton_l);
 mainlayout->addLayout(second);

 pushButton_m=new QPushButton;
 //快捷键
 pushButton_m->setShortcut(QKeySequence(QLatin1String("m")));
 pushButton_m->setText("m");
 pushButton_m->setStyleSheet("QPushButton#pushButton_i:pressed{background-color:rgb(239, 41, 41)}");
 pushButton_back=new QPushButton;
 //快捷键
 pushButton_back->setShortcut(QKeySequence(QLatin1String(",")));
 pushButton_back->setText(",");
 pushButton_back->setStyleSheet("QPushButton#pushButton_i:pressed{background-color:rgb(239, 41, 41)}");
 pushButton_backr=new QPushButton;
 //快捷键
 pushButton_backr->setShortcut(QKeySequence(QLatin1String(".")));
 pushButton_backr->setText(".");
pushButton_backr->setStyleSheet("QPushButton#pushButton_i:pressed{background-color:rgb(239, 41, 41)}");
QHBoxLayout *third=new QHBoxLayout;
third->addWidget(pushButton_m);
third->addWidget(pushButton_back);
third->addWidget(pushButton_backr);
mainlayout->addLayout(third);

QLabel *linera_label=new QLabel;
linera_label->setText("线速度(cm/s)");
linera_slider=new QSlider;
linera_slider->setOrientation(Qt::Horizontal);  // 水平方向
linera_slider->setRange(0,100);
linera_slider->setValue(50);
QHBoxLayout *five=new QHBoxLayout;
five->addWidget(linera_label);
five->addWidget(linera_slider);
mainlayout->addLayout(five);

QLabel *yaw_label=new QLabel;
yaw_label->setText("角速度(cm/s)");
yaw_slider=new QSlider;
yaw_slider->setOrientation(Qt::Horizontal);  // 水平方向
yaw_slider->setRange(0,100);
yaw_slider->setValue(100);
QHBoxLayout *six=new QHBoxLayout;
six->addWidget(yaw_label);
six->addWidget(yaw_slider);
mainlayout->addLayout(six);

 setLayout(mainlayout);

 //绑定信号

 //绑定速度控制按钮
 connect(pushButton_i,SIGNAL(clicked()),this,SLOT(slot_cmd_control()));
 connect(pushButton_u,SIGNAL(clicked()),this,SLOT(slot_cmd_control()));
 connect(pushButton_o,SIGNAL(clicked()),this,SLOT(slot_cmd_control()));
 connect(pushButton_j,SIGNAL(clicked()),this,SLOT(slot_cmd_control()));
 connect(pushButton_l,SIGNAL(clicked()),this,SLOT(slot_cmd_control()));
 connect(pushButton_m,SIGNAL(clicked()),this,SLOT(slot_cmd_control()));
 connect(pushButton_back,SIGNAL(clicked()),this,SLOT(slot_cmd_control()));
 connect(pushButton_backr,SIGNAL(clicked()),this,SLOT(slot_cmd_control()));

 //创建发布者
 velocity_publisher_ = nh_.advertise<geometry_msgs::Twist>( output_topic_.toStdString(), 1 );

}

void cmd_control::slot_cmd_control()
{

    QPushButton* btn=qobject_cast<QPushButton*>(sender());
    char key=btn->text().toStdString()[0];
    //速度
    float liner=linera_slider->value()*0.01;
    float turn=yaw_slider->value()*0.01;
    bool is_all=is_all_check->isChecked();
    switch (key) {
        case 'u':
            move_base(is_all?'U':'u',liner,turn);
        break;
        case 'i':
            move_base(is_all?'I':'i',liner,turn);
        break;
        case 'o':
            move_base(is_all?'O':'o',liner,turn);
        break;
        case 'j':
            move_base(is_all?'J':'j',liner,turn);
        break;
        case 'l':
            move_base(is_all?'L':'l',liner,turn);
        break;
        case 'm':
            move_base(is_all?'M':'m',liner,turn);
        break;
        case ',':
            move_base(is_all?'<':',',liner,turn);
        break;
        case '.':
            move_base(is_all?'>':'.',liner,turn);
        break;
    }

}
void cmd_control::move_base(char k,float speed_linear,float speed_trun)
{
    std::map<char, std::vector<float>> moveBindings
    {
      {'i', {1, 0, 0, 0}},
      {'o', {1, 0, 0, -1}},
      {'j', {0, 0, 0, 1}},
      {'l', {0, 0, 0, -1}},
      {'u', {1, 0, 0, 1}},
      {',', {-1, 0, 0, 0}},
      {'.', {-1, 0, 0, 1}},
      {'m', {-1, 0, 0, -1}},
      {'O', {1, -1, 0, 0}},
      {'I', {1, 0, 0, 0}},
      {'J', {0, 1, 0, 0}},
      {'L', {0, -1, 0, 0}},
      {'U', {1, 1, 0, 0}},
      {'<', {-1, 0, 0, 0}},
      {'>', {-1, -1, 0, 0}},
      {'M', {-1, 1, 0, 0}},
      {'t', {0, 0, 1, 0}},
      {'b', {0, 0, -1, 0}},
      {'k', {0, 0, 0, 0}},
      {'K', {0, 0, 0, 0}}
    };
    char key=k;
    //计算是往哪个方向
    float x = moveBindings[key][0];
    float y = moveBindings[key][1];
    float z = moveBindings[key][2];
    float th = moveBindings[key][3];
    //计算线速度和角速度
    float speed = speed_linear;
    float turn = speed_trun;
    // Update the Twist message
    geometry_msgs::Twist twist;
   twist.linear.x = x * speed;
   twist.linear.y = y * speed;
   twist.linear.z = z * speed;

   twist.angular.x = 0;
   twist.angular.y = 0;
   twist.angular.z = th * turn;

   // Publish it and resolve any remaining callbacks
   velocity_publisher_.publish(twist);
   ros::spinOnce();
}


// 重载父类的功能
void cmd_control::save( rviz::Config config ) const
{
  rviz::Panel::save( config );
  config.mapSetValue( "Topic", output_topic_ );
}




}

// 声明此类是一个rviz的插件
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(rviz_teleop_commander::cmd_control,rviz::Panel )
// END_TUTORIAL

6、编译并使用

  • 编译通过后,打开rviz即可调用插件
    在这里插入图片描述

二、通过Qt可视化工具构建rviz插件

1、qt creator开发

  • rviz插件的源代码的主要库是qt库,qt库的常见开发方式是使用qt creator,代码框架主要是主函数+定义ui界面的cpp文件和h文件。
  • 主函数基本就是启动代码,不用修改。
#include "mainwindow.h"

#include <QApplication>
#include <QLocale>
#include <QTranslator>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QTranslator translator;
    const QStringList uiLanguages = QLocale::system().uiLanguages();
    for (const QString &locale : uiLanguages) {
        const QString baseName = "qt_to_rviz_" + QLocale(locale).name();
        if (translator.load(":/i18n/" + baseName)) {
            a.installTranslator(&translator);
            break;
        }
    }
    MainWindow w;
    w.show();
    return a.exec();
}

  • 头文件中声明需要用到的组件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
private:
    QLabel *lab;  //这里声明了一个标签组建,记得要引入对应组建的头文件
};
#endif // MAINWINDOW_H

  • cpp文件主要在构造函数中定义和启动组建
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    this->lab = new QLabel("Hello, world!", this);
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}


在这里插入图片描述

  • 这是普通qt程序的开发和使用方法,这里只有qt实现的界面可视化代码,没有增加业务功能代码。只要把这部分代码和业务代码耦合在一起就可以实现效果了

2、qt designer

  • 还有一种方法是使用qt designer,这种工具通过可视化界面设计ui界面并设置相关配置,最后通过uic工具生成h文件,h文件中会有qt功能的主要代码,在其基础之上修改即可。
  • 在qt designer中设计ui界面,保存为ui文件
    在这里插入图片描述* 使用uic生成头文件,相关类可以从这个头文件中挑选和复用代码,不过还是有挺多要修改的
uic mainwindow.ui -o qwe.h
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.15.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef QWE_H
#define QWE_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_MainWindow
{
public:
    QWidget *centralwidget;
    QPushButton *pushButton;
    QLabel *label;
    QLineEdit *lineEdit;

    void setupUi(QMainWindow *MainWindow)
    {
        //主界面
        if (MainWindow->objectName().isEmpty())
            MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
        MainWindow->resize(800, 600);
        //核心部件,管理者?
        centralwidget = new QWidget(MainWindow);
        centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
        //按键部件
        pushButton = new QPushButton(centralwidget);
        pushButton->setObjectName(QString::fromUtf8("pushButton"));
        pushButton->setGeometry(QRect(120, 250, 89, 25));
        //标签部件
        label = new QLabel(centralwidget);
        label->setObjectName(QString::fromUtf8("label"));
        label->setGeometry(QRect(370, 220, 201, 21));
        //横线编辑框
        lineEdit = new QLineEdit(centralwidget);
        lineEdit->setObjectName(QString::fromUtf8("lineEdit"));
        lineEdit->setGeometry(QRect(250, 360, 113, 25));
        //设置核心部件
        MainWindow->setCentralWidget(centralwidget);
        //渲染
        retranslateUi(MainWindow);
        //连接槽位
        QMetaObject::connectSlotsByName(MainWindow);
    } // setupUi

    void retranslateUi(QMainWindow *MainWindow)
    {
        MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));
        pushButton->setText(QCoreApplication::translate("MainWindow", "PushButton", nullptr));
        label->setText(QCoreApplication::translate("MainWindow", "hellow world", nullptr));
    } // retranslateUi

};

namespace Ui {
    class MainWindow: public Ui_MainWindow {};
} // namespace Ui

QT_END_NAMESPACE

#endif // QWE_H

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1186947.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL数据库的各种锁介绍以及它们之间的关系

MySQL数据库的各种锁 表级锁、行级锁、间隙锁、意向锁、记录锁&#xff0c;悲观锁和乐观锁 表级锁包含表级共享锁和表级排他锁行级锁包含行级共享锁和行级排他锁间隙锁是行级锁的一种特殊锁&#xff0c;锁定既定列的范围值意向锁是事务对表中某些行或者范围发起的一项操作&am…

Hbuiderx链接到夜神模拟器(DCloud数字天堂)

赞助 DCloud 即数字天堂&#xff08;北京&#xff09;网络技术有限公司是 W3C成员及 HTML5中国产业联盟 发起单位 Hbuiderx切换使用夜神模拟器自带的ADB.exe链接到夜神模拟器 同步资源失败&#xff0c;未得到同步资源的授权&#xff0c;请停止运行后重新运行&#xff0c;并注意…

数据的读取和保存-MATLAB

1 序言 在进行数据处理时&#xff0c;经常需要写代码对保存在文件中的数据进行读取→处理→保存的操作&#xff0c;流程图如下&#xff1a; 笔者每次在进行上述操作时&#xff0c;都需要百度如何“选中目标文件”以及如何“将处理好的数据保存到目标文件中”&#xff0c;对这一…

本地域名 127.0.0.1 / localhost

所谓本地域名就是 只能在本机使用的域名 &#xff0c;一般在开发阶段使用。 编辑文件 C:\Windows\System32\drivers\etc\hosts。 127.0.0.1 www.baidu.com如果修改失败,可以修改该文件的权限。 原理&#xff1a; 在地址栏输入 域名 之后&#xff0c;浏览器会先进行 DNS…

SpringBoot定时任务打成jar 引入到新的项目中后并自动执行

一、springBoot开发定时任务 ①&#xff1a;连接数据库实现新增功能 1. 引入依赖 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional> </dependency> <dependen…

Python高级语法----深入理解Python协程

文章目录 什么是协程?Python中的协程基本示例协程和事件循环总结Python协程是一种非常强大的并发编程概念,让你能够高效地处理多任务。协程在Python中的使用已经变得越来越流行,特别是在异步编程中。本文将用通俗易懂的语言来介绍协程的概念,并提供实际的代码示例和执行结果…

软件测试怎么测别的类的main方法

软件测试怎么测别的类的main方法 🍎如果软测开发者题目待测类里有main方法,我们如何测? 可以采取以下步骤: 了解main函数的功能:首先,你需要了解这个main函数的功能和预期的输出。这样你才能设计出合适的测试用例。设计测试用例:设计测试用例时,需要考虑各种可能的输…

【Linux】了解文件的inode元信息,以及日志分析

目录 一、inode表结构&#xff0c;以及元信息 1、了解inode信息有哪些 2、关于inode表的说明 Linux中访问文件的过程&#xff1a; 3、硬连接与软连接的区别&#xff0c;&#xff08;请看前面&#xff0c;写过的&#xff09; 二、文件系统的备份与恢复 三、几种常见的日志…

【uniapp】签名组件,兼容vue2vue3

网上找了个源码改吧改吧&#xff0c;清除了没用的功能和兼容性&#xff0c;基于uniapp开发的 样子 vue2 使用方法&#xff0c;具体的可以根据业务自行修改 <signature ref"signature" width"100%" height"410rpx"></signature>confi…

C函数的反汇编

fromelf --bin --outputxxx.bin xxx.axf fromelf --text -a -c --outputxxx.dis xxx.axf去Linker下面复制该目录下的xxx.axf xxx.dis名字随便改&#xff0c;保证后缀是dis就行 然后确认&#xff0c;进行编译 就生成了task.dis文件

【MySQL】库操作和表操作

文章目录 一、库操作1. 创建数据库2. 数据库的编码问题查看系统默认支持的字符集查看数据库支持的字符集查看数据库支持的字符集校验规则校验规则对数据库的影响 3. 操纵数据库查看数据库显示创建语句修改数据库删除数据库 4. 数据库的备份和恢复数据库的备份数据库的恢复表的删…

从业务到软件架构——软件建模

一、问题 1.架构到底是什么&#xff1f;架构和业务之间到底什么关系&#xff1f; 2.好的架构的设计出发点是什么&#xff1f;好的架构应该是什么样的&#xff1f; 作为一个计算机领域的词汇&#xff0c;架构的定义是&#xff1a;有关软件整体结构与组件的抽象描述&#xff0c…

ubuntu22.04使用VNC链接服务器远程桌面

一、本地VNC客户端 本地主要需要一个VNC客户端&#xff0c;用来远程连接服务器端的VNC&#xff08;在不安装Web版本VNC情况下&#xff09;。VNC客户端下载地址&#xff1a; VNC客户端下载 二、安装Xfce桌面环境 在远程服务器控制台中安装Xfce桌面&#xff08;这个桌面环境比…

redis持久化和Redis事务

一)Redis持久化之RDBredisDataBase: 什么是持久化: 1)持久性:和持久化说的是同一回事&#xff0c;衡量持久性的前提是重启进程或者是重启主机以后数据是否还存在 持久:把数据存储在硬盘上&#xff0c;那么就是持久性 不持久:把数据存储在内存中 2)redis是一个内存级别的数据库&…

关于electron中使用ffi-napi窗口遍历的过程及问题

使用环境&#xff1a;electorn19 、node16、ffi-napi、user32 前言&#xff1a;这里先提一嘴&#xff0c;windows api也是有32位和64位的区别的&#xff0c;因为我是要快速完成项目&#xff0c;就没用C写&#xff08;不熟练&#xff09;&#xff0c;我想着直接用易语言写DLL&am…

注册商标-保护企业利益

注册商标-保护企业利益&#xff01; 在当今竞争激烈的商业环境中&#xff0c;商标对于企业的成功至关重要。商标不仅是企业形象的代表&#xff0c;也是企业产品和服务的标识。通过注册商标&#xff0c;企业可以获得法律保护&#xff0c;确保其商标的独特性和安全性。本文将探讨…

1212. 地宫取宝

题目&#xff1a; 1212. 地宫取宝 - AcWing题库 思路&#xff1a;dp&#xff08;最长上升子序列和摘花生的结合&#xff09; 代码&#xff1a; #include<iostream> using namespace std; const int N 55; const int MOD 1000000007;int n, m, k; int w[N][N];//每个坐…

【Leetcode】【数据结构】【C语言】判断两个链表是否相交并返回交点地址

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode *tailAheadA;struct ListNode *tailBheadB;int count10;int count20;//分别找尾节点&#xff0c;并顺便统计节点数量&#xff1a;while(tailA){tailAtailA->next;c…

变电站自动化系统中的安全措施分析及应用-安科瑞

安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;阐述变电运行中的问题&#xff0c;电气自动化系统与安全运行措施&#xff0c;包括自动控制设备的投入&#xff0c;电气自动 化与计算机技术相、设备数据的采集与处理、自动化系统的升级、人工智能技术的应用。 关键…

第三章:人工智能深度学习教程-基础神经网络(第五节-了解多层前馈网络)

让我们了解反向传播网络 (BPN) 中的误差是如何计算的以及权重是如何更新的。 考虑下图中的以下网络。 反向传播网络(BPN) 上图中的网络是一个简单的多层前馈网络或反向传播网络。它包含三层,输入层有两个神经元 x 1和 x 2,隐藏层有两个神经元 z 1和 z 2,输出层有一个神经…