本文主要记录QTableView 使用代理添加进度条、下拉选择框、日历等,并实现复制粘贴,右键菜单等,效果如下图所示,最后有动态展示。
图片说明
1:图中红色1处是√和×,双击可以相互切换显示
2:图中红色2处是Qspinbox,实现整数输入
3:图中红色3处是QDateTimeEdit
4:图中红色4处是QCheckBox
5:图中红色5处是进度条
6:图中红色6处是下拉选择框
继承QStyledItemDelegate,实现编辑器控件和项目渲染等
头文件comboboxdelegate.h
#ifndef COMBOBOXDELEGATE_H
#define COMBOBOXDELEGATE_H
#include
#include
#include
class comboboxdelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
comboboxdelegate();
~comboboxdelegate();
protected:
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
public:
QRect CheckBoxRect(const QStyleOptionViewItem &option)const;
private:
QPixmap pixmap1;
QPixmap pixmap2;
};
#endif // COMBOBOXDELEGATE_H
源文件comboboxdelegate.cpp
#include "comboboxdelegate.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
comboboxdelegate::comboboxdelegate()
{
if(pixmap1.load(":/accept.png"))
{
printf("load-----233333\n");
}
else
{
printf("load-----55555\n");
}
}
comboboxdelegate::~comboboxdelegate()
{
}
QWidget* comboboxdelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column()==2&&index.row() ==4)//在第4行第2列创建一个下拉选择框,上图6
{
QComboBox *comBox = new QComboBox(parent);//创建编辑器控件,并设置父对象
comBox->addItem("combox1");
comBox->addItem("combox2");
comBox->addItem("combox3");
// comBox->setCurrentIndex(0);
comBox->setStyleSheet(
"QComboBox::drop-down{subcontrol-origin:padding;subcontrol-position:top right;width:15px;\
border-left-width:1px;\
border-left-color:darkgray;\
border-left-style:solid;\
border-top-right-radius:3px;\
border-bottom-right-radius:3px;}");
return comBox;
}
else if(index.column() ==1&&index.row() ==2)//在第2行第1列创建日历,上图3
{
QDateTimeEdit *timeEdit = new QDateTimeEdit(parent);//创建编辑器控件,并设置父对象
timeEdit->setDisplayFormat("yyyy-MM-dd HH:mm:ss");//显示日期及时间格式
// timeEdit->setCalendarPopup(true); //下拉菜单的方式
return timeEdit;
}
else if(index.column() ==1&&index.row() ==1)//在第1行第1列创建一个QSpinBox ,上图2
{
QSpinBox *spinEdit = new QSpinBox(parent);//创建编辑器控件,并设置父对象
spinEdit->setRange(0,10000);
return spinEdit;
}
else if(index.column() ==0)//第1列不可编辑,直接返回null即可
{
return NULL;
}
else
{
return QStyledItemDelegate::createEditor(parent,option,index);
}
}
void comboboxdelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
/* QStyleOptionViewItem view_option(option);
initStyleOption(&view_option,index);
if(view_option.state & QStyle::State_HasFocus)
{
view_option.state = view_option.state ^ QStyle::State_HasFocus;
} */
if(option.state & QStyle::State_Selected)//选中高亮
{
painter->fillRect(option.rect,option.palette.highlight());
}
if(index.column() ==1&&index.row() ==4)//在第4行第1列处绘制一个进度条,上图5
{
int V = index.data(Qt::UserRole).toInt();
QStyleOptionProgressBarV2 progressBarOption;
progressBarOption.state = QStyle::State_Enabled ;
progressBarOption.direction = QApplication::layoutDirection();
progressBarOption.rect = option.rect;
progressBarOption.fontMetrics = QApplication::fontMetrics();
progressBarOption.minimum =0;
progressBarOption.maximum =100;
progressBarOption.textAlignment = Qt::AlignCenter;
progressBarOption.textVisible =true;
progressBarOption.progress = V;
progressBarOption.text = QString("%1%").arg(V);
QProgressBar bar;
bar.setStyleSheet("QProgressBar{border:none;text-align:center;}"
"QProgressBar::chunk{background:rgb(0,160,230);}");//设置进度条颜色
bar.style()->drawControl(QStyle::CE_ProgressBar,&progressBarOption,painter,&bar);
}
else if(index.column() ==1&&index.row() ==3)//在第3行第1列处绘制一个复选框,上图4
{
bool checkFlag = index.data(Qt::UserRole).toBool();
QStyleOptionButton checkBoxStyle;
checkBoxStyle.state = checkFlag ? QStyle::State_On:QStyle::State_Off;
checkBoxStyle.state |= QStyle::State_Enabled;
checkBoxStyle.rect = CheckBoxRect(option);//改变复选框指示器位置,中心位置
// checkBoxStyle.rect = option.rect;
QCheckBox checbox;
checbox.style()->drawControl(QStyle::CE_CheckBox,&checkBoxStyle,painter,&checbox);
}
else if(index.column() ==0)//绘制文本,颜色为红色
{
QString strValue = index.data().toString();
QPen pen(Qt::red);
painter->save();
painter->setPen(pen);
painter->setFont(QFont("Times",10,QFont::Bold));
QApplication::style()->drawItemText(painter,option.rect,Qt::AlignCenter,QApplication::palette(),true,strValue);
painter->restore();
}
else if(index.row() ==5 && index.column() ==1)//绘制图片,处于中心位置
{
const QPixmap &star = pixmap1;
int x = option.rect.x()+option.rect.width()/2 - star.width()/2;
int y = option.rect.y()+option.rect.height()/2 - star.height()/2;
painter->drawPixmap(x,y,star);
}
else
{
QStyledItemDelegate::paint(painter,option,index);
}
}
void comboboxdelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if(index.column()==2&&index.row() ==4)
{
QComboBox* combox = static_cast(editor);
model->setData(index,combox->currentText(),Qt::DisplayRole);
model->setData(model->index(4,1),50,Qt::UserRole);
}
else if(index.column() ==1&&index.row() ==2)
{
QDateTimeEdit *timeEdit = static_cast(editor);
QDateTime date = timeEdit->dateTime();//日期及时间格式---年月日是日期,时分秒是时间
model->setData(index,date.toString("yyyy-MM-dd HH:mm:ss"));//日期及时间格式
}
else if(index.column() ==1&&index.row() ==1)
{
QSpinBox *spinEdit = static_cast(editor);
model->setData(index,spinEdit->value());
}
else
{
QStyledItemDelegate::setModelData(editor,model,index);
}
}
void comboboxdelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(index.column()==2&&index.row() ==4)
{
QComboBox* combox = static_cast(editor);
int textindex = combox->findText(index.data().toString());
if(textindex !=-1)
{
combox->setCurrentIndex(textindex);
}
}
else if(index.column() ==1&&index.row() ==2)
{
QString dateStr = index.data().toString();
printf("----%s--------\n",dateStr.toAscii().data());
QDateTime date = QDateTime::fromString(dateStr,"yyyy-MM-dd HH:mm:ss");//日期及时间格式
QDateTimeEdit *timeEdit = static_cast(editor);
timeEdit->setDateTime(date);//日期及时间格式
}
else if(index.column() ==1&&index.row() ==1)
{
int iValue = index.data().toInt();
QSpinBox *spinEdit = static_cast(editor);
spinEdit->setValue(iValue);
}
else
{
QStyledItemDelegate::setEditorData(editor,index);
}
}
void comboboxdelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
bool comboboxdelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
QMouseEvent* mouseEvent = static_cast(event);
if(event->type() == QEvent::MouseButtonPress && option.rect.contains(mouseEvent->pos()))
{
if(index.column() ==1&&index.row() ==3)//单击改变复选框状态
{
bool data = model->data(index,Qt::UserRole).toBool();
model->setData(index,!data,Qt::UserRole);
}
}
if(event->type() == QEvent::MouseButtonDblClick && option.rect.contains(mouseEvent->pos()))
{
if(index.column() ==1&&index.row() ==0)//双击实现×和√切换
{
bool data = model->data(index,Qt::UserRole).toBool();
model->setData(index,!data,Qt::UserRole);
model->setData(index,data?QString::fromLocal8Bit("√"):QString::fromLocal8Bit("×"),Qt::DisplayRole);
}
}
return QStyledItemDelegate::editorEvent(event,model,option,index);
}
QRect comboboxdelegate::CheckBoxRect(const QStyleOptionViewItem &option)const
{
QStyleOptionButton checkBoxbuttonOption;
QRect checkBoxRect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator,&checkBoxbuttonOption);
QPoint checkBoxPoint(option.rect.x()+option.rect.width()/2 - checkBoxRect.width()/2,option.rect.y()+option.rect.height()/2 - checkBoxRect.height()/2);
return QRect(checkBoxPoint,checkBoxRect.size());
}
源文件widget.cpp--------- 设置QTableView、菜单、复制粘贴等功能
#include "widget.h"
#include "comboboxdelegate.h"
widget::widget(QWidget *parent) : QWidget(parent)
{
// this->setFocusPolicy(Qt::StrongFocus);
this->resize(500,500);
QHBoxLayout* hlayout = new QHBoxLayout;
model = new QStandardItemModel;
view = new QTableView();
hlayout->addWidget(view);
this->setLayout(hlayout);
view->horizontalHeader()->setStretchLastSection(true);//最后一列自适应宽度
view->setAlternatingRowColors(true);//表格颜色交替
view->setModel(model);
view->setMouseTracking(true);//鼠标跟踪
view->setItemDelegate(new comboboxdelegate);//设置代理
//view->setSelectionBehavior(QAbstractItemView::SelectRows);
//view->setSelectionMode(QAbstractItemView::SingleSelection);
view->setStyleSheet("QTableView::item:hover{background-color:red;}");//鼠标悬浮在item上的样式表
model->setColumnCount(3);
model->setHeaderData(0,Qt::Horizontal,QObject::tr("name"));
model->setHeaderData(1,Qt::Horizontal,QObject::tr("age"));
model->setHeaderData(2,Qt::Horizontal,QObject::tr("sex"));
model->setItem(0,0,new QStandardItem("tom"));
QStandardItem* item4 = new QStandardItem;
item4->setData(0,Qt::UserRole);//用于判断当前项的状态,0显示×,1显示√
item4->setData(QString::fromLocal8Bit("×"),Qt::DisplayRole);
item4->setEditable(false);//设置为不可编辑
item4->setTextAlignment(Qt::AlignCenter);//文本居中显示
model->setItem(0,1,item4);//√
model->setItem(0,2,new QStandardItem(QString::fromLocal8Bit("总线")));
model->setItem(1,0,new QStandardItem("tom2"));
model->setItem(1,1,new QStandardItem("19"));
QStandardItem* item5 = new QStandardItem;
item5->setData(0,Qt::CheckStateRole);//设置可选数据角色
item5->setCheckable(true);//设置为可选择
item5->setEditable(false);//不可编辑
model->setItem(1,2,item5);
model->setItem(2,0,new QStandardItem("qqqq"));
model->setItem(2,1,new QStandardItem("2021-01-16 10:04:21"));//给一个初始日期和时间
model->setItem(2,2,new QStandardItem("f"));
model->setItem(3,0,new QStandardItem("www"));
QStandardItem* item3 = new QStandardItem;
item3->setData(0,Qt::UserRole);//用于判断当前项的状态,0表示未选中,1表示选中
item3->setEditable(false);//设置为不可编辑
model->setItem(3,1,item3);
model->setItem(3,2,new QStandardItem("f"));
QStandardItem* item11=model->itemFromIndex(model->index(3,2));
item11->setEditable(false);
QStandardItem* item = new QStandardItem;
item->setEditable(false);
item->setData("eee",Qt::DisplayRole);
item->setData("tips",Qt::ToolTipRole);
model->setItem(4,0,item);
QStandardItem* item2 = new QStandardItem;
item2->setData(22,Qt::UserRole);//进度条的初始值,数据角色为Qt::UserRole,这样可以避免进度条处的项目显示文本值
item2->setEditable(false);
model->setItem(4,1,item2);
QStandardItem* item1 = new QStandardItem;
item1->setData("combox1",Qt::DisplayRole);
model->setItem(4,2,item1);
/* QModelIndex index = model->index(4,2);
QComboBox * box = new QComboBox;
box->addItem("aa");
box->addItem("bb");
view->setIndexWidget(index,box);*/
model->setItem(5,0,new QStandardItem("ddd"));
model->setItem(5,1,new QStandardItem(30));
model->setItem(5,2,new QStandardItem("mmm"));
// model->setData(model->index(6,0),"zzx");
// model->setData(model->index(6,1),18);
// model->setData(model->index(6,2),"27");//尽量不要使用setData()和insertXXX()等函数,如果指定位置不存在,则可能添加失败
connect(view->itemDelegate(),SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),this,SLOT(print11(QWidget*,QAbstractItemDelegate::EndEditHint)));
connect(model,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(print22(QStandardItem*)));//只有数据改变后,才发送此信号
connect(view,SIGNAL(entered(const QModelIndex& )),this,SLOT(print33(const QModelIndex&)));//鼠标进入,必须设置鼠标跟踪
/添加右键菜单
view->setContextMenuPolicy(Qt::CustomContextMenu);//必须设置,不然菜单不显示
tableviewMen = new QMenu(view);
action1 = new QAction("action1",view);
action2 = new QAction("action2",view);
tableviewMen->addAction(action1);
tableviewMen->addAction(action2);
connect(action1,SIGNAL(triggered()),this,SLOT(action1_slot1()));
connect(action2,SIGNAL(triggered()),this,SLOT(action2_slot2()));
connect(view,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(viewMen_Slot(QPoint)));
}
widget::~widget()
{
}
void widget::action1_slot1()
{
printf("action1_slot1 \n");
}
void widget::action2_slot2()
{
printf("action2_slot2 \n");
}
void widget::viewMen_Slot(QPoint p)
{
printf("viewMen_Slot \n");
QModelIndex index = view->indexAt(p);//鼠标点击处的数据项索引
if(index.isValid())//此判断,可以避免空白处右击菜单的出现
{
QItemSelectionModel* selections = view->selectionModel();//当前选中的模型
QModelIndexList slected = selections->selectedIndexes();//当前选中的模型索引列表
if(slected.count() ==1)//单选时,显示的菜单
{
action1->setVisible(true);
action2->setVisible(true);
}
else//选中多个项目时,显示的菜单
{
action1->setVisible(false);
action2->setVisible(true);
}
tableviewMen->exec(QCursor::pos());
}
}
void widget::print11(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
{
printf("slot------print11\n");
Q_UNUSED(editor);
}
void widget::print22(QStandardItem* item)
{
printf("slot------print22\n");
printf("item.data=%s \n",item->text().toAscii().data());
}
void widget::print33(const QModelIndex &index)
{
printf("slot------print33\n");
printf("item.data=%s \n",index.model()->data(index,Qt::DisplayRole).toString().toAscii().data());
QToolTip::showText(QCursor::pos(),index.model()->data(index,Qt::DisplayRole).toString());//全局tip,鼠标放在项目上,可以显示的信息
}
void widget::keyPressEvent(QKeyEvent *e)
{
if(e->modifiers()== Qt::ControlModifier && e->key() == Qt::Key_C)//ctrl +c 复制被按下
{
printf("-------------\n");
QClipboard* board = QApplication::clipboard();//粘贴板
const QModelIndex index = view->currentIndex();
board->setText(index.model()->data(index,Qt::DisplayRole).toString());//设置粘贴板数据
}
else if(e->matches( QKeySequence::Paste ))//ctrl +v 粘贴被按下,此方法和上面一样,都可以检测组合键被按下
{
QClipboard* board = QApplication::clipboard();
const QModelIndex index = view->currentIndex();//获取当前项模型索引
view->model()->setData(index,board->text());//取出粘贴板数据,并设置当前项数据
printf("----%s-----------\n",board->text().toAscii().data());
QStandardItem* tmpitem=static_cast(view->model())->itemFromIndex(index);
printf("item =%s \n", tmpitem->text().toAscii().data());
}
else
{
return QWidget::keyPressEvent(e);
}
}
关于鼠标右键菜单的逻辑可以参考另一篇文章QTableView添加右键菜单
动图展示