Qt中显示复杂列表

提要

最近想要完成的一个项目需要显示一个列表,可以动态增减,可编辑,有checkbox。类似于这样

或者这样

但网上的例子都是这样

和这样

...

最后实现的效果:

QListWidget解决方案

在Android实现这样的列表是非常简单的,首先定义布局XML,然后再定义一个Adapter就可以了。

Qt中类似的解决方案就是QListWidget。

自定义一个Widget类作为Item,比如

class UsersListItem : public QWidget
{
    Q_OBJECT
public:
    explicit UsersListItem(QWidget *parent = 0);  

    virtual QSize   sizeHint() const
    {
        return QSize(100,48);
    }
private:
    QLabel * m_labAddress;
    QLabel * m_labHeaderPic;
    QLabel * m_labUser;  

signals:  

public slots:  

};  

然后用

void QListWidget::setItemWidget ( QListWidgetItem * item, QWidget * widget )

将widget作为item显示。

这种方法最为简单,但是仔细看下官网的函数说明....

This function should only be used to display static content in the place of a list widget item. If you want to display custom dynamic content or implement a custom editor widget, use QListView and subclass QItemDelegate instead.

只能用来显示静态数据,如果要显示动态数据,请使用QListView和QItemDelegate。

自定义Model自定义View 自定义Delegate

首先要明白这几个东西的概念和关系

与MVC模式不同,model/view结构没有用于与用户交互的完全独立的组件。一般来讲, view负责把数据展示给用户,也处理用户的输入。为了获得更多的灵性性,交互通过delegagte执行。它既提供输入功能又负责渲染view中的每个数据项。
使用Delegate的原因 Qt中当用到QTreeView和QTableView等用于显示item的视图时,你要编辑一个item用到的编辑工具可能是除了默认文字编辑lineEdit以外的工具,例如button,spinBox,甚至Slider,ProgressBar,也有可能是自定义的widget。所以Qt提供了一个委托类,用来处理View中的数据展示方式。

Qt提供的标准views都使用QItemDelegate的实例来提供编辑功能。它以普通的风格来为每个标准view渲染数据项。这些标准的views包括:QListView,QTableView,QTreeView。所有标准的角色都通过标准views包含的缺省delegate进行处理。一个view使用的delegate可以用itemDelegate()函数取得,而setItemDelegate() 函数可以安装一个定制delegate。

简单的说就是需要自己实现的东西变多了,但是可以定制的地方也就多了。下面主要是贴代码,慎入!

首先是model

layertablemodel.h

#ifndef LAYERLISTMODEL_H
#define LAYERLISTMODEL_H

#include <QAbstractTableModel>
#include <QStringList>
#include <QList>
#include <QPixmap>
#include <QImage>
#include <QIcon>
#include <QDebug>
#include <QItemSelectionModel>

class LayerTableModel : public QAbstractTableModel
{
	Q_OBJECT

public:
	LayerTableModel(QObject *parent = 0);
	~LayerTableModel();

	int rowCount(const QModelIndex &parent) const;
	int columnCount(const QModelIndex &parent) const;
	QVariant data(const QModelIndex &index, int role) const;
	QVariant headerData(int section,
		Qt::Orientation orientation,
		int role = Qt::DisplayRole) const;
	Qt::ItemFlags flags(const QModelIndex &index) const;

	bool setData(const QModelIndex &index, const QVariant &value, int role);
	void deleteItem(int index);
	void addItem(QString &layerName, QImage &thumbnail, bool isShow = true);
	void refreshModel();
	QModelIndex& selecttedIndex(int row);

	void setSelecttedRow(int row);
	int getSelecttedRow() const;

public slots:
	void changeLayerVisibility(const QModelIndex&);

private:
	struct LayerItem
	{
		QString layerName;
		QImage thumbnail;
		float transparence;
		bool isShow;
	};
	QList<LayerItem> layerList;

	int selectedRow;

};

#endif // LAYERLISTMODEL_H

layertablemodel.cpp

#include "layertablemodel.h"

LayerTableModel::LayerTableModel(QObject *parent)
: QAbstractTableModel(parent)
{
	QImage image("images\\sample.jpg");
	layerList.reserve(3);
	selectedRow = 0;
	for (int i = 0; i < 3; i++)
	{
		addItem(QString(), image, true);
	}
}

