利用Qt6开发集代码编辑、串口通信、频谱图、OpenOCD调试、拖拽式图形化编程为一体的跨平台桌面应用

文章介绍了使用Qt6开发的一款集成代码编辑、图形化编程、波形分析等功能的模块化SDA系统。开发环境为Qt6.3.0和MinGW,设计思路强调了模块化和动态加载。文章详细阐述了主控件CentralWidget、页面切换QStackedWidget、代码编辑模块CodeEditor、模块设计DesignerPage以及波形模块AnalyzerPage的实现。尽管项目暂停,但提供了代码库供进一步开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

1.1 项目地址

Github/Modular-SDA

1.2 功能简介

功能概览

程序集成了代码编辑编译烧录拖拽式图形化编程串口通信OpenOCD调试器输入/输出频谱图日志打印输出等核心功能。

二、开发环境

  • Qt 6.3.0
  • Windows 10 x64
  • MinGW 11.20_64

基于Qt6框架开发,支持跨平台。

三、设计思路

本文的布局大部分通过代码实现,而不是.ui文件,更便于进行控件的动态加载与响应式布局。

Modular-SDA将各模块(代码编辑、拖拽式编程等)作为单独的QWidget来实现,同时将其布局在不同的“页”中,通过页的切换来实现不同模块间的交互。

为了让不同模块在来回切换中保存其状态,Qt提供的QStackedWidget控件恰满足了这一要求。不同于移动端APP的滑动Swipe,在PC端的应用程序中,不同页之间的切换往往是通过侧边栏、顶部(底部或侧边)标签卡等形式进行交互的,因此我们需要QStackedWidget的标签选项卡的支持。虽然QStackedWidget本身具备标签卡,但并不便于设计成侧边栏按钮的形式,且其封装的信号与槽函数有限,很难扩展成侧边栏。因而这里我们自定义一个SideBar控件,模仿Qt Creator的左侧侧边栏形式,将侧边栏按钮的点击信号与自定义槽函数(调用QStackedWidget的SetCurrentWidget()函数)相连接,以触发QStackedWidget的切换页面的操作。

对于编译烧录连接设备等简单操作,将其作为单独的QAction,利用QToolBar实现即可。

设计页的模块拖拽,可以用QGraphicsScene来实现一个类似画布的页面,再将电路模块作为QGraphicsPolygonItem,将其加入QGraphicScene即可。

最后,波形图的绘制采用QCustomplot第三方库实现。

四、模块介绍

4.1 主控件 CentralWidget

将侧边栏SideBar与主控件QSplitter装入一个水平布局,并将该布局作为MainWindow中CentralWidget的布局。其中,QSplitter分割器垂直分割QStackedWidget和LogWindow子控件。

4.2 页面切换 QStackedWidget

利用QStackedWidget容器将代码编辑页设计页图表页通信设置页等不同控件QWidget装入,同时自定义为不同页定义各自的槽函数(亦可之实现一个槽函数,通过侧边栏Action列表的index来切换QStackedWidget),以接收侧边栏的点击信号。

  • 通过setCurrentWidget(QWidget*)实现页面切换
// 为每个侧边栏Action定义单独的槽函数
void MainWindow::action_edit_clicked()
{
    qDebug() << "current page:" << qStackedWidget->currentIndex();
    qStackedWidget->setCurrentWidget(codePage);
}

// 绑定侧边栏 “编辑Action”与对应的QStackedWidget页切换槽函数
QObject::connect(sidebar_edit, &QAction::triggered, this, &MainWindow::action_edit_clicked);
  • (或)通过setCurrentIndex(int)实现页面切换
// 为所有侧边栏Action定义一个的槽函数
// 另外得自定义侧边栏Action信号,加入index参数
void MainWindow::sidebar_action_clicked(int index)
{
    qDebug() << "current page:" << qStackedWidget->currentIndex();
    qStackedWidget->setCurrentIndex(index);
}

