在Qt中动态创建/销毁自定义小部件

时间:2013-01-09 01:57:23

标签: c++ qt

我刚刚开始使用Qt。我想用自定义小部件创建一个GUI,可用于显示/编辑我的自定义数据类型。我还希望能够动态创建/销毁这些小部件(不破坏底层数据)。

我试图通过在主Window类中存储我的数据项列表(dataContainer)并将指针传递给dataContainer到我的widget的构造函数来实现这一点({ {1}}),存储此指针。然后customWidget可以通过此指针改变基础数据。

以下代码允许用户重复将customWidget个实例添加到列表中并编辑其每个“名称”。当我运行它时,一切都工作正常,因为我实际上没有编辑名称,但如果我编辑名称,然后单击“添加”按钮,我得到一个段错误。在dataContainer customWidget delete myWidget;期间Window::add()的析构函数期间发生此段错误。

两个问题:

  1. 为什么这段代码会崩溃?我不允许动态创建/销毁这样的小部件吗?
  2. 有没有更合适的方法来实现这一目标?
  3. 如果我在这里缺少一些基本的东西,我很抱歉,但我已经上下很多论坛和教程,并没有找到任何有用的东西。

    的main.cpp

    #include <QApplication>
    #include "window.h"
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        Window mainWindow;
        mainWindow.show();
        return app.exec();
    }
    

    window.h中

    #ifndef WINDOW_H
    #define WINDOW_H
    
    #include <QWidget>
    #include "customwidget.h"
    
    class Window : public QWidget {
      Q_OBJECT
      public:
        Window();
    
      public slots:    
        void add();    
    
    private:
    
      // the main data structure
      QList<dataContainer> dataList;
    
      // the widget that displays the custom data
      customWidget *myWidget;     
    
      QVBoxLayout *mainLayout;
      QPushButton *addButton;
    
    };
    
    #endif
    

    window.cpp

    #include <QtGui>
    #include "window.h"
    
    Window::Window(){
    
      // start with a single piece of data in the list
      dataContainer newData;
      dataList.append(newData);
    
      // create layout container
      mainLayout = new QVBoxLayout(this);
      mainLayout->setAlignment(Qt::AlignTop);
    
      // make the Add button, and connect its clicked() SIGNAL
      // to our add() SLOT
      addButton=new QPushButton(tr("Add"),this);
      connect(addButton,SIGNAL(clicked()),this,SLOT(add()));
      mainLayout->addWidget(addButton);  
    
      // create a custom widget to display our data and
      // give it a pointer to the data it will display/modify
      myWidget = new customWidget(this,&(dataList.last()) );
      mainLayout->addWidget(myWidget);
    
      setLayout(mainLayout);   
    
    }
    
    void Window::add(){
    
      // create a new piece of data, and add to the list
      dataContainer newData;
      dataList.append(newData);
    
      // debug: show the current list
      qDebug() << "Data List(" << dataList.size() << ")";
      for (int i=0;i<dataList.size();i++){
        qDebug() << dataList[i].getName().c_str();
      }
    
      // delete the old widget
      delete myWidget;
    
      // and make a new widget with the new data
      myWidget = new customWidget(this,&(dataList.last()) );
      mainLayout->addWidget(myWidget);   
    
    }
    #include "window.moc"
    

    customwidget.h

    #ifndef CUSTOMWIDGET_H
    #define CUSTOMWIDGET_H
    
    #include <QWidget>
    #include <QtGui>
    #include <string>
    
    class dataContainer {
      private:
    
        std::string name;
    
      public:
        dataContainer(){name="oooh";};
        std::string getName()const{return name;};
        std::string setName(const std::string& n){name=n;};
    
    };
    
    class customWidget : public QWidget {
      Q_OBJECT
    
      private:
        dataContainer *data;
    
      public slots:
        void nameChangedSlot(const QString&);
    
      public:
        customWidget(QWidget *parent,  dataContainer *d);
    
    };
    #endif
    

    customwidget.cpp

    #include "customwidget.h"
    
    customWidget::customWidget(QWidget *parent,  dataContainer *d) : QWidget(parent) {
    
      // store a pointer to the data that we want to alter
      data = d;
    
      // create an edit box and initialize it with the data name
      QVBoxLayout *mainLayout=new QVBoxLayout(this);
      QLineEdit *edit=new QLineEdit(QString::fromStdString(data->getName()),this);
      mainLayout->addWidget(edit);
    
      connect(edit,SIGNAL(textChanged(const QString&)),this,SLOT(nameChangedSlot(const QString&)));
    
    }
    
    void customWidget::nameChangedSlot(const QString& name){
    
      // alter the contents of our data based on the changed string
      data->setName(name.toStdString());
    
    }
    
    #include "customwidget.moc"
    

1 个答案:

答案 0 :(得分:3)

无法直接删除添加到布局的窗口小部件。相反,您可以尝试下面的代码,从布局中删除特定小部件和相应的布局项:

QLayoutItem* item;
while ( ( item = mainLayout->takeAt( 0 ) ) != NULL )
{
    if(item->widget() == myWidget){
        delete item->widget();
        delete item;
    }
}