MultiSelectComboBox.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #include "MultiSelectComboBox.h"
  2. #include <QStandardItem>
  3. #include <QHBoxLayout>
  4. #include <QEvent>
  5. #include <QMouseEvent>
  6. MultiSelectComboBox::MultiSelectComboBox(QWidget *parent) : QComboBox(parent), isPermitHidePopup(false)
  7. {
  8. //去掉下拉箭头
  9. setStyleSheet("QComboBox::drop-down{border-style:none;}");
  10. //设置可编辑
  11. setEditable(true);
  12. // selectItemView盖住QComboBox
  13. selectItemView = new QListView(this);
  14. selectItemView->setMinimumHeight(30);
  15. // QListView{outline: none;} 去掉项虚线框 设置正常状态和选中为状态item的背景色相同
  16. selectItemView->setStyleSheet("QListView{outline: none;} QListView::item {background:#BDD7FD;} "
  17. "QListView::item:hover {background: #BDD7FD;}");
  18. selectItemView->setIconSize(QSize(12, 12));
  19. //设置各项的间隔
  20. selectItemView->setSpacing(3);
  21. //设置为不触发,不然点击可修改项内容
  22. selectItemView->setEditTriggers(QAbstractItemView::NoEditTriggers);
  23. //设置会调整
  24. selectItemView->setResizeMode(QListView::Adjust);
  25. //设置为自动换行
  26. selectItemView->setWrapping(true);
  27. //设置浮动方向
  28. selectItemView->setFlow(QListView::LeftToRight);
  29. //水平滚动条设置不不显示
  30. selectItemView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  31. //选择模式设置为不显示
  32. selectItemView->setSelectionMode(QAbstractItemView::NoSelection);
  33. selectModel = new QStandardItemModel();
  34. selectItemView->setModel(selectModel);
  35. QHBoxLayout *lineLayout = new QHBoxLayout(this);
  36. lineLayout->setMargin(0);
  37. lineLayout->setSpacing(0);
  38. lineLayout->addWidget(selectItemView);
  39. //安装事件过滤器,处理点击x删除
  40. selectItemView->viewport()->installEventFilter(this);
  41. popupView = new QListView();
  42. popupModel = new QStandardItemModel();
  43. popupView->setModel(popupModel);
  44. setView(popupView);
  45. setModel(popupModel);
  46. installEventFilter(this);
  47. //激活下拉列表某行的信号处理函数
  48. connect(this, QOverload<int>::of(&QComboBox::activated), [=](int index) {
  49. bool hasExist = false;
  50. QStandardItem *clickItem = popupModel->item(index);
  51. QString text = clickItem->text();
  52. //判断项是否已经选过,选过则删除选中项
  53. for (int row = 0; row < selectModel->rowCount(); row++) {
  54. QStandardItem *item = selectModel->item(row);
  55. if (item->text() == text) {
  56. selectModel->removeRow(row);
  57. hasExist = true;
  58. break;
  59. }
  60. }
  61. if (!hasExist) {
  62. //没选过则添加,并改变选项的状态
  63. clickItem->setCheckState(Qt::Checked);
  64. QStandardItem *item = new QStandardItem(QIcon("://del.png"), text);
  65. selectModel->appendRow(item);
  66. } else {
  67. //选中过点击改为未选中状态
  68. clickItem->setCheckState(Qt::Unchecked);
  69. }
  70. });
  71. // frame为弹出下拉列表框
  72. QFrame *frame = this->findChild<QFrame *>();
  73. if (frame) {
  74. frame->installEventFilter(this);
  75. }
  76. installEventFilter(this);
  77. }
  78. MultiSelectComboBox::~MultiSelectComboBox() { }
  79. //所有添加项的方法都选调用父类方式再设置可以check
  80. void MultiSelectComboBox::addItem(const QString &text, const QVariant &userData)
  81. {
  82. QComboBox::addItem(text, userData);
  83. popupModel->item(findText(text))->setCheckable(true);
  84. }
  85. void MultiSelectComboBox::addItem(const QIcon &icon, const QString &text, const QVariant &userData)
  86. {
  87. QComboBox::addItem(icon, text, userData);
  88. popupModel->item(findText(text))->setCheckable(true);
  89. }
  90. void MultiSelectComboBox::addItems(const QStringList &texts)
  91. {
  92. QComboBox::addItems(texts);
  93. for (int row = 0; row < popupModel->rowCount(); row++) {
  94. popupModel->item(row)->setCheckable(true);
  95. }
  96. }
  97. //返回所有选中项的内容,用QStringList存储
  98. QStringList MultiSelectComboBox::currentText()
  99. {
  100. QStringList items;
  101. for (int row = 0; row < popupModel->rowCount(); row++) {
  102. QStandardItem *item = popupModel->item(row);
  103. if (item->checkState() == Qt::Checked) {
  104. items << item->text();
  105. }
  106. }
  107. return items;
  108. }
  109. //返回所有选中项的索引,用QList<int>存储
  110. QList<int> MultiSelectComboBox::currentIndex()
  111. {
  112. QList<int> indexs;
  113. for (int row = 0; row < popupModel->rowCount(); row++) {
  114. QStandardItem *item = popupModel->item(row);
  115. if (item->checkState() == Qt::Checked) {
  116. indexs << row;
  117. }
  118. }
  119. return indexs;
  120. }
  121. bool MultiSelectComboBox::eventFilter(QObject *watched, QEvent *event)
  122. {
  123. QFrame *frame = this->findChild<QFrame *>();
  124. if (frame && frame == watched) {
  125. if (event->type() == QEvent::MouseButtonPress) {
  126. QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
  127. QPoint globalPos = mouseEvent->globalPos();
  128. QRect rect(frame->mapToGlobal(QPoint(0, 0)), QSize(frame->width(), frame->height()));
  129. QRect rect1(selectItemView->viewport()->mapToGlobal(QPoint(0, 0)),
  130. QSize(selectItemView->viewport()->width(), selectItemView->viewport()->height()));
  131. //不在下拉列表框和显示选项项的viewport范围内的按下则允许关闭
  132. if (!rect.contains(globalPos) && !rect1.contains(globalPos)) {
  133. isPermitHidePopup = true;
  134. } else {
  135. selectItemViewPress(selectItemView->viewport()->mapFromGlobal(globalPos));
  136. }
  137. }
  138. }
  139. if (watched == selectItemView->viewport()) {
  140. //处理selectItemView->viewport的鼠标按下事件
  141. if (event->type() == QEvent::MouseButtonPress) {
  142. QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
  143. selectItemViewPress(mouseEvent->pos());
  144. }
  145. }
  146. //屏蔽滑轮事件
  147. if (watched == this) {
  148. if (event->type() == QEvent::Wheel) {
  149. return true;
  150. }
  151. }
  152. return QComboBox::eventFilter(watched, event);
  153. }
  154. void MultiSelectComboBox::showPopup()
  155. {
  156. QComboBox::showPopup();
  157. isPermitHidePopup = false;
  158. }
  159. void MultiSelectComboBox::hidePopup()
  160. {
  161. if (isPermitHidePopup) {
  162. QComboBox::hidePopup();
  163. }
  164. }
  165. void MultiSelectComboBox::selectItemViewPress(QPoint pos)
  166. {
  167. QModelIndex index = selectItemView->indexAt(pos);
  168. //有效,则该坐标有选中项
  169. if (index.isValid()) {
  170. QRect rect = selectItemView->visualRect(index);
  171. QSize iconSize = selectItemView->iconSize();
  172. // x图标的区域
  173. QRect iconRect = QRect(rect.left(), rect.top(), iconSize.width(), iconSize.height());
  174. //鼠标在x图标的区域内
  175. if (iconRect.contains(pos)) {
  176. QStandardItem *item = selectModel->itemFromIndex(index);
  177. //修改状态为未选中
  178. popupModel->item(findText(item->text()))->setCheckState(Qt::Unchecked);
  179. //删除项
  180. selectModel->removeRow(index.row());
  181. }
  182. }
  183. showPopup();
  184. }