QT listView学习

文章目录

  • listView
    • demo说明
    • demo演示
    • model定义
    • 委托 QStyledItemDelegate
    • 总结

listView

listView 对比 tableView 、 treeView来说,最大的不同就是数据结构的不同。treeView是像树一样的层次结构,而listView则就是像链表一样的结构

跟之前的treeView,tableView一样,使用一个简单的demo来演示一下这个过程,同样的我们使用自定义的model定义。

demo说明

实现一个简单的demo,一个item里有图片、按钮、文字三个部分组成,双击文字出现combobox下拉框。按钮分为选中和非选中,单机修改按钮状态,通过一个额外的按钮将所有按钮为选中的那行item删除

demo演示

listViewDemo

model定义

listView的数据结构似乎比较简单,这里直接用一个List链表来当做数据源了

struct ListData 
{
	bool m_isSelect; 
	QString m_txt;
};

class ListModel : public QAbstractListModel
{
	Q_OBJECT

public:
	ListModel();
	~ListModel();

	int rowCount(const QModelIndex &parent) const;
	QVariant data(const QModelIndex &index, int role) const;
	bool setData(const QModelIndex &index, const QVariant &value, int role);
	QModelIndex index(int row, int column, const QModelIndex &parent) const;
	int columnCount(const QModelIndex &parent) const;
	Qt::ItemFlags flags(const QModelIndex& index) const override;
	void insertData(const ListData &data);

	QList getData() {return m_listData;}
	void SetData(const QList &data){ 
		beginResetModel();
		m_listData = data;
		endResetModel();
	}


private:
	QList m_listData;
};

委托 QStyledItemDelegate

从demo的定义来看,我们需要在一个item上绘制按钮、文本框、图片,这里我们需要使用到委托。

  • 委托是视图中处理用户输入的部件。
  • 视图可以设置委托对象用于处理用户输入。
  • 委托能够提供编辑时需要的上下文环境(编辑器)。
  • 不同委托提供的编辑器类型不同(文本框、单选框等)。
  • 编辑器从模型中获取数据,并将编辑结果返回模型。

委托中的关键函数:

  • createEditor:需要编辑数据时,创建编辑器组件。
  • updateEditorGeometry:更新编辑器组件的大小。
  • setEditorData:通过索引从模型中获取数据。
  • setModelData:将编辑后的新数据返回模型。
  • (print: 描绘画面显示)
  • (editorEvent: 处理鼠标事件)
class MyDelegate : public QStyledItemDelegate
{
	 Q_OBJECT;

public:
	MyDelegate();
	~MyDelegate();

	//描绘画面显示
	void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

	//处理鼠标事件
	bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);

	void updateEditorGeometry(QWidget *editor,
		const QStyleOptionViewItem &option,
		const QModelIndex &index) const;

	virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
	void setEditorData(QWidget *editor, const QModelIndex &index) const ;       //为editor提供编辑的原始数据

	virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const ;
};

我们需要在paint中绘制我们需要的item

void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
	QRect retc = option.rect;

	//这里取的数据 对应model里面的role
	bool isSelect = index.data(Qt::UserRole + 1).toBool();
	QString txt = index.data(Qt::UserRole + 2).toString();
	{
        // picture begin
		QPixmap pix;
		painter -> save();
		if (pix.isNull())
		{	
			auto success = pix.load("D:/3.ico");
		}
		painter->setPen(QColor("#Ff0000"));
		painter->setPen(Qt::DashDotLine);
	 	painter->drawRect(retc);

		int xoffset = 10;
		auto szPix = pix.size();

		auto dy = szPix.height() * 1.0 /  retc.height();
		auto dx = szPix.width() * 1.0 / retc.width();

		auto d = std::max(dy, dx);
		int w = szPix.width() / d;
		int h = szPix.height() /d;

		auto x = retc.left() + xoffset;
		auto y = retc.top() + (retc.height() - h) / 2;
		painter->drawPixmap(x, y, w, h, pix);
        // picture end
        // buttom begin
		g_hight = h;
		//p11.setX(x);
		p11 = QPoint(x, (retc.height() - h) / 2);

		x = x + w + 50;
		//绘制按钮
		QRect butRect(x, y, 100, h);
		p22 = QPoint(x, p11.y());

		if(isSelect)
		{
			painter->setPen(QPen(QColor("#8f9ae6")));
			painter->setBrush(QColor("#8f9ae6"));
			painter->setPen(QPen(QColor("#000000")));
			painter->drawRoundedRect(butRect,0,0);
			painter->drawText(butRect,Qt::AlignCenter,"选中");

		}else
		{
			painter->setPen(QPen(QColor("#FFFFFF")));
			painter->setBrush(QColor("#FFFFFF"));
			painter->setPen(QPen(QColor("#000000")));
			painter->drawRoundedRect(butRect,0,10);
			painter->drawText(butRect,Qt::AlignCenter,"未选");
		}
        //buttom end

		//text begin
		butRect = QRect(w * 3 + 150, y, 200, h);
		p33 = QPoint(butRect.left(), p11.y());
		painter->drawRoundedRect(butRect,0,10);
		painter->drawText(butRect,Qt::AlignCenter,txt);
		painter->restore();
		return;
	}
}

我们需要一个Combobox的Editor来做下拉框

QWidget * MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
	QStringList m_ls_itemtext;
	m_ls_itemtext<<"第一行"<<"第二行"<<"第三行"<<"第四行"<<"第五行"<<"第六行"<<"第七行"<<"第八行"<<"第九行";

	QComboBox *editor = new QComboBox(parent);
	editor->setEditable(true);
	editor->addItems(m_ls_itemtext);
	return editor;
}

void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
	if (!index.isValid())
	{
		return;
	}

	QString value = index.model()->data(index, Qt::EditRole).toString();
	QComboBox *comboBox = static_cast(editor);
	int icurIndex = comboBox->findText(value);

	if (icurIndex <= -1)
	{
		icurIndex = 0;
	}
	comboBox->setCurrentIndex(icurIndex);
}

双击选中的下拉框应该在此item的那一行位置

void MyDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
	auto xx = option.rect;

	auto yy = editor->rect();
	auto x = p33.x() + (200 - editor->geometry().width()) / 2;
	editor->move(x, xx.top());
}

我们需要把选中下拉框的值给到model

void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
	if (dynamic_cast(editor)->currentText() == "")
	{
		return;
	}

	model->setData(index, dynamic_cast(editor)->currentText(), Qt::UserRole+2);
}

QT listView学习_第1张图片

总结

我们通过直接通过一个 List 实现 model 的数据源,通过 paint 来绘制每一个item(每个item里可以放一些内容如按钮),通过 editorEvent 来处理鼠标的点击事件,通过 updateEditorGeometry 来处理更新编辑器的位置, createEditor、setEditorData 来创建和设置一个需要的Editor(下拉框、文本行等等),通过 setModelData 来将editor修改的值返回给model来交互,model值修改了又会反馈给View,达到修改视图的效果

你可能感兴趣的:(QT,qt)