侧边栏具体实现代码见仓库 Modular-SDA/src/custom/sidebar.cpp

4.3 代码编辑模块 CodeEditor

代码编辑页

代码编辑页主要控件是一个自定义的继承自QPlainTextEdit的类CodeEditor,定义如下:

class LineNumberArea;

class CodeEditor : public QPlainTextEdit
{
    Q_OBJECT

public:
    CodeEditor(QWidget *parent = 0);
    void setMode(editorMode mode);	//设置编辑模式
    void lineNumberAreaPaintEvent(QPaintEvent *event); // 自定义的行号绘制事件
    int lineNumberAreaWidth();	// 自定义的行号宽度处理函数

protected:
    void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;	// 重写QPlainTextEdit的resize事件

private slots:
    void updateLineNumberAreaWidth(int newBlockCount);	// 更新行号区域宽度槽函数
    void highlightCurrentLine();	// 高亮当前行槽函数
    void updateLineNumberArea(const QRect &, int);	// 更新行号区域槽函数

private:
    QWidget *lineNumberArea;	// 行号区域QWidget
};

/* 自定义的行号区域控件 */
class LineNumberArea : public QWidget
{
public:
    LineNumberArea(CodeEditor *editor) : QWidget(editor) {
        codeEditor = editor;
    }

    QSize sizeHint() const Q_DECL_OVERRIDE {
        return QSize(codeEditor->lineNumberAreaWidth(), 0);
    }

protected:
    void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE {
        codeEditor->lineNumberAreaPaintEvent(event);
    }

private:
    CodeEditor *codeEditor;
};

除了基本的代码编辑功能外,为了能对代码关键字、标识符等进行高亮,需再定义一个继承自QSyntaxHighlighter类的自定义类MyHighLighter,其定义如下:

class MyHighLighter : public QSyntaxHighlighter
{
    Q_OBJECT

public:
    MyHighLighter(QTextDocument* parent = 0);

protected:
    void highlightBlock(const QString& text) Q_DECL_OVERRIDE;

private:
	
	// 封装高亮规则
    struct HighlightingRule
    {
        QRegExp pattern; //高亮规则的正则表达式
        QTextCharFormat format; // 高亮字符格式
    };
    QVector<HighlightingRule> highlightingRules;

    QRegExp commentStartExpression;	// 注释开始的规则
    QRegExp commentEndExpression;	// 注释结束的规则
	
	/* 各种字符串高亮格式(C语言标识符与关键字) */
    QTextCharFormat keywordFormat;	// 关键字
    QTextCharFormat classFormat;	// 类名
    QTextCharFormat singleLineCommentFormat;	// 单行注释
    QTextCharFormat multiLineCommentFormat;		// 多行注释
    QTextCharFormat quotationFormat;	// 引用
    QTextCharFormat functionFormat;		// 函数
};

具体实现代码见 Modular-SDA/src/syntax/SyntaxHighlighter.cpp

4.4 模块设计DesignerPage

算法模块设计页

画板的核心是参照官方例程Diagram Scene Example设计而成,定义如下:

#ifndef DESIGNERPAGE_H
#define DESIGNERPAGE_H

#include <QWidget>
#include <QListWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QGraphicsView>
#include <QToolBox>
#include <QButtonGroup>
#include <QSplitter>
#include <QThread>
#include <QDoubleSpinBox>
#include <QToolButton>
#include <QStackedWidget>
#include "custom/commonHeaders.h"
#include "Diagram/diagramscene.h"
#include "Diagram/diagramitem.h"

namespace Ui
{
    class DesignerPage;
}

class DesignerPage : public QWidget
{
    Q_OBJECT

public:
    explicit DesignerPage(QGraphicsView* view, DiagramScene* scene, QMenu* itemMenu, QWidget* parent = nullptr);
    ~DesignerPage();

