Qt中显示复杂列表

来源:互联网 发布:剑灵伪娘数据 编辑:程序博客网 时间:2024/05/17 03:29

提要

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


或者这样



但网上的例子都是这样

和这样



...

最后实现的效果:




QListWidget解决方案

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

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


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

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class UsersListItem : public QWidget    
  2. {    
  3.     Q_OBJECT    
  4. public:    
  5.     explicit UsersListItem(QWidget *parent = 0);    
  6.     
  7.     virtual QSize   sizeHint() const    
  8.     {    
  9.         return QSize(100,48);    
  10.     }    
  11. private:    
  12.     QLabel * m_labAddress;    
  13.     QLabel * m_labHeaderPic;    
  14.     QLabel * m_labUser;    
  15.     
  16. signals:    
  17.     
  18. public slots:    
  19.     
  20. };    


然后用

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

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef LAYERLISTMODEL_H  
  2. #define LAYERLISTMODEL_H  
  3.   
  4. #include <QAbstractTableModel>  
  5. #include <QStringList>  
  6. #include <QList>  
  7. #include <QPixmap>  
  8. #include <QImage>  
  9. #include <QIcon>  
  10. #include <QDebug>  
  11. #include <QItemSelectionModel>  
  12.   
  13. class LayerTableModel : public QAbstractTableModel  
  14. {  
  15.     Q_OBJECT  
  16.   
  17. public:  
  18.     LayerTableModel(QObject *parent = 0);  
  19.     ~LayerTableModel();  
  20.   
  21.     int rowCount(const QModelIndex &parent) const;  
  22.     int columnCount(const QModelIndex &parent) const;  
  23.     QVariant data(const QModelIndex &index, int role) const;   
  24.     QVariant headerData(int section,  
  25.         Qt::Orientation orientation,  
  26.         int role = Qt::DisplayRole) const;  
  27.     Qt::ItemFlags flags(const QModelIndex &index) const;  
  28.   
  29.     bool setData(const QModelIndex &index, const QVariant &value, int role);  
  30.     void deleteItem(int index);  
  31.     void addItem(QString &layerName, QImage &thumbnail, bool isShow = true);  
  32.     void refreshModel();  
  33.     QModelIndex& selecttedIndex(int row);  
  34.   
  35.     void setSelecttedRow(int row);  
  36.     int getSelecttedRow() const;  
  37.   
  38.   
  39. public slots:  
  40.     void changeLayerVisibility(const QModelIndex&);  
  41.   
  42. private:  
  43.     struct LayerItem  
  44.     {  
  45.         QString layerName;  
  46.         QImage thumbnail;  
  47.         float transparence;  
  48.         bool isShow;  
  49.     };  
  50.     QList<LayerItem> layerList;  
  51.       
  52.     int selectedRow;  
  53.   
  54. };  
  55.   
  56. #endif // LAYERLISTMODEL_H  

