在开始博文之前,先介绍下背景。这篇博文在写作过程中参考了以下资料:
李明录先生博客:
http://blog.csdn.net/liminlu0314/article/details/7276954
http://blog.csdn.net/liminlu0314/article/details/6127755
yhexie博客
http://www.cnblogs.com/yhlx125/archive/2012/12/22/2816049.html
这三篇博文详细清晰,但我之所以还会重新写一遍,原因在于我想梳理思路。本文代码分析尽可能详尽,也会详尽叙述每一过程,期望能者多指缺陷,后来者多有收获。
代码实现环境:
VS2010/gdal1.9.1_vs2010/QT4.8.4
1、首先建立QT Application程序,取名SatImg
2、实现菜单栏,创建File-Open选项,这一过程比较简单
具体参考http://www.cnblogs.com/carfield/archive/2013/06/04/3117337.html
3、通过以上两步,我们实现了菜单,在菜单实现的槽函数slotOpenFile里面,我们只是简单的实现了一些功能,不要亦可。接下来,我们来进行进度条的生成。
4、首先,添加类——C++类,类名取为基类CProcessBase,这时候会生成.h与.cpp文件,我们在这里是要定义一个基类,不要.cpp文件,删除即可。
在头文件里,我们需要申明基类中的函数,变量等,并在结构函数里赋初值。
CProcessBase.h代码
#pragma once #include "qstring.h" class CProcessBase { public: //构造函数,赋初值 CProcessBase() { m_dPosition = 0.0; m_iStepCount = 100; m_iCurStep = 0; m_bIsContinue = true; } ~CProcessBase(void) {} /** * @brief 设置进度信息 * @param pszMsg 进度信息 */ virtual void SetMessage(const char* pszMsg) = 0; /** * @brief 设置进度值 * @param dPosition 进度值 * @return 返回是否取消的状态,true为不取消,false为取消 */ virtual bool SetPosition(double dPosition) = 0; /** * @brief 进度条前进一步,返回true表示继续,false表示取消 * @return 返回是否取消的状态,true为不取消,false为取消 */ virtual bool StepIt() = 0; /** * @brief 设置进度个数 * @param iStepCount 进度个数 */ virtual void SetStepCount(int iStepCount) { ReSetProcess(); m_iStepCount = iStepCount; } /** * @brief 获取进度信息 * @return 返回当前进度信息 */ QString GetMessage() { return m_strMessage; } /** * @brief 获取进度值 * @return 返回当前进度值 */ double GetPosition() { return m_dPosition; } /** * @brief 重置进度条 */ void ReSetProcess() { m_dPosition = 0.0; m_iStepCount = 100; m_iCurStep = 0; m_bIsContinue = true; } //进度信息 QString m_strMessage; //进度值 double m_dPosition; //进度个数 int m_iStepCount; //进度当前个数 int m_iCurStep; //是否取消,值为false时表示计算取消 bool m_bIsContinue; };
5、新建类CProcessDlg,新建类型为QT4Class,继承的基类类型为QProgressDialog,Constructor signature为QWidget *parent,这个类还需要继承之前生成的基类,所以在.h文件继承代码处中需要添加public CProcessBase,包括相应的头文件。同时CProcessDlg(QWidget *parent);改成CProcessDlg(QWidget *parent=0);按理说默认的就是等于0,但是如果不改的话会提示 “CProcessDlg”: 没有合适的默认构造函数可用。
这里还要进行全局函数int STD_API ALGTermProgress的申明,为什么要这个,可以参见文章开头列出的李明录博文
CProcessDlg.h代码
#ifndef CPROCESSDLG_H #define CPROCESSDLG_H #include <QProgressDialog> #include "CProcessBase.h" #ifndef STD_API #define STD_API __stdcall #endif /** *全局函数,在类之外声明 * \brief 调用GDAL进度条接口 * * 该函数用于将GDAL算法中的进度信息导出到CProcessBase基类中,供给界面显示 * * @param dfComplete 完成进度值,其取值为 0.0 到 1.0 之间 * @param pszMessage 进度信息 * @param pProgressArg CProcessBase的指针 * * @return 返回TRUE表示继续计算,否则为取消 */ int STD_API ALGTermProgress( double dfComplete, const char *pszMessage, void * pProgressArg ); class CProcessDlg : public QProgressDialog, public CProcessBase { Q_OBJECT public: //parent=0,如果为0(默认),新的窗口部件将是一个顶层部件部件。如果不是,它将会使parent的一个孩子,并且被parent的几何形状所强迫(除非你指定Qt.Window作为视窗标识)。 CProcessDlg(QWidget *parent=0); ~CProcessDlg(); /** * @brief 设置进度信息 * @param pszMsg 进度信息 */ void SetMessage(const char* pszMsg); /** * @brief 设置进度值 * @param dPosition 进度值 */ bool SetPosition(double dPosition); /** * @brief 进度条前进一步 */ bool StepIt(); public slots: void updateProgress(int); }; #endif // CPROCESSDLG_H
6、在相应的.cpp文件中进行实现:
下面这段代码中的函数并不是所有都需要用到的,例如StepIt,在GDAL提供的函数中就用不到,如果在自己编写的函数中就需要使用
#include "CProcessDlg.h" #include "QCoreApplication" CProcessDlg::CProcessDlg(QWidget *parent) : QProgressDialog(parent) { m_dPosition = 0.0; m_iStepCount = 100; m_iCurStep = 0; //对进度窗口进行设计,之后还可以修改 setModal(true); setLabelText(tr("处理中...")); setAutoClose(false); setAutoReset(false); setCancelButtonText(tr("取消")); setWindowTitle(tr("进度")); //禁用关闭按钮 setWindowFlags(Qt::WindowTitleHint | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); } CProcessDlg::~CProcessDlg() { } /** * \brief 调用GDAL进度条接口 * * 该函数用于将GDAL算法中的进度信息导出到CProcessBase基类中,供给界面显示 * * @param dfComplete 完成进度值,其取值为 0.0 到 1.0 之间 * @param pszMessage 进度信息 * @param pProgressArg CProcessBase的指针 * * @return 返回TRUE表示继续计算,否则为取消 */ int STD_API ALGTermProgress( double dfComplete, const char *pszMessage, void * pProgressArg ) { if(pProgressArg != NULL) { CProcessBase * pProcess = (CProcessBase*) pProgressArg; pProcess->m_bIsContinue = pProcess->SetPosition(dfComplete); if(pProcess->m_bIsContinue) return TRUE; else return FALSE; } else return TRUE; } /** * @brief 设置进度信息 * @param pszMsg 进度信息 */ void CProcessDlg::SetMessage(const char* pszMsg) { if (pszMsg != NULL) { m_strMessage = pszMsg; setLabelText(QString(pszMsg)); } } /** * @brief 设置进度值 * @param dPosition 进度值 */ bool CProcessDlg::SetPosition(double dPosition) { m_dPosition = dPosition; setValue( std::min( 100u, ( uint )( m_dPosition*100.0 ) ) ); QCoreApplication::instance()->processEvents(); if(this->wasCanceled()) return false; return true; } /** * @brief 进度条前进一步,返回false表示终止操作 */ bool CProcessDlg::StepIt() { m_iCurStep ++; m_dPosition = m_iCurStep*1.0 / m_iStepCount; setValue( std::min( 100u, ( uint )( m_dPosition*100.0 ) ) ); QCoreApplication::instance()->processEvents(); if(this->wasCanceled()) return false; return true; } void CProcessDlg::updateProgress(int step) { this->setValue(step); QCoreApplication::instance()->processEvents(); }
7、在satimg.cpp文件中编写实现金字塔的代码
代码编写完后,在实现过程中,出现两个问题,
第一、进度条会进行三次1-100,后来我想到ERDAS也是三次,应该是金字塔文件创建过程中的三个步骤吧,可以用其他算法验证一下,我暂时没有验证,等验证了再更新博客
第二、有时候打开文件不一定会出现进度条,当然也不进行金字塔处理。这点不知道为什么
//************************************************* //************************************************* //************************************************* //************************************************* #include "satimg.h" #include <QFileDialog> #include <QMessageBox> #include "gdal.h" #include "gdal_priv.h" #include "CProcessBase.h" #include "CProcessDlg.h" SatImg::SatImg(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { ui.setupUi(this); //UI先setupUi之后才能实现其他操作 setWindowTitle(tr("SatImgFrame")); creatActions(); creatMenus(); } SatImg::~SatImg() { } void SatImg::creatMenus() { //文件菜单 menuFile = menuBar()->addMenu(tr("File")); //menuFile->addAction(actionNewfile); menuFile->addAction(actionOpenFile); //menuFile->addAction(actionSaveFileSave); //menuFile->addAction(actionExit); } void SatImg::creatActions() { //open file action //actionOpenFile= new QAction(QIcon(":/images/open.png"),tr("Open"),this); actionOpenFile= new QAction(tr("Open"),this); actionOpenFile->setShortcut(QKeySequence(tr("Ctrl+O"))); actionOpenFile->setStatusTip(tr("open file")); //信号函数和槽函数必须要有相同的参数,这样信号和槽函数才能成功连接。 connect(actionOpenFile,SIGNAL(triggered()),this,SLOT(slotOpenFile())); } void SatImg::slotOpenFile() { QString slotFileName=QFileDialog::getOpenFileName(this,tr("Open Image"),".", tr("Image Files(*.jpg *.png *.tif)")); if(slotFileName.length() == 0) { QMessageBox::information(NULL, tr("Path"), tr("You didn't select any files.")); } if (slotFileName!=NULL) { //QString convert to const char* std::string str=std::string(slotFileName.toAscii().data()); const char *ConstCharFileName = str.c_str(); CProcessDlg *pPro = new CProcessDlg(); pPro->setWindowTitle(tr("正在执行金字塔")); pPro->show(); int irev=CreatePyramids(ConstCharFileName,pPro); delete pPro; } } /* *Create Pyramids *pszFileName:影像文件文件名(const char*) */ int SatImg::CreatePyramids(const char* pszFileName,CProcessBase *pProcess=NULL) { GDALAllRegister(); CPLSetConfigOption("USE_RRD","YES");//创建Erdas格式的字塔文件 GDALDatasetH hDataset; hDataset = GDALOpen( pszFileName, GA_ReadOnly ); /* -------------------------------------------------------------------- */ /* Open data file. */ /* -------------------------------------------------------------------- */ GDALDriverH hDriver = GDALGetDatasetDriver(hDataset); const char* pszDriver = GDALGetDriverShortName(hDriver); if (EQUAL(pszDriver, "HFA") || EQUAL(pszDriver, "PCIDSK")) { GDALClose(hDataset); //如果文件是Erdas的img或者PCI的pix格式,创建内金字塔,其他的创建外金字塔 hDataset = GDALOpen( pszFileName, GA_Update ); } if( hDataset == NULL ) { return 0; } /* -------------------------------------------------------------------- */ /* Get File basic infomation */ /* -------------------------------------------------------------------- */ int iWidth = GDALGetRasterXSize(hDataset); int iHeigh = GDALGetRasterYSize(hDataset); int iPixelNum = iWidth * iHeigh; //图像中的总像元个数 int iTopNum = 4096; //顶层金字塔大小,64*64 int iCurNum = iPixelNum / 4; int anLevels[1024] = { 0 }; int nLevelCount = 0; //金字塔级数 do //计算金字塔级数,从第二级到顶层 { anLevels[nLevelCount] = static_cast<int>(pow(2.0, nLevelCount+2)); nLevelCount ++; iCurNum /= 4; } while (iCurNum > iTopNum); const char *pszResampling = "nearest"; //采样方式 GDALProgressFunc pfnProgress=ALGTermProgress; /* -------------------------------------------------------------------- */ /* Generate overviews. */ /* -------------------------------------------------------------------- */ if (nLevelCount > 0 && GDALBuildOverviews( hDataset,pszResampling, nLevelCount, anLevels,0, NULL, pfnProgress, pProcess ) != CE_None ) { return 0; } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ GDALClose(hDataset); GDALDestroyDriverManager(); return 1; }
相应的头文件
#ifndef SATIMG_H #define SATIMG_H /* 第1和第2句定义头文件包含卫哨 目的是防止重复包含头文件 这两句与结尾"#endif"42句结合在一起使用才是完整的 */ #include <QtGui/QMainWindow> #include "ui_satimg.h" #include "CProcessBase.h" #include "CProcessDlg.h" //前置声明 class QAction; class QMenu; class SatImg : public QMainWindow { Q_OBJECT public: SatImg(QWidget *parent = 0, Qt::WFlags flags = 0); ~SatImg(); void creatMenus(); void creatActions(); private: Ui::SatImgClass ui; public slots: void slotOpenFile(); private: QMenu *menuFile; QAction *actionOpenFile; public: int CreatePyramids(const char* pszFileName,CProcessBase *pProgress); }; #endif // SATIMG_H
最后,为了让控件支持显示中文字符
main.cpp
#include "satimg.h" #include <QtGui/QApplication> #include <QTextCodec> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTextCodec::setCodecForTr(QTextCodec::codecForLocale()); SatImg w; w.show(); return a.exec(); }