• 543阅读
  • 2回复

[讨论]QListView如何实现点击勾选,再点击取消勾选 [复制链接]

上一主题 下一主题
离线lwei24
 

只看楼主 倒序阅读 楼主  发表于: 2023-08-10
如题,为了实现QListView每次只能单击一个item,单击item时,右上角显示勾选,再单击后显示不勾选。具体代码如下:
  1. //初始化QListView
  2.     m_listView = new QListView(m_widgetPage2);
  3.     m_listView->setStyleSheet("...");
  4.     m_itemDelegate = new ItemDelegate;
  5.     m_listView->setItemDelegate(m_itemDelegate);
  6.     m_listView->setSpacing(10);
  7.     m_listView->setFlow(QListView::LeftToRight);
  8.     m_listView->setViewMode(QListView::ListMode);
  9.     m_listView->setDragEnabled(false);
  10.     m_listView->setResizeMode(QListView::Adjust);
  11.     //m_listView->setSelectionMode(QAbstractItemView::MultiSelection); 如果添加此行代码,item能多选,也能单击单选并单击单选取消
  12.     m_listView->setSelectionBehavior(QAbstractItemView::SelectItems);
  13.     m_listView->setWrapping(true);
  14.     m_listView->setContextMenuPolicy(Qt::NoContextMenu);
  15.     m_listView->setCursor(QCursor(Qt::PointingHandCursor));
   当鼠标悬浮在items上时,右上角显示一个圆圈,点击时右上角显示一个勾选,再点击时,右上角取消勾选显示未点击状态。即在代理添加
  1. if(option.state.testFlag(QStyle::State_Selected))
  2.         {
  3.             //选中时勾选png图标
  4.             QPixmap checkImg(":/res/listview/check.png");
  5.             painter->drawPixmap(circle.x(), circle.y(), checkImg.width(), checkImg.height(), checkImg);
  6.         }
  7.         else if(option.state.testFlag(QStyle::State_MouseOver))  //鼠标悬浮
  8.         {
  9.             //未选状态,显示一个圆圈
  10.             QPixmap uncheckImg(":/res/listview/uncheck_1.png");    
  11.             painter->drawPixmap(circle.x(), circle.y(), uncheckImg.width(), uncheckImg.height(), uncheckImg);
  12.         }
因为想要做成每次只能点击一个item,如果选中该item,即鼠标第一次点击后,会出现勾选,第二次点击后,取消勾选(若鼠标仍然悬浮在该item上面,即会显示一个圆圈)。如以上代码,如果加上m_listView->setSelectionMode(QAbstractItemView::MultiSelection);,则可以实现鼠标第一次勾选,第二次取消勾选的功能,可是这样就选择多个item,不满足一次只能勾选一个item。各位大佬,有什么办法,能做到每次只选择一个item,第一次勾选,第二次取消勾选吗?欢迎各位大佬指点一二,小弟感激不尽,在线等!!!


离线20091001753

只看该作者 1楼 发表于: 2023-08-10
当自定义的绘制呈现一定复杂性的时候,例如需要参考其他数据时,你就需要再定义一个类。

例如每个item背后都有一个类实例,储存着相关的数据,你可以把类的指针直接存在item里。

数据例如item是否被选中,也就是在选中或取消时,修改这个指针实例里的类成员就好。

当你需求更复杂时,也可以把部分逻辑放在这个类里,这样可以让代理类专心处理绘制逻辑。
(づ ̄ 3 ̄)づ
离线lwei24

只看该作者 2楼 发表于: 2023-08-11
回 20091001753 的帖子
20091001753:
当自定义的绘制呈现一定复杂性的时候,例如需要参考其他数据时,你就需要再定义一个类。
例如每个item背后都有一个类实例,储存着相关的数据,你可以把类的指针直接存在item里。
数据例如item是否被选中,也就是在选中或取消时,修改这个指针实例里的类成员就好。
.......

多谢指点,刚开始,我也是考虑在item的结构体里添加一个是否选中的标志位或常量,但是考虑到可能有多个item,每个item可能有N次点击事件,假如从A点击选中,然后跳到B点击,在代理类里处理判断点击选中或取消选中这两种状态的切换时,尝试处理处理他们的关系,结果效果不是很好。例如代码如下:
  1. if(m_isSelected == true)
  2.             {
  3.                 painter->setPen(QPen(Qt::blue));
  4.                 painter->setBrush(QColor(229, 241, 255));
  5.                 painter->drawPath(path);
  6.                     QPixmap checkImg(":/res/listview/check_1.png");
  7.                     painter->drawPixmap(circle.x(), circle.y(), checkImg.width(), checkImg.height(), checkImg);
  8.             }
  9.             else
  10.             {
  11.                 painter->setPen(QPen(Qt::green));
  12.                 painter->setBrush(Qt::NoBrush);
  13.                 painter->drawPath(path);
  14.                     QPixmap uncheckImg(":/res/listview/uncheck_1.png");
  15.                     painter->drawPixmap(circle.x(), circle.y(), uncheckImg.width(), uncheckImg.height(), uncheckImg);
  16.             }
后面,我尝试通过QListView派生出一个子类,并重写mousePessEvent时间,代码如下:
  1. void mousePressEvent(QMouseEvent *event)
  2.     {
  3.         QModelIndex item = indexAt(event->pos());
  4.         //QModelIndex item = this->currentIndex();
  5.         if(item.isValid())
  6.         {
  7.             bool selected = selectionModel()->isSelected(item);
  8.             QListView::mousePressEvent(event);
  9.             if (selected)
  10.                 selectionModel()->select(item, QItemSelectionModel::Deselect);
  11.         }
  12.     }
这种做法虽然基本能做到单击某项item选中,再单击该item取消选中,但就是偶尔感觉点击选中和点击取消选中切换的时候,不太灵敏,好像有时候需要多点一次。


快速回复
限100 字节
 
上一个 下一个