layertablemodel.cpp
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "layertablemodel.h"  
  2.   
  3. LayerTableModel::LayerTableModel(QObject *parent)  
  4. : QAbstractTableModel(parent)  
  5. {  
  6.     QImage image("images\\sample.jpg");  
  7.     layerList.reserve(3);  
  8.     selectedRow = 0;   
  9.     for (int i = 0; i < 3; i++)  
  10.     {  
  11.         addItem(QString(), image, true);  
  12.     }  
  13. }  
  14.   
  15. LayerTableModel::~LayerTableModel()  
  16. {  
  17.   
  18. }  
  19.   
  20. QVariant LayerTableModel::data(const QModelIndex &index, int role) const  
  21. {  
  22.     if (!index.isValid())  
  23.         return QVariant();  
  24.   
  25.     int column = index.column();  
  26.     if (column == 0)  
  27.     {  
  28.         if(role ==  Qt::CheckStateRole)  
  29.         {  
  30.             return layerList.at(index.row()).isShow ? Qt::Checked : Qt::Unchecked;  
  31.         }  
  32.         if (role == Qt::SizeHintRole)  
  33.         {  
  34.             return QSize(20, 50);  
  35.         }  
  36.     }  
  37.     else  
  38.     {  
  39.         if (role == Qt::EditRole)  
  40.         {  
  41.             return QVariant(layerList.at(index.row()).layerName);  
  42.         }  
  43.         if (role == Qt::DisplayRole)  
  44.         {  
  45.             return QVariant(layerList.at(index.row()).layerName);  
  46.         }  
  47.   
  48.         if (role == Qt::DecorationRole)  
  49.         {  
  50.             if (layerList.at(index.row()).thumbnail.isNull())  
  51.             {  
  52.                 return  layerList.at(index.row()).thumbnail;  
  53.             }else  
  54.             {  
  55.                 return  layerList.at(index.row()).thumbnail.scaledToHeight(40);  
  56.   
  57.             }  
  58.         }  
  59.         if (role == Qt::SizeHintRole)  
  60.         {  
  61.             return QSize(200, 50);  
  62.         }  
  63.         if (role == Qt::TextAlignmentRole)   
  64.         {  
  65.             return int(Qt::AlignVCenter);  
  66.         }  
  67.     }  
  68.   
  69.     return QVariant();  
  70. }  
  71.   
  72. int LayerTableModel::rowCount(const QModelIndex &parent) const  
  73. {  
  74.     return (parent.isValid() && parent.column() != 0) ? 0 : layerList.size();  
  75. }  
  76.   
  77. int LayerTableModel::columnCount(const QModelIndex &parent) const  
  78. {  
  79.     Q_UNUSED(parent);  
  80.     return 2;  
  81. }  
  82.   
  83. QVariant LayerTableModel::headerData(int section, Qt::Orientation orientation, int role) const  
  84. {  
  85.     if (role == Qt::DisplayRole)  
  86.         return QString::number(section);  
  87.     //if (role == Qt::DecorationRole)  
  88.         //return QVariant::fromValue(services);  
  89.     return QAbstractItemModel::headerData(section, orientation, role);  
  90. }  
  91.   
  92. Qt::ItemFlags LayerTableModel::flags(const QModelIndex &index) const  
  93. {  
  94.   
  95.     if (!index.isValid())  
  96.         return 0;  
  97.   
  98.     if (index.column() == 0)  
  99.         return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;  
  100.   
  101.     return  Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;  
  102. }  
  103.   
  104. bool LayerTableModel::setData(const QModelIndex &index, const  
  105.     QVariant &value, int role)  
  106. {  
  107.     if (!index.isValid())  
  108.     {  
  109.         return false;  
  110.     }  
  111.   
  112.     if (role == Qt::CheckStateRole && value.type() == QVariant::Bool)  
  113.     {  
  114.         layerList[index.row()].isShow = value.toBool();  
  115.         emit(dataChanged(index, index));  
  116.         return true;  
  117.     }  
  118.     if (role == Qt::EditRole && index.column() == 1)  
  119.     {  
  120.         layerList[index.row()].layerName = value.toString();  
  121.         emit(dataChanged(index, index));  
  122.         return true;  
  123.     }  
  124.     return false;;  
  125. }  
  126.   
  127. void LayerTableModel::changeLayerVisibility(const QModelIndex& index)  
  128. {  
  129.     if (index.isValid()&&index.column() == 0)  
  130.     {  
  131.         setData(index, !(layerList.at(index.row()).isShow), Qt::CheckStateRole);  
  132.     }  
  133. }  
  134.   
  135. void LayerTableModel::deleteItem(int index)  
  136. {  
  137.     QList<LayerItem>::iterator it = layerList.begin();  
  138.     layerList.erase(it + index);  
  139. }  
  140.   
  141. void LayerTableModel::addItem(QString &name, QImage &thumb, bool show)  
  142. {  
  143.     LayerItem item;  
  144.     if (name.size() == 0)  
  145.     {  
  146.         item.layerName = QString("Layer ") + QString::number(layerList.size());  
  147.     }else{  
  148.         item.layerName = name;  
  149.     }  
  150.     item.isShow = show;  
  151.       
  152.     item.thumbnail = thumb;  
  153.     layerList.append(item);  
  154.     //this->insertRow()  
  155.     //emit(dataChanged(index, index));  
  156.     qDebug()<<layerList.size();  
  157. }  
  158.   
  159. void LayerTableModel::refreshModel()  
  160. {  
  161.     beginResetModel();  
  162.     endResetModel();  
  163.     //emit updateCount(this->rowCount(QModelIndex()));  
  164. }  
  165.   
  166. QModelIndex& LayerTableModel::selecttedIndex(int row)  
  167. {  
  168.     return this->createIndex(row, 1);  
  169. }  
  170.   
  171. void LayerTableModel::setSelecttedRow(int row)  
  172. {  
  173.     selectedRow = row;  
  174. }  
  175.   
  176. int LayerTableModel::getSelecttedRow() const  
  177. {  
  178.     return selectedRow;  
  179. }  


