Qt 嵌入式设备应用程序,通过U盘升级的一种思路
2019-07-12 18:19发布
生成海报
最近在做一个通过U盘升级的功能,程序是运行在ARM Linux Qt平台上的。这个应该是很多嵌入式设备必备的一个功能了,所以把这部分的实现抽出来,做成一个例子供需要的人参考。这只是U盘升级的一种思路,如果有更好的方法,也可以提供相应的意见。
源码下载:softwareupgrade.tar.gz
升级文件的格式是通过tar压缩后的文件以gz结尾的, 可以通过tar命令生成相应的升级文件如update.tar.gz:
tar -czvf update.tar.gz demo
主要思路就是,点击相应的功能后从U盘中选中需要升级的文件update.tar.gz,之后开启一个线程和一个提示正在升级的对话框,以免让用户觉得假死。在线程中完成的事情是:将选中的升级文件复制到应用程序的目录中,然后将update.tar.gz 解压覆盖原来的程序。最后将update.tar.gz删除。发送一个线程结束的信号。
下面就介绍一下实现过程。
MainWindow很简单,只有一个按钮。 点击按钮开启线程,显示提示框,绑定线程结束后的信号。提示框根据信号的参数值来确定升级是否成功。
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString strSrcFile = QFileDialog::getOpenFileName(this, "选择升级文件", ".", "tar (*.gz)");
qDebug() << "strSrcFile" << strSrcFile;
OperateThread *thread = new OperateThread;
thread->setUpgradeFile(strSrcFile);
ShowProgressDialog dialog(this);
connect(thread, SIGNAL(emitFinish(int)), &dialog, SLOT(onThreadFinished(int)));
thread->start();
dialog.exec();
}
运行的效果图:
提示框: void onThreadFinished(int nExitCode) 线程结束后更新提示框。里面还使用到了一些qss,来设置背景。
class ShowProgressDialog : public QDialog
{
Q_OBJECT
public:
explicit ShowProgressDialog(QWidget *parent = 0);
~ShowProgressDialog();
void setTitleText(const QString &strText);
void setMessageText(const QString &strMsg);
public slots:
void on_btnOk_clicked();
void onThreadFinished(int nExitCode);
private:
QLabel *m_labelTitle;
QLabel *m_labelMsg;
QPushButton *m_btnOk;
QLabel *m_labelWait;
QMovie *m_pMovie;
};
ShowProgressDialog::ShowProgressDialog(QWidget *parent) : QDialog(parent)
{
setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint | Qt::Dialog);
setAttribute(Qt::WA_X11DoNotAcceptFocus);
setFocusPolicy(Qt::NoFocus);
//更改背景 {MOD}
QPalette palette = this->palette();
QPixmap pix(":/res/dialog_bg.png");
palette.setBrush(QPalette::Background,QBrush(pix));
setAutoFillBackground(true);
this->setPalette(palette);
resize(410, 260);
setMinimumSize(QSize(410, 260));
setMaximumSize(QSize(410, 260));
m_labelTitle = new QLabel(this);
m_labelMsg = new QLabel(this);
m_btnOk = new QPushButton(this);
m_labelWait = new QLabel(this);
m_pMovie = new QMovie(":/res/loading.gif");
m_labelTitle->setGeometry(QRect(10, 1, 220, 30));
m_labelMsg->setGeometry(QRect(30, 60, 350, 60));
m_labelMsg->setWordWrap(true);
m_btnOk->setGeometry(QRect(320, 180, 58, 58));
m_labelWait->setGeometry(QRect(30, 120, 322, 18));
m_labelWait->setMovie(m_pMovie);
m_pMovie->start();
m_labelTitle->setStyleSheet("font: bold 17px; color: white;");
m_labelMsg->setStyleSheet("font: bold 17px ; color: black; ");
m_btnOk->setStyleSheet("QPushButton{background-image: url(:/res/dialog_ok.png);border: 0px;}"
"QPushButton:pressed{background-image: url(:/res/dialog_ok_p.png);border: 0px;}");
connect(m_btnOk , SIGNAL(clicked()) , this , SLOT(on_btnOk_clicked()));
setTitleText("升级");
setMessageText("正在升级,请勿插拔U盘!");
m_btnOk->hide();
}
ShowProgressDialog::~ShowProgressDialog()
{
delete m_labelTitle;
delete m_labelMsg;
delete m_btnOk;
}
void ShowProgressDialog::setTitleText(const QString &strText)
{
m_labelTitle->setText(strText);
}
void ShowProgressDialog::setMessageText(const QString &strMsg)
{
m_labelMsg->setText(strMsg);
}
void ShowProgressDialog::on_btnOk_clicked()
{
QDialog::accept();
}
void ShowProgressDialog::onThreadFinished(int nExitCode)
{
qDebug() << "nExitCode" << nExitCode;
if (nExitCode == 0)
{
setMessageText("升级成功,请重新上电。");
m_btnOk->show();
m_pMovie->stop();
}
else
{
setMessageText("升级出错!请断电以恢复!");
m_btnOk->show();
m_pMovie->stop();
}
}
线程,继承自QThread,完成复制工作。使用QProcess来完成Linux下的解压和删除的工作。关于Qt的多线程,可以去查找一下其他的教程,这里就不做过多的解释。
class OperateThread : public QThread
{
Q_OBJECT
public:
explicit OperateThread(QObject *parent = 0);
public:
void setUpgradeFile(QString strUpgradeFile)
{
m_UpgradeFile = strUpgradeFile;
}
protected:
void run();
signals:
void emitFinish(int);
public slots:
private:
void OprUpgradeUp();
private:
QString m_UpgradeFile;
};
OperateThread::OperateThread(QObject *parent) : QThread(parent)
{
}
void OperateThread::run()
{
//很复杂的数据处理
OprUpgradeUp();
}
void OperateThread::OprUpgradeUp()
{
#define DEST_DIR "../"
QString destDir = QString("%1/update.tar.gz").arg(DEST_DIR);
if( QFile::copy(m_UpgradeFile, destDir) )
{
qDebug()<<"-------成功-----------";
}
else
{
qDebug()<<"-------出错-----------";
//升级失败
emit emitFinish(1);
return;
}
#ifdef Q_OS_LINUX
QString exe = QString("tar -zxvf %1 -C %2").arg(destDir).arg(DEST_DIR);
QProcess::execute(exe);
//升级成功,自动同步磁盘并删除ARM上的升级包
exe = QString("sync");
QProcess::execute(exe);
exe = QString("rm -rf %1").arg(destDir);
QProcess::execute(exe);
#endif
//升级成功
emit emitFinish(0);
}
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