如何将 QTableWidget 添加到 QTreeWidget 但作为 QTreeWidgetItem

Posted

技术标签:

【中文标题】如何将 QTableWidget 添加到 QTreeWidget 但作为 QTreeWidgetItem【英文标题】:How to add a QTableWidget into a QTreeWidget but as a QTreeWidgetItem 【发布时间】:2021-12-18 05:04:35 【问题描述】:

我正在设计一个主要界面,但在如何将QTableWidget 添加到QTreeWidget 中但作为QTreeWidgetItem 时遇到了问题。为了节省大家的时间并提供最好的信息,下面是一个完全复制我遇到的问题的示例。我尽量简洁:

    在我目前不正确的小型用户界面下方:
    界面下方我正在努力实现

如您所见,我正在尝试在树中插入一个额外的小部件。 看下面的界面最终外观:

准备示例并真正小规模复制问题真的很困难,所以如果有任何疑问,请告诉我:

ma​​inwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSettings>
#include <QTreeWidget>
#include <QComboBox>
#include <QGraphicsView>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QObject>

#include "gaussianfilter.h"

class ImgPreProc;
class PreProcessing;
class MyMainWindow;

QT_BEGIN_NAMESPACE
namespace Ui  class MainWindow; 
QT_END_NAMESPACE

class ImgPreProc : public QObject 
    Q_OBJECT
public:
    explicit ImgPreProc(QSettings *Settings = new QSettings("default", QSettings::IniFormat), QMainWindow *UserParent = nullptr);
    MyMainWindow *MainWindow;
    PreProcessing *PreProc;

public slots:
    void OpenWindow();
private:
    QWidget *parent;
    bool mainWinOpen;
    bool loadProp;
;

class MyMainWindow : public QMainWindow 
    Q_OBJECT
public:
    explicit MyMainWindow(QWidget *parent = nullptr);
    ~MyMainWindow();
;

class MainWindow : public QMainWindow 
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void OpenPreProcessingWindow(void) 
        mImgPreProc->OpenWindow();
    

private:
    Ui::MainWindow *ui;
    QSettings *Settings;
    ImgPreProc *mImgPreProc;
;

class PreProcessing : public QObject 
    Q_OBJECT
public:
    PreProcessing(QSettings *Settings = new QSettings(QString("default"), QSettings::IniFormat));
    ~PreProcessing(void);
    void CreateWidgets(QWidget *UserParent = nullptr);
    QWidget *MainWidget;
    Filter *filter;

private slots:
    void addFilter();
    int addFilterItem(std::string FilterType = "?");

private:
    QWidget *parent;
    QTreeWidget *mainTree;
    QComboBox *filterChoose;
    QTreeWidget* getTree(void)
        return mainTree;
    
;

#endif // MAINWINDOW_H

ma​​inwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "gaussianfilter.h"
#include <QTabWidget>
#include <QStatusBar>
#include <QLabel>
#include <QString>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)

    ui->setupUi(this);
    mImgPreProc = new ImgPreProc(Settings);
    QAction *showPreProc = new QAction(this);
    showPreProc->setIcon(QIcon(QPixmap(QString((":/images/gauss.png")))));
    ui->mainToolBar->addAction(showPreProc);
    connect(showPreProc,SIGNAL(triggered()),this,SLOT(OpenPreProcessingWindow()));


MainWindow::~MainWindow()delete ui;

ImgPreProc::ImgPreProc(QSettings *set, QMainWindow *UserParent) 
    mainWinOpen = false;
    loadProp = false;
    parent = UserParent;
    PreProc = new PreProcessing(set);


void ImgPreProc::OpenWindow() 
    loadProp = true;
    MainWindow = new MyMainWindow(parent);
    QWidget *centralWidget = new QWidget(MainWindow);
    MainWindow->setCentralWidget(centralWidget);
    QVBoxLayout *MainLayout = new QVBoxLayout();
    centralWidget->setLayout(MainLayout);

    QStatusBar *statusbar = new QStatusBar(MainWindow);
    MainWindow->setStatusBar(statusbar);
    QTabWidget *mainTab = new QTabWidget(MainWindow);
    MainLayout->addWidget(mainTab);
    PreProc->CreateWidgets(MainWindow);
    mainTab->addTab(PreProc->MainWidget, QString("PreProcessing"));
    MainWindow->show();