LayerTableModel::~LayerTableModel()
{

}

QVariant LayerTableModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())
		return QVariant();

	int column = index.column();
	if (column == 0)
	{
		if(role ==  Qt::CheckStateRole)
		{
			return layerList.at(index.row()).isShow ? Qt::Checked : Qt::Unchecked;
		}
		if (role == Qt::SizeHintRole)
		{
			return QSize(20, 50);
		}
	}
	else
	{
		if (role == Qt::EditRole)
		{
			return QVariant(layerList.at(index.row()).layerName);
		}
		if (role == Qt::DisplayRole)
		{
			return QVariant(layerList.at(index.row()).layerName);
		}

		if (role == Qt::DecorationRole)
		{
			if (layerList.at(index.row()).thumbnail.isNull())
			{
				return  layerList.at(index.row()).thumbnail;
			}else
			{
				return  layerList.at(index.row()).thumbnail.scaledToHeight(40);

			}
		}
		if (role == Qt::SizeHintRole)
		{
			return QSize(200, 50);
		}
		if (role == Qt::TextAlignmentRole)
		{
			return int(Qt::AlignVCenter);
		}
	}

	return QVariant();
}

int LayerTableModel::rowCount(const QModelIndex &parent) const
{
	return (parent.isValid() && parent.column() != 0) ? 0 : layerList.size();
}

int LayerTableModel::columnCount(const QModelIndex &parent) const
{
	Q_UNUSED(parent);
	return 2;
}

QVariant LayerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (role == Qt::DisplayRole)
		return QString::number(section);
	//if (role == Qt::DecorationRole)
		//return QVariant::fromValue(services);
	return QAbstractItemModel::headerData(section, orientation, role);
}

Qt::ItemFlags LayerTableModel::flags(const QModelIndex &index) const
{

	if (!index.isValid())
		return 0;

	if (index.column() == 0)
		return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;

	return  Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}

bool LayerTableModel::setData(const QModelIndex &index, const
	QVariant &value, int role)
{
	if (!index.isValid())
	{
		return false;
	}

	if (role == Qt::CheckStateRole && value.type() == QVariant::Bool)
	{
		layerList[index.row()].isShow = value.toBool();
		emit(dataChanged(index, index));
		return true;
	}
	if (role == Qt::EditRole && index.column() == 1)
	{
		layerList[index.row()].layerName = value.toString();
		emit(dataChanged(index, index));
		return true;
	}
	return false;;
}

void LayerTableModel::changeLayerVisibility(const QModelIndex& index)
{
	if (index.isValid()&&index.column() == 0)
	{
		setData(index, !(layerList.at(index.row()).isShow), Qt::CheckStateRole);
	}
}

void LayerTableModel::deleteItem(int index)
{
	QList<LayerItem>::iterator it = layerList.begin();
	layerList.erase(it + index);
}

void LayerTableModel::addItem(QString &name, QImage &thumb, bool show)
{
	LayerItem item;
	if (name.size() == 0)
	{
		item.layerName = QString("Layer ") + QString::number(layerList.size());
	}else{
		item.layerName = name;
	}
	item.isShow = show;

	item.thumbnail = thumb;
	layerList.append(item);
	//this->insertRow()
	//emit(dataChanged(index, index));
	qDebug()<<layerList.size();
}

void LayerTableModel::refreshModel()
{
	beginResetModel();
	endResetModel();
	//emit updateCount(this->rowCount(QModelIndex()));
}

QModelIndex& LayerTableModel::selecttedIndex(int row)
{
	return this->createIndex(row, 1);
}

void LayerTableModel::setSelecttedRow(int row)
{
	selectedRow = row;
}

int LayerTableModel::getSelecttedRow() const
{
	return selectedRow;
}

然后是delegate

layeritemdelegate.h

#ifndef LAYERITEMDELEGATE_H
#define LAYERITEMDELEGATE_H

#include <QStyledItemDelegate>
#include <QLineEdit>
#include <QDebug>
#include <QPainter>

class LayerItemDelegate : public QStyledItemDelegate
{
	Q_OBJECT

public:
	LayerItemDelegate(QObject *parent=0);
	~LayerItemDelegate();