然后是delegate

layeritemdelegate.h

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef LAYERITEMDELEGATE_H  
  2. #define LAYERITEMDELEGATE_H  
  3.   
  4. #include <QStyledItemDelegate>  
  5. #include <QLineEdit>  
  6. #include <QDebug>  
  7. #include <QPainter>  
  8.   
  9. class LayerItemDelegate : public QStyledItemDelegate  
  10. {  
  11.     Q_OBJECT  
  12.   
  13. public:  
  14.     LayerItemDelegate(QObject *parent=0);  
  15.     ~LayerItemDelegate();  
  16.   
  17.   
  18.     void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;  
  19.     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,  
  20.         const QModelIndex &index) const;  
  21.     bool editorEvent(QEvent * event,  
  22.         QAbstractItemModel * model,  
  23.         const QStyleOptionViewItem & option,  
  24.         const QModelIndex & index);  
  25.     void setEditorData(QWidget *editor, const QModelIndex &index) const;  
  26.     void setModelData(QWidget *editor, QAbstractItemModel *model,  
  27.         const QModelIndex &index) const;  
  28.     void updateEditorGeometry(QWidget *editor,  
  29.         const QStyleOptionViewItem &option, const QModelIndex &index) const;  
  30.   
  31. private:  
  32.     QPixmap m_gridPixmap;  
  33. };  
  34.   
  35. #endif // LAYERITEMDELEGATE_H  