MyMainWindow::MyMainWindow(QWidget *parent)(void) parent;
MyMainWindow::~MyMainWindow()

PreProcessing::PreProcessing(QSettings *Settings) : QObject() 
    mainTree = nullptr;
    filter = new Filter("Filter Node");
    (void) Settings;


PreProcessing::~PreProcessing()
void PreProcessing::CreateWidgets(QWidget *UserParent)

    parent = UserParent;
    MainWidget = new QWidget(parent);
    QVBoxLayout *MainLayout = new QVBoxLayout(MainWidget);
    MainWidget->setLayout(MainLayout);

        QHBoxLayout *filterLayout = new QHBoxLayout();
        MainLayout->addLayout(filterLayout);
        filterLayout->setAlignment(Qt::AlignLeft);

            filterChoose = new QComboBox(MainWidget);
            for(int x = 0; x < (int)filter->NameOfFilter.size(); x++)
                filterChoose->addItem(filter->NameOfFilter.at(x).c_str());
            
            filterLayout->addWidget(new QLabel("Filter"));
            filterLayout->addWidget(filterChoose);

        QToolBar *toolbar = new QToolBar(MainWidget);
        MainLayout->addWidget(toolbar);
        toolbar->addAction("Insert",this,SLOT(addFilter()));

        mainTree = new QTreeWidget(MainWidget);
        QStringList headerList;
        headerList.append("Type Of Filter");
        headerList.append("Iteration");
        headerList.append("Save Configuration?");

        mainTree->setColumnCount(headerList.size());
        mainTree->setHeaderLabels(headerList);
        MainLayout->addWidget(mainTree);
        filter->setTree(mainTree);
        for(int x = 0; x < (int)filter->ItemFilter.size(); x++)
            filter->ItemFilter.at(x).CreateWidgets(parent);
        


void PreProcessing::addFilter() 
    int index = addFilterItem(filterChoose->currentText().toStdString());
    filter->ItemFilter.at(index).CreateWidgets(parent);


int PreProcessing::addFilterItem(std::string FilterType) 
    if(FilterType == filter->NameOfFilter.at(Filter::GAUSSIAN))
        filter->addFilterGauss();
    
    return ((int)filter->ItemFilter.size() - 1);

gaussianfilter.h

#ifndef GAUSSIANFILTER_H
#define GAUSSIANFILTER_H
#include <QObject>
#include <QTreeWidget>
#include <QTreeWidgetItem>

class FilterItem;
class Filter : public QObject
    Q_OBJECT

public:
    enum GAUSSIAN, OTHER ;
    Filter(std::string Name, QTreeWidget *userTree = new QTreeWidget());
    ~Filter();
    std::vector<std::string>NameOfFilter;
    std::vector<FilterItem>ItemFilter;

    void setTree(QTreeWidget *userTree)
        tree = userTree;
    

    QTreeWidget* getTree(void)
        return tree;
    

    int getItemCount(void)
        return ((int)ItemFilter.size());
    

    QTreeWidget *tree;

private:
    std::string filterName;

public slots:
    void addFilterGauss(int width = 3, int height = 3, int iter = 1, bool ok = true);
;

class GaussianFilter : public QObject
    Q_OBJECT

public:
    GaussianFilter(Filter *UserFilter, int width = 3, int height = 3, int iter = 1, bool ok = true);
    void CreateFilterWidgets(QWidget *parent);
    void CreateAdvancedFilterWidgets(QWidget *parent);

    ~GaussianFilter();

    QWidget *type,*iteration,*execute, *type2;
    void setRectHeight(int x)rectH = x;
    int getRectHeight(void)return rectH;
    void setRectWidth(int x)rectW = x;
    int getRectWidth(void)return rectW;
    void setIteration(int x)gaussItera = x;
    int getIteration(void)return gaussItera;
    void setExecute(bool x)gaussOk = x;
    bool getExecute(void)return gaussOk;

private:
    Filter *filter;
    int rectH, rectW, gaussItera;
    bool gaussOk;
    QTreeWidgetItem *otherItem;

private slots:
    void changeRectHeight(int x)setRectHeight(x);
    void changeIteration(int x)setIteration(x);
    void changeExecute(bool x)setExecute(x);
;

class FilterItem

