Qt中显示复杂列表

来源:互联网 发布:网络销售平台搭建方案 编辑:程序博客网 时间:2024/05/16 11:42

提要

最近想要完成的一个项目需要显示一个列表,可以动态增减,可编辑,有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_OBJECTpublic: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, constQVariant &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_OBJECTpublic: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 backgroundbrush.setTexture(m_gridPixmap);painter->fillRect(x, y, 40, 40, brush);//Draw imagepainter->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_OBJECTpublic: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

0 1
原创粉丝点击