动态生成的QTreeWidget中,依赖于父项的QTreeWidgetItem复选框

3

我在编写一个应用程序,其中包含一个QTreeWidget,通过解析包含树级别的XML文件进行填充。如果我选择一个顶层复选框,则需要将所有子级复选框也选中。

我已经使XML解析器工作,并使用具有复选框的QTreeWidgetItems填充QTreeWidget,但它们只能逐个检查。


这是两件不同的事情,rabid正在谈论:勾选复选框(在段落1中)和选择项目(在段落2中)。你指的是哪一个? - TonyK
3个回答

6
为了实现此功能,请保留用于生成XML树的代码。然后连接到itemChanged()信号并在槽中更新复选框状态。代码应该如下所示:
connect(treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
        this,       SLOT(updateChecks(QTreeWidgetItem*, int)));

void ClassName::updateChecks(QTreewidgetItem* item, int column)
{
    // Checkstate is stored on column 0
    if(column != 0)
        return;

    recursiveChecks(item);
}

void ClassName::recursiveChecks(QTreeWidgetItem* parent)
{
    Qt::CheckState checkState = parent->checkState(0);
    for(int i = 0; i < parent->childCount(); ++i)
    { 
       parent->child(i)->setCheckState(0, checkState);
       recursiveChecks(parent->child(i));
    }   
}

请注意以下几点:

  1. 您可能会想使用itemClicked信号而不是itemChanged信号。这通常有效,但当用户使用箭头键和空格键更改复选框状态时将无法正常工作。
  2. 当您取消选中父项中已选中的子项之一时,您需要考虑会发生什么。通常这意味着您需要使所有祖先节点变为未选中或部分选中。但这可能不适用于您的情况。
  3. itemUpdated还将在对项进行其他更改(如文本更改)时触发,因此请注意这不是一种超级高效的方法。

Rick,非常感谢!我对C++和Qt完全是新手,所以这对我帮助很大。不过我有一个问题,如果QTreeWidget是Qt Creator/Designer表单的一部分,那ClassName应该是什么?它只是包含的QMainWindow的类名吗? - rabidhamper7
另外,在recursiveChecks()方法中,item变量是从哪里来的? - rabidhamper7
没关系,我将它添加到了我正在使用的 QMainWindow 扩展类中,并在第二个方法中将 item 更改为 parent。非常完美!再次感谢! - rabidhamper7
@rabidhamper7 很高兴你解决了问题...QMainWidget是我给你的代码的有效放置位置。祝你好运! - Rick Smith

4

这篇文章在搜索引擎中仍然很高,但已经过时了。 只需在顶级项目上设置 Qt::ItemIsAutoTristate 标记。


如果您正在使用现代Qt,那么这绝对是正确的答案。 - Maspe36

4

我稍微改进了一下Rick的答案,并得到了不错的结果。也许对其他人有所帮助。 它通过三态状态更新父节点和子节点的状态,但只针对父节点(选中、未选中、部分选中)。

void ClassName::updateChecks(QTreeWidgetItem *item, int column)
{
    bool diff = false;
    if(column != 0 && column!=-1)
        return;
    if(item->childCount()!=0 && item->checkState(0)!=Qt::PartiallyChecked && column!=-1){
        Qt::CheckState checkState = item->checkState(0);
        for (int i = 0; i < item->childCount(); ++i) {
           item->child(i)->setCheckState(0, checkState);
        }
    } else if (item->childCount()==0 || column==-1) {
        if(item->parent()==0)
            return;
        for (int j = 0; j < item->parent()->childCount(); ++j) {
            if(j != item->parent()->indexOfChild(item) && item->checkState(0)!=item->parent()->child(j)->checkState(0)){
                diff = true;
            }
        }
        if(diff)
            item->parent()->setCheckState(0,Qt::PartiallyChecked);
        else
            item->parent()->setCheckState(0,item->checkState(0));
        if(item->parent()!=0)
            updateChecks(item->parent(),-1);
    }
}

不再需要recursiveChecks()。treeWidget和updateChecks之间的连接仍然保持活动状态。

当处理大量项目时,速度非常缓慢。 - def

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接