思路:
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
版权声明:本文为博主原创文章,转载请附上博文链接!