演示如何使用QTableView显示列表

Author:kagula@20150415

测试环境:vs2010sp1+qt541

调用者-初始化的时候

TestListTable::TestListTable(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	
	//connect controls with process!
	connect(ui.pbChangeCellValue, SIGNAL(released()), this, SLOT(OnChangeCellValue()));
	connect(ui.pbGrow, SIGNAL(released()), this, SLOT(OnAddRow()));
	connect(ui.pbShrinkColumns, SIGNAL(released()), this, SLOT(OnRemoveRow()));

	//sort by user click table header title!
	QHeaderView *headerGoods = ui.tableView->horizontalHeader();
	//SortIndicator为水平标题栏文字旁边的三角指示器
	headerGoods->setSortIndicator(0, Qt::AscendingOrder);
	headerGoods->setSortIndicatorShown(true);
	connect(headerGoods, SIGNAL(sectionClicked(int)), ui.tableView, SLOT (sortByColumn(int)));

	//Note:below statement which set default sort will not take effect,only you can do is modify the model directly!
	//ui.tableView->sortByColumn(1,Qt::SortOrder::DescendingOrder);
	
	//i have not test.
	//ui.tableView->setAlternatingRowColors(true);

	//set model. the correlation from model to view.
	ui.tableView->setModel(&_myTable);

	//custom cell background color in table
	ui.tableView->setItemDelegate(new ColorDelegate(ui.tableView));

	//change select mode is single row selection. default is single cell selection.
	ui.tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
	ui.tableView->setSelectionMode(QAbstractItemView::SingleSelection);//if no this invoke, user can select multi-rows.

	//hide first anonymous column. by default is show in table.
	ui.tableView->verticalHeader()->hide();

	//set column width in tableView of QTableView.
	ui.tableView->setColumnWidth(0,32);

	//set row height in tableView of QTableView.
	QHeaderView *verticalHeader = ui.tableView->verticalHeader();
	verticalHeader->sectionResizeMode(QHeaderView::Fixed);
	verticalHeader->setDefaultSectionSize(64);

	//set do not show grid line. default have gray grid line.
	ui.tableView->setShowGrid(false);

	//Using QSS for Custom QHeaderView!
	//《Can headeview stylesheet style just the selected section?》
	//http://www.qtforum.org/article/28848/can-headeview-stylesheet-style-just-the-selected-section.html
	//《Qt Style Sheets Examples》
	//http://qt.developpez.com/doc/4.6/stylesheet-examples/
	//ui.tableView->setStyleSheet("QHeaderView::section:horizontal {margin-right: 0; background-color: white;color: blue;font: 10pt \"MS Shell Dlg 2\";padding-left: 4px;border: 1px solid #6c6c6c;}");

	//if you do not like using QSS, you can derive QHeaderView class to custom your table header.
	//MyHeaderView *pHeaderView = new MyHeaderView(Qt::Orientation::Horizontal);
	//pHeaderView->setFixedHeight(32);
	//ui.tableView->setHorizontalHeader(pHeaderView);

	//set grid line style!
	//ui.tableView->setGridStyle(Qt::PenStyle::NoPen);

	/*
	//change default selection row text and background color in table control
	//This method do not need subclass of QItemDelegate but less flexibility!
	const QColor hlClr = Qt::darkYellow; // highlight color to set
	const QColor txtClr = Qt::white; // highlighted text color to set

	QPalette p = palette();
	p.setColor(QPalette::Highlight, hlClr);
	p.setColor(QPalette::HighlightedText, txtClr);
	setPalette(p);
	*/
}


调用者-响应事件的时候

void TestListTable::OnChangeCellValue()
{
	QMessageBox::information(this,"Information",tr("方式类似删除记录,这里不重复了!"));
}

void TestListTable::OnAddRow()
{
	std::vector<QString> record;

	record.push_back(QString("NewLine ID"));
	record.push_back(QString("NewLine Value1"));
	record.push_back(QString("NewLine Value2"));

	_myTable.addRow(record);
}

void TestListTable::OnRemoveRow()
{
	if( ui.tableView)
	{
		QItemSelectionModel *selectionModel = ui.tableView->selectionModel();
		QModelIndexList list = selectionModel->selectedIndexes();

		if (list.size()>0)
		{
			_myTable.removeRow(list[0].row(),list[0]);
		}//end if
	}//end if
}//end func

自定义表头用到的代码

MyHeaderView.h

#ifndef _MyHeaderView_H_
#define _MyHeaderView_H_

#pragma once

#include <QHeaderView>
class MyHeaderView:public QHeaderView
{
	Q_OBJECT
public:
	MyHeaderView(Qt::Orientation orientation, QWidget *parent = 0):QHeaderView( orientation, parent)	{ }
	//void paintEvent ( QPaintEvent * event );//if you want entire redraw using this function.
	void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const;
};

