『Qt』多元素控件

个人博客地址

|----------------------------------------|
| 个人博客: 花开富贵 |


文章目录

  • 个人博客地址
    • [1 多元素控件介绍](#1 多元素控件介绍)
    • [2 QListWidget](#2 QListWidget)
      • [2.1 核心属性](#2.1 核心属性)
      • [2.2 核心方法](#2.2 核心方法)
      • [2.3 核心信号](#2.3 核心信号)
      • [2.4 QListWidgetItem](#2.4 QListWidgetItem)
      • [2.5 代码示例 - 基于 QHash 与 QDialog 的图片查看器](#2.5 代码示例 - 基于 QHash 与 QDialog 的图片查看器)
    • [3 QTableWidget](#3 QTableWidget)
      • [3.1 核心方法](#3.1 核心方法)
      • [3.2 核心信号](#3.2 核心信号)
      • [3.3 QTableWidgetItem 核心方法](#3.3 QTableWidgetItem 核心方法)
      • [3.4 代码示例 - 基于 QTableWidget 的表格模拟器](#3.4 代码示例 - 基于 QTableWidget 的表格模拟器)
    • [4 QTreeWidget](#4 QTreeWidget)
      • [4.1 核心方法](#4.1 核心方法)
      • [4.2 核心信号](#4.2 核心信号)
      • [4.3 QTreeWidgetItem 属性](#4.3 QTreeWidgetItem 属性)
      • [4.4 QTreeWidgetItem 核心方法](#4.4 QTreeWidgetItem 核心方法)
      • [4.5 代码示例 - QTreeWidget 的动态节点与表头管理](#4.5 代码示例 - QTreeWidget 的动态节点与表头管理)

1 多元素控件介绍

Qt提供了众多的多元素控件, 其中包括:

  • QListWidget - 列表
  • QListView- 列表
  • QTableWidget - 表格
  • QTableView - 表格
  • QTreeWidget - 树形
  • QTreeView - 树形

可以看到, 每一组控件都提供了对应的Widget版本与View版本;

对于Widget版本与View版本我们对其的分别为单纯的视图功能与MVC设计的控件;

  • MVC

    MVC是一种典型的软件架构模式, 将一套用户操作视图并进行业务处理的逻辑进行区分并统筹;

    分别分为View视图, Model模型, Controller控制器;

    1. View

      用来担任控件的视图部分, 负责向用户进行显示操作;

    2. Model

      用来负责对数据进行存储与业务处理部分;

    3. Controller

      用来连通视图部分与模型部分, 使得二者能在一定程度上进行交互;

其中针对于Qt提供的View版本控件, 只提供视图, 不提供业务处理的Model与连通两者的Controller, 若是需要使用该版本的控件, 需要自行编写Model部分与Controller部分, 使用成本较高;

Widget版本的多元素控件为MVC设计方式的控件, 其涵盖了View, ModelController部分, 并将三者进行整合, 从而节约使用成本;

当然若是存在一些Widget版本不存在的功能, 可以自定义ControllerModel以此实现拓展;

此处我们重点介绍Widget版本的对应控件;


2 QListWidget

该控件是Qt所提供的一个多元素控制的列表控件, 列表展出的方式为纵向的展出若干个Items, 其可以添加, 删除对应的列表项;

ListWidget中的每个列表项都可以被选中;

该控件有可以通过QListView使用"右键->变形为"的方式变为QListWidget;

同时, QListWidget控件可以在QtDesigner中通过"右键->编辑项目"来手动添加/删除列;


2.1 核心属性

属性 说明
currentRow 当前被选中的是第几行(由0开始计算)
count 一共有多少行
sortingEnable 是否允许排序
isWrapping 是否允许换行
itemAlignment 元素的对齐方式
selectRectVisible 被选中的元素矩形是否可见
spacing 元素之间的间隔

2.2 核心方法

方法 说明
addItem(const QString &label) addItem(QListWidgetItem *item) 列表中添加元素 该函数存在重载有两个版本 一个是传入需要显示的label, 另一个为传入一个QListWidgetItem对象指针
currentItem() 返回当前选中元素Item, 返回值为QListWidgetItem *
setCurrentItem(QListWidgetItem *item) 设置选中哪个元素
setCurrentRow(int row) 设置选中第几行的元素
insertItem(const QString &label, int row) insertItem(QListWidgetItem *item, int row) 在指定的位置插入元素, 不同的重载版本 一个为传入一个QString为显示的标签名, 另一个为传入具体的QListWidgetItem*对象指针
item(int row) 返回第row行的QListWidgetItem*
takeItem(int row) 表示删除第row行的元素, 返回被删除的QListWidgetItem*对象指针

2.3 核心信号

信号 说明
currentItemChanged(QListWidgetItem *current, QListWidgetItem *old) 选中不同元素时触发, 参数表示当前选中元素与选中前的元素;
currentRowChanged(int) 选中不同的元素触发, 参数是当前选中元素的行数
itemClicked(QListWidgetItem *item) 点击某个元素时触发
itemDoubleClicked(QListWidgetItem *item) 双击某个元素时触发
itemEntered(QListWidgetItem *item) 鼠标进入元素时触发

2.4 QListWidgetItem

该类为QListWidget控件中的子元素, 实际即为列表中每个列表项;

该控件本质上由文本与图标来构成;

其对应的方法有如下:

方法 说明
setFont 设置字体
setIcon 设置图标
setHidden 设置隐藏
setSizeHint 设置尺寸
setSelected 设置是否被选中
setText 设置文本
setTaxtAlignment 设置对齐方式

2.5 代码示例 - 基于 QHash 与 QDialog 的图片查看器

利用QListWidget显示图片名称列表, 结合QHash存储图片数据;

实现单击列表项在主窗口Label中预览, 双击列表项弹出QDialog进行独立查看的功能;

  • 所需控件

    • QListWidget (用于显示名称列表)
    • QLabel (用于预览图片)
  1. 初始化数据与控件

    为了高效地管理图片名称与图片资源的对应关系, 我们引入了 QHash . 它与 C++ STL 中的 std::unordered_map 非常相似, 内部基于哈希表实现, 查找速度通常快于 QMap.

    在构造函数中, 我们初始化 elements 哈希表, 并遍历它将 Key (图片名称) 添加到 QListWidget 中.

    cpp 复制代码
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
        , elements(new QHash<QString, QPixmap>({    // 初始化字符和Pixmap之间的映射
              {"Cat",    QPixmap(":/Cat.png")},
              {"Flower", QPixmap(":/Flower.png")},
              {"Dog",    QPixmap(":/Dog.png")},
              {"Fish",   QPixmap(":/Fish.png")}
          }))
    {
        ui->setupUi(this);
    
        // 1) 初始化控件
        ui->label->setText("");
    
        const QSize itemsSize(120, 30);
        // 使用迭代器遍历 QHash
        auto begin = elements->begin();
        while(begin != elements->end()){
            QListWidgetItem *item = new QListWidgetItem(begin.key());
            item->setSizeHint(itemsSize);
            ui->listWidget->addItem(item);
            ++begin;
        }
    }
  2. 设计槽函数 - 单击预览

    利用 currentItemChanged 信号实现预览功能;

    当用户点击列表项时, 从 elements 哈希表中取出对应的 QPixmap, 并根据 UI 中 Label 的尺寸进行缩放;

    cpp 复制代码
    // 单击加载图片
    void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
    {
        (void)previous;
        if(!current) return;
    
        QString str = current->text();
        // 根据 Label 当前的几何尺寸缩放图片, 填满 Label
        QPixmap tmp = elements->value(str).scaled(ui->label->geometry().size());
        ui->label->setPixmap(tmp);
    }
  3. 设计槽函数 - 双击独立查看

    双击时我们需要弹出一个新的窗口来展示大图, 这里使用了 QDialog , 它是 QMessageBox 的父类, 提供了一个干净的对话框窗口;

    为了让图片在窗口中自动适应布局, 我们引入了 QVBoxLayout (垂直布局管理器);

    布局管理器能自动处理控件的位置和大小, 省去了手动计算坐标的麻烦;

    cpp 复制代码
    // 双击显示图片
    void Widget::on_listWidget_itemDoubleClicked(QListWidgetItem *item)
    {
        // 使用 QDialog 显示 (QMessageBox 的父类 - 纯净弹窗)
        QDialog *imageDialog = new QDialog(this);
        imageDialog->setWindowTitle("图片查看");
    
        // SetAttribute: 删除时自动释放内存 (非隐藏) 以免内存堆积
        imageDialog->setAttribute(Qt::WA_DeleteOnClose);
    
        // 创建垂直布局管理器, 并将其父对象设置为 imageDialog
        QVBoxLayout *layout = new QVBoxLayout(imageDialog);
        // 设置边缘 (ContentsMargins) 为 0, 让图片充满窗口
        layout->setContentsMargins(0, 0, 0, 0);
    
        // 创建 Label 指定 imageDialog 为父对象
        QLabel *label = new QLabel(imageDialog);
        label->setAlignment(Qt::AlignCenter); // 让图片居中显示
    
        // 设置图片逻辑
        QString key = item->text();
        if (elements->contains(key)) {
            QPixmap pix = elements->value(key);
            // 使用 KeepAspectRatio 保持长宽比缩放, SmoothTransformation 抗锯齿
            QPixmap showPix = pix.scaled(1000, 700, Qt::KeepAspectRatio, Qt::SmoothTransformation);
            label->setPixmap(showPix);
        }
    
        // 将 Label 加入布局, 布局会自动管理 Label 的大小和位置
        layout->addWidget(label);
    
        imageDialog->show(); // 非模态显示
    }
  4. 运行结果 (图片过大 CSDN 无法显示)


3 QTableWidget

QTableWidget控件是Qt提供的表格控件;

QListWidget类似, 在QTableWidget中的每一个单元格都是一个QTableWidgetList;

同样的, QTableWidget控件也可以在QtDesigner中直接"右键->编辑项目"来手动添加行列;

同时该控件也可以通过View版本的控件提升而来;


3.1 核心方法

属性 说明
item(int row, int column) 根据行数列数获取指定的QTableWidgetItem*
setItem(int row, int column, QTableWidget*) 根据行数列数设置表格中的元素
currentItem() 返回被选中的元素QTableWidgetItem*
currentRow() 返回被选中的元素是第几行
currentColumn() 返回被选中的元素是第几列
row(QTableWidgetItem*) 获取指定item是第几行
column(QTableWidgetItem*) 获取指定item是第几列
rowCount() 获取行数
columnCount() 获取列数
insertRow(int row) 在第row行处插入新行, 新行成为第row
insertColumn(int column) 在第column列处插入新列, 新列成为第column
removeRow(int row) 删除第row
removeColumn(int column) 删除第column
setHorizontalHeaderItem(int column, QTableWidget*) 设置指定列的表头
setVerticalHeaderItem(int row, QTableWidget*) 设置指定行的表头

3.2 核心信号

信号 说明
cellClicked(int row, int column) 点击单元格时触发
cellDoubleClicked(int row, int column) 双击单元格时触发
cellEntered(int row, int column) 鼠标进入单元格时触发
currentCellChanged(int, row, int column, int previousRow, intpreviousColumn) 选中不同单元格时触发, 参数给出当前的行列信息与前一列的行列信息

3.3 QTableWidgetItem 核心方法

方法 说明
row() 获取当前是第几行
column() 获取当前是第几列
setText(const QString&) 设置文本
setTextAlignment(int) 设置文本对齐
setIcon(const QIcon&) 设置图标
setSelected(bool) 设置被选中
setSizeHints(const QSize&) 设置尺寸
setFont(const QFont&) 设置字体

3.4 代码示例 - 基于 QTableWidget 的表格模拟器

利用QTableWidget实现一个表格功能, 表格存在四个PushButton, 分别用于:

  • 行的增加
  • 列的增加
  • 行的删除
  • 列的删除

其中关于行的增加直接以"第n行/条", n表示该条数据的顺序, 列的增加需要有一个QLineEdit使用户可以获取列名, 行列的删除都由最后一条由后往前删, 表格有几条硬性规则:

  1. 行列删除时只剩下默认行列时不允许删除操作(列为3, 行为1)
  2. QLineEdit中没有内容时无法创建新列
  3. 一个列新创建后, 对应的QLineEdit内容将会被清空;
  • 所需控件

    1. QPushButton

      用于行列的增删操作;

    2. QLineEdit

      用于获取列名;

    3. QTableWidget

      具体的表格整体;

  1. 初始化控件

    控件需要进行初始化, 主要初始化的部分是默认的行列, 与LineEditplaceHolderText以及三个按钮的默认禁用状态;

    • 两个删除按钮在只剩默认行列时不允许进行对应删除
    • 一个column的增加操作需要LineEdit中存在内容否则禁用
    cpp 复制代码
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        /*
            # 1) 初始化UI状态与基础数据
            设置占位文本, 重命名按钮, 并预设表格的基础结构(3列1行); 
        */
        ui->lineEdit->setPlaceholderText("需要增加的列名");
    
        ui->pushButton_addCol->setText("增加列");
        ui->pushButton_addRow->setText("增加行");
        ui->pushButton_delCol->setText("删除列");
        ui->pushButton_delRow->setText("删除行");
    
        // 初始化固定的三列: ID, 姓名, 性别
        QVector<QString> normalColumns({"ID", "姓名", "性别"});
        for(int i=0;i<normalColumns.size();++i){
            ui->tableWidget->insertColumn(i); // 在第i个位置插入列
            ui->tableWidget->setHorizontalHeaderItem(i, new QTableWidgetItem(normalColumns[i])); // 设置表头
        }
    
        // 初始化默认的一行
        ui->tableWidget->insertRow(0);
        ui->tableWidget->setVerticalHeaderItem(0, new QTableWidgetItem("第1条"));
    
        /*
            # 2) 设置按钮的初始保护状态
            刚启动时只有基础行列, 不允许删除, 且输入框为空也不允许添加列; 
        */
        ui->pushButton_delCol->setEnabled(false);
        ui->pushButton_delRow->setEnabled(false);
        ui->pushButton_addCol->setEnabled(false);
    }
  2. 输入框的非空校验

    当输入框为非空时, column的增加按钮的Enable状态才为可用, 否则不可用;

    主要监听QLineEdittextChanged信号;

    cpp 复制代码
    void Widget::on_lineEdit_textChanged(const QString &arg1)
    {
        /*
            # 3) 输入框非空校验
            监听输入框变化, 只有当用户输入了列名后, 才激活"增加列"按钮, 防止添加空表头; 
        */
        if(!arg1.size())
            ui->pushButton_addCol->setEnabled(false);
        else
            ui->pushButton_addCol->setEnabled(true);
    }
  3. 增加列并判断是否解除删除列的禁用状态

    获取输入框内容, 将输入框内容作为新列的表头;

    当新列被插入后, 查询当前列数是否满足允许解除删除列的PushButton的禁用状态;

    cpp 复制代码
    void Widget::on_pushButton_addCol_clicked()
    {
        /*
            # 4) 动态增加列
            获取输入框内容, 在表格末尾追加一列, 并更新表头文字; 
        */
        QString str = ui->lineEdit->text();
    
        // 在当前总列数的位置插入新列(即追加在最后)
        ui->tableWidget->insertColumn(ui->tableWidget->columnCount());
    
        // 设置新列的表头
        ui->tableWidget->setHorizontalHeaderItem(
            ui->tableWidget->columnCount()-1,
            new QTableWidgetItem(str));
    
        ui->lineEdit->clear(); // 清空输入框, 方便下一次输入
    
        /*
            # 5) 更新计数与按钮状态
            列数增加后, 如果超过了基础的3列, 则允许使用"删除列"按钮; 
        */
        if(ui->tableWidget->columnCount()>3)
            ui->pushButton_delCol->setEnabled(true);
        else
            ui->pushButton_delCol->setEnabled(false);
    }
  4. 增加行并判断是否解除删除行的禁用状态

    增加行可以直接进行增加, 其中行表头采用"第n条"的方式进行命名, 其中ni(当前行下标+1);

    cpp 复制代码
    void Widget::on_pushButton_addRow_clicked()
    {
        /*
            # 6) 动态增加行
            逻辑同增加列, 但在垂直表头显示"第N条"作为标识; 
        */
        QString str = "第"+QString::number(ui->tableWidget->rowCount()+1)+"条";
    
        ui->tableWidget->insertRow(ui->tableWidget->rowCount());
        ui->tableWidget->setVerticalHeaderItem(
            ui->tableWidget->rowCount()-1,
            new QTableWidgetItem(str));
    
        if(ui->tableWidget->rowCount()>1)
            ui->pushButton_delRow->setEnabled(true);
        else
            ui->pushButton_delRow->setEnabled(false);
    }
  5. 删除行/列

    直接删除末尾的行/列, 在数值更新后判断是否禁用删除按钮;

    cpp 复制代码
    void Widget::on_pushButton_delCol_clicked()
    {
        /*
            # 7) 动态删除列
            移除最后一列, 并判断剩余列数; 如果回到了基础的3列, 则禁用删除按钮; 
        */
        ui->tableWidget->removeColumn(ui->tableWidget->columnCount()-1);
    
        if(ui->tableWidget->columnCount()>3)
            ui->pushButton_delCol->setEnabled(true);
        else
            ui->pushButton_delCol->setEnabled(false);
    }
    
    void Widget::on_pushButton_delRow_clicked()
    {
        /*
            # 8) 动态删除行
            移除最后一行, 若只剩最后一条基础数据, 则禁用删除按钮以保护底线; 
        */
    
        ui->tableWidget->removeRow(ui->tableWidget->rowCount()-1);
        if(ui->tableWidget->rowCount()>1)
            ui->pushButton_delRow->setEnabled(true);
        else
            ui->pushButton_delRow->setEnabled(false);
    }
  6. 运行结果


4 QTreeWidget

QTreeWidgetQt提供的树形结构的多元素控件, 其类似于QListWidget;

但在结构划分上, QTreeWidget采用树形结构, 类似于我们常用的文件管理器;

同时虽然该树形结构是一种树形结构, 但其未体现出树的根节点, 更像是树的子树;

通常可以创建的是TopLevelItem, 与其的子节点ChildItem;

该控件同样可以使用View控件通过"右键->提升为"的方式进行提升;

同时"右键->编辑项目"可以对该控件进行预先设置;


4.1 核心方法

方法 说明
clear 清空所有子节点
addTopLevelItem(QTreeWidgetItem* item) 新增顶层节点
topLevelItem(int index) 获取指定下标的顶层节点
topLevelItemCount() 获取顶层节点个数
indexOfTopLevelItem(QTreeWidgetItem* item) 查询指定节点是顶层节点中的下标
takeTopLevelItem(int index) 删除指定的顶层节点, 返回QTreeWidgetItem*表示被删除的元素
currentItem() 获取到当前选中的节点, 返回QTreeWidgetItem*
setCurrentItem(QTreeWidgetItem* item) 选中指定节点
setExpanded(bool) 展开/关闭节点
setHeaderLabel(const QString& text) 设置QTreeWidgetheader名称

4.2 核心信号

信号 说明
currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* old) 切换选中元素时触发
itemClicked(QTreeWidgetItem* item, int col) 点击元素时触发
itemDoubleClicked(QTreeWidgetItem* item, int col) 双击元素时触发
itemEntered(QTreeWidgetItem* item, int col) 鼠标进入时触发
itemExpanded(QRteeWidgetItem* item) 元素被展开时触发
itemCollapsend(QTreeWidgetItem* item) 元素被折叠时触发

4.3 QTreeWidgetItem 属性

属性 说明
text 持有的文本
textAlignment 文本对齐方式
icon 持有的图表
font 文本字体
hiddent 是否隐藏
disabled 是否禁用
expand 是否展开
sizeHint 尺寸大小
selected 是否选中

4.4 QTreeWidgetItem 核心方法

方法 说明
addChild(QTreeWidgetItem* child) 新增子节点
childCount() 子节点的个数
child(int index) 获取指定下标的子节点, 返回QTReeWidgetItem*
tackChild(int index) 删除对应下标的子节点
removeChild(QTreeWidgetItem) 删除对应的子节点
parent() 获取该元素的父节点

4.5 代码示例 - QTreeWidget 的动态节点与表头管理

创建一个基于 QTreeWidget 的综合管理工具; 不仅实现对树形节点 (顶层项, 子项)的增删改查, 还实现了对表格结构(增加列, 修改列名)的动态调整, 演示了如何构建一个高容错的交互界面;

  • 所需控件

    • QTreeWidget (核心控件)
    • QLineEdit (输入名称)
    • QPushButton (x6: 添加顶层/子节点/列, 删除列/节点, 重命名)
  1. 初始化与信号连接

    在构造函数中, 我们需要初始化树的基础状态(1列), 并设置交互逻辑的"安全锁"(默认禁用按钮); 最关键的是, 为了实现修改写错的表头 , 我们需要连接 QHeaderView 的双击信号;

    cpp 复制代码
    Widget::Widget(QWidget *parent) : ...
    {
        ui->setupUi(this);
    
        // 1. 初始化树控件状态
        ui->treeWidget->clear();
        ui->treeWidget->setColumnCount(1); // 默认为1列
        ui->treeWidget->setHeaderLabels(QStringList{"项目列表"});
    
        // 2. 初始化按钮状态 (防呆设计)
        ui->pushButton_addChild->setEnabled(false);
        // ... (其他按钮禁用代码略)
    
        // 3. 【高级技巧】连接表头双击信号 (用于修正列名)
        connect(ui->treeWidget->header(), &QHeaderView::sectionDoubleClicked,
                this, &Widget::on_header_doubleClicked);
    
        // 4. 连接选择变化信号 (用于控制删除按钮)
        connect(ui->treeWidget, &QTreeWidget::itemSelectionChanged, 
                this, &Widget::on_treeWidget_itemSelectionChanged);
    }
  2. 节点管理逻辑 (增/删/改)

    这里展示了 QTreeWidget 最核心的三种操作;

    • 添加顶层项 : 使用 addTopLevelItem;
    • 添加子项 : 必须先获取 currentItem, 然后调用 item->addChild;
    • 构造函数陷阱 : 必须使用 QStringList 构造 QTreeWidgetItem, 即使只有一列;
    cpp 复制代码
    // 添加子项目
    void Widget::on_pushButton_addChild_clicked()
    {
        QTreeWidgetItem *current = ui->treeWidget->currentItem();
        // 安全检查: 必须选中父节点
        if(!current) return; 
    
        QString str = ui->lineEdit->text();
        // 注意: 构造函数必须传 QStringList
        QTreeWidgetItem *child = new QTreeWidgetItem(QStringList{str});
    
        current->addChild(child);
        current->setExpanded(true); // 自动展开方便查看
        ui->lineEdit->clear();
    }
  3. 表头/列管理逻辑 (容错处理)

    这是针对"列加错了"或"列名写错了"的补救方案;

    • 增加列 : 通过 setColumnCount(n+1) 扩展空间, 并设置 Header 文本;
    • 修正列名: 响应表头双击事件, 弹出输入框修改;
    cpp 复制代码
    // 增加新列 (Add Table)
    void Widget::on_pushButton_addTable_clicked()
    {
        QString str = ui->lineEdit->text();
        int cols = ui->treeWidget->columnCount();
        ui->treeWidget->setColumnCount(cols + 1); // 扩容
        ui->treeWidget->headerItem()->setText(cols, str); // 命名
    }
    
    // 双击表头修改 (Fix Header)
    void Widget::on_header_doubleClicked(int index)
    {
        QString oldName = ui->treeWidget->headerItem()->text(index);
        // 使用 QInputDialog 获取新名字...
    }
  4. 运行结果

  5. 完整代码

    cpp 复制代码
    #include "widget.h"
    #include "ui_widget.h"
    #include <QString>
    #include <QStringList>
    #include <QMessageBox> // 引入消息框用于提示
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        // 1) 初始化界面状态
        ui->treeWidget->clear();
        // 设置初始列数为1, 并设置默认表头
        ui->treeWidget->setColumnCount(1);
        ui->treeWidget->setHeaderLabels(QStringList{"项目列表"});
    
        ui->lineEdit->setPlaceholderText("请输入名称");
        ui->lineEdit->setClearButtonEnabled(true);
    
        ui->pushButton_addChild->setText("添加子项");
        ui->pushButton_addTopLevel->setText("添加根项");
        ui->pushButton_deleteItem->setText("删除项目");
        ui->pushButton_addTable->setText("增加新列"); // addTable 理解为增加列
        ui->pushButton_rename->setText("重命名");
        ui->pushButton_removeTable->setText("删除列");
    
        // 2) 初始禁用所有操作按钮
        ui->pushButton_addChild->setEnabled(false);
        ui->pushButton_addTopLevel->setEnabled(false);
        ui->pushButton_deleteItem->setEnabled(false);
        ui->pushButton_addTable->setEnabled(false);
        ui->pushButton_rename->setEnabled(false);
    
        // 【重要】连接选择改变信号, 以便在用户点击树节点时, 判断"删除"按钮是否可用
        // 如果没有这一步, 用户未选中节点就点删除会很奇怪
        connect(ui->treeWidget, &QTreeWidget::itemSelectionChanged,
                this, &Widget::on_treeWidget_itemSelectionChanged);
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    // ---------------------------------------------------------
    // 状态控制逻辑
    // ---------------------------------------------------------
    
    // 文本框内容改变: 控制 "添加" 类按钮
    void Widget::on_lineEdit_textChanged(const QString &arg1)
    {
        bool hasText = !arg1.isEmpty();
    
        // 只要有文字, 就可以添加顶层项, 增加列
        ui->pushButton_addTopLevel->setEnabled(hasText);
        ui->pushButton_addTable->setEnabled(hasText);
    
        // 对于"添加子项"和"重命名", 不仅要有文字, 还必须选中了一个父节点
        // 这里简单处理, 先启用, 在点击函数里再做判断
        ui->pushButton_addChild->setEnabled(hasText);
        ui->pushButton_rename->setEnabled(hasText);
    }
    
    // 树节点选择改变: 控制 "删除" 按钮
    // 只有选中了东西, 才能删除
    void Widget::on_treeWidget_itemSelectionChanged()
    {
        bool hasSelection = !ui->treeWidget->selectedItems().isEmpty();
        ui->pushButton_deleteItem->setEnabled(hasSelection);
    }
    
    // ---------------------------------------------------------
    // 核心功能逻辑
    // ---------------------------------------------------------
    
    // 1. 添加顶层项目 (Root)
    void Widget::on_pushButton_addTopLevel_clicked()
    {
        QString str = ui->lineEdit->text();
        if(str.isEmpty()) return;
    
        // 使用 QStringList 构造函数
        QTreeWidgetItem *item = new QTreeWidgetItem(QStringList{str});
        ui->treeWidget->addTopLevelItem(item);
    
        ui->lineEdit->clear();
    }
    
    // 2. 增加新表 (增加列 Column)
    void Widget::on_pushButton_addTable_clicked()
    {
        QString str = ui->lineEdit->text();
        if(str.isEmpty()) return;
    
        // 获取当前有多少列
        int colCount = ui->treeWidget->columnCount();
    
        // 增加一列
        ui->treeWidget->setColumnCount(colCount + 1);
    
        // 设置新一列的表头名称
        // headerItem() 获取表头指针, setText(列索引, 名称)
        ui->treeWidget->headerItem()->setText(colCount, str);
    
        ui->lineEdit->clear();
    }
    
    // 3. 添加子项目 (Child)
    void Widget::on_pushButton_addChild_clicked()
    {
        // 获取当前选中的节点
        QTreeWidgetItem *currentItem = ui->treeWidget->currentItem();
    
        //如果没有选中父节点, 就不能添加子节点
        if(!currentItem) {
            QMessageBox::warning(this, "提示", "请先选中一个项目作为父节点!");
            return;
        }
    
        QString str = ui->lineEdit->text();
        if(str.isEmpty()) return;
    
        // 创建新节点
        QTreeWidgetItem *childItem = new QTreeWidgetItem(QStringList{str});
    
        // 挂载到当前选中的节点下
        currentItem->addChild(childItem);
    
        // 自动展开父节点, 以便看到刚添加的子项
        currentItem->setExpanded(true);
    
        ui->lineEdit->clear();
    }
    
    // 4. 删除项目
    void Widget::on_pushButton_deleteItem_clicked()
    {
        // 获取当前选中的节点
        QTreeWidgetItem *currentItem = ui->treeWidget->currentItem();
    
        if(!currentItem) return;
    
        // 在 Qt 中, 删除 QTreeWidgetItem 最简单的办法就是直接 delete 指针
        // Qt 会自动处理它与父节点或 TreeWidget 的断开逻辑
        delete currentItem;
    
        // 删除后禁用删除按钮, 防止误触
        ui->pushButton_deleteItem->setEnabled(false);
    }
    
    // 5. 重命名
    void Widget::on_pushButton_rename_clicked()
    {
        QTreeWidgetItem *currentItem = ui->treeWidget->currentItem();
        if(!currentItem) {
            QMessageBox::warning(this, "提示", "请先选中要重命名的项目!");
            return;
        }
    
        QString str = ui->lineEdit->text();
    
        // 修改当前节点第0列的文字
        // 如果你想重命名选中的那一列, 可以用 ui->treeWidget->currentColumn();
        currentItem->setText(0, str);
    
        ui->lineEdit->clear();
    }
    
    // 槽函数: 删除最后一列
    void Widget::on_pushButton_removeTable_clicked()
    {
        int currentCount = ui->treeWidget->columnCount();
    
        // 保护机制: 至少保留 1 列
        if (currentCount > 1) {
            ui->treeWidget->setColumnCount(currentCount - 1);
        } else {
            QMessageBox::information(this, "提示", "至少保留一列!");
        }
    }
相关推荐
Jay Chou why did20 分钟前
13. Qt深入 样式表继承规则
qt
技术净胜21 分钟前
MATLAB 基因表达数据处理与可视化全流程案例
开发语言·matlab
hmbbcsm29 分钟前
练习python题目小记(六)
开发语言·python
4***V2021 小时前
Vue3响应式原理详解
开发语言·javascript·ecmascript
q***98521 小时前
VS Code 中如何运行Java SpringBoot的项目
java·开发语言·spring boot
共享家95271 小时前
QT-界面优化(中)
开发语言·qt
李日灐1 小时前
手搓简单 string 库:了解C++ 字符串底层
开发语言·c++
say_fall1 小时前
C语言编程实战:每日一题 - day7
c语言·开发语言
LiLiYuan.1 小时前
【Lombok库常用注解】
java·开发语言·python