diff --git a/LinkScope.pro b/LinkScope.pro index 3f77b2d..e20c9f8 100644 --- a/LinkScope.pro +++ b/LinkScope.pro @@ -1,4 +1,5 @@ QT += core gui +QT += network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -8,7 +9,8 @@ CONFIG += c++11 # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS +DEFINES += QT_DEPRECATED_WARNINGS \ + APP_VERSION=\\\"1.0.2\\\" # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. @@ -16,17 +18,26 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ + aboutwindow.cpp \ graphwindow.cpp \ + helpwindow.cpp \ + listwindow.cpp \ main.cpp \ mainwindow.cpp HEADERS += \ + aboutwindow.h \ graphwindow.h \ + helpwindow.h \ + listwindow.h \ mainwindow.h \ vartype.h FORMS += \ + aboutwindow.ui \ graphwindow.ui \ + helpwindow.ui \ + listwindow.ui \ mainwindow.ui RC_ICONS = icon.ico diff --git a/README.md b/README.md index 51c3676..5320b7c 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,15 @@ > 注:变量名不仅可以填入单个变量名,还可以填入合法的C语言表达式(GDB支持即可);复合类型不能修改和绘图,只能实时查看 -1. 编辑`修改变量`列可以修改变量值,双击`图线颜色`列可以选择绘图颜色 +3. 在选择窗口中可以查看所选Axf文件包含的变量名,也可以一键添加到编辑框或变量列表中 + +4. 编辑`修改变量`列可以修改变量值,双击`图线颜色`列可以选择绘图颜色 ![基本操作](imgs/simp-oper.gif) -4. 单击`变量名`列选中对应的变量,绘图窗口会加粗绘制波形,左下角会显示当前值和查看值(拖动鼠标进行查看) +5. 单击`变量名`列选中对应的变量,绘图窗口会加粗绘制波形,左下角会显示当前值和查看值(拖动鼠标进行查看) -5. 绘图界面说明可以在绘图窗口点击操作说明查看,滚轮配合`Ctrl`、`Shift`、`Alt`可以实现画面的缩放和移动 +6. 绘图界面说明可以在绘图窗口点击操作说明查看,滚轮配合`Ctrl`、`Shift`、`Alt`可以实现画面的缩放和移动 ![绘图操作](imgs/graph-oper.gif) @@ -76,6 +78,8 @@ * 将采样频率提升至约1kHz +* 添加串口模式 + --- ## 运行过程简介 diff --git a/aboutwindow.cpp b/aboutwindow.cpp new file mode 100644 index 0000000..441cf7d --- /dev/null +++ b/aboutwindow.cpp @@ -0,0 +1,19 @@ +#include "aboutwindow.h" +#include "ui_aboutwindow.h" + +AboutWindow::AboutWindow(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutWindow) +{ + ui->setupUi(this); +} + +AboutWindow::~AboutWindow() +{ + delete ui; +} + +void AboutWindow::on_btn_back_clicked() +{ + accept(); +} diff --git a/aboutwindow.h b/aboutwindow.h new file mode 100644 index 0000000..aa32be6 --- /dev/null +++ b/aboutwindow.h @@ -0,0 +1,25 @@ +#ifndef ABOUTWINDOW_H +#define ABOUTWINDOW_H + +#include + +namespace Ui { +class AboutWindow; +} + +class AboutWindow : public QDialog +{ + Q_OBJECT + +public: + explicit AboutWindow(QWidget *parent = nullptr); + ~AboutWindow(); + +private slots: + void on_btn_back_clicked(); + +private: + Ui::AboutWindow *ui; +}; + +#endif // ABOUTWINDOW_H diff --git a/aboutwindow.ui b/aboutwindow.ui new file mode 100644 index 0000000..6328433 --- /dev/null +++ b/aboutwindow.ui @@ -0,0 +1,111 @@ + + + AboutWindow + + + + 0 + 0 + 360 + 279 + + + + Dialog + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + + 0 + 0 + + + + + 60 + 60 + + + + + + + Qt::AutoText + + + :/icon.ico + + + true + + + + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">LinkScope</span></p></body></html> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + <html><head/><body><hr width="300"/><p align="center">版本号:V1.0.2</p><p align="center">更新时间:2022/1/29</p><hr width="300"/><p align="center">Developed by Skythinker</p></body></html> + + + + + + + 返回 + + + + + + + + + + diff --git a/helpwindow.cpp b/helpwindow.cpp new file mode 100644 index 0000000..4832e90 --- /dev/null +++ b/helpwindow.cpp @@ -0,0 +1,19 @@ +#include "helpwindow.h" +#include "ui_helpwindow.h" + +HelpWindow::HelpWindow(QWidget *parent) : + QDialog(parent), + ui(new Ui::HelpWindow) +{ + ui->setupUi(this); +} + +HelpWindow::~HelpWindow() +{ + delete ui; +} + +void HelpWindow::on_btn_back_clicked() +{ + accept(); +} diff --git a/helpwindow.h b/helpwindow.h new file mode 100644 index 0000000..277504f --- /dev/null +++ b/helpwindow.h @@ -0,0 +1,25 @@ +#ifndef HELPWINDOW_H +#define HELPWINDOW_H + +#include + +namespace Ui { +class HelpWindow; +} + +class HelpWindow : public QDialog +{ + Q_OBJECT + +public: + explicit HelpWindow(QWidget *parent = nullptr); + ~HelpWindow(); + +private slots: + void on_btn_back_clicked(); + +private: + Ui::HelpWindow *ui; +}; + +#endif // HELPWINDOW_H diff --git a/helpwindow.ui b/helpwindow.ui new file mode 100644 index 0000000..d29c91b --- /dev/null +++ b/helpwindow.ui @@ -0,0 +1,81 @@ + + + HelpWindow + + + + 0 + 0 + 569 + 504 + + + + LinkScope - Help + + + + + + + + + false + + + + + + true + + + + + 0 + 0 + 523 + 906 + + + + false + + + background-color: white; + + + + + + + 0 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">LinkScope简介</span></p><p>本程序使用QT编写,基于OpenOCD和GDB,用于硬件设备的调试,可以实时查看并修改变量值,有波形绘制和数据导出功能 </p><p>程序支持OpenOCD支持的各种调试器及硬件芯片,如STLink、JLink、CMSIS-DAP等以及STM32全系列等</p><hr><p><span style=" font-weight:600;">使用方法</span></p><p>1.在下拉框中选择调试器和芯片类型,选择Axf文件路径,点击连接即可尝试连接芯片 </p><p>2.在表格最后一行变量名处填写变量名可以添加查看变量,选中变量名按Del键可以删除变量 </p><p>3.在选择窗口中可以查看所选Axf文件包含的变量名,可以一键添加到编辑框或变量列表</p><p>4.编辑【修改变量】列可以修改变量值,双击【图线颜色】列可以选择绘图颜色 </p><p>5.单击【变量名】列选中对应的变量,可以在绘图窗口查看历史数据,并会加粗绘制 </p><p>6.绘图界面说明请到绘图窗口点击操作说明 </p><p>7.点击菜单中的保存/导入配置可以将当前配置保存到INI文件或从文件中恢复配置,点击导出数据可以将获取到的采样数据导出到CSV表格文件</p><hr><p><span style=" font-weight:600;">注意事项 </span></p><p>1.修改Axf路径后需要重新连接 </p><p>2.在【变量名】列不仅能填写单个变量名,还可以填入任何合法的C语言表达式 </p><p>3.连接目标前请确认已使用该调试器为目标芯片下载过指定程序 </p><p>4.若程序闪退后发现下一次运行时无法连接目标,请尝试手动结束openocd.exe进程 </p><p>5.连接配置文件位于openocd/share/openocd/scripts下的target和interface中,用户可按照openocd语法编写配置脚本,放入对应目录下后点击“刷新连接配置”菜单项</p></body></html> + + + Qt::AutoText + + + true + + + + + + + + + + + 返回 + + + + + + + + diff --git a/imgs/run-demo.png b/imgs/run-demo.png index 2e40c93..1a7fc49 100644 Binary files a/imgs/run-demo.png and b/imgs/run-demo.png differ diff --git a/listwindow.cpp b/listwindow.cpp new file mode 100644 index 0000000..fa26500 --- /dev/null +++ b/listwindow.cpp @@ -0,0 +1,271 @@ +#include "listwindow.h" +#include "ui_listwindow.h" + +ListWindow::ListWindow(QWidget *parent) : + QDialog(parent), + ui(new Ui::ListWindow) +{ + ui->setupUi(this); + setWindowTitle("LinkScope - Selector"); + + treeModel=new QStandardItemModel(ui->tree); + ui->tree->setModel(treeModel); + + gdbProcess=new QProcess(); + + setGDBState(true);//启动GDB进程 +} + +ListWindow::~ListWindow() +{ + deleteTempFile();//删除临时文件 + setGDBState(false);//结束GDB进程 + delete gdbProcess; + delete treeModel; + delete ui; +} + +//设置GDB进程状态 +void ListWindow::setGDBState(bool run) +{ + if(run)//启动进程 + { + gdbProcess->setProgram(QCoreApplication::applicationDirPath()+"/gdb/gdb.exe");//设置程序路径 + gdbProcess->setWorkingDirectory(QCoreApplication::applicationDirPath()+"/gdb");//设置工作路径 + gdbProcess->setNativeArguments("-q");//设置gdb在安静模式下打开 + gdbProcess->start(); + runGDBCmd("set confirm off\r\n");//设置不要手动确认 + runGDBCmd("set print pretty on\r\n");//设置结构体规范打印 + } + else//结束进程 + { + gdbProcess->kill(); + } +} + +//向GDB进程发送命令并获取标准输出 +QString ListWindow::runGDBCmd(const QString &input) +{ + gdbProcess->readAllStandardOutput(); + gdbProcess->write(input.toStdString().c_str()); + QString res=""; + do{ + gdbProcess->waitForReadyRead(); + res+=gdbProcess->readAllStandardOutput(); + }while(!res.endsWith("(gdb) ")); + return res; +} + +//使用GDB检查变量名是否为可展开类型 +bool ListWindow::checkCanExpand(const QString &varFullName) +{ + QString whatis=runGDBCmd(QString("whatis %1\r\n").arg(varFullName));//先使用whatis指令判断数组和函数指针 + whatis.remove("type = "); + whatis.remove("\r\n(gdb) "); + if(whatis.contains("[")) + return true; + if(whatis.contains('(')) + return false; + QString ptype=runGDBCmd(QString("ptype %1\r\n").arg(varFullName));//再使用ptype指令判断是否是其他可展开类型 + ptype.remove("type = "); + if(ptype.startsWith("struct")||ptype.startsWith("union")) + return true; + return false; +} + +//从原始变量列表字符串中解析出变量列表 +QStringList ListWindow::parseVarList(const QString &raw) +{ + QStringList list; + QRegExp rootRx("\\s([^ (]*\\(\\*|)([^ )]+)(\\)\\(.*\\)|\\s:\\s\\d+|);");//正则匹配模板 + rootRx.setMinimal(true);//非贪心匹配 + int pos=0; + while((pos=rootRx.indexIn(raw,pos))!=-1) + { + QString name=rootRx.cap(2);//获取截取出的变量名部分 + if(name.contains('*'))//手动剔除'*' + name.remove('*'); + if(name.contains('['))//手动剔除数组长度部分 + name.remove(QRegExp("\\[\\d+\\]")); + list.append(name); + pos+=rootRx.matchedLength(); + } + return list; +} + +//删除一个原始变量列表字符串中的嵌套部分,跳过前offset个字符 +void ListWindow::removeInnerSection(QString &raw,int offset) +{ + for(int startPos=offset;startPosparent->parent)//到父节点为根节点为止 + { + if(curNode->name.contains('['))//若为数组元素,父节点为数组名,直接拼接(无需加'.') + fullName=curNode->parent->name+fullName; + else//非数组类型与父节点拼接时还需加一个'.' + fullName=curNode->parent->name+'.'+fullName; + curNode=curNode->parent;//指针向上移动一层 + } + return fullName; +} + +//解析一个节点的子节点,并更新子节点的可展开状态 +void ListWindow::parseVarChildren(VarNode &node) +{ + if(node.parent==NULL)//传入的是根节点 + { + QString rawVarList=runGDBCmd("info variables\r\n");//使用info variables指令列出axf中所有变量 + QStringList varList=parseVarList(rawVarList);//解析出变量列表 + foreach(QString name,varList)//依次添加子节点并更新可展开状态 + { + node.append(name); + node.children.last().canExpand=checkCanExpand(getVarFullName(node.children.last())); + } + } + else//传入的是普通节点 + { + QString fullName=getVarFullName(node);//计算节点全名 + QString rawVarType=runGDBCmd(QString("whatis %1\r\n").arg(fullName));//使用whatis指令获取类型 + rawVarType.remove("type = "); + rawVarType.remove("\r\n(gdb) "); + if(rawVarType.contains("["))//判定是否为数组类型 + { + QRegExp rx("\\[(\\d+)\\]");//使用正则表达式提取出第一维长度len + rx.setMinimal(true); + rx.indexIn(rawVarType); + int len=rx.cap(1).toInt(); + for(int i=0;isetData((qlonglong)&varTree);//将item的数据指向根节点 + rootItem->appendRow(new QStandardItem());//附加一个空item让树状图显示为可展开 + + treeModel->clear();//清理树状图数据 + treeModel->appendRow(rootItem);//添加根节点item +} + +//树状图展开槽函数 +void ListWindow::on_tree_expanded(const QModelIndex &index) +{ + QStandardItem *item=treeModel->itemFromIndex(index);//获取所展开的item + VarNode &node=*(VarNode*)(item->data().toULongLong());//获取对应的节点 + if(!node.parsed)//若节点未解析过,则进行解析 + { + parseVarChildren(node);//解析该节点的子节点,更新各子节点的可展开状态 + item->removeRows(0,item->rowCount());//先清空当前item下的所有子项 + for(int i=0;isetText(childNode.name);//设定item显示变量名 + childItem->setData((qlonglong)&childNode);//建立item到对应节点的寻址方式 + if(childNode.canExpand)//若该子节点可展开,则添加一个空item使其显示为可展开状态 + childItem->appendRow(new QStandardItem()); + item->appendRow(childItem);//子节点item附加到当前被展开的item下 + } + } +} + +//添加到编辑框按钮槽函数 +void ListWindow::on_btn_add2edit_clicked() +{ + QModelIndex index=ui->tree->currentIndex();//获取当前所选index + if(index.row()==-1) + return; + VarNode &node=*(VarNode*)(treeModel->itemFromIndex(index)->data().toULongLong());//获取所选节点 + if(node.parent) + emit add2Edit(getVarFullName(node));//将变量全名使用信号发出去 +} + +//添加到列表按钮槽函数(逻辑与添加到编辑框相同,仅发送的信号不同) +void ListWindow::on_btn_add2list_clicked() +{ + QModelIndex index=ui->tree->currentIndex(); + if(index.row()==-1) + return; + VarNode &node=*(VarNode*)(treeModel->itemFromIndex(index)->data().toULongLong()); + if(node.parent) + emit add2List(getVarFullName(node)); +} diff --git a/listwindow.h b/listwindow.h new file mode 100644 index 0000000..cea289e --- /dev/null +++ b/listwindow.h @@ -0,0 +1,77 @@ +#ifndef LISTWINDOW_H +#define LISTWINDOW_H + +#include +#include +#include +#include +#include +#include +#include + +namespace Ui { +class ListWindow; +} + +//变量信息结点,用于组成变量树 +class VarNode{ +public: + QString name;//变量名 + QList children;//子节点 + VarNode *parent=NULL;//父节点 + bool canExpand=false;//可展开状态,即该变量类型是否可被展开 + bool parsed=false;//是否已经解析出子节点信息 + VarNode(const QString &_name="",VarNode *_parent=NULL) + { + name=_name; + parent=_parent; + } + void append(const QString &name)//指定变量名添加一个子节点 + { + VarNode node(name,this);//创建一个子节点并将其父节点设为自己 + children.append(node); + } + void clear()//清空数据 + { + children.clear(); + name=""; + canExpand=parsed=false; + } +}; + +class ListWindow : public QDialog +{ + Q_OBJECT + +public: + explicit ListWindow(QWidget *parent = nullptr); + ~ListWindow(); + void loadNewAxfFile(const QString &path); + +signals: + void add2Edit(const QString &name); + void add2List(const QString &name); + +private slots: + void on_tree_expanded(const QModelIndex &index); + void on_btn_add2edit_clicked(); + void on_btn_add2list_clicked(); + +private: + Ui::ListWindow *ui; + QProcess *gdbProcess; + VarNode varTree; + QStandardItemModel *treeModel; + void setGDBState(bool run); + QString runGDBCmd(const QString &input); + QStringList parseVarList(const QString &raw); + void removeInnerSection(QString &raw,int offset=0); + QString getVarFullName(const VarNode &node); + bool checkCanExpand(const QString &varFullName); + void parseVarChildren(VarNode &node); + void updateTempFile(const QString &path); + void deleteTempFile(); + void updateTree(); +}; + +#endif // LISTWINDOW_H diff --git a/listwindow.ui b/listwindow.ui new file mode 100644 index 0000000..953e00b --- /dev/null +++ b/listwindow.ui @@ -0,0 +1,52 @@ + + + ListWindow + + + + 0 + 0 + 400 + 680 + + + + Dialog + + + + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + + + + + + + 添加到编辑框 + + + + + + + 直接添加到列表 + + + + + + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp index 48f66c0..349093f 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -14,6 +14,11 @@ MainWindow::MainWindow(QWidget *parent) graph->setVarList(&varList); graph->show(); + listWindow=new ListWindow(); + listWindow->show(); + connect(listWindow,SIGNAL(add2Edit(const QString &)),this,SLOT(slotOnVarAdd2Edit(const QString &))); + connect(listWindow,SIGNAL(add2List(const QString &)),this,SLOT(slotOnVarAdd2List(const QString &))); + stampTimer=new QElapsedTimer();//创建并运行时间戳定时器 stampTimer->start(); @@ -83,6 +88,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { Q_UNUSED(event); graph->close(); + listWindow->close(); } //ocd进程发生错误,自动断开连接 @@ -162,6 +168,20 @@ void MainWindow::slotTableTimerTrig() } } +//选择器窗口添加到编辑框槽函数 +void MainWindow::slotOnVarAdd2Edit(const QString &name) +{ + tableModel->disconnect(this,SLOT(slotTableEdit(QModelIndex,QModelIndex)));//断开信号连接,否则触发后会直接添加到列表 + tableModel->item(tableModel->rowCount()-1,0)->setText(name); + connect(tableModel,SIGNAL(dataChanged(QModelIndex,QModelIndex)),this,SLOT(slotTableEdit(QModelIndex,QModelIndex)));//恢复信号连接 +} + +//选择器窗口添加到列表槽函数 +void MainWindow::slotOnVarAdd2List(const QString &name) +{ + tableModel->item(tableModel->rowCount()-1,0)->setText(name); +} + //连接按钮点击,触发连接状态切换 void MainWindow::on_bt_conn_clicked() { @@ -326,7 +346,7 @@ void MainWindow::parseGDBRawDisp(QString &raw) } } -//延时制定毫秒数,进行子任务循环 +//延时指定毫秒数,进行子任务循环 void MainWindow::sleep(uint32_t ms) { QTime untilTime=QTime::currentTime().addMSecs(ms); @@ -365,6 +385,7 @@ void MainWindow::on_bt_set_axf_clicked() QFileInfo info(fileName); ui->txt_axf_path->setText(info.filePath()); axfChosen=true; + listWindow->loadNewAxfFile(info.filePath()); } } @@ -478,6 +499,9 @@ void MainWindow::loadFromFile(const QString &filename) } redrawTable();//重绘表格 + + if(axfChosen)//刷新选择窗口 + listWindow->loadNewAxfFile(ui->txt_axf_path->text()); } //导出变量采样数据到指定CSV文件中 @@ -635,39 +659,13 @@ void MainWindow::on_action_export_triggered() //关于菜单栏点击 void MainWindow::on_action_about_triggered() { - //弹出messagebox显示关于信息 - QString str="LinkScope 版本号:V1.0.1\n\n" - "Developed by Skythinker"; - QMessageBox box; - box.setWindowTitle("关于 LinkScope"); - box.setText(str); - box.exec(); + AboutWindow().exec(); } //帮助菜单栏点击 void MainWindow::on_action_help_triggered() { - //弹出messagebox显示帮助信息 - QString str="LinkScope简介\n" - "本程序使用QT编写,基于OpenOCD和GDB,用于硬件设备的调试,可以实时查看并修改变量值,有波形绘制和数据导出功能\n" - "程序支持OpenOCD支持的各种调试器及硬件芯片,如STLink、JLink、CMSIS-DAP等以及STM32全系列等\n\n" - "使用方法\n" - "1.在下拉框中选择调试器和芯片类型,选择Axf文件路径,点击连接即可尝试连接芯片\n" - "2.在表格最后一行变量名处填写变量名可以添加查看变量,选中变量名按Del键可以删除变量\n" - "3.编辑【修改变量】列可以修改变量值,双击【图线颜色】列可以选择绘图颜色\n" - "4.单击【变量名】列选中对应的变量,可以在绘图窗口查看历史数据,并会加粗绘制\n" - "5.绘图界面说明请到绘图窗口点击操作说明\n" - "6.点击菜单中的保存/导入配置可以将当前配置保存到INI文件或从文件中恢复配置,点击导出数据可以将获取到的采样数据导出到CSV表格文件\n\n" - "注意事项\n" - "1.修改Axf路径后需要重新连接\n" - "2.在【变量名】列不仅能填写单个变量名,还可以填入任何合法的C语言表达式\n" - "3.连接目标前请确认已使用该调试器为目标芯片下载过指定程序\n" - "4.若程序闪退后发现下一次运行时无法连接目标,请尝试手动结束openocd.exe进程\n" - "5.连接配置文件位于openocd/share/openocd/scripts下的target和interface中,用户可按照openocd语法编写配置脚本,放入对应目录下后点击“刷新连接配置”菜单项\n"; - QMessageBox box; - box.setWindowTitle("LinkScope 帮助"); - box.setText(str); - box.exec(); + HelpWindow().exec(); } //显示绘图窗口菜单点击 @@ -696,3 +694,74 @@ void MainWindow::setStylesheet() if(qss.open(QIODevice::ReadOnly)) qApp->setStyleSheet(QLatin1String(qss.readAll())); } + +//显示选择窗口菜单点击 +void MainWindow::on_action_show_selector_triggered() +{ + listWindow->show(); + listWindow->activateWindow(); +} + +//反馈菜单点击 +void MainWindow::on_action_feedback_triggered() +{ + QDesktopServices::openUrl(QUrl("https://support.qq.com/product/378753"));//打开反馈页面 +} + +//检查更新 +void MainWindow::checkUpdate() +{ + QNetworkAccessManager *manager=new QNetworkAccessManager; + if(manager->networkAccessible()!=QNetworkAccessManager::Accessible) + manager->setNetworkAccessible(QNetworkAccessManager::Accessible); + connect(manager,&QNetworkAccessManager::finished, + [=](QNetworkReply *reply){ //解析收到的网络数据 + if(reply->error()==QNetworkReply::NoError) + { + QString raw=reply->readAll(); + QRegExp rx("\"tag_name\":\"v([0-9.]+)\"");//正则匹配原始字符串中的版本号 + rx.setMinimal(true); + if(rx.indexIn(raw)!=-1) + { + QString tag=rx.cap(1);//截取出版本号字符串 + if(!tag.isEmpty()) + { + if(tag!=APP_VERSION)//与宏定义中的当前版本号进行比较 + { + QMessageBox msgBox; + msgBox.setWindowTitle("提示"); + msgBox.setText("检查到新版本 V"+tag+" ,是否去更新?"); + msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No); + if(msgBox.exec()==QMessageBox::Yes) + { + QDesktopServices::openUrl(QUrl("https://gitee.com/skythinker/link-scope/releases"));//打开仓库release页面 + } + } + else + { + QMessageBox::information(this,"提示","当前已是最新版本"); + } + } + } + else//正则匹配失败,说明服务器返回的格式有误,无法继续解析 + { + QMessageBox::warning(this,"错误","检查失败,建议点击菜单转到主页查看"); + } + } + else + { + QMessageBox::warning(this,"错误","网络错误,请检查网络"); + } + } + ); + QNetworkRequest request; + request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded"); + request.setUrl(QUrl("https://gitee.com/api/v5/repos/skythinker/link-scope/releases/latest"));//发送get请求到gitee服务器 + manager->get(request); +} + +//检查更新菜单点击 +void MainWindow::on_action_checkupdate_triggered() +{ + checkUpdate(); +} diff --git a/mainwindow.h b/mainwindow.h index 01a3337..ccb92c7 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -19,6 +19,11 @@ #include #include #include +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -39,6 +44,8 @@ private slots: void slotTableEdit(QModelIndex topleft, QModelIndex bottomright); void slotWatchTimerTrig(); void slotTableTimerTrig(); + void slotOnVarAdd2Edit(const QString &name); + void slotOnVarAdd2List(const QString &name); void on_bt_conn_clicked(); void on_bt_set_axf_clicked(); void on_bt_reset_clicked(); @@ -52,6 +59,9 @@ private slots: void on_action_show_graph_triggered(); void on_action_refresh_conf_triggered(); void on_action_homepage_triggered(); + void on_action_show_selector_triggered(); + void on_action_feedback_triggered(); + void on_action_checkupdate_triggered(); private: Ui::MainWindow *ui; @@ -64,6 +74,8 @@ private: GraphWindow *graph;//绘图窗口指针 bool isWatchProcessing=false;//标记当前是否正在处理变量值查看 bool axfChosen=false;//是否已经选择了axf文件 + ListWindow *listWindow; + void checkUpdate(); void setStylesheet(); void setConnState(bool connect); void setOCDState(bool connect); diff --git a/mainwindow.ui b/mainwindow.ui index 09fc99e..26a72b8 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -91,24 +91,23 @@ - - - - Qt::Horizontal - - - - 557 - 20 - - - - + + + 0 + 0 + + 请设置符号文件 + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + @@ -136,8 +135,6 @@ 菜单 - - @@ -151,10 +148,21 @@ + + + + + + 窗口 + + + + + @@ -175,7 +183,7 @@ - 帮助 + 使用说明 @@ -201,6 +209,21 @@ 转到主页 + + + 显示选择窗口 + + + + + 反馈 + + + + + 检查更新 + + diff --git a/qss/light-blue.qss b/qss/light-blue.qss index f4b4cd3..06c0f27 100644 --- a/qss/light-blue.qss +++ b/qss/light-blue.qss @@ -3,7 +3,7 @@ QMainWindow,QDialog{ } *:disabled{ - background: rgb(221, 221, 221); + background: rgb(221, 221, 221); } QGroupBox{ @@ -151,5 +151,31 @@ QMenu::separator{ } QTableView{ - border: 2px solid rgb(85, 170, 255); + border: 2px solid rgb(85, 170, 255); +} + +QTreeView{ + border: 2px solid rgb(85, 170, 255); +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings{ + image: url(:/qss/qss-img/light-blue-tree-closed.png); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings{ + image: url(:/qss/qss-img/light-blue-tree-open.png); +} + +QTreeView::branch:has-siblings:!adjoins-item{ + image: url(:/qss/qss-img/light-blue-tree-vline.png); +} + +QTreeView::branch:has-siblings:adjoins-item{ + image: url(:/qss/qss-img/light-blue-tree-more.png); +} + +QTreeView::branch:!has-children:!has-siblings:adjoins-item{ + image: url(:/qss/qss-img/light-blue-tree-end.png); } diff --git a/qss/qss-img/light-blue-tree-closed.png b/qss/qss-img/light-blue-tree-closed.png new file mode 100644 index 0000000..0aa4543 Binary files /dev/null and b/qss/qss-img/light-blue-tree-closed.png differ diff --git a/qss/qss-img/light-blue-tree-end.png b/qss/qss-img/light-blue-tree-end.png new file mode 100644 index 0000000..322a832 Binary files /dev/null and b/qss/qss-img/light-blue-tree-end.png differ diff --git a/qss/qss-img/light-blue-tree-more.png b/qss/qss-img/light-blue-tree-more.png new file mode 100644 index 0000000..a7390fb Binary files /dev/null and b/qss/qss-img/light-blue-tree-more.png differ diff --git a/qss/qss-img/light-blue-tree-open.png b/qss/qss-img/light-blue-tree-open.png new file mode 100644 index 0000000..2895fa2 Binary files /dev/null and b/qss/qss-img/light-blue-tree-open.png differ diff --git a/qss/qss-img/light-blue-tree-vline.png b/qss/qss-img/light-blue-tree-vline.png new file mode 100644 index 0000000..914c6c2 Binary files /dev/null and b/qss/qss-img/light-blue-tree-vline.png differ diff --git a/res.qrc b/res.qrc index c28f4f1..84ed59d 100644 --- a/res.qrc +++ b/res.qrc @@ -7,5 +7,11 @@ qss/qss-img/light-blue-radiobutton-checked.png qss/qss-img/light-blue-radiobutton-unchecked.png qss/qss-img/light-blue-uparrow.png + qss/qss-img/light-blue-tree-open.png + qss/qss-img/light-blue-tree-closed.png + qss/qss-img/light-blue-tree-end.png + qss/qss-img/light-blue-tree-more.png + qss/qss-img/light-blue-tree-vline.png + icon.ico