#endif


MyHeaderView.cpp

#include "MyHeaderView.h"
#include <QPainter>
#include <QPaintEvent>
void MyHeaderView::paintSection( QPainter* painter, const QRect& rect, int logicalIndex ) const
{
	const QString strTemp1 = model()->headerData(logicalIndex,Qt::Horizontal).toString().section("[",0,0);
	const QString strTemp2 = model()->headerData(logicalIndex,Qt::Horizontal).toString().section("[",1,1);

	painter->drawText(rect,Qt::AlignLeft,strTemp1+"NewAppended");

	if (!strTemp2.isEmpty())
		painter->drawText(rect,Qt::AlignRight,"[" + strTemp2);

	//QHeaderView::paintSection(painter,rect,logicalIndex);
}
//
//void MyHeaderView::paintEvent( QPaintEvent * event )
//{
//	QPainter painter(this);
//	painter.drawRect(event->rect());
//}


自定义表体用到的代码

ColorDelegate.h

#pragma once

#include <QItemDelegate>

class ColorDelegate: public QItemDelegate
{
public:
	ColorDelegate(QObject *parent = 0) : QItemDelegate(parent) {}

public:
	virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

protected:
	virtual void drawBackground(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
	virtual void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
	virtual void drawArrow2(QPainter *painter, const QStyleOptionViewItem &option) const;
};


ColorDelegate.cpp

#include "ColorDelegate.h"

#include <QApplication>
#include <QtGui>
#include <QPainter>
#include <QImage>

#include "MyTable.h"

void ColorDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
	Q_ASSERT(index.isValid());

	drawBackground(painter,option,index);
	//drawDisplay(painter,option,index);

	//QItemDelegate::paint(painter,option,index);//draw in default manner, you can invoke it after you custom cell background color;

	{
		//invoke parent class draw text
		const MyTable* model = 
			static_cast<const MyTable*>(index.model());
		QString text = model->item(index);
		if (index.column()>0)
		{
			QItemDelegate::drawDisplay(painter,option,option.rect,text);
		} else
		{
			this->drawArrow2(painter,option);
			drawArrow2(painter,option);
		}
	}
}

void ColorDelegate::drawBackground( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
	/*
	//Every cell background color is random generation.
	Q_UNUSED(index);
	painter->fillRect(option.rect, QColor(qrand()%255, qrand()%255, qrand()%255));	
	*/

	/*
	//Except the first column, other cell's background is white.
	int row = index.row();
	int col = index.column();

	if (col == 0)
	{
		painter->fillRect(option.rect, QColor(222,255,255));
	}
	else
	{
		painter->fillRect(option.rect, QColor(255,255,255));
	}	
	*/
	if (option.showDecorationSelected && (option.state & QStyle::State_Selected)){
		//if you invoke parent class drawDisplay function, below statement will not take effect.
		painter->fillRect(option.rect, QColor(222,255,255));
	}  else {
		painter->fillRect(option.rect, QColor(255,255,255));
	}

	/*
	// Paint the grid line
	painter->save();
	painter->setPen(QColor(0, 0, 0, 220));
	painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
	painter->setPen(QColor(255, 255, 255,255));
	painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
	painter->restore();	
	*/
}

void ColorDelegate::drawDisplay( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
	QStyleOptionViewItem opt = setOptions(index, option);

	const MyTable* model = 
		static_cast<const MyTable*>(index.model());
	QString text = model->item(index);

	if (text.isEmpty())
		return;

	/*
	//draw the cell with myOption:
	QStyleOptionViewItemV4 myOption = option;
	myOption.text = text;

	if (option.showDecorationSelected && (option.state & QStyle::State_Selected)){
		myOption.font.setBold(true);//text to be bold when selected
	}  else {
		myOption.font.setBold(false);//text not to be bold when unselected
	}
	QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &myOption, painter);
	*/

	
	//this method can let's you set font size in indifferent cell
	QFont font;
	font.setPixelSize(16);
	painter->save();
	painter->setFont(font);
	painter->drawText(option.rect,text);
	painter->restore();	
}

void ColorDelegate::drawArrow2( QPainter *painter, const QStyleOptionViewItem &option ) const
{
	QImage qimage("D:\\workspace\\testPlugin2\\TestListTable\\arrow.png");
	
	int top = (option.rect.height() - qimage.height())/2 + option.rect.top();
	int left = (option.rect.width() - qimage.width())/2 + option.rect.left();
	painter->drawImage(left,top, qimage);  // Paint the mask onto the image
}


Model源代码

