使 QComboBox 下拉一个带复选框的树形列表

2023-10-26

背景

在项目开发过程中需要使 QComboBox 下拉一个树形列表,直接通过 setModel 和 setView 设置 combox 控件可以实现,但是在单击节点箭头按钮时也会隐藏下拉框的显示。因此需要重新实现 QComboBox 的方法来实现自己控制。

①.通过 QCheckTreeComboBoxView子类化 QTreeWidget 类,以重写 mousePressEvent 事件自己实现节点的展开和收缩,否则会有事件冲突。

②.通过 QCheckTreeComboBox子类化 QComboBox 类,以重写 hidePopup 方法,判断条件是否满足。

③.通过响应 QComboBox 类的 activated 信号,遍历获取当前的选择结果。

QCheckTreeComBox.h

#include <QComboBox>
#include "ui_QCheckTreeComboBox.h"
#include "QTreeWidget"
#include <functional>

class QCheckTreeComboBox : public QComboBox
{
  Q_OBJECT
public:
  QCheckTreeComboBox(QWidget *parent = Q_NULLPTR);
  ~QCheckTreeComboBox();
public:
  typedef std::function<QString()> getTreeSelectedFunc;//用于指定自定义方法
  class QCheckTreeComboBoxView : public QTreeWidget
  {
    public:
      QCheckTreeComboBoxView(QCheckTreeComboBox * cbx ,QWidget *parent = Q_NULLPTR) :QTreeWidget(parent),treeComboBox(cbx) {}
      ~QCheckTreeComboBoxView() {};
    protected:
      void mousePressEvent(QMouseEvent *event) override;
    private:
      void treeMousePressed(bool inItem);
      void setChildSelected(QTreeWidgetItem* root);
    private:
      //Qt 嵌套类不允许有信号槽,变为友元
      QCheckTreeComboBox * treeComboBox = nullptr;
    public :
      void setItemChecked();
  };
private:
  Ui::QCheckTreeComboBox ui;
protected:
  void hidePopup() override;//下拉列表收缩
  bool eventFilter(QObject *watched, QEvent *event) override;
private:
  bool canHidePopup = true;//允许收缩
  bool clickItem = false;//是否单击了节点
public:
  QCheckTreeComboBoxView * displayTreeWidget = nullptr;
  getTreeSelectedFunc getTreeSelectedText;//自定义的数据获取方法
  getTreeSelectedFunc getTreeSelectedData;
private:
  QString getCurrentSelectedText();//默认获取读取方法
  QString getCurrentSelectedData();
  void updateTreeWidgetSelected();//更新节点选择状态
  void updateEditText();//更新文本显示
public:
  void iniSelectText();//初始化文本显示
signals:
  void currentSelectedDataChange(QString & m_text);
  void currentSelectedTextChange(QString & m_text);
};

QCheckTreeComBox.cpp

#include "QCheckTreeComboBox.h"
#include "qevent.h"
#include "QLineEdit"


using namespace std::placeholders;

QCheckTreeComboBox::QCheckTreeComboBox(QWidget *parent)
  : QComboBox(parent)
{
  ui.setupUi(this);

  getTreeSelectedText = std::bind(&QCheckTreeComboBox::getCurrentSelectedText, this);
  getTreeSelectedData = std::bind(&QCheckTreeComboBox::getCurrentSelectedData, this);

  displayTreeWidget = new QCheckTreeComboBoxView(this);
  displayTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
  displayTreeWidget->setHeaderHidden(true);

  QLineEdit * displayEdit = new QLineEdit(this);
  displayEdit->installEventFilter(this);
  displayEdit->setEnabled(false);
  this->setLineEdit(displayEdit);
  this->setModel(displayTreeWidget->model());
  this->setView(displayTreeWidget);
  
  connect(this, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated), this, [&](int index) {
    if (clickItem) updateTreeWidgetSelected();
    updateEditText();
    canHidePopup = true;
  });
}

QCheckTreeComboBox::~QCheckTreeComboBox()
{
}

void QCheckTreeComboBox::hidePopup()
{
  if (canHidePopup) QComboBox::hidePopup();
}

bool QCheckTreeComboBox::eventFilter(QObject *watched, QEvent *event)
{
  if (watched == this->lineEdit() && event->type() == QEvent::MouseButtonPress)
  {
    if (((QMouseEvent*)event)->button() == Qt::LeftButton)
    {
      showPopup();
    }
  }
  return QComboBox::eventFilter(watched, event);
}

QString QCheckTreeComboBox::getCurrentSelectedText()
{
  QString result = "";
  QTreeWidgetItemIterator it(displayTreeWidget);
  while (*it)
  {
    if ((*it)->checkState(0) == Qt::Checked)
    {
      result += (*it)->text(0)+",";
    }  
    ++it;
  }
  return result;
}

