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(); }