    QWidget* getInstance();
    void unCheckButtonGroupItem(int index);
    void unCheckButtonGroupTextItem();
    void addAttributesBox(QWidget* widget);
    void updateAttributesBox(QWidget* widget);
    void resetAttributesBox();

private slots:

    void buttonGroupClicked(QAbstractButton* button);


private:
    Ui::DesignerPage* ui;

    // variables
    QGraphicsView* view = nullptr;
    DiagramScene* scene = nullptr;
    QMenu* itemMenu;
    QFrame* toolBoxes;
    QStackedWidget* attributesBox;
    QWidget* designBoard;
    QWidget* noModuleSelected;
    QButtonGroup* buttonGroup_1;
    QLabel* toolBoxName_1;
    QToolBox* toolBox_1;
    QSpinBox* qSpinBox_pointCnt;
    QSpinBox* qSpinBox_SampleFreq;


    // functions
    void init();
    void createToolbars();
    void initToolBox();
    void initAttributesBox();

    // QWidget* createCellWidget(QButtonGroup*, const QString&, DiagramItem::DiagramType);
    QWidget* createCellWidget(QButtonGroup*, const QString&, DiagramItem::ModuleType);
};

#endif // DESIGNERPAGE_H

具体实现代码见 Modular-SDA/src/Pages/designerpage.cpp

其中,算法模块属性等功能已实现,算法模块的代码生成未实现。

4.5 波形模块AnalyzerPage

绘图控件基于QCustomplot进行修改,加入了自定义的XTracer追踪指针位置,以显示横纵轴参考线及数值,波形图使用频谱图QCustomplot::SpectrumPlot即可。
波形分析页
用于追踪光标位置的XTracer类定义如下:

#ifndef MYTRACER_H
#define MYTRACER_H

#include <QObject>
#include "qcustomplot.h"

class XTracer : public QObject
{
    Q_OBJECT

public:
    enum TracerType
    {
        XAxisTracer,//依附在x轴上显示x值
        YAxisTracer,//依附在y轴上显示y值
        DataTracer//在图中显示x,y值
    };
    explicit XTracer(QCustomPlot* _plot, TracerType _type, QObject* parent = Q_NULLPTR);
    ~XTracer();
    void setPen(const QPen& pen);
    void setBrush(const QBrush& brush);
    void setText(const QString& text);
    void setLabelPen(const QPen& pen);
    void updatePosition(double xValue, double yValue);
    void setVisible(bool m_visible);

protected:
    bool m_visible;//是否可见
    TracerType m_type;//类型
    QCustomPlot* m_plot;//图表
    QCPItemTracer* m_tracer;//跟踪的点
    QCPItemText* m_label;//显示的数值
    QCPItemLine* m_arrow;//箭头
};

class XTraceLine : public QObject
{
public:
    enum LineType
    {
        VerticalLine,//垂直线
        HorizonLine, //水平线
        Both//同时显示水平和垂直线
    };
    explicit XTraceLine(QCustomPlot* _plot, LineType _type = VerticalLine, QObject* parent = Q_NULLPTR);
    ~XTraceLine();
    void initLine();
    void updatePosition(double xValue, double yValue);

    void setVisible(bool vis)
    {
        if(m_lineV)
        {
            m_lineV->setVisible(vis);
        }
        if(m_lineH)
        {
            m_lineH->setVisible(vis);
        }
    }

protected:
    bool m_visible;//是否可见
    LineType m_type;//类型
    QCustomPlot* m_plot;//图表
    QCPItemStraightLine* m_lineV; //垂直线
    QCPItemStraightLine* m_lineH; //水平线
};

#endif // MYTRACER_H

具体实现代码参见Modular-SDA/src/lib/XTracer.cpp

五、结语

由于个人时间问题,该项目暂时告一段落,后续应该不会再着手。

该项目目前还有以下主要功能需完善:

  • 代码编辑页的文件保存功能
  • 模块设计页的代码生成功能

项目地址见文章开头,欢迎各位fork后进行拓展。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值