/*********************************************************************************** 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_OBJECTpublic:/*** @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_OBJECTpublic: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 featuresui->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);}