layeritemdelegate.cpp

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "layeritemdelegate.h"  
  2.   
  3. LayerItemDelegate::LayerItemDelegate(QObject *parent)  
  4.     : QStyledItemDelegate(parent)  
  5. {  
  6.     QImage gridImage(200, 200, QImage::Format_RGB32);  
  7.     QRgb grey = QColor(204, 204, 204).rgb();  
  8.     QRgb white = QColor(255, 255, 255).rgb();  
  9.     for (int i = 0; i < 200; i++)  
  10.     for (int j = 0; j < 200; j++)  
  11.     {  
  12.         int tmpX = i % 10;  
  13.         int tmpY = j % 10;  
  14.         if (tmpX < 5)  
  15.         {  
  16.             gridImage.setPixel(i, j, tmpY < 5 ? grey : white);  
  17.         }  
  18.         else  
  19.         {  
  20.             gridImage.setPixel(i, j, tmpY < 5 ? white : grey);  
  21.         }  
  22.     }  
  23.   
  24.     m_gridPixmap = QPixmap::fromImage(gridImage);  
  25. }  
  26.   
  27. LayerItemDelegate::~LayerItemDelegate()  
  28. {  
  29.   
  30. }  
  31.   
  32.   
  33.   
  34. void LayerItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const  
  35. {  
  36.   
  37.   
  38.     if (index.column() == 1) // value column  
  39.     {  
  40.         if (option.state & QStyle::State_Selected)  
  41.             painter->fillRect(option.rect, option.palette.highlight());  
  42.   
  43.         QImage image = qvariant_cast<QImage>(index.data(Qt::DecorationRole));  
  44.         //QImage image = index.model()->data(index, Qt::DecorationRole).toString();  
  45.         QRect rect = option.rect;  
  46.         int x = rect.x() + 10;  
  47.         int y = rect.y() + 5;  
  48.   
  49.         QBrush brush;  
  50.         //Draw grid background  
  51.         brush.setTexture(m_gridPixmap);  
  52.         painter->fillRect(x, y, 40, 40, brush);  
  53.   
  54.         //Draw image  
  55.         painter->drawImage(x, y, image);  
  56.   
  57.         QRect textRect(rect.x() + 60, rect.y(), rect.width() - 60, rect.height());  
  58.   
  59.         QString layerName = index.model()->data(index, Qt::DisplayRole).toString();  
  60.         QTextOption textOption = Qt::AlignLeft | Qt::AlignVCenter;  
  61.         painter->drawText(textRect, layerName, textOption);  
  62.   
  63.     }  
  64.     else  
  65.     {  
  66.         QStyledItemDelegate::paint(painter, option, index);  
  67.     }  
  68. }  
  69.   
  70.   
  71. bool LayerItemDelegate::editorEvent(QEvent * event,  
  72.     QAbstractItemModel * model,  
  73.     const QStyleOptionViewItem & option,  
  74.     const QModelIndex & index)  
  75. {  
  76.     return false;  
  77. }  
  78.   
  79. QWidget *LayerItemDelegate::createEditor(QWidget *parent,  
  80.     const QStyleOptionViewItem &option,  
  81.     const QModelIndex &index) const  
  82. {  
  83.     qDebug() << "createEditor";  
  84.     if (index.column() == 1) // value column  
  85.     {  
  86.         QLineEdit* edit = new QLineEdit(parent);  
  87.         edit->setFixedHeight(33);  
  88.         edit->setContentsMargins(48, 15, 50, 0);  
  89.         return edit;  
  90.     }  
  91.     else return 0;  // no editor attached  
  92. }  
  93.   
  94. void LayerItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const  
  95. {  
  96.     QString value = index.model()->data(index, Qt::EditRole).toString();  
  97.   
  98.     QLineEdit *edit = static_cast<QLineEdit*>(editor);  
  99.     edit->setText(value);  
  100.     qDebug() << "setEditorData";  
  101. }  
  102.   
  103. void LayerItemDelegate::updateEditorGeometry(QWidget *editor,  
  104.     const QStyleOptionViewItem &option, const QModelIndex & index ) const  
  105. {  
  106.     editor->setGeometry(option.rect);  
  107. }  
  108.   
  109. void LayerItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,  
  110.     const QModelIndex &index) const  
  111. {  
  112.     qDebug() << "setModelData";  
  113.     QLineEdit *edit = static_cast<QLineEdit*>(editor);  
  114.     model->setData(index, edit->text(), Qt::EditRole);  
  115. }  


最后是view

layertableview.h

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef LAYERLISTVIEW_H  
  2. #define LAYERLISTVIEW_H  
  3.   
  4. #include <QTableView>  
  5. #include <QMouseEvent>  
  6. #include <QDebug>  
  7. #include <QHeaderView>  
  8. #include <QStandardItemModel>  
  9. #include <QContextMenuEvent>  
  10. #include <QMenu>  
  11. #include "layertablemodel.h"  
  12. #include "layeritemdelegate.h"  
  13.   
  14. class LayerTableView : public QTableView  
  15. {  
  16.     Q_OBJECT  
  17.   
  18. public:  
  19.     LayerTableView(QWidget *parent = 0);  
  20.     ~LayerTableView();  
  21.     void setLayerSize(QSize s);  
  22.   
  23. public slots:  
  24.     void addNewLayer();  
  25.     void deleteLayer();  
  26.   
  27. protected:  
  28.     void mouseMoveEvent(QMouseEvent * event);  
  29.     void contextMenuEvent(QContextMenuEvent * event);  
  30.   
  31. private:  
  32.     LayerItemDelegate *delegate;  
  33.     LayerTableModel *model;  
  34.     QSize layerSize;  
  35.   
  36. private slots:  
  37.     void itemClicked(const QModelIndex&);  
  38.   
  39. };  
  40.   
  41. #endif // LAYERLISTVIEW_H  