QString QCheckTreeComboBox::getCurrentSelectedData()
{
  QString result = "";
  QTreeWidgetItemIterator it(displayTreeWidget);
  while ( (*it) && (*it)->data(0, Qt::UserRole).isValid() )
  {
    if ( (*it)->checkState(0) == Qt::Checked )
    {
      result += (*it)->data(0, Qt::UserRole).toString() + ",";
    }

    ++it;
  }
  return result;
}

void QCheckTreeComboBox::updateTreeWidgetSelected()
{
  displayTreeWidget->setItemChecked();
}

void QCheckTreeComboBox::updateEditText()
{
  QString selText = getTreeSelectedText();
  QString selData = getTreeSelectedData();
  lineEdit()->setText(selText);
  lineEdit()->setCursorPosition(0);

  emit currentSelectedTextChange(selText);
  emit currentSelectedDataChange(selData);
}

void QCheckTreeComboBox::iniSelectText()
{
  updateEditText();
}

void QCheckTreeComboBox::QCheckTreeComboBoxView::mousePressEvent(QMouseEvent *event)
{
  treeComboBox->canHidePopup = false;

  auto curIndex = currentIndex();
  auto rect = this->visualRect(curIndex);
  auto buttonRect = QRect(rect.left() - 20, rect.top(), 20, rect.height());
  if (buttonRect.contains(event->pos()))
  {
    if (isExpanded(curIndex)) setExpanded(curIndex, false);
    else setExpanded(curIndex, true);  

    treeMousePressed(false);
  }
  else
  {
    treeMousePressed(true);
  }
  
}

void QCheckTreeComboBox::QCheckTreeComboBoxView::treeMousePressed(bool inItem)
{
  treeComboBox->clickItem = inItem;
}

void QCheckTreeComboBox::QCheckTreeComboBoxView::setChildSelected(QTreeWidgetItem* root)
{
  int count = root->childCount();
  for (int i = 0; i < count; ++i)
  {
    root->child(i)->setCheckState(0,root->checkState(0));
  }
}

void QCheckTreeComboBox::QCheckTreeComboBoxView::setItemChecked()
{
  currentItem()->setCheckState(0, currentItem()->checkState(0) == Qt::Checked ? Qt::Unchecked : Qt::Checked);
  setChildSelected(currentItem());
}

代码示例

auto tree = ui.comboBox->displayTreeWidget;
  for (int i = 1;i < 4;i++ )
  {
    QTreeWidgetItem* item = new QTreeWidgetItem(tree, { QString::number(i) });
    item->setCheckState(0, Qt::Unchecked);

    for (int j = 1; j < 5; j++)
    {
      QTreeWidgetItem* sub = new QTreeWidgetItem(item, { QString("%1.%2").arg(i).arg(j) });
      sub->setCheckState(0, Qt::Unchecked);
    }
    
  }

在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使 QComboBox 下拉一个带复选框的树形列表 的相关文章

  • 如何使用 C# 中的参数将用户重定向到 paypal

    如果我有像下面这样的简单表格 我可以用它来将用户重定向到 PayPal 以完成付款
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 按成员序列化

    我已经实现了template
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 类模板参数推导 - clang 和 gcc 不同

    下面的代码使用 gcc 编译 但不使用 clang 编译 https godbolt org z ttqGuL template
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • 在 Qt 中自动调整标签文本大小 - 奇怪的行为

    在 Qt 中 我有一个复合小部件 它由排列在 QBoxLayouts 内的多个 QLabels 组成 当小部件调整大小时 我希望标签文本缩放以填充标签区域 并且我已经在 resizeEvent 中实现了文本大小的调整 这可行 但似乎发生了某
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现

