c++qtqt5

Qt::FindDirectChildren does not work, but should


I'm having some trouble with the Qt Object tree. I have a RangeValidator that inherits from a ValidatorInterface. I create it on the heap and couple the parent to it for memory management. This parent is the SettingsForm.

However, even though the new RangeValidator is coupled to the form directly (using "this"), it does not seem to find it as a direct child. It only finds it recursively. You can see this in the debugger's "Locals" tab.

Note that the RangeValidator-object is a direct child of the SettingsForm. I've checked in the debugger under QObject::children.

Anyone have a clue whats going on here? I can't seem to figure this out.

code and debug info

EDIT: It looks like it has something to do with the QString& name parameter. When changing it to an empty string (aka match all) it does find it directly AND recursively as well. The previous recursive finds were actually bogus. I'm missing how the setObjectName() fails to be used like I would expect.

//finds the child
BalVfpValidatorInterface* childDirect = this->findChild<BalVfpValidatorInterface*>(QString(), Qt::FindDirectChildrenOnly);
//does not find the child
BalVfpValidatorInterface* childDirect2 = this->findChild<BalVfpValidatorInterface*>(QString("customValidator"), Qt::FindDirectChildrenOnly);

Code:

SettingsForm.cpp

SettingsForm::SettingsForm(QWidget* pParent, const QString& name)
    : DialogForm(staticMetaObject.className(), pParent, name)
{
    setupUi(this);
}


SettingsForm::~SettingsForm (void)
{
}
void SettingsForm::formInitialized(void)
{

    RangeValidator rangeValidator = new RangeValidator(this);
    rangeValidator.setObjectName("customValidator");

    ValidatorInterface* childRecursive = this->findChild<ValidatorInterface*>("customValidator", Qt::FindChildrenRecursively);
    ValidatorInterface* childDirect = this->findChild<ValidatorInterface*>("customValidator", Qt::FindDirectChildrenOnly);

    QList<ValidatorInterface*> childrenRecursive = this->findChildren<ValidatorInterface*>("customValidator", Qt::FindChildrenRecursively);
    QList<ValidatorInterface*> childrenDirect = this->findChildren<ValidatorInterface*>("customValidator", Qt::FindDirectChildrenOnly);

    
    DialogForm::formInitialized();
}

ValidatorInterface.h

class CORE_EXPORT ValidatorInterface : public QObject
{
    Q_OBJECT

public:
    explicit ValidatorInterface(QObject* pParent) : QObject(pParent){};
    virtual ~ValidatorInterface() {};

public:
    /*!
     * @brief This function will give a default implementation for parameter support.
     * @details This function should be overridden if the validator needs dynamic properties from the parameter.
     * @param value The value to validate
     * @param pParameter The parameter to use dynamics from
     * @return If value is valid.
     */
    virtual bool validate(const QVariant& value, Parameter* pParameter) {
        return validate(value);
    }
    /*!
     * @brief Validates a value
     * @param value The value to validate
     * @return If it is valid.
     */
    virtual bool validate(const QVariant& value) = 0;

};

RangeValidator.cpp

#include "rangevalidator.h"
#include "validatorinterface.h"

RangeValidator::RangeValidator(QObject* pParent)
    : ValidatorInterface(pParent)
{
}


RangeValidator::~RangeValidator()
{
}

bool RangeValidator::validate(const QVariant& value) 
{
    if (!value.canConvert<double>())
    {
        return false;
    }

    double l_val = value.toDouble();

    return (l_val <= m_max) && (l_val >= m_min);
}

Solution

  • I've managed to find it. This is a stupid mistake. QT is perfectly fine. I set the ObjectName at line 30, however. This is regarding the object on the stack. They are different objects. Using the pointer and pointer operator (->), I actually call the right object. The one that is tied to the form. Now that object has an actual name (default this is an empty string), and can be found using the QString& name parameter.

    RangeValidator rangeValidator = new RangeValidator(this);
    rangeValidator.setObjectName("customValidator");
    

    Should become:

    RangeValidator* rangeValidator = new RangeValidator(this);
    rangeValidator->setObjectName("customValidator");