layertableview.cpp

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "layertableview.h"  
  2.   
  3. LayerTableView::LayerTableView(QWidget *parent)  
  4. : QTableView(parent)  
  5. {  
  6.     delegate = new LayerItemDelegate();  
  7.     model = new LayerTableModel();  
  8.       
  9.     this->setContentsMargins(0, 0, 0, 0);  
  10.     this->setModel(model);  
  11.     this->setItemDelegate(delegate);  
  12.   
  13.     this->horizontalHeader()->setStretchLastSection(true);  
  14.     this->horizontalHeader()->setHighlightSections(false);  
  15.     this->setFrameShape(QFrame::NoFrame);  
  16.     this->setColumnWidth(0, 30);  
  17.     this->setColumnWidth(1, 170);  
  18.     this->verticalHeader()->setVisible(false);  
  19.     this->horizontalHeader()->setVisible(false);  
  20.     this->resizeColumnsToContents();  
  21.     this->resizeRowsToContents();  
  22.     /*this->setEditTriggers(QAbstractItemView::NoEditTriggers); 
  23.     this->setSelectionBehavior(QAbstractItemView::SelectRows);*/  
  24.     this->setMouseTracking(true);//important  
  25.   
  26.     //When click on the checkbox it will emit signal twice.Click on the cell emit only once.  
  27.     connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(itemClicked(const QModelIndex&)));  
  28. }  
  29.   
  30. LayerTableView::~LayerTableView()  
  31. {  
  32.   
  33. }  
  34.   
  35. void LayerTableView::mouseMoveEvent(QMouseEvent * event)  
  36. {  
  37.   
  38. }  
  39.   
  40.   
  41.   
  42. void LayerTableView::contextMenuEvent(QContextMenuEvent * event)  
  43. {  
  44.   
  45.     QMenu *pMenu = new QMenu(this);  
  46.     QAction *pAddGroupAct = new QAction(tr("Delete"), pMenu);  
  47.     pMenu->addAction(pAddGroupAct);  
  48.     pMenu->popup(mapToGlobal(event->pos()));  
  49.   
  50. }  
  51.   
  52. void LayerTableView::addNewLayer()  
  53. {  
  54.     model->addItem(QString(), QImage(layerSize, QImage::Format_RGB32), true);  
  55.     //model->addItem(QString(), QImage("images\\sample.jpg"), true);  
  56.     model->refreshModel();  
  57.     this->resizeRowsToContents();  
  58. }  
  59.   
  60. void LayerTableView::itemClicked(const QModelIndex& index)  
  61. {  
  62.     if (index.isValid() )  
  63.     {  
  64.         //When click in column 0.  
  65.         if (index.column() == 0)  
  66.         {  
  67.             model->changeLayerVisibility(index);  
  68.             QModelIndex tmp = model->selecttedIndex(model->getSelecttedRow());  
  69.             this->selectionModel()->select(tmp, QItemSelectionModel::Select);  
  70.         }  
  71.         //When click in column 1.  
  72.         else if (index.column() == 1)  
  73.         {  
  74.             model->setSelecttedRow(index.row());  
  75.         }  
  76.     }  
  77. }  
  78.   
  79. void LayerTableView::deleteLayer()  
  80. {  
  81.     model->deleteItem(model->getSelecttedRow());  
  82.     model->refreshModel();  
  83.   
  84.     QModelIndex tmp = model->selecttedIndex(0);  
  85.     this->selectionModel()->select(tmp, QItemSelectionModel::Select);  
  86. }  
  87.   
  88. void LayerTableView::setLayerSize(QSize s)  
  89. {  
  90.     layerSize = s;  
  91. }  


参考

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 0
原创粉丝点击