思路:
1:為每一列定義委托:
A:第一列是編號列,使用只讀委托,令該列的單元格是只讀的
B:第三列是ID列,只能輸入1-12個數字,利用QLineEdit委托和正則表達式對輸入進行限制
C:第四年齡列,利用QSpinBox委托進行輸入限制,只能輸入1-100之間的數字
D:第五列是性別列,利用QComboBox委托對輸入進行限制,該列的單元格只能輸入Male或Female
E:第六列是頭像列,在該列的單元格中央放置一張頭像
2:定義代理類,把所有單元格中的字符居中顯示。
3:利用QSS,將表格的背景色弄成黃藍相間。
截圖:

上代碼:
#include <QtGui>
#include <QItemDelegate>
#include <QSpinBox>
//編號列,只讀委托
//這個方法我還真想不到,呵呵
class ReadOnlyDelegate : public QItemDelegate
{
Q_OBJECT
public:
ReadOnlyDelegate(QObject *parent = 0): QItemDelegate(parent) { }
QWidget *createEditor(QWidget*parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
return NULL;
}
};
//ID列,只能輸入1-12個數字
//利用QLineEdit委托和正則表達式對輸入進行限制
class UserIDDelegate : public QItemDelegate
{
Q_OBJECT
public:
UserIDDelegate(QObject *parent = 0): QItemDelegate(parent) { }
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QLineEdit *editor = new QLineEdit(parent);
QRegExp regExp("[0-9]{0,10}");
editor->setValidator(new QRegExpValidator(regExp, parent));
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString text = index.model()->data(index, Qt::EditRole).toString();
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
lineEdit->setText(text);
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
QString text = lineEdit->text();
model->setData(index, text, Qt::EditRole);
}
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
};
//年齡列,利用QSpinBox委托進行輸入限制,只能輸入1-100之間的數字
class AgeDelegate : public QItemDelegate
{
Q_OBJECT
public:
AgeDelegate(QObject *parent = 0): QItemDelegate(parent) { }
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setMinimum(1);
editor->setMaximum(100);
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
};
//性別列,利用QComboBox委托對輸入進行限制
//這一列的單元格只能輸入Male或Female
class SexDelegate : public QItemDelegate
{
Q_OBJECT
public:
SexDelegate(QObject *parent = 0): QItemDelegate(parent) { }
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QComboBox *editor = new QComboBox(parent);
editor->addItem("Female");
editor->addItem("Male");
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString text = index.model()->data(index, Qt::EditRole).toString();
QComboBox *comboBox = static_cast<QComboBox*>(editor);
int tindex = comboBox->findText(text);
comboBox->setCurrentIndex(tindex);
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QComboBox *comboBox = static_cast<QComboBox*>(editor);
QString text = comboBox->currentText();
model->setData(index, text, Qt::EditRole);
}
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
};
//頭像列,只是在單元格中央放一張小圖而已
class IconDelegate : public QItemDelegate
{
Q_OBJECT
public:
IconDelegate(QObject *parent = 0): QItemDelegate(parent) { }
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex & index ) const
{
//show.bmp是在工程目錄中的一張圖片(其實就是QQ的圖標啦,呵呵)
QPixmap pixmap = QPixmap("show.bmp").scaled(24, 24);
qApp->style()->drawItemPixmap(painter, option.rect, Qt::AlignCenter, QPixmap(pixmap));
}
};
//代理類,把所有單元格中的字符居中顯示
class VIPModel : public QStandardItemModel
{
Q_OBJECT
public:
VIPModel(QObject *parent=NULL) : QStandardItemModel(parent) { }
VIPModel(int row, int column, QObject *parent=NULL)
: QStandardItemModel(row, column, parent) { }
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
{
if( Qt::TextAlignmentRole == role )
return Qt::AlignCenter;
return QStandardItemModel::data(index, role);
}
};
#include "main.moc"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
VIPModel *model = new VIPModel(5, 5);
QTableView *tableView = new QTableView;
//把表格的背景調成黃藍相間
//這種方法是在網上看到的,用起來還真方便啊
tableView->setAlternatingRowColors(true);
tableView->setStyleSheet("QTableView{background-color: rgb(250, 250, 115);"
"alternate-background-color: rgb(141, 163, 215);}");
tableView->setWindowTitle("VIP List");
tableView->resize(700, 400);
tableView->setModel(model);
QStringList headerList;
headerList << "No." << "ID" << "Name" << "Age" << "Sex" << "Show";
model->setHorizontalHeaderLabels(headerList);
tableView->verticalHeader()->setVisible(false);
tableView->horizontalHeader()->setStretchLastSection(true);
//為每一列加載委托
ReadOnlyDelegate readOnlyDelegate;
//tableView->setItemDelegateForColumn(0, &readOnlyDelegate); //我用了會報錯
tableView->setItemDelegateForColumn(0, new ReadonlyDelegate(this)); //我用的是這種
UserIDDelegate userIDDelegate;
tableView->setItemDelegateForColumn(1, &userIDDelegate);
AgeDelegate spinBoxDelegate;
tableView->setItemDelegateForColumn(3, &spinBoxDelegate);
SexDelegate comboBoxDelegate;
tableView->setItemDelegateForColumn(4, &comboBoxDelegate);
IconDelegate iconDelegate;
tableView->setItemDelegateForColumn(5, &iconDelegate);
for(int i=0; i<10; i++)
{
QModelIndex index = model->index(i, 0, QModelIndex());
model->setData(index, i);
}
tableView->show();
return app.exec();
}
QTableView、QStandardItemModel/QAbstractItemModel 、QStyledItemDelegate/QItemDelegate和QModelIndex;
先上圖看效果吧

