本章有3個自定義元件的,這裡就不詳細去細講,後期會有一章全面的講解,由于時間問題,例子裡面中文是對每個代碼的解析,希望簡單去記錄裡面的實作過程:
老規矩,先上頁面布局,後期需要源碼的同學們,留言我會添加進取:

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include "qwintspindelegate.h"
#include "qwfloatspindelegate.h"
#include "qwcomboboxdelegate.h"
#define FixedColumnCount 6 //檔案固定6行
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
//用于狀态欄的資訊顯示
// QLabel *LabCurFile; //目前檔案
QLabel *LabCellPos; //目前單元格行列号
QLabel *LabCellText; //目前單元格内容
QWIntSpinDelegate intSpinDelegate; //整型數
QWFloatSpinDelegate floatSpinDelegate; //浮點數
QWComboBoxDelegate comboBoxDelegate; //清單選擇
// QString fCurFile;//目前檔案名
QStandardItemModel *theModel;//資料模型
QItemSelectionModel *theSelection;//Item選擇模型
// void iniModelFromStringList(QStringList&);//從StringList初始化資料模型
void resetTable(int aRowCount); //表格複位,設定行數
bool saveDataAsStream(QString& aFileName);//将資料儲存為資料流檔案
bool openDataAsStream(QString& aFileName);//讀取資料流檔案
bool saveBinaryFile(QString& aFileName);//儲存為二進制檔案
bool openBinaryFile(QString& aFileName);//打開二進制檔案
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
void on_actOpen_triggered(); //打開檔案
void on_actAppend_triggered(); //添加行
void on_actInsert_triggered();//插入行
void on_actDelete_triggered();//删除行
void on_actSave_triggered();//儲存檔案
void on_actAlignCenter_triggered(); //居中對齊
void on_actFontBold_triggered(bool checked); //字型粗體設定
void on_actAlignLeft_triggered(); //左對齊
void on_actAlignRight_triggered(); //右對齊
void on_actTabReset_triggered(); //表格複位
void on_actSaveBin_triggered(); //儲存為自編碼二進制檔案
void on_actOpenBin_triggered(); //打開自編碼二進制檔案
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDataStream>
#include <QMessageBox>
//#include "qw.h"
void MainWindow::resetTable(int aRowCount)
{ //表格複位,先删除所有行,再設定新的行數,表頭不變
// QStringList headerList;
// headerList<<"測深(m)"<<"垂深(m)"<<"方位(°)"<<"總位移(m)"<<"固井品質"<<"測井取樣";
// theModel->setHorizontalHeaderLabels(headerList); //設定表頭文字
theModel->removeRows(0,theModel->rowCount()); //删除所有行
theModel->setRowCount(aRowCount);//設定新的行數
// QStandardItem *aItem;
// QModelIndex index;
QString str=theModel->headerData(theModel->columnCount()-1,
Qt::Horizontal,Qt::DisplayRole).toString();
for (int i=0;i<theModel->rowCount();i++)
{ //設定最後一列
QModelIndex index=theModel->index(i,FixedColumnCount-1); //擷取模型索引
QStandardItem* aItem=theModel->itemFromIndex(index); //擷取item
aItem->setCheckable(true);
aItem->setData(str,Qt::DisplayRole);
aItem->setEditable(false); //不可編輯
}
}
bool MainWindow::saveDataAsStream(QString &aFileName)
{//将模型資料儲存為Qt預定義編碼的資料檔案
QFile aFile(aFileName); //以檔案方式讀出
if (!(aFile.open(QIODevice::WriteOnly | QIODevice::Truncate)))
return false;
QDataStream aStream(&aFile);
aStream.setVersion(QDataStream::Qt_5_9); //設定版本号,寫入和讀取的版本号要相容
qint16 rowCount=theModel->rowCount(); //資料模型行數
qint16 colCount=theModel->columnCount(); //資料模型列數
aStream<<rowCount; //寫入檔案流,行數
aStream<<colCount;//寫入檔案流,列數
//擷取表頭文字
for (int i=0;i<theModel->columnCount();i++)
{
QString str=theModel->horizontalHeaderItem(i)->text();//擷取表頭文字
aStream<<str; //字元串寫入檔案流,Qt預定義編碼方式
}
//擷取資料區的資料
// qint16 ceShen;
// qreal chuiShen;
// qreal fangWei;
// qreal weiYi;
// QString zhiLiang;
// bool quYang;
// QStandardItem *aItem;
for (int i=0;i<theModel->rowCount();i++)
{
QStandardItem* aItem=theModel->item(i,0); //測深
qint16 ceShen=aItem->data(Qt::DisplayRole).toInt();
aStream<<ceShen;// 寫入檔案流,qint16
aItem=theModel->item(i,1); //垂深
qreal chuiShen=aItem->data(Qt::DisplayRole).toFloat();
aStream<<chuiShen;//寫入檔案流, qreal
aItem=theModel->item(i,2); //方位
qreal fangWei=aItem->data(Qt::DisplayRole).toFloat();
aStream<<fangWei;//寫入檔案流, qreal
aItem=theModel->item(i,3); //位移
qreal weiYi=aItem->data(Qt::DisplayRole).toFloat();
aStream<<weiYi;//寫入檔案流, qreal
aItem=theModel->item(i,4); //固井品質
QString zhiLiang=aItem->data(Qt::DisplayRole).toString();
aStream<<zhiLiang;// 寫入檔案流,字元串
aItem=theModel->item(i,5); //測井
bool quYang=(aItem->checkState()==Qt::Checked);
aStream<<quYang;// 寫入檔案流,bool型
}
aFile.close();
return true;
}
bool MainWindow::openDataAsStream(QString &aFileName)
{ //從Qt預定義流檔案讀入資料
QFile aFile(aFileName); //以檔案方式讀出
if (!(aFile.open(QIODevice::ReadOnly)))
return false;
QDataStream aStream(&aFile); //用文本流讀取檔案
aStream.setVersion(QDataStream::Qt_5_9); //設定流檔案版本号
qint16 rowCount,colCount;
aStream>>rowCount; //讀取行數
aStream>>colCount; //列數
this->resetTable(rowCount); //表格複位
//擷取表頭文字
QString str;
for (int i=0;i<colCount;i++)
aStream>>str; //讀取表頭字元串
//擷取資料區文字,
qint16 ceShen;
qreal chuiShen;
qreal fangWei;
qreal weiYi;
QString zhiLiang;
bool quYang;
QStandardItem *aItem;
QModelIndex index;
for (int i=0;i<rowCount;i++)
{
aStream>>ceShen;//讀取測深, qint16
index=theModel->index(i,0);
aItem=theModel->itemFromIndex(index);
aItem->setData(ceShen,Qt::DisplayRole);
aStream>>chuiShen;//垂深,qreal
index=theModel->index(i,1);
aItem=theModel->itemFromIndex(index);
aItem->setData(chuiShen,Qt::DisplayRole);
aStream>>fangWei;//方位,qreal
index=theModel->index(i,2);
aItem=theModel->itemFromIndex(index);
aItem->setData(fangWei,Qt::DisplayRole);
aStream>>weiYi;//位移,qreal
index=theModel->index(i,3);
aItem=theModel->itemFromIndex(index);
aItem->setData(weiYi,Qt::DisplayRole);
aStream>>zhiLiang;//固井品質,QString
index=theModel->index(i,4);
aItem=theModel->itemFromIndex(index);
aItem->setData(zhiLiang,Qt::DisplayRole);
aStream>>quYang;//bool
index=theModel->index(i,5);
aItem=theModel->itemFromIndex(index);
if (quYang)
aItem->setCheckState(Qt::Checked);
else
aItem->setCheckState(Qt::Unchecked);
}
aFile.close();
return true;
}
bool MainWindow::saveBinaryFile(QString &aFileName)
{ //儲存為純二進制檔案
QFile aFile(aFileName); //以檔案方式讀出
if (!(aFile.open(QIODevice::WriteOnly)))
return false;
QDataStream aStream(&aFile); //用文本流讀取檔案
// aStream.setVersion(QDataStream::Qt_5_9); //無需設定資料流的版本
aStream.setByteOrder(QDataStream::LittleEndian);//windows平台
// aStream.setByteOrder(QDataStream::BigEndian);//QDataStream::LittleEndian
qint16 rowCount=theModel->rowCount();
qint16 colCount=theModel->columnCount();
aStream.writeRawData((char *)&rowCount,sizeof(qint16)); //寫入檔案流
aStream.writeRawData((char *)&colCount,sizeof(qint16));//寫入檔案流
//擷取表頭文字
// QString str;
QByteArray btArray;
QStandardItem *aItem;
for (int i=0;i<theModel->columnCount();i++)
{
aItem=theModel->horizontalHeaderItem(i); //擷取表頭item
QString str=aItem->text(); //擷取表頭文字
btArray=str.toUtf8(); //轉換為字元數組
aStream.writeBytes(btArray,btArray.length()); //寫入檔案流,長度uint型,然後是字元串内容
}
//擷取資料區文字,
// qint16 ceShen;
// qreal chuiShen;
// qreal fangWei;
// qreal weiYi;
// QString zhiLiang;
// bool quYang;
qint8 yes=1,no=0; //分别代表邏輯值 true和false
for (int i=0;i<theModel->rowCount();i++)
{
aItem=theModel->item(i,0); //測深
qint16 ceShen=aItem->data(Qt::DisplayRole).toInt();//qint16類型
aStream.writeRawData((char *)&ceShen,sizeof(qint16));//寫入檔案流
aItem=theModel->item(i,1); //垂深
qreal chuiShen=aItem->data(Qt::DisplayRole).toFloat();//qreal 類型
aStream.writeRawData((char *)&chuiShen,sizeof(qreal));//寫入檔案流
aItem=theModel->item(i,2); //方位
qreal fangWei=aItem->data(Qt::DisplayRole).toFloat();
aStream.writeRawData((char *)&fangWei,sizeof(qreal));
aItem=theModel->item(i,3); //位移
qreal weiYi=aItem->data(Qt::DisplayRole).toFloat();
aStream.writeRawData((char *)&weiYi,sizeof(qreal));
aItem=theModel->item(i,4); //固井品質
QString zhiLiang=aItem->data(Qt::DisplayRole).toString();
btArray=zhiLiang.toUtf8();
aStream.writeBytes(btArray,btArray.length()); //寫入長度,uint,然後是字元串
// aStream.writeRawData(btArray,btArray.length());//對于字元串,應使用writeBytes()函數
aItem=theModel->item(i,5); //測井取樣
bool quYang=(aItem->checkState()==Qt::Checked); //true or false
if (quYang)
aStream.writeRawData((char *)&yes,sizeof(qint8));
else
aStream.writeRawData((char *)&no,sizeof(qint8));
}
aFile.close();
return true;
}
bool MainWindow::openBinaryFile(QString &aFileName)
{//打開二進制檔案
QFile aFile(aFileName); //以檔案方式讀出
if (!(aFile.open(QIODevice::ReadOnly)))
return false;
QDataStream aStream(&aFile); //用文本流讀取檔案
// aStream.setVersion(QDataStream::Qt_5_9); //設定資料流的版本
aStream.setByteOrder(QDataStream::LittleEndian);
// aStream.setByteOrder(QDataStream::BigEndian);
qint16 rowCount,colCount;
aStream.readRawData((char *)&rowCount, sizeof(qint16));
aStream.readRawData((char *)&colCount, sizeof(qint16));
this->resetTable(rowCount);
//擷取表頭文字,但是并不利用
// QByteArray btArray;
char *buf;
uint strLen; //也就是 quint32
// QString str;
for (int i=0;i<colCount;i++)
{
aStream.readBytes(buf,strLen);//同時讀取字元串長度,和字元串内容
QString str=QString::fromLocal8Bit(buf,strLen); //可處理漢字
// btArray.setRawData(buf,strLen);
// str=QString::fromLatin1(btArray);
}
//擷取資料區資料
QStandardItem *aItem;
qint16 ceShen;
qreal chuiShen;
qreal fangWei;
qreal weiYi;
QString zhiLiang;
qint8 quYang; //分别代表邏輯值 true和false
QModelIndex index;
for (int i=0;i<rowCount;i++)
{
aStream.readRawData((char *)&ceShen, sizeof(qint16)); //測深
index=theModel->index(i,0);
aItem=theModel->itemFromIndex(index);
aItem->setData(ceShen,Qt::DisplayRole);
aStream.readRawData((char *)&chuiShen, sizeof(qreal)); //垂深
index=theModel->index(i,1);
aItem=theModel->itemFromIndex(index);
aItem->setData(chuiShen,Qt::DisplayRole);
aStream.readRawData((char *)&fangWei, sizeof(qreal)); //方位
index=theModel->index(i,2);
aItem=theModel->itemFromIndex(index);
aItem->setData(fangWei,Qt::DisplayRole);
aStream.readRawData((char *)&weiYi, sizeof(qreal)); //位移
index=theModel->index(i,3);
aItem=theModel->itemFromIndex(index);
aItem->setData(weiYi,Qt::DisplayRole);
aStream.readBytes(buf,strLen);//固井品質
zhiLiang=QString::fromLocal8Bit(buf,strLen);
// btArray.setRawData(buf,strLen);
// zhiLiang=QString::fromLatin1(btArray);
index=theModel->index(i,4);
aItem=theModel->itemFromIndex(index);
aItem->setData(zhiLiang,Qt::DisplayRole);
aStream.readRawData((char *)&quYang, sizeof(qint8)); //測井取樣
index=theModel->index(i,5);
aItem=theModel->itemFromIndex(index);
if (quYang==1)
aItem->setCheckState(Qt::Checked);
else
aItem->setCheckState(Qt::Unchecked);
}
aFile.close();
return true;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
theModel = new QStandardItemModel(5,FixedColumnCount,this); //建立資料模型
QStringList headerList;
headerList<<"Depth"<<"Measured Depth"<<"Direction"<<"Offset"<<"Quality"<<"Sampled";
theModel->setHorizontalHeaderLabels(headerList); //設定表頭文字
theSelection = new QItemSelectionModel(theModel);//Item選擇模型
connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
//為tableView設定資料模型
ui->tableView->setModel(theModel); //設定資料模型
ui->tableView->setSelectionModel(theSelection);//設定選擇模型
//為各列設定自定義代理元件
ui->tableView->setItemDelegateForColumn(0,&intSpinDelegate); //測深,整數
ui->tableView->setItemDelegateForColumn(1,&floatSpinDelegate); //浮點數
ui->tableView->setItemDelegateForColumn(2,&floatSpinDelegate); //浮點數
ui->tableView->setItemDelegateForColumn(3,&floatSpinDelegate); //浮點數
ui->tableView->setItemDelegateForColumn(4,&comboBoxDelegate); //Combbox選擇型
resetTable(5); //表格複位
setCentralWidget(ui->tabWidget); //
//建立狀态欄元件
// LabCurFile = new QLabel("目前檔案:",this);
// LabCurFile->setMinimumWidth(300);
LabCellPos = new QLabel("目前單元格:",this);
LabCellPos->setMinimumWidth(180);
LabCellPos->setAlignment(Qt::AlignHCenter);
LabCellText = new QLabel("單元格内容:",this);
LabCellText->setMinimumWidth(200);
// ui->statusBar->addWidget(LabCurFile);
ui->statusBar->addWidget(LabCellPos);
ui->statusBar->addWidget(LabCellText);
// ui->statusBar->addWidget(LabSelectionRange);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
{
if (current.isValid())
{
LabCellPos->setText(QString::asprintf("目前單元格:%d行,%d列",
current.row(),current.column()));
QStandardItem *aItem;
aItem=theModel->itemFromIndex(current); //從模型索引獲得Item
this->LabCellText->setText("單元格内容:"+aItem->text());
QFont font=aItem->font();
ui->actFontBold->setChecked(font.bold());
}
}
void MainWindow::on_actOpen_triggered()
{
QString curPath=QDir::currentPath();
//調用打開檔案對話框打開一個檔案
QString aFileName=QFileDialog::getOpenFileName(this,tr("打開一個檔案"),curPath,
"流資料檔案(*.stm)");
if (aFileName.isEmpty())
return; //
if (openDataAsStream(aFileName)) //儲存為流資料檔案
QMessageBox::information(this,"提示消息","檔案已經打開!");
}
void MainWindow::on_actAppend_triggered()
{ //添加行
QList<QStandardItem*> aItemList; //容器類
QStandardItem *aItem;
QString str;
for(int i=0;i<FixedColumnCount-2;i++)
{
aItem=new QStandardItem("0"); //建立Item
aItemList<<aItem; //添加到容器
}
aItem=new QStandardItem("優"); //建立Item
aItemList<<aItem; //添加到容器
str=theModel->headerData(theModel->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();
aItem=new QStandardItem(str); //建立Item
aItem->setCheckable(true);
aItem->setEditable(false);
aItemList<<aItem; //添加到容器
theModel->insertRow(theModel->rowCount(),aItemList); //插入一行,需要每個Cell的Item
QModelIndex curIndex=theModel->index(theModel->rowCount()-1,0);//建立最後一行的ModelIndex
theSelection->clearSelection();
theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}
void MainWindow::on_actInsert_triggered()
{//插入行
QList<QStandardItem*> aItemList; //QStandardItem的容器類
QStandardItem *aItem;
QString str;
for(int i=0;i<FixedColumnCount-2;i++)
{
aItem=new QStandardItem("0"); //建立一個QStandardItem
aItemList<<aItem;//添加到容器類
}
aItem=new QStandardItem("優"); //建立一個QStandardItem
aItemList<<aItem;//添加到容器類
str=theModel->headerData(theModel->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();
aItem=new QStandardItem(str); //建立Item
aItem->setCheckable(true);
aItem->setEditable(false);
aItemList<<aItem;//添加到容器類
// theModel->insertRow(ui->tableView->currentIndex().row(),aItemList);
QModelIndex curIndex=theSelection->currentIndex();
theModel->insertRow(curIndex.row(),aItemList);
theSelection->clearSelection();
theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}
void MainWindow::on_actDelete_triggered()
{ //删除行
QModelIndex curIndex=theSelection->currentIndex();
if (curIndex.row()==theModel->rowCount()-1)//(curIndex.isValid())
theModel->removeRow(curIndex.row());
else
{
theModel->removeRow(curIndex.row());
theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}
}
void MainWindow::on_actSave_triggered()
{ //以Qt預定義編碼儲存資料檔案
QString curPath=QDir::currentPath();
QString aFileName=QFileDialog::getSaveFileName(this,tr("選擇儲存檔案"),curPath,
"Qt預定義編碼資料檔案(*.stm)");
if (aFileName.isEmpty())
return; //
if (saveDataAsStream(aFileName)) //儲存為流資料檔案
QMessageBox::information(this,"提示消息","檔案已經成功儲存!");
}
void MainWindow::on_actAlignCenter_triggered()
{
if (!theSelection->hasSelection())
return;
QModelIndexList selectedIndix=theSelection->selectedIndexes();
QModelIndex aIndex;
QStandardItem *aItem;
for (int i=0;i<selectedIndix.count();i++)
{
aIndex=selectedIndix.at(i);
aItem=theModel->itemFromIndex(aIndex);
aItem->setTextAlignment(Qt::AlignHCenter);
}
}
void MainWindow::on_actFontBold_triggered(bool checked)
{
if (!theSelection->hasSelection())
return;
QModelIndexList selectedIndix=theSelection->selectedIndexes();
QModelIndex aIndex;
QStandardItem *aItem;
QFont font;
for (int i=0;i<selectedIndix.count();i++)
{
aIndex=selectedIndix.at(i);
aItem=theModel->itemFromIndex(aIndex);
font=aItem->font();
font.setBold(checked);
aItem->setFont(font);
}
}
void MainWindow::on_actAlignLeft_triggered()
{
if (!theSelection->hasSelection())
return;
QModelIndexList selectedIndix=theSelection->selectedIndexes();
QModelIndex aIndex;
QStandardItem *aItem;
for (int i=0;i<selectedIndix.count();i++)
{
aIndex=selectedIndix.at(i);
aItem=theModel->itemFromIndex(aIndex);
aItem->setTextAlignment(Qt::AlignLeft);
}
}
void MainWindow::on_actAlignRight_triggered()
{
if (!theSelection->hasSelection())
return;
QModelIndexList selectedIndix=theSelection->selectedIndexes();
QModelIndex aIndex;
QStandardItem *aItem;
for (int i=0;i<selectedIndix.count();i++)
{
aIndex=selectedIndix.at(i);
aItem=theModel->itemFromIndex(aIndex);
aItem->setTextAlignment(Qt::AlignRight);
}
}
void MainWindow::on_actTabReset_triggered()
{//表格複位
resetTable(10);
}
void MainWindow::on_actSaveBin_triggered()
{//儲存二進制檔案
QString curPath=QDir::currentPath();
//調用打開檔案對話框選擇一個檔案
QString aFileName=QFileDialog::getSaveFileName(this,tr("選擇儲存檔案"),curPath,
"二進制資料檔案(*.dat)");
if (aFileName.isEmpty())
return; //
if (saveBinaryFile(aFileName)) //儲存為流資料檔案
QMessageBox::information(this,"提示消息","檔案已經成功儲存!");
}
void MainWindow::on_actOpenBin_triggered()
{//打開二進制檔案
QString curPath=QDir::currentPath();//系統目前目錄
QString aFileName=QFileDialog::getOpenFileName(this,tr("打開一個檔案"),curPath,
"二進制資料檔案(*.dat)");
if (aFileName.isEmpty())
return; //
if (openBinaryFile(aFileName)) //儲存為流資料檔案
QMessageBox::information(this,"提示消息","檔案已經打開!");
}
對于剩下的3個頭檔案,我會上傳項目上,需要的請留言。