	void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
	QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
		const QModelIndex &index) const;
	bool editorEvent(QEvent * event,
		QAbstractItemModel * model,
		const QStyleOptionViewItem & option,
		const QModelIndex & index);
	void setEditorData(QWidget *editor, const QModelIndex &index) const;
	void setModelData(QWidget *editor, QAbstractItemModel *model,
		const QModelIndex &index) const;
	void updateEditorGeometry(QWidget *editor,
		const QStyleOptionViewItem &option, const QModelIndex &index) const;

private:
	QPixmap m_gridPixmap;
};

#endif // LAYERITEMDELEGATE_H

layeritemdelegate.cpp

#include "layeritemdelegate.h"

LayerItemDelegate::LayerItemDelegate(QObject *parent)
	: QStyledItemDelegate(parent)
{
	QImage gridImage(200, 200, QImage::Format_RGB32);
	QRgb grey = QColor(204, 204, 204).rgb();
	QRgb white = QColor(255, 255, 255).rgb();
	for (int i = 0; i < 200; i++)
	for (int j = 0; j < 200; j++)
	{
		int tmpX = i % 10;
		int tmpY = j % 10;
		if (tmpX < 5)
		{
			gridImage.setPixel(i, j, tmpY < 5 ? grey : white);
		}
		else
		{
			gridImage.setPixel(i, j, tmpY < 5 ? white : grey);
		}
	}

	m_gridPixmap = QPixmap::fromImage(gridImage);
}

LayerItemDelegate::~LayerItemDelegate()
{

}

void LayerItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{

	if (index.column() == 1) // value column
	{
		if (option.state & QStyle::State_Selected)
			painter->fillRect(option.rect, option.palette.highlight());

		QImage image = qvariant_cast<QImage>(index.data(Qt::DecorationRole));
		//QImage image = index.model()->data(index, Qt::DecorationRole).toString();
		QRect rect = option.rect;
		int x = rect.x() + 10;
		int y = rect.y() + 5;

		QBrush brush;
		//Draw grid background
		brush.setTexture(m_gridPixmap);
		painter->fillRect(x, y, 40, 40, brush);

		//Draw image
		painter->drawImage(x, y, image);

		QRect textRect(rect.x() + 60, rect.y(), rect.width() - 60, rect.height());

		QString layerName = index.model()->data(index, Qt::DisplayRole).toString();
		QTextOption textOption = Qt::AlignLeft | Qt::AlignVCenter;
		painter->drawText(textRect, layerName, textOption);

	}
	else
	{
		QStyledItemDelegate::paint(painter, option, index);
	}
}

bool LayerItemDelegate::editorEvent(QEvent * event,
	QAbstractItemModel * model,
	const QStyleOptionViewItem & option,
	const QModelIndex & index)
{
	return false;
}

QWidget *LayerItemDelegate::createEditor(QWidget *parent,
	const QStyleOptionViewItem &option,
	const QModelIndex &index) const
{
	qDebug() << "createEditor";
	if (index.column() == 1) // value column
	{
		QLineEdit* edit = new QLineEdit(parent);
		edit->setFixedHeight(33);
		edit->setContentsMargins(48, 15, 50, 0);
		return edit;
	}
	else return 0;  // no editor attached
}

void LayerItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
	QString value = index.model()->data(index, Qt::EditRole).toString();

	QLineEdit *edit = static_cast<QLineEdit*>(editor);
	edit->setText(value);
	qDebug() << "setEditorData";
}

void LayerItemDelegate::updateEditorGeometry(QWidget *editor,
	const QStyleOptionViewItem &option, const QModelIndex & index ) const
{
	editor->setGeometry(option.rect);
}

void LayerItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
	const QModelIndex &index) const
{
	qDebug() << "setModelData";
	QLineEdit *edit = static_cast<QLineEdit*>(editor);
	model->setData(index, edit->text(), Qt::EditRole);
}

最后是view

layertableview.h

#ifndef LAYERLISTVIEW_H
#define LAYERLISTVIEW_H

#include <QTableView>
#include <QMouseEvent>
#include <QDebug>
#include <QHeaderView>
#include <QStandardItemModel>
#include <QContextMenuEvent>
#include <QMenu>
#include "layertablemodel.h"
#include "layeritemdelegate.h"