選擇文件按鈕這一列,第0行是點擊后進入編輯模式時顯示按鈕的情況。
下面一行是顯示的選擇文件的全路徑。
第2行”C:“是初始化時設置的值,只是為了測試顯示。
最后一行是沒有選擇文件。
我實現的這個SelectFileButton辦法:
QPushButton;
SelectFileButton里實現一個槽函數:功能,點擊時選擇文件並返回路徑。
cQItemDelegate;
d、然后再重寫createEditor();返回SelectFileButton的指針
e、重寫setModelData()、setEditorData(); 設置模型數據和設置編輯數據的。
#ifndef SELECTFILEBUTTONDELEGATE_H
#define SELECTFILEBUTTONDELEGATE_H
#include <QItemDelegate>
#include <QPushButton>
#include <QModelIndex>
#include <QFileDialog>
#include <QAbstractItemModel>
#include <QDebug>
class TableModel;
class SelectFileButton: public QPushButton
{
Q_OBJECT
public:
SelectFileButton(const QModelIndex & index, QWidget *parent = 0)
: QPushButton(parent)
{
Init(index);
}
SelectFileButton(const QModelIndex & index, const QString &text, QWidget *parent = 0)
: QPushButton(text, parent)
{
Init(index);
}
SelectFileButton(const QModelIndex & index, const QIcon& icon, const QString &text, QWidget *parent = 0)
:QPushButton(icon, text, parent)
{
Init(index);
}
~SelectFileButton() {
qDebug() << "~SelectFileButton";
}
protected:
void Init(const QModelIndex & index)
{
m_index = index;
connect(this, SIGNAL(clicked()), this, SLOT(btnClick_slot()));
}
public slots:
void btnClick_slot()
{
QString strValue;
QModelIndex index = this->m_index;
QFileDialog * dlg = new QFileDialog(0);
int res =dlg->exec(); //這里開啟新的線程,頂層會釋放這個按鈕,所以要把Index 保存一份
if (res==QFileDialog::Accepted)
{
strValue = dlg->selectedFiles()[0];
QAbstractItemModel* model = const_cast<QAbstractItemModel*>(index.model());
model->setData(index, strValue);
}
}
private:
QModelIndex m_index;
};
/**********************************************************************/
class SelectFileButtonDelegate : public QItemDelegate
{
Q_OBJECT
public:
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
SelectFileButton* btn = new SelectFileButton(index,QStringLiteral("查找文件路徑"), parent); //這個是其他線程里的 所以不能保存下來。每次的btn還不一樣
return btn;
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
public:
SelectFileButtonDelegate(QObject *parent);
~SelectFileButtonDelegate();
private:
QPushButton* m_btn;
};
#endif // SELECTFILEBUTTONDELEGATE_H
通過painter畫自定義控件
QStyleOption子類:
QStyleOptionButton, QStyleOptionComplex, QStyleOptionDockWidget, QStyleOptionFocusRect, QStyleOptionFrame, QStyleOptionGraphicsItem, QStyleOptionHeader, QStyleOptionMenuItem, QStyleOptionProgressBar, QStyleOptionRubberBand, QStyleOptionTab, QStyleOptionTabBarBase, QStyleOptionTabWidgetFrame, QStyleOptionToolBar, QStyleOptionToolBox, and QStyleOptionViewItem
一 、painter 自定義進度條
//自定義進度條
BarDelegate::BarDelegate( QObject *parent ) : QAbstractItemDelegate( parent ) { }
void BarDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
if( option.state & QStyle::State_Selected )
painter->fillRect( option.rect, option.palette.highlight() );
// 數據是存儲在QStandardItemModel的QStandardItem,會自動根據當前行進行匹配(我認為)
int value = index.model()->data( index, Qt::DisplayRole ).toInt(); // 這句,取得當前行的數據
qDebug() << value;
double factor = double(value)/100.0; // 計算比例因子
painter->save(); // 保存舊畫板(我認為)
// 進度條背景色
if( factor > 0.8 )
{
painter->setBrush( Qt::red ); // 超過0.8畫純紅色
factor = 1;
}
else
painter->setBrush( QColor( 0, int(factor*255), 255-int(factor*255) ) ); // 否則顏色依次變淡
int n = factor*100;
QString str1 = QString("%1\%").arg(n);
painter->setPen( Qt::red ); // 畫筆顏色(這里沒用到,我認為)
// 前面都是准備工作,這里才是真正畫進度條
painter->drawRect( option.rect.x()+2, option.rect.y()+2, int(factor*(option.rect.width()-5)), option.rect.height()-5 );
painter->drawText(option.rect.x()+int(factor*(option.rect.width()))+2, option.rect.y()+option.rect.height()/2, str1);
painter->restore(); // 恢復新畫板(我認為)
}
QSize BarDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
return QSize( 45, 15 ); // 隨便改,不影響(我認為)
}
class BarDelegate : public QAbstractItemDelegate
{
public:
BarDelegate( QObject *parent = 0 );
// 覆蓋兩個函數就可以顯示進度條
void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const;
QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const;
};
1 painter進度條 QStyleOptionProgressBar
void ProgressBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() == 0) {
int value = index.model()->data(index).toInt();
QStyleOptionProgressBarV2 progressBarOption;
progressBarOption.rect = option.rect.adjusted(4, 4, -4, -4);
progressBarOption.minimum = 0;
progressBarOption.maximum = 100;
progressBarOption.textAlignment = Qt::AlignRight;
progressBarOption.textVisible = true;
progressBarOption.progress = value;
progressBarOption.text = tr("%1%").arg(progressBarOption.progress);
painter->save();
if (option.state & QStyle::State_Selected) {
painter->fillRect(option.rect, option.palette.highlight());
painter->setBrush(option.palette.highlightedText());
}
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
painter->restore();
} else {
return QItemDelegate::paint (painter, option, index);
}
}
二、painter自定義按鈕 QStyTableViewDelegate::TableViewDelegate(int z_Column, int z_NumberButtons,QWidget *parent)
: QStyledItemDelegate(parent), m_pOpenButton(new QPushButton()), m_pDeleteButton(new QPushButton()), m_nSpacing(5), m_nWidth(25), m_nHeight(20), m_Column(z_Column), m_NumberButtons(z_NumberButtons) {if (2 == m_NumberButtons) { m_list << QStringLiteral("編輯按鈕") << QStringLiteral("刪除按鈕"); } // 設置按鈕正常、划過、按下樣式
QString z_Path = QCoreApplication::applicationDirPath(); m_pOpenButton->setStyleSheet("QPushButton {border: none; background-color: transparent; image:url("+z_Path+"/res/system.png);} \
QPushButton:hover {image:url("+z_Path+"/res/system.png);} \ QPushButton:pressed {image:url("+z_Path+"/res/system.png);}");
m_pDeleteButton->setStyleSheet("QPushButton {border: none; background-color: transparent; image:url("+z_Path+"/res/delete.png);} \
QPushButton:hover {image:url("+z_Path+"/res/delete.png);} \ QPushButton:pressed {image:url("+z_Path+"/res/delete.png);}");
} TableViewDelegate::~TableViewDelegate() { } // 繪制按鈕
void TableViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem viewOption(option); initStyleOption(&viewOption, index); if (option.state.testFlag(QStyle::State_HasFocus)) viewOption.state = viewOption.state ^ QStyle::State_HasFocus; QStyledItemDelegate::paint(painter, viewOption, index); if (index.column() == m_Column) { // 計算按鈕顯示區域
int nCount = m_list.count(); int nHalf = (option.rect.width() - m_nWidth * nCount - m_nSpacing * (nCount - 1)) / 2; int nTop = (option.rect.height() - m_nHeight) / 2; for (int i = 0; i < nCount; ++i) { // 繪制按鈕
QStyleOptionButton button; button.rect = QRect(option.rect.left() + nHalf + m_nWidth * i + m_nSpacing * i, option.rect.top() + nTop, m_nWidth, m_nHeight); button.state |= QStyle::State_Enabled; button.iconSize = QSize(20, 20); if (button.rect.contains(m_mousePoint)) { if (m_nType == 0) { button.state |= QStyle::State_MouseOver; //button.icon = QIcon(QString(":/Images/%1Hover").arg(m_list.at(i)));
} else if (m_nType == 1) { button.state |= QStyle::State_Sunken; //button.icon = QIcon(QString(":/Images/%1Pressed").arg(m_list.at(i)));
} } //QWidget *pWidget = m_pOpenButton.data();
QWidget *pWidget = (i == 0) ? m_pOpenButton.data() : m_pDeleteButton.data(); pWidget->style()->drawControl(QStyle::CE_PushButton, &button, painter, pWidget); } } } // 響應按鈕事件 - 划過、按下
bool TableViewDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) { if (index.column() != m_Column) return false; m_nType = -1; bool bRepaint = false; QMouseEvent *pEvent = static_cast<QMouseEvent *> (event); m_mousePoint = pEvent->pos(); int nCount = m_list.count(); int nHalf = (option.rect.width() - m_nWidth * nCount - m_nSpacing * (nCount - 1)) / 2; int nTop = (option.rect.height() - m_nHeight) / 2; // 還原鼠標樣式
QApplication::restoreOverrideCursor(); for (int i = 0; i < nCount; ++i) { QStyleOptionButton button; button.rect = QRect(option.rect.left() + nHalf + m_nWidth * i + m_nSpacing * i, option.rect.top() + nTop, m_nWidth, m_nHeight); // 鼠標位於按鈕之上
if (!button.rect.contains(m_mousePoint)) continue; bRepaint = true; switch (event->type()) { // 鼠標滑過
case QEvent::MouseMove: { // 設置鼠標樣式為手型 //QApplication::setOverrideCursor(Qt::PointingHandCursor);
m_nType = 0; QToolTip::showText(pEvent->globalPos(), m_list.at(i)); break; } // 鼠標按下
case QEvent::MouseButtonPress: { m_nType = 1; break; } // 鼠標釋放
case QEvent::MouseButtonRelease: { if (i == 0) { emit EditData(index); } else { emit deleteData(index); } break; } default: break; } } return bRepaint; }
三 painter 設置圖片
void ItemdelegateTest::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem viewOption(option);
if (viewOption.state & QStyle::State_HasFocus)
{
viewOption.state = viewOption.state ^ QStyle::State_HasFocus;
}
QStyledItemDelegate::paint(painter, viewOption, index);
int height = (viewOption.rect.height()) / 2;
QPixmap pixmap = QPixmap(":/check.png");
//QPixmap pixmap = QPixmap("E:/qt/QtDelegateTestT/zhj.png");
QRect DrawRect = QRect(viewOption.rect.left() + viewOption.rect.width() - 30, viewOption.rect.top() + height, 9, 9);
painter->drawPixmap(DrawRect, pixmap);
}
bool ItemdelegateTest::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
int height = (option.rect.height()) / 2;
QRect DrawRect = QRect(option.rect.left() + option.rect.width() - 30, option.rect.top() + height, 9, 9);
//QMouseEvent *mouseEvent = static_cast(event);
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (event->type() == QEvent::MouseButtonPress && DrawRect.contains(mouseEvent->pos()))
{
emit deleteItem(index);
}
if (event->type() == QEvent::MouseMove && DrawRect.contains(mouseEvent->pos()))
{
QCursor cursor(Qt::PointingHandCursor);
QApplication::setOverrideCursor(cursor);
QToolTip::showText(mouseEvent->globalPos(), "刪除");
}
else
{
QCursor cursor(Qt::ArrowCursor);
QApplication::setOverrideCursor(cursor);
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}

