SerJS
SerJS

Reputation: 85

Check whether a widget is in the layout Qt

How to check whether a widget is in a layout? I have a layout that may contain the widget or not.

Need to check if the widget exists in the layout, then do not add a new one.
And if does not exist, add a new one.
How to do it?

void MainWindow::slotPush1()
{
    if <there is no infoClient> ui->verticalLayout_3->addWidget(new infoClient(this));
}

Upvotes: 8

Views: 10657

Answers (5)

Anonymous
Anonymous

Reputation: 4777

Another possibility would be to keep track of the pointers of your created widgets (e.g., by storing them in a std::vector or Qt equivalent). This allows to use indexof(QWidget*):

Searches for widget widget in this layout (not including child layouts). Returns the index of widget, or -1 if widget is not found.

Upvotes: 0

UmNyobe
UmNyobe

Reputation: 22920

Few points:

  • The parent of a widget in a layout is the widget containing the top-level layout
  • Layouts can be nested.
  • A layout contains items (QLayoutItem), which are either layouts (layout() is not null) or widgets (widget() is not null). In the end you have a tree of layout items.

So You need to do a search from the parent widget (dfs, bfs).

bool checkWidgetInsideLayout(const QWidget* _someWidget){

return _someWidget != NULL && 
       _someWidget->parent() != NULL && 
       _someWidget->parent()->layout() != NULL && 
       foundItem(_someWidget->parent()->layout(), _someWidget ); 
}

//clumsy dfs
bool foundItem(const QLayout* layout, const QWidget* _someWidget ){

     for(int i = 0; i < layout->count(); i++){
        QLayoutItem* item = layout->itemAt(i);
        if(item->widget() == _someWidget )
            return true;
         if(item->layout() && foundItem(item->layout(), _someWidget)  )
             return true;
     }
     return false;
}

Upvotes: 3

tomvodi
tomvodi

Reputation: 5897

I agree with Tom Panning's solution to find your child with the QObject::findChild() method. But adding a Widget to QLayout will reparent it to the layout's parent. So you'll have to find it by calling it with the MainWindow object like that:

void MainWindow::slotPush1()
{
    if (this->findChild<QWidget*>("infoClient")) {
        // ...
    }
}

If your infoClient widget was added in the QtDesigner, you won't have problems with this solution. The designer sets per default the object name. If the infoClient was added to the layout in your code, you have to set the object name explicitly, otherwise you won't be able to find it because its name is empty: (Assuming, m_client is a member variable of MainWindow)

void MainWindow::createWidgets()
{
    if (infoClientShouldBeAdded) {
        m_client = new infoClient(this);
        m_client->setObjectName("infoClient");
        ui->verticalLayout_3->addWidget(m_infoClient);
    }
}

Upvotes: 1

Tom Panning
Tom Panning

Reputation: 4772

Use QObject::findChild to find a child by its name. For instance:

void MainWindow::slotPush1()
{
    if (ui->verticalLayout_3->findChild<QWidget*>("infoClient")) // your code to add it here
}

Note: findChild is a template function. If you're not familiar with template functions, just know that you pass the type of object you want to find (in your example, it looks like you could use ui->verticalLayout_3->findChild<infoClient*>("infoClient")). If you want to find a QWidget, or anything that inherits from QWidget, you can just use findChild<QWidget*>() and you'll be safe.

Upvotes: 2

RA.
RA.

Reputation: 7777

There is no mechanism within Qt that will perform the check that you are looking for. You will have to implement it yourself:

void MainWindow::slotPush1()
{
   if (doesLayoutContainInfoClient(ui->verticalLayout_3))
   {
      ui->verticalLayout_3->addWidget(new infoClient(this));
   }
}

bool MainWindow::doesLayoutContainInfoClient(QLayout* layout)
{
   const QString infoClientName("infoClient");

   for (int i=0; i<layout->count(); i++)
   {
      QWidget* layoutWidget = layout->itemAt(i)->widget();
      if (layoutWidget)
      {
         if (infoClientName == layoutWidget->metaObject()->className())
         {
            return true;
         }
      }
   }
   return false;
}

Despite what I've suggested above, I don't really recommend it. It makes more sense to store whether or not you've added infoClient to your layout as an independent boolean within your program somewhere. Querying the contents of layouts in this manner is somewhat unusual, and is messier than just using a bool.

Upvotes: 3

Related Questions