class LayerTableView : public QTableView
{
	Q_OBJECT

public:
	LayerTableView(QWidget *parent = 0);
	~LayerTableView();
	void setLayerSize(QSize s);

public slots:
	void addNewLayer();
	void deleteLayer();

protected:
	void mouseMoveEvent(QMouseEvent * event);
	void contextMenuEvent(QContextMenuEvent * event);

private:
	LayerItemDelegate *delegate;
	LayerTableModel *model;
	QSize layerSize;

private slots:
	void itemClicked(const QModelIndex&);

};

#endif // LAYERLISTVIEW_H

layertableview.cpp

#include "layertableview.h"

LayerTableView::LayerTableView(QWidget *parent)
: QTableView(parent)
{
	delegate = new LayerItemDelegate();
	model = new LayerTableModel();

	this->setContentsMargins(0, 0, 0, 0);
	this->setModel(model);
	this->setItemDelegate(delegate);

	this->horizontalHeader()->setStretchLastSection(true);
	this->horizontalHeader()->setHighlightSections(false);
	this->setFrameShape(QFrame::NoFrame);
	this->setColumnWidth(0, 30);
	this->setColumnWidth(1, 170);
	this->verticalHeader()->setVisible(false);
	this->horizontalHeader()->setVisible(false);
	this->resizeColumnsToContents();
	this->resizeRowsToContents();
	/*this->setEditTriggers(QAbstractItemView::NoEditTriggers);
	this->setSelectionBehavior(QAbstractItemView::SelectRows);*/
	this->setMouseTracking(true);//important

	//When click on the checkbox it will emit signal twice.Click on the cell emit only once.
	connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(itemClicked(const QModelIndex&)));
}

LayerTableView::~LayerTableView()
{

}

void LayerTableView::mouseMoveEvent(QMouseEvent * event)
{

}

void LayerTableView::contextMenuEvent(QContextMenuEvent * event)
{

	QMenu *pMenu = new QMenu(this);
	QAction *pAddGroupAct = new QAction(tr("Delete"), pMenu);
	pMenu->addAction(pAddGroupAct);
	pMenu->popup(mapToGlobal(event->pos()));

}

void LayerTableView::addNewLayer()
{
	model->addItem(QString(), QImage(layerSize, QImage::Format_RGB32), true);
	//model->addItem(QString(), QImage("images\\sample.jpg"), true);
	model->refreshModel();
	this->resizeRowsToContents();
}

void LayerTableView::itemClicked(const QModelIndex& index)
{
	if (index.isValid() )
	{
		//When click in column 0.
		if (index.column() == 0)
		{
			model->changeLayerVisibility(index);
			QModelIndex tmp = model->selecttedIndex(model->getSelecttedRow());
			this->selectionModel()->select(tmp, QItemSelectionModel::Select);
		}
		//When click in column 1.
		else if (index.column() == 1)
		{
			model->setSelecttedRow(index.row());
		}
	}
}

void LayerTableView::deleteLayer()
{
	model->deleteItem(model->getSelecttedRow());
	model->refreshModel();

	QModelIndex tmp = model->selecttedIndex(0);
	this->selectionModel()->select(tmp, QItemSelectionModel::Select);
}

void LayerTableView::setLayerSize(QSize s)
{
	layerSize = s;
}

参考

Qt Delgate的使用 简单说明 - http://qimo601.iteye.com/blog/1536444

Qt Model/View 学习笔记 - http://www.cppblog.com/yuanyajie/archive/2007/06/19/26641.html

Model/View Programming - https://qt-project.org/doc/qt-4.7/model-view-programming.html#an-editable-model

Qt实现QQ好友下拉列表 - http://blog.csdn.net/hai200501019/article/details/10283553

QTableView使用自定义委托 - http://www.haogongju.net/art/2811045

时间: 2024-10-16 16:22:15

Qt中显示复杂列表的相关文章

centos中设置apache显示目录列表

apache中显示目录列表 在http.conf中加入如下代码(如有虚拟主机配置,加在虚拟主机配置段内),并把主目录内的index.pho,index.html,index.htm文件删除 复制代码 代码如下: Alias /download "/download"  <Directory "/download">    Options Indexes    Order allow,deny    IndexOptions Charset=UTF-8  