panier繪制checkbox
CheckBoxDelegate::CheckBoxDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
CheckBoxDelegate::~CheckBoxDelegate()
{
}
// 繪制復選框
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem viewOption(option);
initStyleOption(&viewOption, index);
if (option.state.testFlag(QStyle::State_HasFocus))
viewOption.state = viewOption.state ^ QStyle::State_HasFocus;
QStyledItemDelegate::paint(painter, viewOption, index);
if (index.column() == CHECK_BOX_COLUMN)
{
bool data = index.model()->data(index, Qt::UserRole).toBool();
QStyleOptionButton checkBoxStyle;
checkBoxStyle.state = data ? QStyle::State_On : QStyle::State_Off;
checkBoxStyle.state |= QStyle::State_Enabled;
checkBoxStyle.iconSize = QSize(20, 20);
checkBoxStyle.rect = option.rect;
QCheckBox checkBox;
QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &checkBoxStyle, painter, &checkBox);
}
}
// 響應鼠標事件,更新數據
bool CheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
QRect decorationRect = option.rect;
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (event->type() == QEvent::MouseButtonPress && decorationRect.contains(mouseEvent->pos()))
{
if (index.column() == CHECK_BOX_COLUMN)
{
bool data = model->data(index, Qt::UserRole).toBool();
model->setData(index, !data, Qt::UserRole);
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
---------------------
作者:一去丶二三里
來源:CSDN
原文:https://blog.csdn.net/liang19890820/article/details/50721200
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!