2026-07-02_14_31_VX5 韩国

This commit is contained in:
2026-07-02 14:32:38 +08:00
parent ea3c3fb234
commit 1074c98eb6
15 changed files with 764 additions and 198 deletions
+1 -1
View File
@@ -1054,7 +1054,7 @@ void InkJetPrinter::timerHandler(void){
qInfo() << "Self check done and send print para to FPGA";
sysPara->devOp->setHighVoltageAmplitudetoSTM32();
sysPara->devOp->writeFpgaCalandar(0);
sysPara->devOp->writeFpgaPrintPara();
sysPara->devOp->writeFpgaPrintPara(true);
if(sysPara->para.Reciclar)
test_flag = 1;
+25 -1
View File
@@ -50,6 +50,9 @@ PrintSetting::PrintSetting(QWidget *parent) :
ui->eleEyeEdgetTriggerInner->click();
ui->radioButtonSynTriggerInner->click();
ui->tabWidget->setCurrentIndex(0);
ui->tabWidget->removeTab(4);
}
PrintSetting::~PrintSetting()
@@ -250,6 +253,18 @@ void PrintSetting::updateSysStatusToUI(){
void PrintSetting::on_pushButtonApplyPulseFix_clicked()
{
float circle = ui->lineEditDiameter->text().toFloat() * 3.1415926;
float pulseNum = ui->lineEditPulsePerCycle->text().toFloat();
if(circle != 0){
auto pulseNumPerMM = 4*pulseNum/circle; //电路和Fpga做了4倍频处理,这里乘以4是为了匹配4倍频的处理进行正确的显示
m_model.encoderPulsePerMm = pulseNumPerMM;
auto b = ui->lineEditTriggerPulsePerMm->blockSignals(true);
ui->lineEditTriggerPulsePerMm->setText(QString::number(pulseNumPerMM));
ui->lineEditTriggerPulsePerMm->blockSignals(b);
}
return;
if(!sysPara)
return;
@@ -385,12 +400,13 @@ void PrintSetting::setTriggerUI(int triggerMode){
if(triggerMode == PRINT_TRIGGER_SYNCHRONIZER)
{
ui->labelEleEyeTriggerPrintDelay->setText(tr("触发延时(毫米)"));
ui->labelEleEyeTriggerIntervalMs->setText(tr("重复间隔(毫米)"));
}
else
{
ui->labelEleEyeTriggerPrintDelay->setText(tr("触发延时(毫秒)"));
}
ui->labelEleEyeTriggerIntervalMs->setText(tr("重复间隔(毫秒)"));
}
ui->labelEleMaskTime->setText(tr("封锁时间(毫秒)"));
}
if(triggerMode == PRINT_TRIGGER_ELEC_EYE_VOLTATE_LEVEL
@@ -582,7 +598,13 @@ void PrintSetting::on_eleEyeEdgetTriggerExternal_clicked()
m_model.eleEyeTriggerSynPrintEn = ui->radioButtonSynTriggerExternal->isChecked();
on_checkEyeTriggerSynPrintEn_clicked(m_model.eleEyeTriggerSynPrintEn);
if(ui->radioButtonEleEyeEdgetTrigger->isChecked())
m_model.triggerMode = PRINT_TRIGGER_ELEC_EYE_EDGE;
else
m_model.triggerMode = PRINT_TRIGGER_ELEC_EYE_VOLTATE_LEVEL;
setEnableEleEyeSetting(true);
setTriggerUI(m_model.triggerMode);
}
void PrintSetting::setEnableSynTriggerSetting(bool flag){
@@ -666,9 +688,11 @@ void PrintSetting::on_radioButtonSynTriggerExternal_clicked()
}
m_model.eleEyeTriggerSynPrintEn = ui->eleEyeEdgetTriggerExternal->isChecked();
on_checkEyeTriggerSynPrintEn_clicked(m_model.eleEyeTriggerSynPrintEn);
setEnableSynTriggerSetting(true);
setEnableEleEyeSetting(!ui->eleEyeEdgetTriggerInner->isChecked());
setTriggerUI(m_model.triggerMode);
}
void PrintSetting::on_radioButtonEleEyeEdgetTrigger_clicked()
+95 -31
View File
@@ -561,39 +561,13 @@
<widget class="QWidget" name="layoutWidget_5">
<property name="geometry">
<rect>
<x>210</x>
<x>230</x>
<y>60</y>
<width>521</width>
<width>341</width>
<height>81</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="2">
<widget class="QPushButton" name="pushButtonApplyPulseFix">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>脉冲数修正</string>
</property>
<property name="icon">
<iconset resource="image.qrc">
<normaloff>:/icon/pulse.png</normaloff>:/icon/pulse.png</iconset>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelTriggerPulsePerMm">
<property name="minimumSize">
@@ -629,7 +603,7 @@
</property>
<property name="maximumSize">
<size>
<width>150</width>
<width>170</width>
<height>37</height>
</size>
</property>
@@ -638,7 +612,7 @@
</property>
</widget>
</item>
<item row="1" column="2">
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxSyncActType">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@@ -839,6 +813,96 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLineEdit" name="lineEditDiameter">
<property name="geometry">
<rect>
<x>400</x>
<y>220</y>
<width>161</width>
<height>31</height>
</rect>
</property>
<property name="inputMethodHints">
<set>Qt::ImhNone</set>
</property>
</widget>
<widget class="QLabel" name="labelDiameter">
<property name="geometry">
<rect>
<x>220</x>
<y>220</y>
<width>171</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>同步器直径(毫米):</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLabel" name="labelPulsePerCycle">
<property name="geometry">
<rect>
<x>260</x>
<y>170</y>
<width>131</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>脉冲数/转:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLineEdit" name="lineEditPulsePerCycle">
<property name="geometry">
<rect>
<x>400</x>
<y>170</y>
<width>161</width>
<height>31</height>
</rect>
</property>
<property name="inputMethodHints">
<set>Qt::ImhNone</set>
</property>
</widget>
<widget class="QPushButton" name="pushButtonApplyPulseFix">
<property name="geometry">
<rect>
<x>400</x>
<y>260</y>
<width>161</width>
<height>37</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>脉冲数修正</string>
</property>
<property name="icon">
<iconset resource="image.qrc">
<normaloff>:/icon/pulse.png</normaloff>:/icon/pulse.png</iconset>
</property>
</widget>
</widget>
<widget class="QWidget" name="other">
<attribute name="title">
@@ -1301,7 +1365,7 @@
</layout>
</widget>
</widget>
<widget class="QWidget" name="tab_2">
<widget class="QWidget" name="debugTab">
<attribute name="title">
<string>调试设置</string>
</attribute>
+5 -13
View File
@@ -32,8 +32,10 @@ greaterThan(QT_VER_MAJ, 5) | greaterThan(QT_VER_MIN, 9) QT += serialbus
greaterThan(QT_MAJOR_VERSION, 4):QMAKE_CXXFLAGS += -fpermissive
greaterThan(QT_MAJOR_VERSION, 4):CONFIG += c++11
# 启用release下带调试信息,详见`VX5 Release编译发行.md`,如果不需要,可以注释掉,但请在软件绝对稳定时注释
CONFIG += qt warn_on debug_and_release
QMAKE_CXXFLAGS += -g
#QMAKE_POST_LINK += ulimit -c unlimited
LIBS += -ldl
@@ -177,7 +179,8 @@ HEADERS += Public.h \
Log/logmessage.h \
Log/logglobal.h \
loginfoctrl.h \
runtimectrl.h
runtimectrl.h \
dump.h
FORMS += \
@@ -232,6 +235,7 @@ SOURCES +=\
mainwidget.cpp \
testprintwidget.cpp\
main.cpp \
dump.cpp \
InkJetPrinter.cpp \
MyInputMethod.cpp \
InputMethod.cpp \
@@ -383,15 +387,3 @@ if(contains(DEFINES,__2451WIFI__))
#INCLUDEPATH += /home/student/newDisk/2451_linux/wpa_supplicant_hostapd/wpa_supplicant_hostapd-0.8/src
#INCLUDEPATH += /home/student/newDisk/2451_linux/wpa_supplicant_hostapd/wpa_supplicant_hostapd-0.8/src/utils
}
+1 -1
View File
@@ -199,7 +199,7 @@ void SystemSetting::applyUIPara(){
quint16 diaphramOffset = 5*(ui->comboBoxDiaphramOffset->currentIndex()+1);
sysPara->para.diaphramOffset = diaphramOffset;
//sysPara->para.mixValveisNewVersion = ui->radioButtonMixValveNewVersion->isChecked();
if(sysPara->devOp->writeFpgaPrintPara() != -1){
if(sysPara->devOp->writeFpgaPrintPara(true) != -1){
QMessageBox::information(this,tr("提示"),tr("应用成功"));
}
emit changeEditMode(sysPara->para.EditMode);
+144
View File
@@ -0,0 +1,144 @@
## 带崩溃转储功能的VX5 Release 编译发行、dump收集、问题分析
由于VX5相比VX4在稳定性上有些许差异,目前VX5在用户端仍然可能存在崩溃问题,作为兜底方案,我们引入了崩溃转储功能。
崩溃转储功能是工程化的软件项目中几乎必有的一个功能,它可以在软件崩溃时,将当前程序的函数调用栈、寄存器状态、内存状态等保存到dump上,开发人员依据dump文件结合程序日志可以快速定位到崩溃的位置。
带崩溃转储的发行版发布、dump收集、问题分析,步骤是:使用带-g编译标记编译release版本、生成带调试符号的可执行文件、分离调试符号生成符号调试表和不带调试符号的发行版可执行程序、将发行版可执行程序发布给用户上机运行、运行过程中触发崩溃、收集dump文件、将dump与之前分离的调试信息表以及发行版可执行程序放在一起,使用 addr2line 等工具封装为脚本将dump中的需要观察的调用栈地址、程序地址等转换为包含源码位置等的信息,最后进行源码分析并修复。
## 项目先决条件
在进行此方式编译发行前,可能需要检查以下先决条件,虽然这些已经在最新 VX5_V6.7.1 和 韩国VX5 项目中默认配置。
1. QtUI.pro 中需包含如下配置:
``` pro
CONFIG += qt warn_on debug_and_release # 启用警告和调试信息
QMAKE_CXXFLAGS += -g # 启用 -g 编译标记
#QMAKE_POST_LINK += ulimit -c unlimited
LIBS += -ldl # 链接 dl 库,用于获取当前程序的基址
# ... 其他内容
# 包含 dump转储功能的头文件和源文件
HEADERS += dump.h
SOURCES += dump.cpp
```
2. `main.cpp` 中需包含 `dump.h` 文件,并在 `QApplication app` 后第一时间调用 `installSignalHandler()` 函数,用于安装信号处理函数。
```cpp
QApplication a(argc, argv);
gAppNameStr = QString::fromUtf8(argv[0]);
installSignalHandlers(); // 这里安装信号处理函数
```
3. `dump.cpp` `dump.h` 已添加至最新的标准VX5、韩国VX5项目中。
4. 用于分离调试符号的脚本 `strip_debug.sh` 已添加至项目源码目录中。
5. 用于分析dump文件的脚本 `resolve_dump.sh` 已添加至项目源码目录中。
## 编译发行
1. 使用QtCreator IDE 一键release编译,或使用VScode 配置命令行,编译release版本的带调试符号的、满足项目需求的可执行文件,得到`QtUI`。
```shell
inkjet@ubuntu:/mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface$ ls ../arm_build/QtUI* -lh
-rwxrwxrwx 1 root root 55M 7月 1 10:22 ../arm_build/QtUI
```
可以看到`QtUI`的大小为55M,说明包含了调试符号,但是因为携带了调试符号,运行时可能会占用更多内存,且不利于用户发行更新,同时还包含了源码信息,存在泄漏风险。为此我们需要将调试符号分离出来,生成符号调试表和不带调试符号的发行版可执行程序。
2. 使用之前编译`QtUI`时使用的交叉编译工具链中的 `objcopy` 工具,将`QtUI`的调试符号分离出来,对于 `InkjetUbuntu-T1` 虚拟机,已经包含了 `objcopy` 工具。
使用命令行分离:进入QtUI所在目录,按如下命令进行操作:
```shell
inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ aarch64-linux-gnu-objcopy --only-keep-debug QtUI QtUI.dbg # 分离调试符号生成符号调试表
inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ aarch64-linux-gnu-objcopy --strip-debug QtUI QtUI # 移除调试符号
inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ aarch64-linux-gnu-objcopy --add-gnu-debuglink=QtUI.dbg QtUI # 关联调试符号文件和发行程序
inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ls ./QtUI* -lh
-rwxrwxrwx 1 root root 6.7M 7月 1 10:43 ./QtUI
-rwxrwxrwx 1 root root 48M 7月 1 10:43 ./QtUI.dbg
```
注意输出结果,一个大小为6.7M的`QtUI`,该文件与平常不带`-g`编译出来的`QtUI`一致,用于用户发布;一个大小为48M的`QtUI.dbg`,存放调试符号信息,用于内部保留日后分析dump文件,两个文件进行了关联,因此两个文件在内部必须成对存放,不可缺一。
第二种方法:使用`strip_debug.sh`脚本分离调试符号
进入QtUI所在目录,按如下命令进行操作:
```shell
inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ./strip_debug.sh
```
或者指定QtUI路径:
```shell
inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ./strip_debug.sh QtUI
```
两种方式都可以生成`QtUI`和`QtUI.dbg`两个文件,此时将 `QtUI` 附上更新说明发布。将 `QtUI.dbg` `QtUI` 打包上传SVN仓库内部存放。
```shell
inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ls ./QtUI_V6.7.1_韩国_2026年7月* -lh
-rwxrwxrwx 1 root root 23M 7月 1 11:11 ./QtUI_V6.7.1_韩国_2026年7月1日11_11_08.zip
```
注意明确标准编译时间,避免与用户端软件编译时间不一致导致的dump文件时间错误。
将携带`QtUI.dbg`的`QtUI_V6.7.1_韩国_2026年7月1日11_11_08.zip`上传至 `https://pc-20181215fqqf/svn/src/QTUI软件版本/VX5` 仓库。
然后仅将 `QtUI`与发行说明打包按正常流程发布。
## 收集dump文件
当用户端或产线测试发生崩溃,dump文件会被收集到`/home/plg/loginfo`目录下。
```shell
cat@lubancat:/home/plg/loginfo$ ls /home/plg/loginfo/dumpfile_2026_07_01_11_33_07.txt -lh
-rw-r--r-- 1 root root 3.1K 7月 1 11:33 /home/plg/loginfo/dumpfile_2026_07_01_11_33_07.txt
```
使用 `QtUI` 的日志导出功能,可将所有 dump 文件导出至U盘,dump 文件格式为 `dumpfile_YYYY_MM_DD_HH_MM_SS.txt`,按照崩溃时间记录。
拿到的dump文件可能如下
```txt
Stack trace info:
Base address: 0x557162e000
/home/plg/QtUI(+0x6b29c) [0x557169929c]
??:?
/home/plg/QtUI(+0x6b96c) [0x557169996c]
??:?
linux-vdso.so.1(__kernel_rt_sigreturn+0) [0x7f9d72458c]
??:0
...... 省略更多....
```
注意dump文件中缺失了源码信息,需要结合之前的`QtUI.dbg`文件进行分析。
## 分析dump文件
由于之前对编译好的`QtUI`进行了调试符号分离,因此崩溃捕获到的dump信息与普通不带`-g`编译的`QtUI`崩溃捕获的dump一样,会缺少调试符号。
因此我们将该dump文件与之前内部保存的 `QtUI` `QtUI.dbg` 放在一起,进行一点处理就可以获得完整的调试源码信息。
执行脚本`resolve_dump.sh`,即可获得完整的dump信息。
```shell
inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ./resolve_dump.sh ./dumpfile_2026_07_01_11_33_07.txt
Base address: 0x557162e000
QtUI 路径: /mnt/hgfs/share/bSpec/arm_build/QtUI
QtUI.dbg: /mnt/hgfs/share/bSpec/arm_build/QtUI.dbg
输出文件: ./dumpfile_2026_07_01_11_33_07_resolved.txt
正在解析 dump 文件: ./dumpfile_2026_07_01_11_33_07.txt
=========================================
Stack trace info:
Base address: 0x557162e000
/home/plg/QtUI(+0x6b29c) [0x557169929c]
createStackTraceFile(char const*, char const*) at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/../800X600_New_SystemProject-_NewInterface/dump.cpp:54
/home/plg/QtUI(+0x6b96c) [0x557169996c]
signalHandler(int) at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/../800X600_New_SystemProject-_NewInterface/dump.cpp:96 (discriminator 9)
linux-vdso.so.1(__kernel_rt_sigreturn+0) [0x7f9d72458c]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZNK7QWidget11windowTitleEv+0xc) [0x7f9d1ad56c]
??:0
/home/plg/QtUI(+0x189f30) [0x55717b7f30]
SetNumDlg::on_btn_confirm_clicked() at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/../800X600_New_SystemProject-_NewInterface/setnumdlg.cpp:39
/home/plg/QtUI(+0x1b14d0) [0x55717df4d0]
SetNumDlg::qt_metacall(QMetaObject::Call, int, void**) at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/tmp/moc_setnumdlg.cpp:147
...... 省略更多....
```
注意输出结果
``` text
SetNumDlg::on_btn_confirm_clicked() at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/../800X600_New_SystemProject-_NewInterface/setnumdlg.cpp:39
```
说明崩溃位于`setnumdlg.cpp`文件的`39`行。同时`resolve_dump.sh`脚本会生成`dumpfile_2026_07_01_11_33_07_resolved.txt`文件。
+106
View File
@@ -0,0 +1,106 @@
#define _GNU_SOURCE
#include <link.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <iostream>
#include <fstream>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <cxxabi.h>
#include <cstdlib>
#include <cstdio>
#include <QString>
#include "dump.h"
#include <QDateTime>
extern QString gAppNameStr;
static uintptr_t g_base_address = 0;
static int find_base_address(struct dl_phdr_info *info, size_t size, void *data)
{
(void)size;
(void)data;
if (info->dlpi_name == nullptr || info->dlpi_name[0] == '\0') {
g_base_address = info->dlpi_addr;
return 1;
}
return 0;
}
static uintptr_t get_base_address()
{
if (g_base_address == 0) {
dl_iterate_phdr(find_base_address, nullptr);
}
return g_base_address;
}
void createStackTraceFile(const char *fileName, const char *appName)
{
std::ofstream file(fileName);
if (!file.is_open()) {
std::cerr << "Error opening file: " << fileName << std::endl;
return;
}
void *array[50];
size_t size;
char **strings;
size = backtrace(array, 50);
if (size == 0) {
std::cerr << "No stack frames obtained" << std::endl;
return;
}
uintptr_t base_addr = get_base_address();
strings = backtrace_symbols(array, size);
file << "Stack trace info:\n";
file << "Base address: 0x" << std::hex << base_addr << std::dec << "\n\n";
for (size_t i = 0; i < size; ++i) {
file << strings[i] << std::endl;
uintptr_t addr = reinterpret_cast<uintptr_t>(array[i]);
uintptr_t offset = addr - base_addr;
char cmd[512];
snprintf(cmd, sizeof(cmd), "addr2line -e %s 0x%lx", appName, offset);
FILE *fp = popen(cmd, "r");
if (fp) {
char line[256];
while (fgets(line, sizeof(line), fp)) {
file << " " << line;
}
pclose(fp);
} else {
std::cerr << "Failed to run addr2line command" << std::endl;
}
file << std::endl;
}
free(strings);
file.close();
}
static void signalHandler(int signum)
{
QString dumpFileName = QString("/home/plg/loginfo/dumpfile_%1.txt").arg(QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss"));
QString appName = gAppNameStr;
createStackTraceFile(dumpFileName.toUtf8().data(), appName.toUtf8().data());
exit(signum);
}
void installSignalHandlers()
{
signal(SIGSEGV, signalHandler);
signal(SIGABRT, signalHandler);
signal(SIGILL, signalHandler);
signal(SIGFPE, signalHandler);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef DUMP_H
#define DUMP_H
void installSignalHandlers();
#endif // DUMP_H
+105
View File
@@ -0,0 +1,105 @@
Stack trace info:
Base address: 0x557162e000
/home/plg/QtUI(+0x6b29c) [0x557169929c]
??:?
/home/plg/QtUI(+0x6b96c) [0x557169996c]
??:?
linux-vdso.so.1(__kernel_rt_sigreturn+0) [0x7f9d72458c]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZNK7QWidget11windowTitleEv+0xc) [0x7f9d1ad56c]
??:0
/home/plg/QtUI(+0x189f30) [0x55717b7f30]
??:?
/home/plg/QtUI(+0x1b14d0) [0x55717df4d0]
??:?
/opt/Qt/lib/libQt5Core.so.5(_ZN11QMetaObject8activateEP7QObjectiiPPv+0x6a8) [0x7f9c72b32c]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZN15QAbstractButton7clickedEb+0x3c) [0x7f9d268e4c]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(+0x2890ec) [0x7f9d2690ec]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(+0x28ac5c) [0x7f9d26ac5c]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZN15QAbstractButton17mouseReleaseEventEP11QMouseEvent+0x184) [0x7f9d26aee4]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZN7QWidget5eventEP6QEvent+0x218) [0x7f9d1c5eb8]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent+0x5c) [0x7f9d181aa0]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZN12QApplication6notifyEP7QObjectP6QEvent+0x1038) [0x7f9d18a5fc]
??:0
/opt/Qt/lib/libQt5Core.so.5(_ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent+0x178) [0x7f9c6fd308]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZN19QApplicationPrivate14sendMouseEventEP7QWidgetP11QMouseEventS1_S1_PS1_R8QPointerIS0_Ebb+0x194) [0x7f9d188c24]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(+0x200590) [0x7f9d1e0590]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(+0x202e9c) [0x7f9d1e2e9c]
??:0
/opt/Qt/lib/libQt5Widgets.so.5(_ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent+0x5c) [0x7f9d181aa0]
??:0
/opt/Qt/lib/libQt5Core.so.5(_ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent+0x178) [0x7f9c6fd308]
??:0
/opt/Qt/lib/libQt5Gui.so.5(_ZN22QGuiApplicationPrivate17processMouseEventEPN29QWindowSystemInterfacePrivate10MouseEventE+0x68c) [0x7f9cb54e3c]
??:0
/opt/Qt/lib/libQt5Gui.so.5(_ZN22QGuiApplicationPrivate17processTouchEventEPN29QWindowSystemInterfacePrivate10TouchEventE+0x17e8) [0x7f9cb53c18]
??:0
/opt/Qt/lib/libQt5Gui.so.5(_ZN22QWindowSystemInterface22sendWindowSystemEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE+0xe0) [0x7f9cb2ce54]
??:0
/opt/Qt/lib/libQt5XcbQpa.so.5(+0x705e8) [0x7f98a005e8]
??:0
/lib/aarch64-linux-gnu/libglib-2.0.so.0(g_main_context_dispatch+0x250) [0x7f9b625a70]
??:0
/lib/aarch64-linux-gnu/libglib-2.0.so.0(+0xaaebc) [0x7f9b67aebc]
??:0
/lib/aarch64-linux-gnu/libglib-2.0.so.0(g_main_context_iteration+0x34) [0x7f9b622f14]
??:0
/opt/Qt/lib/libQt5Core.so.5(_ZN20QEventDispatcherGlib13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE+0x54) [0x7f9c7584c4]
??:0
/opt/Qt/lib/libQt5Core.so.5(_ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE+0xf4) [0x7f9c6fb994]
??:0
/opt/Qt/lib/libQt5Core.so.5(_ZN16QCoreApplication4execEv+0x98) [0x7f9c7045a8]
??:0
/home/plg/QtUI(+0x47350) [0x5571675350]
??:?
/lib/aarch64-linux-gnu/libc.so.6(+0x273fc) [0x7f9c0573fc]
??:0
/lib/aarch64-linux-gnu/libc.so.6(__libc_start_main+0x98) [0x7f9c0574cc]
??:0
/home/plg/QtUI(+0x480d0) [0x55716760d0]
??:?
+55 -26
View File
@@ -36,7 +36,12 @@ FileManageWidget::FileManageWidget(QWidget *parent) :
connect(ui->systemFileListView, &QListWidget::itemSelectionChanged, this, &FileManageWidget::refreshButtonsStatus);
connect(ui->udiskFileListView, &QListWidget::itemSelectionChanged, this, &FileManageWidget::refreshButtonsStatus);
updateUDiskDevList();
m_hasUDisk = checkUDiskPresent();
onUDiskStateChanged();
m_udiskCheckTimer = new QTimer(this);
connect(m_udiskCheckTimer, &QTimer::timeout, this, &FileManageWidget::onUDiskCheckTimeout);
m_udiskCheckTimer->start(1000);
m_focusedListView = ui->systemFileListView;
m_focusedListView->setFocus();
@@ -47,6 +52,7 @@ FileManageWidget::FileManageWidget(QWidget *parent) :
FileManageWidget::~FileManageWidget()
{
m_udiskCheckTimer->stop();
ui->systemFileListView->removeEventFilter(this);
ui->udiskFileListView->removeEventFilter(this);
delete ui;
@@ -94,20 +100,22 @@ void FileManageWidget::onFilterCBoxSelectChanged(int i)
}
m_currFilterType = i;
updateFileListView(ui->systemFileListView);
updateFileListView(ui->udiskFileListView);
refreshFileList(ui->systemFileListView);
if (m_hasUDisk) {
refreshFileList(ui->udiskFileListView);
}
}
void FileManageWidget::onExportBtnClicked()
{
copyFiles(ui->systemFileListView, ui->udiskFileListView);
updateFileListView(ui->udiskFileListView);
refreshFileList(ui->udiskFileListView);
}
void FileManageWidget::onImportBtnClicked()
{
copyFiles(ui->udiskFileListView, ui->systemFileListView);
updateFileListView(ui->systemFileListView);
refreshFileList(ui->systemFileListView);
}
void FileManageWidget::onSelectAllBtnClicked()
@@ -138,37 +146,59 @@ void FileManageWidget::onDelSelectedBtnClicked()
qInfo() << "Delete: " << filename << ", result: " << ret;
}
updateFileListView(m_focusedListView);
refreshFileList(m_focusedListView);
}
void FileManageWidget::updateUDiskDevList()
bool FileManageWidget::checkUDiskPresent()
{
bool hasUDisk = false;
QFile mountsFile("/proc/mounts");
if (mountsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&mountsFile);
while (!in.atEnd()) {
const QString line = in.readLine();
if (line.contains("/udisk ")) {
hasUDisk = true;
break;
}
}
QString mountsContent = QString::fromLocal8Bit(mountsFile.readAll());
mountsFile.close();
if (mountsContent.lastIndexOf("/udisk ") != -1) {
return true;
}
}
return false;
}
if (!hasUDisk) {
bool FileManageWidget::ensureUDiskDocDir()
{
QDir dir(UDISK_DOC_ROOT_DIR);
hasUDisk = dir.exists();
if (!dir.exists()) {
if (!dir.mkpath(UDISK_DOC_ROOT_DIR)) {
qCritical() << "Cannot create UDisk doc dir:" << UDISK_DOC_ROOT_DIR;
return false;
}
qInfo() << "Created UDisk doc dir:" << UDISK_DOC_ROOT_DIR;
}
return true;
}
void FileManageWidget::onUDiskCheckTimeout()
{
bool hasUDisk = checkUDiskPresent();
if (hasUDisk == m_hasUDisk) {
return;
}
m_hasUDisk = hasUDisk;
onUDiskStateChanged();
}
void FileManageWidget::onUDiskStateChanged()
{
ui->udiskSelectBox->clear();
if (hasUDisk) {
if (m_hasUDisk) {
ui->udiskSelectBox->addItem(tr("U盘"));
ui->udiskSelectBox->setCurrentIndex(0);
if (ensureUDiskDocDir()) {
refreshFileList(ui->udiskFileListView);
} else {
ui->udiskFileListView->clear();
}
} else {
ui->udiskFileListView->clear();
}
updateFileListView(ui->udiskFileListView);
}
void FileManageWidget::refreshButtonsStatus()
@@ -187,15 +217,14 @@ void FileManageWidget::refreshButtonsStatus()
ui->selectAllBtn->setEnabled(m_focusedListView->count() != selectedItems.size());
}
int FileManageWidget::updateFileListView(QListWidget* listView)
int FileManageWidget::refreshFileList(QListWidget* listView)
{
QString searchPath = listView->property("searchPath").toString();
// 判断目录是否存在
QDir dir(searchPath);
if(!dir.exists()) {
qCritical() << "Cannot open path: " << searchPath;
return -1;
if (!dir.exists()) {
listView->clear();
return 0;
}
// 根据过滤类型设置过滤器字符串
+9 -3
View File
@@ -3,6 +3,7 @@
#include <QWidget>
#include <QListWidget>
#include <QTimer>
namespace Ui {
class FileManageWidget;
@@ -33,13 +34,16 @@ private slots:
void onSelectAllBtnClicked();
void onCancelAllBtnClicked();
void onDelSelectedBtnClicked();
void updateUDiskDevList();
void onUDiskCheckTimeout();
void refreshButtonsStatus();
private:
int updateFileListView(QListWidget* listView);
bool checkUDiskPresent();
bool ensureUDiskDocDir();
int refreshFileList(QListWidget* listView);
void onUDiskStateChanged();
void copyFiles(QListWidget* from, QListWidget* to);
@@ -48,9 +52,11 @@ private:
int m_currFilterType;
QListWidget* m_focusedListView = nullptr;
// 用于文件显示列表中,存放每个文件名对应的绝对路径所用的数据键
static constexpr int AbsPathRole = Qt::UserRole + 1;
QTimer* m_udiskCheckTimer = nullptr;
bool m_hasUDisk = false;
void applyStyleSheet(); // 应用样式表
};
+3 -104
View File
@@ -1,8 +1,3 @@
#define _GNU_SOURCE // 必须放在所有头文件之前
#include <link.h> // dl_iterate_phdr 的声明
#include <dlfcn.h> // dladdr 等
#include <execinfo.h> // backtrace
#include <QApplication>
#include <QVBoxLayout>
#include <InputMethod.h>
@@ -26,101 +21,9 @@
#include "InkJetPrinter.h"
#include "Log/filelogger.h"
#include <iostream>
#include <fstream>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <cxxabi.h>
#include <cstdlib>
#include <cstdio>
#include <execinfo.h>
#include "dump.h"
QString gAppNameStr = "";//这是个全局变量,用于后续获取当前运行程序的绝对路径
// 全局变量保存基址
static uintptr_t g_base_address = 0;
// 回调函数:找到当前可执行文件的基址
static int find_base_address(struct dl_phdr_info *info, size_t size, void *data) {
// 检查是否是主程序(第一个加载的通常是主程序)
if (info->dlpi_name == nullptr || info->dlpi_name[0] == '\0') {
// 获取第一个段的加载地址(通常是基址)
g_base_address = info->dlpi_addr;
return 1; // 停止遍历
}
return 0; // 继续遍历
}
// 获取程序基址的函数
uintptr_t get_base_address() {
if (g_base_address == 0) {
dl_iterate_phdr(find_base_address, nullptr);
}
return g_base_address;
}
void createStackTraceFile(const char *fileName, const char *appName)
{
std::ofstream file(fileName);
if (!file.is_open()) {
std::cerr << "Error opening file: " << fileName << std::endl;
return;
}
void *array[100];
size_t size;
char **strings;
size = backtrace(array, 100);
if (size == 0) {
std::cerr << "No stack frames obtained" << std::endl;
return;
}
// 获取程序基址(PIE需要)
uintptr_t base_addr = get_base_address();
strings = backtrace_symbols(array, size);
file << "Stack trace info:\n";
file << "Base address: 0x" << std::hex << base_addr << std::dec << "\n\n";
for (size_t i = 0; i < size; ++i) {
file << strings[i] << std::endl;
// 计算偏移地址:实际地址 - 基址
uintptr_t addr = reinterpret_cast<uintptr_t>(array[i]);
uintptr_t offset = addr - base_addr;
char cmd[512];
// 使用偏移地址而不是实际地址
snprintf(cmd, sizeof(cmd), "addr2line -e %s 0x%lx", appName, offset);
FILE *fp = popen(cmd, "r");
if (fp) {
char line[256];
while (fgets(line, sizeof(line), fp)) {
file << " " << line; // 缩进显示更清晰
}
pclose(fp);
} else {
std::cerr << "Failed to run addr2line command" << std::endl;
}
file << std::endl;
}
free(strings);
file.close();
}
void signalHandler(int signum)
{
// 直接指定固定的路径
QString dumpFileName = "/home/plg/doc/dumpfile.txt";
QString appName = gAppNameStr;
createStackTraceFile(dumpFileName.toUtf8().data(), appName.toUtf8().data());
exit(signum);
}
QString gAppNameStr = "";
//#define SYS_CN
@@ -175,10 +78,7 @@ int main(int argc, char *argv[])
QApplication a(argc, argv);
gAppNameStr = QString::fromUtf8(argv[0]);
signal(SIGSEGV, signalHandler);
signal(SIGABRT, signalHandler);
signal(SIGILL, signalHandler);
signal(SIGFPE, signalHandler);
installSignalHandlers();
// 配置日志
QString configFileName = ":/conf/config.ini";
@@ -224,7 +124,6 @@ int main(int argc, char *argv[])
langurageFile= "./thai.qm";
f.setPointSize(12);
f.setPixelSize(12);
}
else if(langurageType=="Vietnamese") {
f.setFamily("Arial");//f.setFamily("Zfull-GB"); //f.setFamily("WenQuanYiMH");//Cambria
+103
View File
@@ -0,0 +1,103 @@
#!/bin/bash
TOOLCHAIN_PREFIX="aarch64-linux-gnu-"
ADDR2LINE="${TOOLCHAIN_PREFIX}addr2line"
if [ -z "$1" ]; then
echo "错误: 请指定 dump 文件路径"
echo "用法: $0 <dump文件路径> [QtUI所在目录]"
echo ""
echo "示例:"
echo " $0 ./dumpfile_2026_07_01_11_33_07.txt"
echo " $0 ./dumpfile_2026_07_01_11_33_07.txt /path/to/QtUI_dir"
exit 1
fi
DUMP_FILE="$1"
if [ ! -f "$DUMP_FILE" ]; then
echo "错误: 找不到 dump 文件: $DUMP_FILE"
exit 1
fi
DUMP_DIR="$(dirname "$DUMP_FILE")"
DUMP_BASENAME="$(basename "$DUMP_FILE")"
DUMP_NAME="${DUMP_BASENAME%.*}"
DUMP_EXT="${DUMP_BASENAME##*.}"
RESOLVED_FILE="${DUMP_DIR}/${DUMP_NAME}_resolved.${DUMP_EXT}"
if [ -n "$2" ]; then
QTUI_DIR="$2"
else
QTUI_DIR="$(cd "$(dirname "$0")" && pwd)"
fi
QTUI_PATH="${QTUI_DIR}/QtUI"
QTUI_DBG="${QTUI_DIR}/QtUI.dbg"
if [ ! -f "$QTUI_PATH" ]; then
echo "错误: 找不到 QtUI 文件: $QTUI_PATH"
echo "请确保 QtUI 和 QtUI.dbg 在同一目录下"
exit 1
fi
if [ ! -f "$QTUI_DBG" ]; then
echo "警告: 找不到 QtUI.dbg 文件: $QTUI_DBG"
echo "addr2line 将仅使用 QtUI 中的调试信息(如果有)"
fi
if ! command -v "$ADDR2LINE" &> /dev/null; then
echo "错误: 找不到 $ADDR2LINE"
exit 1
fi
BASE_ADDR=$(grep -oP 'Base address:\s*\K0x[0-9a-fA-F]+' "$DUMP_FILE")
if [ -z "$BASE_ADDR" ]; then
echo "错误: 无法从 dump 文件中解析 Base address"
exit 1
fi
echo "Base address: $BASE_ADDR"
echo "QtUI 路径: $QTUI_PATH"
echo "QtUI.dbg: $QTUI_DBG"
echo "输出文件: $RESOLVED_FILE"
echo ""
echo "正在解析 dump 文件: $DUMP_FILE"
echo "========================================="
echo ""
ADDR_LINE_REGEX='^(.+/QtUI)\(\+0x([0-9a-fA-F]+)\)\s+\[(0x[0-9a-fA-F]+)\]'
{
while IFS= read -r line; do
if [[ "$line" =~ $ADDR_LINE_REGEX ]]; then
OFFSET="0x${BASH_REMATCH[2]}"
RUNTIME_ADDR="${BASH_REMATCH[3]}"
read -r source_line
RESOLVED=$($ADDR2LINE -e "$QTUI_PATH" -f -C -p "$OFFSET" 2>/dev/null)
echo "$line"
if [ -n "$RESOLVED" ] && [ "$RESOLVED" != "?? ??:0" ] && [ "$RESOLVED" != "?? ??:?" ]; then
echo " $RESOLVED"
else
echo " $source_line"
fi
echo ""
elif [[ "$line" =~ ^Base\ address: ]]; then
echo "$line"
echo ""
elif [[ "$line" =~ ^Stack\ trace\ info: ]]; then
echo "$line"
echo ""
else
echo "$line"
fi
done < "$DUMP_FILE"
echo "========================================="
echo "解析完成"
} | tee "$RESOLVED_FILE"
+61
View File
@@ -0,0 +1,61 @@
#!/bin/bash
TOOLCHAIN="aarch64-linux-gnu-objcopy"
if [ -n "$1" ]; then
QTUI_PATH="$1"
else
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
QTUI_PATH="${SCRIPT_DIR}/QtUI"
fi
if [ ! -f "$QTUI_PATH" ]; then
echo "错误: 找不到 QtUI 文件: $QTUI_PATH"
echo "用法: $0 [QtUI路径]"
exit 1
fi
if ! command -v "$TOOLCHAIN" &> /dev/null; then
echo "错误: 找不到工具链 $TOOLCHAIN"
exit 1
fi
QTUI_DIR="$(dirname "$QTUI_PATH")"
QTUI_NAME="$(basename "$QTUI_PATH")"
QTUI_DBG="${QTUI_DIR}/${QTUI_NAME}.dbg"
echo "目标文件: $QTUI_PATH"
echo ""
echo "步骤 1/3: 分离调试符号..."
$TOOLCHAIN --only-keep-debug "$QTUI_PATH" "$QTUI_DBG"
if [ $? -ne 0 ]; then
echo "错误: 分离调试符号失败"
exit 1
fi
echo "完成: $QTUI_DBG"
echo "步骤 2/3: 移除调试符号..."
$TOOLCHAIN --strip-debug "$QTUI_PATH" "$QTUI_PATH"
if [ $? -ne 0 ]; then
echo "错误: 移除调试符号失败"
exit 1
fi
echo "完成"
echo "步骤 3/3: 关联调试符号文件..."
$TOOLCHAIN --add-gnu-debuglink="$QTUI_DBG" "$QTUI_PATH"
if [ $? -ne 0 ]; then
echo "错误: 关联调试符号文件失败"
exit 1
fi
echo "完成"
echo ""
echo "========== 结果 =========="
ls -lh "$QTUI_PATH" "$QTUI_DBG"
echo ""
echo "操作完成:"
echo " 发行程序: $QTUI_PATH"
echo " 调试符号: $QTUI_DBG"
echo " 注意: 两个文件已关联,必须成对存放"
+39 -12
View File
@@ -44,8 +44,11 @@ TestPrintWidget::TestPrintWidget(QWidget* parent)
// m_ButtonGroup->addButton(ui.btnList, 7);
dialogSaveFile =new DialogSaveFile(0);
connect(dialogSaveFile,SIGNAL(returnMainWidget(int)),this,SIGNAL(sendButtonClickedSignal(int)));
dialogFileOperation = new DialogFileOperation(0);
connect(dialogFileOperation,SIGNAL(openFile(QString,bool)),this,SLOT(onFileOpen(QString,bool)));
connect(dialogFileOperation,SIGNAL(createSceneImage(QString)),this,SLOT(onCreateSceneImage(QString)));
m_CreateImageFlag = false;
m_pSavePicScene = new QGraphicsScene();
@@ -81,11 +84,6 @@ TestPrintWidget::TestPrintWidget(QWidget* parent)
getShowSelectItemText();
});
connect(dialogSaveFile,SIGNAL(returnMainWidget(int)),this,SIGNAL(sendButtonClickedSignal(int)));
connect(dialogFileOperation,SIGNAL(openFile(QString,bool)),this,SLOT(onFileOpen(QString,bool)));
connect(dialogFileOperation,SIGNAL(createSceneImage(QString)),this,SLOT(onCreateSceneImage(QString)));
// ========== 连接所有信号槽 ==========
// 左侧工具栏按钮组
connect(m_ButtonGroup, QOverload<QAbstractButton*>::of(&QButtonGroup::buttonClicked),
@@ -214,12 +212,18 @@ TestPrintWidget::~TestPrintWidget()
if(m_pSavePicScene)
{
delete m_pSavePicScene;
m_pSavePicScene = nullptr;
}
if(m_TextEdit){
delete m_TextEdit;
m_TextEdit = nullptr;
}
if (imageLoader) {
delete imageLoader;
imageLoader = nullptr;
}
}
QPixmap TestPrintWidget::loadIcon(const QString& iconName, const QSize& size)
@@ -233,9 +237,11 @@ void TestPrintWidget::on_openfileButton_pressed()
{
pPicScene->clearSelection();
pPicScene->clearFocus();
if (dialogFileOperation) {
dialogFileOperation->refreshListView(editMode);
dialogFileOperation->exec();
}
}
void TestPrintWidget::addDateItem()
{
@@ -261,7 +267,9 @@ void TestPrintWidget::on_enlargeButton_pressed()
// pViewer->scale(scaleFactor, scaleFactor);
// TODO:: 保留,以后真的要用到放大缩小
((MyView*)pViewer)->ZoomOut();
// ((MyView*)pViewer)->ZoomOut();
auto myView = dynamic_cast<MyView*>(pViewer);
if (myView) myView->ZoomOut();
}
void TestPrintWidget::on_addButton_pressed(const SourceType type)
@@ -294,7 +302,9 @@ void TestPrintWidget::onEditItemDone()
const QString content = m_LineEdit->text();
foreach (QGraphicsItem *item, pPicScene->selectedItems())
{
PicTextItem *pTextItem = (PicTextItem *)item;
PicTextItem* pTextItem = dynamic_cast<PicTextItem*>(item);
if (pTextItem == nullptr) continue;
if(pTextItem->sourceType() == SourceType::TEXT)
pTextItem->setSource(content);
}
@@ -302,8 +312,6 @@ void TestPrintWidget::onEditItemDone()
void TestPrintWidget::getShowSelectItemText()
{
//Scene Test
ui.m_LineEdit->setEnabled(false);
ui.m_LineEdit->setText("");
@@ -314,6 +322,8 @@ void TestPrintWidget::getShowSelectItemText()
PicTextItem* lastSelectedTxtItem = nullptr;
for(auto item : selectedItems) {
PicTextItem* txtItem = dynamic_cast<PicTextItem*>(item);
if (txtItem == nullptr) continue;
if(txtItem->sourceType() != SourceType::IMAGE && txtItem->sourceType() != SourceType::CODE && txtItem->sourceType() != SourceType::UNKNOWN) {
lastSelectedTxtItem = txtItem;
}
@@ -401,6 +411,8 @@ void TestPrintWidget::saveFile(){
int index=0;
foreach (QGraphicsItem *item, items) {
PicTextItem *picText = qgraphicsitem_cast<PicTextItem*>(item);
if (picText == nullptr) continue;
writer.writeStartElement("VBfile"); // 开始子元素 <picscene>
writer.writeTextElement(QString::fromLocal8Bit("pointer_x"), QString::fromLocal8Bit("%1").arg(picText->pos().x()));
writer.writeTextElement(QString::fromLocal8Bit("pointer_y"), QString::fromLocal8Bit("%1").arg(picText->pos().y()));
@@ -431,9 +443,12 @@ void TestPrintWidget::saveFile(){
writer.writeEndElement(); // 结束子元素 </picscene>
}
if (m_printSetting) {
writer.writeEmptyElement("PrintSettings");
if(m_printSetting)
PrintSettingModel::saveToXml(m_printSetting->model(), writer);
}
writer.writeEndElement(); // 结束根元素 </picscenes>
writer.writeEndDocument(); // 结束文档
@@ -468,14 +483,17 @@ void TestPrintWidget::onFileOpen(QString filePath,bool reviewFlag){
QFile file(filePath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { // 以只写模式打开文件
if(reviewFlag)
xmlfileName=filePath;
QXmlStreamReader reader(&file);
if(!m_CreateImageFlag)
{
pPicScene->clear();
pViewer->viewport()->update();
unsigned char SpecialVarEnable = 0;
sysPara->devOp->fpgaWr(0xa4b0,(unsigned char *)&SpecialVarEnable,1);
if (sysPara) sysPara->devOp->fpgaWr(0xa4b0,(unsigned char *)&SpecialVarEnable,1);
}
// 解析 XML,直到结束
while (!reader.atEnd()) {
@@ -683,7 +701,7 @@ void TestPrintWidget::parseVbfile(QXmlStreamReader &reader, bool loadPrintSettin
// Condition= false ;
// CatchValue = -1;
//LogInfo::setRunStatusText(tr("接收文件解析::2"));
if(!sysPara->status.forTemplateUse || m_CreateImageFlag)
if(sysPara!=nullptr && !sysPara->status.forTemplateUse || m_CreateImageFlag)
{
pPictText->setHtml(strCDATA);
}
@@ -967,6 +985,7 @@ void TestPrintWidget::on_delButton_pressed()
foreach (QGraphicsItem *item, pPicScene->selectedItems()) {
pPicScene->removeItem(item);
delete item;
break;
}
}
@@ -1040,9 +1059,12 @@ void TestPrintWidget::onBtnItemConfigClicked()
return;
}
auto item = dynamic_cast<PicTextItem*>(selectedItems[0]);
PicTextItem* item = dynamic_cast<PicTextItem*>(selectedItems[0]);
if (item == nullptr) return;
if(item->sourceType() == SourceType::COUNTER) {
auto counterItem = dynamic_cast<PicCounterItem*>(item);
if (counterItem) {
CounterViewModel vm;
vm.counterType = counterItem->counterType();
vm.digitalNum = counterItem->digitalNum();
@@ -1050,6 +1072,7 @@ void TestPrintWidget::onBtnItemConfigClicked()
vm.enbCustomCharWidth = false;
vm.charWidth = counterItem->charWidth();
emit sig_showEditCounter(vm);
}
return;
}
@@ -1067,12 +1090,14 @@ void TestPrintWidget::onBtnItemConfigClicked()
if(item->sourceType() == SourceType::DATETIME) {
// @see TestPrintWidget::addDateTimeItem
auto dateTimeItem = dynamic_cast<PicDateItem*>(item);
if (dateTimeItem)
emit sig_showEditDateTime(dateTimeItem->model(), dateTimeItem->textItemModel());
return;
}
if(item->sourceType() == SourceType::SCHEDULE_SHIFT) {
auto scheduleItem = dynamic_cast<PicScheduleShiftItem*>(item);
if (scheduleItem)
emit sig_showScheduleShiftsEditor(scheduleItem->schedules(), scheduleItem->textItemModel());
return;
}
@@ -1097,6 +1122,8 @@ void TestPrintWidget::onBtnItemConfigClicked()
void TestPrintWidget::onItemEditorAccepted()
{
if(!itemEditor || !itemEditor->currentItem()) return;
if(itemEditor->currentItem()->source() == SourceType::UNKNOWN) {
// Nothing....
}