QT中循环显示图片和简单的显示图片

请关注我的github https://github.com/linqiaozhou 以下实例代码不久后将会上传到我的github 这是我最近一个项目中的部分代码 //以下是简单的在QT中显示图片的代码 this->imageOrg = new QImage();     if(fileName != "")     {         if(imageOrg->load(fileName))         {               this->scene =

故障描述:VM在vCenter列表中显示为unknown状态

故障描述:VM在vCenter列表中显示为灰色不可用状态,在vCenter界面打开其所在数据存储,"添加到清单"呈现灰色:直连该VM所在ESXi主机显示为"unknown"状态 处理过程: 1.使用SSH连接至该VM当前所在的ESXi主机上: 2.使用如下命令,确认该VM当前被哪台ESXi主机锁定: vmkfstools -D  虚拟机vmx的绝对路径 图例(截图源于网络): 如上黄线所示为当前锁定该VM的ESXi主机的一个物理网卡mac地址,可在vCenter中E

在ECSHOP后台的订单列表中显示配送方式

熟悉ECSHOP后台的人都知道,只有点击某个具体的订单,进入订单详细页面才能看到该订单的配送方式,最模板修改的目的,是想让管理者在订单列表页面 就能看到该订单的配送方式. 下面是修改方法:首先来修改 程序文件, 打开文件 /admin/order.php 将 $sql = "SELECT o.order_id, o.order_sn, o.add_time, o.order_status, o.shipping_status, o.order_amount, o.money_paid,"

Qt中图像的显示与基本操作

Qt可显示基本的图像类型,利用QImage.QPxmap类可以实现图像的显示,并且利用类中的方法可以实现图像的基本操作(缩放.旋转). 1. Qt可显示的图像类型 参考Qt的帮助文档,可支持的类型,即可以直接读取并显示的格式有BMP.GIF.JPG.JPEG.PNG.TIFF.PBM.PGM.PPM.XBM.XPM. 2. Qt用如何显示图像 通常用QLabel显示图像,QLabel类有setPixmap()函数,可以用来显示图像.也可以直接用QPainter画出图像. 如果图像过大,直接用QL

QT使用tableWidget显示双排列表 并且选中用红框圈出来

如需转载请标明出处:http://blog.csdn.net/itas109 整个工程下载地址:http://download.csdn.net/detail/itas109/7607735 这里采用tableWidget显示双排列表 双排列表代码 QTableWidgetItem* item[50]; int Row; if (num%2 == 1) { Row = num/picColumn+1; } else { Row = num/picColumn; } int index;//表格坐

Qt中QWidget加入到父类QWidget不能显示的问题

最近忙活了半天发现了一个不容易发现的问题,比如我有一个父类的自定义Widget,并且自己设置了Pattle,但这个时候我如果再在当前Widget内部加入自己的widget就不能正常显示,但是加QPushButton就可以显示. 百思不得其解,我还特意让两个widget各自设置了不同的pattle,还是不行. 最后我发现原来在Qt中,子类widget就算内部自己设置了pattle,在setParent之后还是会继承父类的pattle,所以你就算父亲是绿色,孩子是红色,加入之后,孩子依旧还是父亲的绿

QT中关于窗口全屏显示与退出全屏的实现

近期在学习QT时遇到了很多问题这也是其中一个,个人通过在各种书籍和网络上的查阅找到了一些关于这方面的答案,希望能给大家一些帮助. 首先,在QT中对于窗口显示常用的有这么几个方法可以调用: Qt全屏显示函数            showFullScreen() Qt最大化显示函数         showMaximized()Qt最小化显示函数         showMinimized()Qt固定尺寸显示函数      resize(x,y)Qt设置最大尺寸函数      setMaximum

Android如何修改app不在多任务列表中显示

在实际开发中,我们希望某些activity或者应用程序不在多任务列表中显示,即长按Home键或者多任务按钮键不显示最近运行的程序,我们可以在相应应用程序的AndroidManifest.xml文件中的activity标签中添加如下属性: android:excludeFromRecents="true" 比如不需要xxxActivity显示在多任务列表中: <activity android:name="xxxActivity" android:label=&