public:
    explicit FilterItem(Filter *userFilter);
    void CreateWidgets(QWidget *parent);
    void CreateAdvancedWidgets(QWidget *parent);
    GaussianFilter *gaussian;

    int getFilterType(void)return filterType;
    void determFilterType(int x) filterType = x;

    std::string getFilterTypeStr(void)
        if(filterType != (-1))
            return filter->NameOfFilter.at(filterType);
        
        else
            return "\0";
        
    

    ~FilterItem();

private:
    Filter *filter;
    QWidget *parent;
    QTreeWidget *tree;
    QTreeWidgetItem *item;
    QTreeWidgetItem *advancedChildItem;
    QList<QTreeWidgetItem *> options;
    int filterType;
    QString iconPath;
    QTreeWidgetItem *childItem;
    QTreeWidgetItem *otherItem;


;
#endif // GAUSSIANFILTER_H

gaussianfilter.cpp

#include "gaussianfilter.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QToolBar>
#include <QLabel>
#include <QSpinBox>
#include <QCheckBox>
#include <QComboBox>
#include <QPainter>
#include <QTableWidget>
#include <QPushButton>

Filter::Filter(std::string Name, QTreeWidget *userTree) 
    filterName = Name;
    ItemFilter.clear();

    for(int x = 0; x < OTHER; x++)
        NameOfFilter.push_back(std::string());
    
    // Here we will add the filter inside the QComboBox
    NameOfFilter.at(GAUSSIAN) = "Gaussian";
    tree = userTree;


Filter::~Filter()

void Filter::addFilterGauss(int width, int height, int iter, bool ok) 
    ItemFilter.push_back(FilterItem(this));
    ItemFilter.at(((int)ItemFilter.size() - 1)).gaussian = new GaussianFilter(this,width,height,iter,ok);
    ItemFilter.at(((int)ItemFilter.size() - 1)).determFilterType(GAUSSIAN);


GaussianFilter::GaussianFilter(Filter *UserFilter, int width, int height, int iter, bool ok) 
    filter = UserFilter;
    setRectWidth(width);
    setRectHeight(height);
    setIteration(iter);
    setExecute(ok);


void GaussianFilter::CreateFilterWidgets(QWidget *parent) 
    type = new QWidget(parent);
    iteration = new QWidget(parent);
    execute = new QWidget(parent);

    QGridLayout *group = new QGridLayout(type);
    type->setLayout(group);
    QSpinBox *width = new QSpinBox(parent);
    width->setSingleStep(2);
    width->setValue(getRectWidth());
//    connect(width,SIGNAL(valueChanged(int)),this,SLOT(changeRectWidth(int)));
    width->setRange(3,33);
    group->addWidget(new QLabel("Search"),0,0,1,1,Qt::AlignLeft);
    group->addWidget(width,0,1,1,1,Qt::AlignLeft);
    group->addWidget(new QLabel("pix"),0,2,1,1,Qt::AlignLeft);
    QHBoxLayout *iter = new QHBoxLayout(iteration);
    iteration->setLayout(iter);

    QSpinBox *It = new QSpinBox(parent);
    iter->addWidget(It);
    iter->addWidget(new QLabel("Time(s)"));
    It->setRange(1,10);
    It->setValue(getIteration());
    connect(It,SIGNAL(valueChanged(int)),this,SLOT(changeIteration(int)));

    QHBoxLayout *executeHBox = new QHBoxLayout(execute);
    execute->setLayout(executeHBox);
    QCheckBox *Execute = new QCheckBox(parent);
    executeHBox->addWidget(Execute);
    Execute->setChecked(getExecute());
    connect(Execute,SIGNAL(clicked(bool)),this,SLOT(changeExecute(bool)));


void GaussianFilter::CreateAdvancedFilterWidgets(QWidget *parent) 
    // This is the part that is giving me doubts


GaussianFilter::~GaussianFilter()

FilterItem::FilterItem(Filter *userFilter)

    filter = userFilter;


void FilterItem::CreateWidgets(QWidget *parent)

    item = new QTreeWidgetItem();
    QPushButton *childButton = new QPushButton("Child Button 0");
    QTreeWidgetItem *childItemButton = new QTreeWidgetItem();
    if(filterType == Filter::GAUSSIAN)
        item->setText(0,QString("Gaussian"));
        filter->tree->addTopLevelItem(item);

        childItem = new QTreeWidgetItem();
        item->addChild(childItem);
        gaussian->CreateFilterWidgets(parent);
        filter->tree->setItemWidget(childItem,0,gaussian->type);
        filter->tree->setItemWidget(childItem,1,gaussian->iteration);
        filter->tree->setItemWidget(childItem,2,gaussian->execute);
    