随机推荐

  • 算法-宽度优先搜索

    算法 宽度优先搜索 一 宽度优先搜索 广度优先或横向优先搜索 是一种图形搜索算法 简单的说 BFS是从根节点开始 沿着树的宽度遍历树的节点 如果所有节点均被访问 则算法中止 DFS Depth First Search 深度优先搜索 对每一
  • 解决Mac版微信小程序开发工具打开后无法显示二维码

    问题描述 正常情况下 打开微信小程序开发工具后 首页提示扫描二维码进行登陆 但是如果不显示二维码 当然无法登陆 解决方案 无法显示二维码肯定是程序运行哪里出错了 我们直接点击桌面图标是无法排查错误 所以需要切换至命令行进行启动 打开命令行
  • 华为交换机开局配置

    sysname SWITCH aaa undo local aaa user password policy administrator local user admin password irreversible cipher admin
  • 四、无人机知识笔记(初级:基本运动原理)

    笔记来源于 沈阳无距科技 工业级无人机的中国名片 编程外星人 目录 一 多旋翼直升机 二 基本飞行姿态 三 多旋翼飞行原理 四 反扭力与偏航运动 五 螺旋桨 六 有刷电机和无刷电机 七 电调与PWM信号 八 动力电池 九 遥控器 十 机架设
  • C++ ——STL(上)

    前言 STL基本概念 1 STL Standard Template Library 标准模板库 2 STL从广义上分为 容器 container 算法 algorithm 迭代器 iterator 3 容器和算法之间通过迭代器进行无缝连接
  • SQL注入***

    SQL注入 是 对数据库进行 的常用手段之一 随着B S模式应用开发的发展 使用这种模式编写应用程序的程序员也越来越多 但是由于程序员的水平及经验也参差不齐 相当大一部分程序员在编写代码的时候 没有对用户输入数据的合法性进行判断 使应用程序
  • npm 安装卸载模块 & ionic插件安装与卸载

    npm安装模块 npm install xxx利用 npm 安装xxx模块到当前命令行所在目录 npm install g xxx利用npm安装全局模块xxx 本地安装时将模块写入package json中 npm install xxx
  • 用回车键实现MFC对话框中TAB键控制输入焦点在控件中跳转的效果

    用回车键实现MFC对话框中TAB键控制输入焦点在控件中跳转的效果 以下转载自 http blog csdn net ghgk archive 2004 10 20 144795 aspx 近日在为一个数据应用写数据输入界面 大量的编辑框要想
  • maven本地仓库批量上传私服

    最近做项目遇到一个问题 从别的地方拿过来的工程是用maven构建的 而且用了许多自有的依赖包 如果一个个的上传到私服简直是浪费时间 于是用Python 写了一个批量上传的工具 简化自己的工作量 使用的是Python3 分别依赖了os sub
  • Run-Time Check Failure #2 - Stack around the variable ‘password(数组名)‘ was corrupted.

    记录一些小小的bug 使用visaul 2019编辑c语言程序 程序可以正常运行 但程序结束退出时忽然报错闪退 原来是我定义password 数组时没有规定数组大小 导致栈溢出 正确的做法只要给数组规定一个大小就行了 以下讲解来自chatg
  • 芯片的英文手册需要全部看吗?

    以下文章来源于 公 众 号开源电子网 读取更多技术文章 请扫码关注 芯片的英文手册需要全部看吗 进入嵌入式行业的人都知道 必定和英文手册打交道的 例如使用一款PHY芯片设置电路 那么首要任务就是查找该PHY芯片的手册以及相关资料 这些资料呢
  • 用房屋建筑方式理解软件构建

    如果你是在建一栋房子 那么这个建造过程就会复杂得多 而糟糕的设计所引发的后果也更严重 首先你要决定准备建一个什么类型的房子 在软件开发里的类似事项称为问题定义 problem definition 接下来 你必须和某个建筑师 archite
  • java代码规范(转载整合)

    1 标识符命名规范 1 1 概述 标识符的命名力求做到统一 达意和简洁 1 1 1 统一 统一是指 对于同一个概念 在程序中用同一种表示方法 比如对于供应商 既可以用supplier 也可以用provider 但是我们只能选定一个使用 至少
  • 数据库文件被.eight后缀勒索病毒加密?不要惊慌,91数据恢复专家教您应对处理!

    当企业遭受勒索病毒攻击时 数据库文件被加密 这会导致企业无法访问其重要的业务数据 会给企业带来较大的困扰 本篇文章 91数据恢复专家将会针对 tsai shen zohomail eu eight勒索病毒 介绍如何恢复被 tsai shen
  • keras部分介绍

    1 keras 关于batch normalization函数参数axis 3的解释 https www zhihu com question 318398221 tips BN层的作用 1 加速收敛 2 控制过拟合 可以少用或不用Drop
  • 2023年面试问答-二分查找

    正常实现 Input 1 2 3 4 5 key 3 return the index 2 public int binarySearch int nums int key int l 0 h nums length 1 while l l
  • 一键端2

    新仙剑ol 链接 http pan baidu com s 1i3xZHLb 密码 hyly 链接 http pan baidu com s 1c0HgGKw 密码 druj 本帖隐藏的内容 龙之谷133服务端 链接 http pan ba
  • 索琦c语言程序设计第二版第七章,C语言程序设计自学考试大纲(2000年7月版).doc...

    天津市高等教育自学考试课程考试大纲 课程名称 应用程序基础及设计 课程代码 1115 4874 第一部分 课程性质与设置目的 一 课程性质与特点 应用程序基础及设计 课程是高等教育自学考试电子信息工程专业的必修课 是该专业一门重要的基础课
  • Qt实现TCP客户端和服务器通讯程序

    复习的心态过一遍之前基础的一些东西 Qt封装了QTcpServer和QTcpSocket两个类 其中QTcpServer继承自QObject 通过listen 函数监听传入的客户端连接 当Client连接上时 QTcpServer会发出ne
  • 使 QComboBox 下拉一个带复选框的树形列表

    背景 在项目开发过程中需要使 QComboBox 下拉一个树形列表 直接通过 setModel 和 setView 设置 combox 控件可以实现 但是在单击节点箭头按钮时也会隐藏下拉框的显示 因此需要重新实现 QComboBox 的方法