Qt 嵌入式设备应用程序,通过U盘升级的一种思路

最近在做一个通过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);
    //更改背景色
    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);
}

猜你喜欢

转载自blog.csdn.net/qq1113231395/article/details/81867153