void FilterItem::CreateAdvancedWidgets(QWidget *parent)

    otherItem->setText(0,QString("Advanced Gaussian"));
    filter->tree->addTopLevelItem(otherItem);

    QTreeWidgetItem *childItem1 = new QTreeWidgetItem();
    QTableWidget *tw = new QTableWidget();
    tw->setColumnCount(3);
    tw->setRowCount(3);


FilterItem::~FilterItem()



终于ma​​in.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();

如果您需要查看ui 的组件,请参见下文,这非常少:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <layout class="QHBoxLayout" name="HLayout"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <widget class="QToolBar" name="mainToolBar">
   <property name="windowTitle">
    <string>toolBar</string>
   </property>
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

我尝试自己解决问题,并首先咨询了QTreeWidgetItem 课程,以确保我没有遗漏任何规范。此外,我还咨询了QTreeWidget 课程,以确保我正确使用了setItemWidget。在我看来是这样。 但是,一旦我实现了附加功能CreateAdvancedWidgets(QWidget *parent),事情就按我的计划停止了。

所以做了更多的研究并遇到了this useful source。我复制了该示例以确保我没有遗漏任何内容并将其应用于我的案例,但它没有用。我还经历了this、this source,最后是this source too。

感谢愿意花一点时间仔细研究并提出解决此问题的潜在解决方案的任何人。

【问题讨论】:

这个链接有用吗?forum.qt.io/topic/18603/qtablewidget-in-a-qtreewidget他说你可以试试treeWidget-&gt;setItemWidget 【参考方案1】:

每当我使用 Qt 并考虑使用 QTableWidget 时,我总是首先考虑其他选项,因为它们不容易使用。在这一点上我会考虑以下几点:

是否会出现需要多行的情况? 您的布局是否需要动态属性,例如用户可调整大小的列或排序功能?

如果这些问题的答案是否定的,那么也许可以考虑使用一个 QGridLayout 和一个或两个 QSpacerItem。

但是,如果您必须拥有其中一些东西(或者它们可能是为未来计划的),请查看 QAbstractItemModel 和一些与之相关的示例(例如:https://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html

【讨论】:

感谢您抽出宝贵时间阅读问题。回答您的问题:是的,会有多行,因为每次用户更改参数时,我希望将这些搜索参数存储在历史记录中。可能有一些参数可以提供更好的结果而不是其他参数。因此,要回答您的第二个问题,是的,表需要动态属性。例如,每次进行新搜索并且用户选择保存参数时,都会自动创建一个额外的行。 我对@9​​87654322@ 概念没有足够的经验,但我现在正在研究。如果可能的话,我希望有某种编码解决方案。我知道人们很忙,这就是为什么我试图整理一个小的工作示例。如果无论如何你们可以帮助我继续前进,我将不胜感激。如果你不能,我也明白。无论如何,感谢大家花时间阅读问题! 对于小部件示例,您始终可以转到您的 Qt 安装并转到示例文件夹,例如 Qt5.15.2/Examples/Qt-5.15.2/widgets。然后grep -Rni QAbstractItemModel会列出使用QAbstractItemModel对象的文件 @EsoMars 是的,会有多行,因为每次用户更改参数时,我希望这些搜索参数存储在历史记录中。 不要将前端用作后端. 感谢@scopchanov 阅读问题并抽出宝贵时间。我花了一些时间研究和组织示例代码以准确复制问题。有没有机会请你帮我写代码?我知道你很忙,如果你不能,我理解。

以上是关于如何将 QTableWidget 添加到 QTreeWidget 但作为 QTreeWidgetItem的主要内容,如果未能解决你的问题,请参考以下文章

如何将带有数据的标题添加到 Qt 中的 QTableWidget?

如何仅在 QTableWidget 的一列中添加一行?

如何向现有 QTableWidget 添加新行?

在 PyQt 中将图像添加到 QTableWidget

如何将数据发送到 QTableView/QTableWidget (PyQt)

如何使 QTableWidget 内的单元格小部件的背景不可选?