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); }