Qt SD卡 文件系统挂载、文件预览

/**********************************************************************************
 *                         Qt SD卡 文件系统挂载、文件预览
 * 声明:
 *     1. 验证挂载SD卡;
 *     2. QTreeView显示文件系统文件;
 *     3. UI线程、普通线程通信,以及理解其工作分配;
 *     4. static const的使用;
 *     5. QString与const char *的转换;
 *
 *                                           2015-10-20 晴 深圳 南山平山村 曾剑锋
 *********************************************************************************/

                    \\\\\\\\\\-*- 目录 -*-//////////
                    |    一、cat main.cpp
                    |    二、cat mountthread.h
                    |    三、cat mountthread.cpp
                    |    四、cat mainwidow.h
                    |    五、cat mainwindow.cpp
                    --------------------------------
一、cat main.cpp
    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        /**
         * 1. 创建窗口
         * 2. 设置标题
         * 3. 设置无最大最小化按钮
         * 4. 显示窗口
         */
        MainWindow w;
        w.setWindowTitle("fileSystem");
        w.setWindowFlags(w.windowFlags()& ~Qt::WindowMaximizeButtonHint& ~Qt::WindowMinimizeButtonHint);
        w.show();
    
        return a.exec();
    }

二、cat mountthread.h
    #ifndef MOUNTTHREAD_H
    #define MOUNTTHREAD_H
    
    #include <QThread>
    #include <QString>
    #include <QMessageBox>
    #include <QFileInfo>
    
    /**
     * @brief The MountThread class
     * 挂载文件系统线程,需要创建这个线程的原因如下:
     *     1. 当mountSD按钮被按下的时候,需要使按钮处于无效状态;
     *     2. 当SD卡文件系统挂载完毕时,按钮要处于有效状态;
     *     3. 这么做主要是防止一些误操作,或者也可当作为一种状态提示;
     *     4. 基于以上原因,就出现了preMount()、postMount()这两个信号;
     *     5. preMount()在处理mount之前发出的信号,UI线程可以更新按钮到无效状态;
     *     6. postMout()在处理mount之后发出的信号,UI先生可以更新按钮到有效状态;
     *
     * 其实之所以要这么做,是因为如果这些在UI线程中做,一般在一个函数里完成,UI线程采用
     * 从上到下的程序执行流程,无法更新UI控件的状态,所以目前只能采用这种方式来做。
     */
    class MountThread : public QThread
    {
        Q_OBJECT
    public:
        /**
         * @param exsdNode         扩展sd卡生成的设备节点
         * @param mountNode        要将sd卡挂载到那个文件系统节点上
         * @param parent
         */
        explicit MountThread(QString exsdNode, QString mountNode, QObject *parent = 0);
    
        /**
         * 信号通过传参的方式,后续由UI线程dealWithUi()槽统一处;
         */
        static const int PRE_MOUNT       = 1;
        static const int POST_MOUNT      = 2;
        static const int DEVICE_UNEXIST  = 3;
        /**
         * @brief SLEEP_DELAY_MS
         * 设置mount后等待的时间,这里其实可以不需要,但是本人还是设置了,没有原因   :)
         */
        static const int SLEEP_DELAY_MS = 1000;
    
    signals:
        void preMount(int mesg);
        void postMount(int mesg);
        void deviceUnExist(int mesg);
    
    private:
        /**
         * 重写run方法
         */
        void run();
    
    private:
        /**
         * 扩展sd卡生成的设备节点
         */
        QString exsdNode;
        /**
         * 要将sd卡挂载到那个文件系统节点上
         */
        QString mountNode;
    };
    
    #endif // MOUNTTHREAD_H

三、cat mountthread.cpp
    #include "mountthread.h"
    
    MountThread::MountThread(QString exsdNode, QString mountNode, QObject *parent) :
        QThread(parent)
    {
        /* 获取sd卡设备节点,mount需要挂载到的文件系统节点 */
        this->exsdNode = exsdNode;
        this->mountNode = mountNode;
    }
    
    void MountThread::run()
    {
        /* 发送开始mount信号 */
        emit preMount( PRE_MOUNT );
    
        QFileInfo fileInfo( exsdNode );
        if( fileInfo.exists() ) {
    
            /**
             * 1. 先卸载一下,保证当前次挂载
             * 2. 重新挂载在目标文件节点上
             * 3. 等待一下,这里貌似可以不等待的,没有理由  :)
             */
            system( QString( "umount " ).append( exsdNode ).toLocal8Bit() );
            system( QString( "mount " ).append( exsdNode ).append( " " ).append( mountNode ).toLocal8Bit() );
            msleep( SLEEP_DELAY_MS );
    
        } else {
            /* 设备节点不存在,弹出提示框 */
            /* 2015-11-12 modify : move this to UI thread
            // QMessageBox::warning(NULL, "WARNING", "Please check your SD card has plugin slot.");
            emit deviceUnExist(DEVICE_UNEXIST);
        }
    
        /* 发送结束mount信号 */
        emit postMount( POST_MOUNT );
    }


四、cat mainwidow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QFileSystemModel>
    #include <QThread>
    #include <mountthread.h>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    
    protected:
        void moveEvent(QMoveEvent *);
        void resizeEvent(QResizeEvent *);
        void closeEvent(QCloseEvent *);
    
    private slots:
        void on_detectButton_clicked();
        void on_umountButton_clicked();
        /**
         * 处理MountThread线程发送过来的preMount()和postMount()信号
         */
        void dealwithUi(int mesg);
    
    private:
        QFileSystemModel model;
        Ui::MainWindow *ui;
        MountThread *mountThread;    // 挂载线程
    };
    
    #endif // MAINWINDOW_H