MyTable.h

#ifndef _MYTABLE_H_
#define _MYTABLE_H_

#pragma once
#include <QAbstractTableModel>

/*
Title:Column View of QT5 示例代码
Author:kagula
Environment:VS2010SP1 + QT5.4.1 for vs2010
*/
class MyTable:public QAbstractTableModel
{
	Q_OBJECT
public:
	MyTable();

	int rowCount(const QModelIndex &parent = QModelIndex()) const;
	int columnCount(const QModelIndex &parent = QModelIndex()) const;
	QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
	QVariant headerData(int section, Qt::Orientation orientation, int role) const;
	
	//sort table
	void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);

	//add row
	void addRow(std::vector<QString> record);
	void removeRow(int row, QModelIndex modelIndex);

	//for my custom delegate retrieve cell's value
	QString item(const QModelIndex &index) const;	
	
public:
	static int _column;
	
private slots:
		void layoutAboutToBeChanged();
private:
	std::vector<std::vector<QString>> _body;
};


#endif


MyTable.cpp

#include "MyTable.h"
#include <QTextCodec>

#include <algorithm>

int MyTable::_column = 0;

MyTable::MyTable()
{
	const int countRow = 3;
	const int countCol = 3;

	for (int row=0;row<countRow;row++)
	{
		std::vector<QString> record;
		for (int col = 0;col<countCol;col++)
		{
			QString qsValue;
			qsValue.append("(row=");
			qsValue.append(QString::number(row));
			qsValue.append(",col=");
			qsValue.append(QString::number(col));
			qsValue.append(")");

			record.push_back(qsValue);
		}
		_body.push_back(record);
	}//end double for statement
}


int MyTable::rowCount( const QModelIndex &parent /*= QModelIndex()*/ ) const
{
	return _body.size();
}

int MyTable::columnCount( const QModelIndex &parent /*= QModelIndex()*/ ) const
{
	if (_body.size()>0)
	{
		return _body[0].size();
	}
	return 0;
}

QVariant MyTable::data( const QModelIndex &index, int role /*= Qt::DisplayRole*/ ) const
{
	int row = index.row();
	int col = index.column();

	if (row >= _body.size() || col >= _body[row].size() )
		return QVariant(QString(""));

	if (role == Qt::DisplayRole)
	{
		return QVariant(_body[row][col]);
	}
	else if (role == Qt::CheckStateRole)
	{
	}


	return QVariant();
}

QVariant MyTable::headerData( int section, Qt::Orientation orientation, int role ) const
{
	if (role == Qt::DisplayRole)
	{
		if (orientation == Qt::Horizontal) {
			switch (section)
			{
			case 0:
				return QStringLiteral("ID");
			case 1:
				return QStringLiteral("列1");
			case 2:
				return QStringLiteral("列2");
			case 3:
				return QStringLiteral("列3");
			case 4:
				return QStringLiteral("列4");
			}
		}
	}
	return QVariant();
}

QString MyTable::item( const QModelIndex &index ) const
{
	int row = index.row();
	int col = index.column();

	if (row >= _body.size() || col >= _body[row].size() )
		return QString("");
	
	return _body[row][col];	
}

static inline bool my_greater(std::vector<QString> a, std::vector<QString> b)
{
	return a[MyTable::_column]>b[MyTable::_column];
}

static inline bool my_lesser(std::vector<QString> a, std::vector<QString> b)
{
	return a[MyTable::_column]<b[MyTable::_column];
}

void MyTable::sort( int column, Qt::SortOrder order /*= Qt::AscendingOrder*/ )
{
	emit layoutAboutToBeChanged();

	_column = column;

	if (order == Qt::DescendingOrder)
	{
		std::sort(_body.begin(), _body.end(), my_greater);
	}
	else
	{
		std::sort(_body.begin(), _body.end(), my_lesser);
	}
}//func end

//refresh view when the model is modified!
void MyTable::layoutAboutToBeChanged()
{
	beginResetModel();
	endResetModel();
}

void MyTable::addRow( std::vector<QString> record )
{
	int newRow = _body.size();	
	beginInsertRows(QModelIndex(), newRow, newRow);
	_body.push_back(record);
	endInsertRows();
}

void MyTable::removeRow( int row, QModelIndex modelIndex)
{
	if (row>=_body.size())
	{
		return;
	}
	/*
	Only when user click the view of table, the effect will appear!
	beginRemoveRows(modelIndex,row,row);
	_body.erase(_body.begin() + row);
	endRemoveRows();
	Instead you must you below code!
	*/
	beginResetModel();
	_body.erase(_body.begin() + row);
	endResetModel();
}


你可能感兴趣的:(演示如何使用QTableView显示列表)