近来抽时间写了一个txt、bin、hex格式互转工具,由其中一种格式生成对应名称的其他两种格式文件。记录一下。
平台:Qt Creator 10.0.2
QT版本:Qt 6.2.4 (MinGW 11.2.0 64bit)
下面是widget.cpp原码:
#include <QRegularExpressionValidator>
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->groupBox->setTitle("");//不显示groupBox名
ui->plaTxtEdit_hexBaseAddr->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // 禁用垂直滚动条
ui->plaTxtEdit_hexBaseAddr->setStyleSheet("background-color: #FFFFFF; color:black; font-family:\"Helvetica\"; font-size:28px;");
hex_base_addr = "00000000";
ui->plaTxtEdit_hexBaseAddr->setPlainText(hex_base_addr);
//show pictures of supported txt format
QPixmap pixmap1(":/new/prefix1/txt_examp1.png");
QSize p1Sz = pixmap1.size();
ui->exampPic1->setFixedSize(p1Sz);//根据图片大小来显示
ui->exampPic1->setPixmap(pixmap1);
ui->exampPic1->show();
QPixmap pixmap2(":/new/prefix1/txt_examp2.png");
QSize p2Sz = pixmap2.size();
ui->exampPic2->setFixedSize(p2Sz);
ui->exampPic2->setPixmap(pixmap2);
ui->exampPic2->show();
}
Widget::~Widget()
{
delete ui;
}
typedef enum
{
NONE_FILE_TYPE,
BIN_FILE,
HEX_FILE,
TXT_FILE,
OTHER_FILE_TYPE
}OpenedFileType;
typedef enum
{
NORMAL_DATA,
HEX_FILE_END,
EXPAND_ADDR,
BEGIN_ADDR,
EXPAND_LINE_ADDR,
BEGIN_LINE_ADDR
}HexDataType;
void Widget::on_pushButton_select_clicked()
{
QString curPath = QDir::currentPath(); //获取应用程序当前目录
QString dlgTitle = "打开一个文件"; //设置对话框名称
QString fileFilter = "文本文件(*.txt);;二进制文件(*.bin);;十六进制文件(*.hex)"; //设置过滤文件类型
QString objFileName = QFileDialog::getOpenFileName(this, dlgTitle, curPath, fileFilter);
if (objFileName.isEmpty())
return;
ui->plainTextEdit->setPlainText(objFileName);
openByIO_Whole(objFileName);
}
unsigned char char_to_hex_transfer(char preTransfer)
{
unsigned char result = 0;
if (preTransfer >= 0x30 && preTransfer <= 0x39) // 0~9
{
result = preTransfer - 0x30;
}
else if (preTransfer >= 0x41 && preTransfer <= 0x46) //A ~ F
{
result = preTransfer - 0x41 + 0x0A;
}
else if (preTransfer >= 0x61 && preTransfer <= 0x66) //a ~ f
{
result = preTransfer - 0x61 + 0x0A;
}
return result;
}
unsigned char decToChar_transfer(unsigned char preTranData)
{
if (preTranData <= 9)
{
return preTranData + 0x30;
}
else if (preTranData < 16)
{
return preTranData - 10 + 0x41;
}
return 0x30;
}
/* hex文件解析
* 02 0000 04 0001 F9
* 数据长度 数据写入地址 数据类型 数据 校验
* 数据类型:00数据,01文件结束,02扩展段地址,03开始段地址,04扩展线性地址,05开始线性地址
*/
void charToByte_Transfer(unsigned char *write_buff, char * read_buff, int size)
{
for (int ind = 0; ind < size; ind ++)
{
if (ind % 2)
write_buff[ind/2] |= char_to_hex_transfer(read_buff[ind]);
else
write_buff[ind/2] = (char_to_hex_transfer(read_buff[ind])) << 4;
}
}
uint Widget::hexToBin_Transfer(uint readSize, unsigned char *org_buff, char *obj_buff)
{
uint realSize = 0;
int data_len = 0; //record the length of one line data
unsigned int data_addr = 0;//record the address of one line data
unsigned int curr_data_addr = 0; // point to address that next data going write to
unsigned char hex_buff[16] = {0};
HexDataType data_type = NORMAL_DATA;
for (uint i = 0; i < readSize; i ++)
{
if (org_buff[i] == ':') //begin of line
{
data_len = (org_buff[i+1] - 0x30) * 16 + org_buff[i+2] - 0x30;
data_type = (HexDataType)(org_buff[i+8] - 0x30);
}
else
continue;
switch(data_type)
{
case NORMAL_DATA:
curr_data_addr = char_to_hex_transfer(org_buff[i + 3]) << 12;
curr_data_addr |= char_to_hex_transfer(org_buff[i + 4]) << 8;
curr_data_addr |= char_to_hex_transfer(org_buff[i + 5]) << 4;
curr_data_addr |= char_to_hex_transfer(org_buff[i + 6]);
charToByte_Transfer(hex_buff, (char *)(org_buff + i + 9), data_len*2);
memcpy(obj_buff + data_addr + curr_data_addr, hex_buff, data_len);
realSize += data_len;
break;
case HEX_FILE_END:
break;
case EXPAND_ADDR:
data_addr = char_to_hex_transfer(org_buff[i + 9]) << 12;
data_addr |= char_to_hex_transfer(org_buff[i + 10]) << 8;
data_addr |= char_to_hex_transfer(org_buff[i + 11]) << 4;
data_addr |= char_to_hex_transfer(org_buff[i + 12]);
data_addr <<= 2;
break;
case EXPAND_LINE_ADDR:
data_addr = char_to_hex_transfer(org_buff[i + 9]) << 12;
data_addr |= char_to_hex_transfer(org_buff[i + 10]) << 8;
data_addr |= char_to_hex_transfer(org_buff[i + 11]) << 4;
data_addr |= char_to_hex_transfer(org_buff[i + 12]);
data_addr <<= 16;
break;
default:
break;
}
}
return realSize;
}
uint Widget::binToTxt_Transfer(uint readSize, unsigned char *org_buff, char *obj_buff)
{
uint realSize = 0, lst_realSize = 0;
char tmp_data = 0;
char mid_data = 0;
for (uint i = 0; i < readSize; i ++)
{
obj_buff[realSize] = '0';
obj_buff[realSize + 1] = 'x';
realSize += 2;
mid_data = org_buff[i] >> 4;
if (mid_data >= 0 && mid_data <= 9) // 0~9
{
tmp_data = mid_data + 0x30;
}
else if (mid_data >= 0x0A && mid_data <= 0x0F) //A ~ F
{
tmp_data = mid_data - 0x0A + 0x41;
}
obj_buff[realSize] = tmp_data;
realSize ++;
mid_data = org_buff[i] & 0x0f;
if (mid_data >= 0 && mid_data <= 9) // 0~9
{
tmp_data = mid_data + 0x30;
}
else if (mid_data >= 0x0A && mid_data <= 0x0F) //A ~ F
{
tmp_data = mid_data - 0x0A + 0x41;
}
obj_buff[realSize] = tmp_data;
obj_buff[realSize + 1] = ',';
realSize += 2;
if ((realSize - lst_realSize) == 80) //go to next line per 16bytes
{
obj_buff[realSize] = '\r';
obj_buff[realSize + 1] = '\n';
realSize += 2;
lst_realSize = realSize;
}
}
return realSize;
}
void hexFileLineChecksumCalc_func(char *cal_buff)
{
unsigned short checksum = 0;
unsigned char test_data = 0;
int data_length = char_to_hex_transfer(cal_buff[2]) + ((char_to_hex_transfer(cal_buff[1])) << 4);
//wrong data, return immediately
if (data_length > 16)
return;
checksum = data_length;
data_length = data_length * 2 + 9;
for (int i = 3; i < data_length; i += 2)
{
test_data = char_to_hex_transfer(cal_buff[i + 1]) + ((char_to_hex_transfer(cal_buff[i])) << 4);
checksum += test_data;
}
checksum = 0x100 - checksum%0x100;
cal_buff[data_length] = decToChar_transfer((checksum >> 4) & 0x0f);
cal_buff[data_length + 1] = decToChar_transfer(checksum & 0x0f);
}
uint Widget::binToHex_Transfer(uint readSize, unsigned char *org_buff, char *obj_buff, unsigned int base_addr)
{
uint firstLineSize = 0, ri = 0, wi = 0;
unsigned short tmp_addr = 0, data_addr = 0;
unsigned char tmp_data = 0;
// char mid_data = 0;
const char first_line[] = {':','0','2','0','0','0','0','0','4','0','0','0','0','F','A','\r','\n'};
const char end_line[] = {':','0','0','0','0','0','0','0','1','F','F'};
tmp_addr = base_addr >> 16;
data_addr = base_addr & 0xffff;
firstLineSize = sizeof(first_line);
memcpy(obj_buff, first_line, firstLineSize);
obj_buff[9] = decToChar_transfer((tmp_addr >> 12) & 0x0f);
obj_buff[10] = decToChar_transfer((tmp_addr >> 8) & 0x0f);
obj_buff[11] = decToChar_transfer((tmp_addr >> 4) & 0x0f);
obj_buff[12] = decToChar_transfer(tmp_addr & 0x0f);
hexFileLineChecksumCalc_func(obj_buff);
wi = firstLineSize;
while (ri < readSize)
{
obj_buff[wi] = ':';
tmp_data = (readSize - ri) >= 16?(16):(readSize - ri);
if (tmp_data >= 16)
{
tmp_data = 16;
obj_buff[wi + 1] = 0x31; // '1'
obj_buff[wi + 2] = 0x30; // '0'
}
else
{
obj_buff[wi + 1] = decToChar_transfer((tmp_data >> 4) & 0x0f);
obj_buff[wi + 2] = decToChar_transfer(tmp_data & 0x0f);
}
obj_buff[wi + 3] = decToChar_transfer((data_addr >> 12) & 0x0f);
obj_buff[wi + 4] = decToChar_transfer((data_addr >> 8) & 0x0f);
obj_buff[wi + 5] = decToChar_transfer((data_addr >> 4) & 0x0f);
obj_buff[wi + 6] = decToChar_transfer(data_addr & 0x0f);
obj_buff[wi + 7] = 0x30; //'0'
obj_buff[wi + 8] = 0x30; //'0'
wi += 9;
for (int j = 0; j < tmp_data; j ++)
{
obj_buff[wi] = decToChar_transfer((org_buff[ri] >> 4) & 0x0f);
wi ++;
obj_buff[wi] = decToChar_transfer(org_buff[ri] & 0x0f);
wi ++;
ri ++;
}
hexFileLineChecksumCalc_func(obj_buff + wi - tmp_data*2 - 9);
wi += 2;
obj_buff[wi] = '\r';
obj_buff[wi + 1] = '\n';
wi += 2;
if (data_addr + tmp_data > 0xffff)
{
tmp_addr += 1; //increase 0x10000 offset
memcpy(obj_buff + wi, first_line, firstLineSize);
obj_buff[wi + 9] = decToChar_transfer((tmp_addr >> 12) & 0x0f);
obj_buff[wi + 10] = decToChar_transfer((tmp_addr >> 8) & 0x0f);
obj_buff[wi + 11] = decToChar_transfer((tmp_addr >> 4) & 0x0f);
obj_buff[wi + 12] = decToChar_transfer(tmp_addr & 0x0f);
hexFileLineChecksumCalc_func(obj_buff + wi);
wi += firstLineSize;
data_addr = data_addr + tmp_data - 0x10000;
}
else
data_addr += tmp_data;
}
memcpy(obj_buff + wi, end_line, sizeof(end_line));
return wi + sizeof(end_line);
}
uint Widget::txtToBin_Transfer(uint readSize, char *org_buff, char *obj_buff)
{
uint realSize = 0;
char tmp_data = 0;
for (uint i = 0; i < readSize; i ++)
{
if (org_buff[i] == '0' && (org_buff[i + 1] == 'x' || org_buff[i + 1] == 'X'))
{
i ++;
continue;
}
else if (org_buff[i] >= 0x30 && org_buff[i] <= 0x39) // 0~9
{
tmp_data = org_buff[i] - 0x30;
}
else if (org_buff[i] >= 0x41 && org_buff[i] <= 0x46) //A ~ F
{
tmp_data = org_buff[i] - 0x41 + 0x0A;
}
else if (org_buff[i] >= 0x61 && org_buff[i] <= 0x66) //a ~ f
{
tmp_data = org_buff[i] - 0x61 + 0x0A;
}
else
continue;
if (realSize % 2 == 0)
obj_buff[realSize/2] = tmp_data << 4;
else
{
obj_buff[realSize/2] |= tmp_data;
}
realSize ++;
}
return realSize/2;
}
bool Widget::openByIO_Whole(const QString &tgtFileName)
{
QString objFile1, objFile2, tmpQStrFileName;
uint readSize = 0, writeSize_file1 = 0, writeSize_file2 = 0;
unsigned int hex_start_addr = 0;
bool ok;
char *tmp_buff = NULL, *obj_buff1 = NULL, *obj_buff2 = NULL;
QByteArray org_file_byte_array;
OpenedFileType fileType = NONE_FILE_TYPE;
fileDevice = new QFile(tgtFileName);
if (!fileDevice->exists())
return false;
if (!fileDevice->open(QIODevice::ReadOnly))
return false;
tmpQStrFileName = tgtFileName;
if (tgtFileName.endsWith("txt"))
{
objFile1 = tmpQStrFileName.replace(".txt", ".bin");
objFile2 = tmpQStrFileName.replace(".bin", ".hex");
fileType = TXT_FILE;
}
else if (tgtFileName.endsWith("bin"))
{
objFile1 = tmpQStrFileName.replace(".bin", ".txt");
objFile2 = tmpQStrFileName.replace(".txt", ".hex");
fileType = BIN_FILE;
}
else if (tgtFileName.endsWith("hex"))
{
objFile1 = tmpQStrFileName.replace(".hex", ".bin");
objFile2 = tmpQStrFileName.replace(".bin", ".txt");
fileType = HEX_FILE;
}
else if (tgtFileName.endsWith("TXT"))
{
objFile1 = tmpQStrFileName.replace(".TXT", ".bin");
objFile2 = tmpQStrFileName.replace(".bin", ".hex");
fileType = TXT_FILE;
}
else if (tgtFileName.endsWith("BIN"))
{
objFile1 = tmpQStrFileName.replace(".BIN", ".txt");
objFile2 = tmpQStrFileName.replace(".txt", ".hex");
fileType = BIN_FILE;
}
else if (tgtFileName.endsWith("HEX"))
{
objFile1 = tmpQStrFileName.replace(".HEX", ".bin");
objFile2 = tmpQStrFileName.replace(".bin", ".txt");
fileType = HEX_FILE;
}
ui->label_oprtTip->setText("正在读取文件");
fileStream = new QDataStream(fileDevice);
fileStream->setVersion(QDataStream::Qt_6_2);
fileStream->setByteOrder(QDataStream::LittleEndian);
// fileStream->readRawData(ch,strLen);
readSize = fileDevice->size();
// fileStream->readRawData(tmp_buff, readSize);
switch(fileType)
{
case BIN_FILE:
obj_buff1 = (char *)malloc(readSize*5 + readSize/16*2);
if (obj_buff1 == NULL)
{
ui->label_oprtTip->setText("申请内存失败!");
return false;
}
tmp_buff = (char *)malloc(readSize);
if (tmp_buff == NULL)
{
ui->label_oprtTip->setText("申请内存失败!");
return false;
}
fileStream->readRawData(tmp_buff, readSize);
writeSize_file1 = binToTxt_Transfer(readSize, (unsigned char*)tmp_buff, obj_buff1);
hex_start_addr = hex_base_addr.toInt(&ok, 16);
obj_buff2 = (char *)malloc((readSize+7)*3);
if (obj_buff2 == NULL)
{
ui->label_oprtTip->setText("申请内存失败!");
return false;
}
writeSize_file2 = binToHex_Transfer(readSize, (unsigned char*)tmp_buff, obj_buff2, hex_start_addr);
free(tmp_buff);
tmp_buff = NULL;
break;
case HEX_FILE:
org_file_byte_array = fileDevice->readAll();
tmp_buff = org_file_byte_array.data();
obj_buff1 = (char *)malloc(readSize/2);
if (obj_buff1 == NULL)
{
ui->label_oprtTip->setText("申请内存失败!");
return false;
}
writeSize_file1 = hexToBin_Transfer(readSize, (unsigned char*)tmp_buff, obj_buff1);
obj_buff2 = (char *)malloc(writeSize_file1*5 + writeSize_file1/16*2);
if (obj_buff2 == NULL)
{
ui->label_oprtTip->setText("申请内存失败!");
return false;
}
writeSize_file2 = binToTxt_Transfer(writeSize_file1, (unsigned char*)obj_buff1, obj_buff2);
break;
case TXT_FILE:
org_file_byte_array = fileDevice->readAll();
tmp_buff = org_file_byte_array.data();
obj_buff1 = (char *)malloc(readSize/2);
if (obj_buff1 == NULL)
{
ui->label_oprtTip->setText("申请内存失败!");
return false;
}
writeSize_file1 = txtToBin_Transfer(readSize, tmp_buff, obj_buff1);
hex_start_addr = hex_base_addr.toInt(&ok, 16);
obj_buff2 = (char *)malloc((writeSize_file1+7)*3);
if (obj_buff2 == NULL)
{
ui->label_oprtTip->setText("申请内存失败!");
return false;
}
writeSize_file2 = binToHex_Transfer(writeSize_file1, (unsigned char*)obj_buff1, obj_buff2, hex_start_addr);
break;
default:
break;
}
ui->label_oprtTip->setText("读取完成");
fileDevice->close();
QFile *File1_handle = new QFile(objFile1);
if (!File1_handle->open(QIODevice::WriteOnly))
return false;
fileStream = new QDataStream(File1_handle);
fileStream->setVersion(QDataStream::Qt_6_2);
fileStream->setByteOrder(QDataStream::LittleEndian);
fileStream->writeRawData(obj_buff1, writeSize_file1);
File1_handle->close();
delete fileStream;
delete File1_handle;
QFile *File2_handle = new QFile(objFile2);
if (!File2_handle->open(QIODevice::WriteOnly))
return false;
fileStream = new QDataStream(File2_handle);
fileStream->setVersion(QDataStream::Qt_6_2);
fileStream->setByteOrder(QDataStream::LittleEndian);
fileStream->writeRawData(obj_buff2, writeSize_file2);
File2_handle->close();
delete fileStream;
delete File2_handle;
if (obj_buff1 != NULL)
{
free(obj_buff1);
obj_buff1 = NULL;
}
if (obj_buff2 != NULL)
{
free(obj_buff2);
obj_buff2 = NULL;
}
ui->label_oprtTip->setText("转换完成");
return true;
}
void Widget::on_plaTxtEdit_hexBaseAddr_textChanged()
{
bool ok;
hex_base_addr = ui->plaTxtEdit_hexBaseAddr->toPlainText();
//user only can input letter or number all 8 characters
QRegularExpression expre("^[A-Fa-f0-9]{1,8}$");
if (!expre.match(hex_base_addr).hasMatch())
{
if (hex_base_addr.length() > 0)
{
hex_base_addr = hex_base_addr.left(hex_base_addr.length() - 1);
ui->plaTxtEdit_hexBaseAddr->setPlainText(hex_base_addr);
}
else
{
hex_base_addr = "00000000";
ui->plaTxtEdit_hexBaseAddr->setPlainText(hex_base_addr);
}
}
qDebug()<<hex_base_addr.toInt(&ok, 16);
}
main.cpp代码如下:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setWindowTitle("格式转换器");
w.show();
return a.exec();
}
widget.h代码如下:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QFileDialog>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
uint txtToBin_Transfer(uint readSize, char *org_buff, char *obj_buff);
uint binToTxt_Transfer(uint readSize, unsigned char *org_buff, char *obj_buff);
uint hexToBin_Transfer(uint readSize, unsigned char *org_buff, char *obj_buff);
uint binToHex_Transfer(uint readSize, unsigned char *org_buff, char *obj_buff, unsigned int base_addr);
private slots:
void on_pushButton_select_clicked();
bool openByIO_Whole(const QString &tgtFileName);
void on_plaTxtEdit_hexBaseAddr_textChanged();
private:
Ui::Widget *ui;
QDataStream *fileStream;
QFile *fileDevice;
QString hex_base_addr;
};
#endif // WIDGET_H
widget.ui代码如下
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>20</x>
<y>60</y>
<width>751</width>
<height>161</height>
</rect>
</property>
<property name="title">
<string>GroupBox</string>
</property>
<widget class="QPlainTextEdit" name="plainTextEdit">
<property name="geometry">
<rect>
<x>10</x>
<y>44</y>
<width>621</width>
<height>51</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="pushButton_select">
<property name="geometry">
<rect>
<x>650</x>
<y>70</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>打开</string>
</property>
</widget>
<widget class="QPlainTextEdit" name="plaTxtEdit_hexBaseAddr">
<property name="geometry">
<rect>
<x>50</x>
<y>110</y>
<width>151</width>
<height>41</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label0x">
<property name="geometry">
<rect>
<x>10</x>
<y>110</y>
<width>41</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>0x</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="addrInputTip">
<property name="geometry">
<rect>
<x>220</x>
<y>120</y>
<width>351</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="text">
<string>HEX数据起始地址,输入后不需要按Enter键。</string>
</property>
</widget>
</widget>
<widget class="QLabel" name="label_oprtTip">
<property name="geometry">
<rect>
<x>90</x>
<y>230</y>
<width>521</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>请选择要转换的文件</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="exampPic1">
<property name="geometry">
<rect>
<x>70</x>
<y>360</y>
<width>69</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>示例1</string>
</property>
</widget>
<widget class="QLabel" name="exampPic2">
<property name="geometry">
<rect>
<x>70</x>
<y>470</y>
<width>69</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>示例2</string>
</property>
</widget>
<widget class="QLabel" name="txt_type_tip">
<property name="geometry">
<rect>
<x>70</x>
<y>308</y>
<width>281</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>txt文件仅支持以下两种格式</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
QT工程文件代码如下
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
RC_ICONS = tubiao.ico
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
txtPic.qrc
运行效果如图所示