五、cat mainwindow.cpp
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <QFileInfo>
    #include <QMessageBox>
    #include <QTreeView>
    #include <QDebug>
    
    /* sd卡生成的设备节点 */
    #define EXSD_NODE             "/dev/mmcblk1p1"
    /* sd卡挂载的文件系统节点 */
    #define MOUNT_NODE            "/mnt/exsd"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
    
        ui->setupUi(this);
    
        /**
         * 这里主要是设置treeview的一些参数
         */
        ui->showDir->setModel( &model );
        model.setRootPath( MOUNT_NODE );
        ui->showDir->setRootIndex( model.index( MOUNT_NODE ) );
    
        // Demonstrating look and feel features
        ui->showDir->setAnimated( false );
        ui->showDir->setIndentation( 20 );
        ui->showDir->setSortingEnabled( true );
        ui->showDir->setColumnWidth( 0, 250 );
    
        /**
         * 1. 创先mount线程;
         * 2. 绑定信号与槽。
         */
        mountThread = new MountThread( EXSD_NODE, MOUNT_NODE );
        connect( mountThread, SIGNAL(preMount(int)), this, SLOT(dealwithUi(int)) );
        connect( mountThread, SIGNAL(postMount(int)), this, SLOT(dealwithUi(int)) );
    
    }
    
    void MainWindow::dealwithUi(int mesg)
    {
        if( MountThread::PRE_MOUNT == mesg ) {
    
            /* 将button设置为无效效果 */
            ui->detectButton->setEnabled( false );
            ui->umountButton->setEnabled( false );
    
            qDebug() << "premount." << endl;
    
        } else if ( MountThread::POST_MOUNT == mesg ) {
    
            /**
             * 1. 这里一定需要:
             *        model.setRootPath( "/mnt" );
             *     model.setRootPath( MOUNT_NODE );
             * 2. /mnt不是固定的,随便什么值都行,这里主要是为了触发rootPath改变了,在设置回来,
             *        要不然,treeview不会显示。
             */
            model.setRootPath( "/mnt" );
            model.setRootPath( MOUNT_NODE );
            ui->showDir->setRootIndex( model.index( MOUNT_NODE ) );
    
            /* 恢复按钮有效效果 */
            ui->detectButton->setEnabled( true );
            ui->umountButton->setEnabled( true );
    
            qDebug() << "postmount." << endl;
    
        /* 2015-11-12 add this for in UI thread */
        } else if ( MountThread::DEVICE_UNEXIST == mesg ) {
            QMessageBox::warning(NULL, "WARNING", "Please check your SD card has plugin slot.");
        }
    }
    
    void MainWindow::on_detectButton_clicked()
    {
        /**
         * 1. 开启线程,看似无关紧要的,只有短短一行,却包暗含着UI线程与普通线程的区别;
         * 2. UI线程维护UI界面的更新;
         * 3. UI界面不宜做时间很长、耗费资源的事;
         * 4. 普通线程通过发送信号与UI线程进行沟通,处理UI显示更新。
         */
        mountThread->start();
    }
    
    void MainWindow::on_umountButton_clicked()
    {
        /* 卸载sd卡 */
        system( QString( "umount " ).append( EXSD_NODE ).toLocal8Bit() );
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    void MainWindow::moveEvent(QMoveEvent *)
    {
        this->move( QPoint( 0, 0 ) );
    }
    
    void MainWindow::resizeEvent(QResizeEvent *)
    {
        this->showMaximized();
    }
    
    void MainWindow::closeEvent(QCloseEvent *)
    {
        exit(0);
    }

 

posted on 2015-10-19 20:49  zengjf  阅读(1462)  评论(1编辑  收藏  举报

导航