Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED] QWizard: Workaround for registerField function
QtWS25 Last Chance

[SOLVED] QWizard: Workaround for registerField function

Scheduled Pinned Locked Moved General and Desktop
21 Posts 2 Posters 6.3k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Z Offline
    Z Offline
    Zarkon
    wrote on last edited by
    #1

    I have made forms to be added as widgets to a QWizard page. Now I would like register the widgets on the form so I can be sure that "Next" is not pressed without filling something on each field on the page. The registerfield procedure is however protected. I have trying to find a work around but without succes. Any suggestions?

    @
    QWizardPage *MainWindow::createPage(QString title, QWidget *pWidget)
    {
    QWizardPage *page = new QWizardPage;
    QVBoxLayout *layout = new QVBoxLayout;
    QList <QWidget *> childWidgets = pWidget->findChildren <QWidget *>();
    int i;

    page->setTitle(title);
    layout->addWidget(pWidget);
    page->setLayout(layout);
    for (i = 0; i < childWidgets.count(); i++)
    {
        if (!childWidgets.at(i)->inherits("QLabel"))
        {
            if (childWidgets.at(i)->objectName() != "")
            {
                // page->registerField(childWidgets.at(i)->objectName(), NULL, NULL, NULL);
            }
        }
    }
    qDebug() << "Page ready" <&lt; title;
    return page;
    

    }
    @

    @
    pWidget = new firstWidget_UI_Form;
    MyWizard.addPage(createPage("Fancy title", pWidget));
    pWidget = new secondWidget_UI_Form;
    MyWizard.addPage(createPage("Fancy title 2", pWidget));
    @

    1 Reply Last reply
    0
    • A Offline
      A Offline
      andre
      wrote on last edited by
      #2

      I'd just make a custom QWizardPage subclass where you do have access to that method. You can even just give it a special method that does the iteration over the label-type widgets inside it, so you still don't need to expose the registerField function.

      1 Reply Last reply
      0
      • Z Offline
        Z Offline
        Zarkon
        wrote on last edited by
        #3

        I tried something like this

        @class ModifiedWizardPage : QWizardPage
        {
        public:
        explicit ModifiedWizardPage(QWidget *parent = 0);
        void addField(QString fieldName);
        void addTitle(QString title);
        void addLayout(QLayout *pLayout);
        QWizardPage *getBase() { return static_cast<QWizardPage *>(this); }
        };

        pWidget = new firstWidget_UI_Form;
        ModifiedWizardPage *modPage = createPage("Fancy title 2", pWidget);
        QWizardPage *wizPage = ModifiedWizardPage->getBase();
        // CRASHED After this statement
        MyWizard.addPage(wizPage);
        @

        1 Reply Last reply
        0
        • A Offline
          A Offline
          andre
          wrote on last edited by
          #4

          The whole getBase thing is not needed. Simply publicly inherit ModifiedWizardPage from QWizardPage, and you can use your ModifiedWizardPage instance like you can any QWizardPage instance. Your approach also works if you prefer that, but in that case, don't use the class name on line 13, but the instance. So, replace ModifiedWizardPage with modPage and you should be fine. What you have now should not even compile, so I wonder why/how you get a crash.

          1 Reply Last reply
          0
          • Z Offline
            Z Offline
            Zarkon
            wrote on last edited by
            #5

            It still eludes me a bit. This is the full code now and it crashes at the last statement.

            @
            class ModifiedWizardPage : public QWizardPage
            {
            public:
            explicit ModifiedWizardPage(QWidget *parent = 0);
            };

            ModifiedWizardPage::ModifiedWizardPage(QWidget *parent)
            {
            QList <QWidget *> childWidgets = parent->findChildren <QWidget *>();
            int i;

            setParent(parent);
            setTitle(parent->windowTitle());
            setObjectName(parent->windowTitle());
            for (i = 0; i < childWidgets.count(); i++)
            {
                if (!childWidgets.at(i)->inherits("QLabel"))
                {
                    if (childWidgets.at(i)->objectName() != "")
                    {
                        qDebug() << childWidgets.at(i)->objectName();
                        registerField(childWidgets.at(i)->objectName(), NULL, NULL, NULL);
                    }
                }
            }
            

            }

            QWidget *pWidget;
            ModifiedWizardPage *modPage;

            pWidget = new firstWidget_UI_Form;
            modpage = new ModifiedWizardPage(pWidget);
            MyWizard.addPage(modpage); // crashes here

            Internal error: pc 0x0 in read in psymtab, but not in symtab.)
            @

            1 Reply Last reply
            0
            • Z Offline
              Z Offline
              Zarkon
              wrote on last edited by
              #6

              Just a thought can it be that I get an error because I am registering fields that are not part of the QWizard yet?

              1 Reply Last reply
              0
              • A Offline
                A Offline
                andre
                wrote on last edited by
                #7

                You're doing weird things with parents and children. To get things straight: your wizard page is supposed to contain pWidget right?

                If so, then pWidget can't be the parent of your wizard page. It should become the child.

                How about something like this
                @
                class ModifiedWizardPage : public QWizardPage
                {
                public:
                explicit ModifiedWizardPage(QWidget* content, QWidget *parent = 0);
                };

                ModifiedWizardPage::ModifiedWizardPage(QWidget* content, QWidget parent):
                QWizardPage(parent)
                {
                QVerticalLayout
                layout = new QVerticalLayout(this);
                layout->addWidget(content);

                QList <QWidget *> childWidgets = parent->findChildren <QWidget *>();
                int i;
                
                setTitle(content->windowTitle());
                setObjectName(content->windowTitle()); //you probably don't want to do this. windowTitle is translable, while object names should not be
                for (i = 0; i < childWidgets.count(); i++)
                {
                    if (!childWidgets.at(i)->inherits("QLabel"))
                    {
                        if (childWidgets.at(i)->objectName() != "") // not a good plan. Use another property instead.
                        {
                            qDebug() << childWidgets.at(i)->objectName();
                            registerField(childWidgets.at(i)->objectName(), NULL, NULL, NULL); 
                        }
                    }
                }
                

                }

                QWidget *pWidget;
                ModifiedWizardPage *modPage;

                myWizard = new MyWizard();
                pWidget = new firstWidget_UI_Form;
                modpage = new ModifiedWizardPage(pWidget, myWizard);
                myWizard->addPage(modpage);
                myWizard->exec();
                @

                1 Reply Last reply
                0
                • Z Offline
                  Z Offline
                  Zarkon
                  wrote on last edited by
                  #8

                  Thanks for straightening out my code. It helps, but I still have a crash. When I comment this (#if 0) it works. Otherwise not. And it was this part that I needed to add. :(

                  @
                  for (i = 0; i < childWidgets.count(); i++)
                  {
                  if (childWidgets.at(i)->inherits("QLineEdit"))
                  {
                  if (childWidgets.at(i)->objectName() != "")
                  {
                  qDebug() << childWidgets.at(i)->objectName();
                  registerField(childWidgets.at(i)->objectName(), NULL, NULL, NULL);
                  }
                  }
                  }@

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    andre
                    wrote on last edited by
                    #9

                    Come on... Did you even try a debugger? And it should be obvious that claiming "a crash" without including a backtrace is... eh... less than informative.

                    1 Reply Last reply
                    0
                    • Z Offline
                      Z Offline
                      Zarkon
                      wrote on last edited by
                      #10

                      Like before (see end of 3rd post)

                      Internal error: pc 0x0 in read in psymtab, but not in symtab.)
                      signal name: sigsegv (segmentation fault)

                      I review it bit more.

                      1 Reply Last reply
                      0
                      • Z Offline
                        Z Offline
                        Zarkon
                        wrote on last edited by
                        #11

                        The problem is here (for example QLineEdit)

                        @registerField(childWidgets.at(i)->objectName(), NULL, NULL, NULL);@

                        I was relying on defaults, but it seems that I have to be explicit

                        @registerField(childWidgets.at(i)->objectName(), childWidgets.at(i), "text", "textChanged");@

                        That also means I have to distinguish between widgets. Which is not impossible, but somewhat annoying.

                        @
                        QAbstractButton bool checked toggled()
                        QAbstractSlider int value valueChanged()
                        QComboBox int currentIndex currentIndexChanged()
                        QDateTimeEdit QDateTime dateTime dateTimeChanged()
                        QLineEdit QString text textChanged()
                        QListWidget int currentRow currentRowChanged()
                        QSpinBox int value valueChanged()
                        @

                        The next button is still enabled even though the fields are reqistered.

                        1 Reply Last reply
                        0
                        • A Offline
                          A Offline
                          andre
                          wrote on last edited by
                          #12

                          Automatic should work just fine, I think. At least, as long as you handle only widget types that make sense and have a user property. Input type widgets generally have that, non-input type widgets don't. It is not hard to check though:

                          @
                          bool hasUserProperty(QObect* object) const
                          {
                          if (!object)
                          return false;

                          QMetaObject* mo = object->metaObject();
                          return mo->userProperty().isValid();
                          

                          }
                          @

                          That would result in code like:
                          @
                          QWidget* childWidget = childWidgets.at(i);
                          if (hasUserProperty(childWidget)) {
                          registerField(childWidget->objectName(), childWidget);
                          } else {
                          // you'll need to handle these widgets in a different way
                          }
                          @

                          1 Reply Last reply
                          0
                          • Z Offline
                            Z Offline
                            Zarkon
                            wrote on last edited by
                            #13

                            Just saw my mistake. The NULL in the second argument made it crash.

                            @registerField(childWidgets.at(i)->objectName(), NULL, NULL, NULL);@

                            should be

                            @registerField(childWidgets.at(i)->objectName(), childWidgets.at(i), NULL, NULL);@

                            I have combined that with your code. Filtering out widgets that not on the ui-form and buttons.

                            @ModifiedWizardPage::ModifiedWizardPage(QWidget* content, QWidget parent):
                            QWizardPage(parent)
                            {
                            QVBoxLayout
                            layout = new QVBoxLayout(this);
                            layout->addWidget(content);

                            QList <QWidget *> childWidgets = content->findChildren <QWidget *>();
                            int i;
                            setTitle(content->windowTitle());
                            
                            for (i = 0; i < childWidgets.count(); i++)
                            {       
                                if (childWidgets.at(i)->objectName() != "")
                                { // exclude runtime widgets - ui only
                                    if (childWidgets.at(i)->metaObject()->userProperty().isValid() && !childWidgets.at(i)->inherits("QAbstractButton"))
                                        registerField(childWidgets.at(i)->objectName(), childWidgets.at(i), NULL, NULL);
                                }
                            
                            }
                            

                            }@

                            The fields are registred now, but how is validation done?

                            1 Reply Last reply
                            0
                            • Z Offline
                              Z Offline
                              Zarkon
                              wrote on last edited by
                              #14

                              Ok. Found the answer to my last question in the documentation pages.

                              http://qt-project.org/doc/qt-4.8/qwizardpage.html#registerField

                              To make it mandatory add a '*'.

                              Full code here and my problem is solved. Thanks to Andre for helping out.

                              @class ModifiedWizardPage : public QWizardPage
                              {
                              public:
                              explicit ModifiedWizardPage(QWidget* content, QWidget *parent = 0);
                              };

                              ModifiedWizardPage::ModifiedWizardPage(QWidget* content, QWidget parent):
                              QWizardPage(parent)
                              {
                              QVBoxLayout
                              layout = new QVBoxLayout(this);
                              layout->addWidget(content);

                              QList <QWidget *> childWidgets = content->findChildren <QWidget *>();
                              int i;
                              setTitle(content->windowTitle());
                              
                              for (i = 0; i < childWidgets.count(); i++)
                              {       
                                  if (childWidgets.at(i)->objectName() != "")
                                  {
                                      if (childWidgets.at(i)->metaObject()->userProperty().isValid() && !childWidgets.at(i)->inherits("QAbstractButton"))
                                          registerField(childWidgets.at(i)->objectName() + "*", childWidgets.at(i), NULL, NULL);
                                  }
                              }
                              

                              }

                              QWizard *myWizard;
                              QWidget *pWidget;
                              QWizardPage *modWizardPage;

                              myWizard = new QWizard(this);
                              myWizard->setWizardStyle(QWizard::ModernStyle);

                              pWidget = new uiForm1;
                              pWidget->setWindowTitle("My fancy title 1");
                              modWizardPage = new ModifiedWizardPage(pWidget, csWizard);
                              myWizard->addPage(modWizardPage);
                              ..........
                              pWidget = new uiForm2;--
                              pWidget->setWindowTitle("My fancy title 2");
                              modWizardPage = new ModifiedWizardPage(pWidget, csWizard);
                              myWizard->addPage(modWizardPage);

                              @

                              1 Reply Last reply
                              0
                              • A Offline
                                A Offline
                                andre
                                wrote on last edited by
                                #15

                                What I don't get is that you're changing the type of widgets you're interested in with every iteration of your code... You started out with QLabel, then it became QLineEdit, and now you're on to using QAbstractButton.

                                Note that the NULL, NULL arguments are not needed, and rather C-ish. The default value for these parameters is 0 already (C++ style before C++/11), and the C++/11 version would be nullptr.

                                final suggestion:
                                @
                                myWizard->addPage(new ModifiedWizardPage(
                                new uiForm1,
                                tr("My fancy title 1"),
                                myWizard));
                                myWizard->addPage(new ModifiedWizardPage(
                                new uiForm2,
                                tr("My fancy title 2"),
                                myWizard));
                                @

                                that is: make the title simply an argument for the ModifiedWizardPage constructor as you're not setting it in the ui file anyway. You can also get rid of the intermediary variables.

                                1 Reply Last reply
                                0
                                • Z Offline
                                  Z Offline
                                  Zarkon
                                  wrote on last edited by
                                  #16

                                  When I started this I wanted to exclude QLabel from the widgets to be registered because they are not writable by the user. Then, just for debugging, I used only included QLineEdit objects. After that you came with

                                  metaObject()->userProperty().isValid()

                                  I put debugs and noticed that QLabel was false, but not the buttons so I modified that line. The buttons also dont need to be registered. They are just there to launch a dialog to fill the QLineEdit's.

                                  PS: I took your "final suggestion" and cleaned up the code a bit. I also included the tr() although it is not really necessary. The tool I am making is not for large scale deployment.

                                  1 Reply Last reply
                                  0
                                  • A Offline
                                    A Offline
                                    andre
                                    wrote on last edited by
                                    #17

                                    Ok. Just checking. Are you sure want to ignore all QAbstractButtons? Including QCheckBox and QRadioButton?

                                    1 Reply Last reply
                                    0
                                    • Z Offline
                                      Z Offline
                                      Zarkon
                                      wrote on last edited by
                                      #18

                                      I noticed that too. :)

                                      QCheckbox and QRadiobutton are not part of this wizard, but in general I would like to have them. I assume it would that some tweak to include them again.

                                      1 Reply Last reply
                                      0
                                      • Z Offline
                                        Z Offline
                                        Zarkon
                                        wrote on last edited by
                                        #19

                                        Not very elegant but it could be something like this

                                        @
                                        if (childWidgets.at(i)->metaObject()->userProperty().isValid())
                                        {
                                        if (!childWidgets.at(i)->inherits("QAbstractButton"))
                                        registerField(childWidgets.at(i)->objectName() + "", childWidgets.at(i));
                                        else
                                        {
                                        QString aMetaObject = (QString) childWidgets.at(i)->metaObject()->className();
                                        if (aMetaObject.compare("QRadioButton", Qt::CaseSensitive) == 0)
                                        registerField(childWidgets.at(i)->objectName() + "
                                        ", childWidgets.at(i));
                                        else if (aMetaObject.compare("QCheckBox", Qt::CaseSensitive) == 0)
                                        registerField(childWidgets.at(i)->objectName() + "*", childWidgets.at(i));
                                        }
                                        }
                                        @

                                        1 Reply Last reply
                                        0
                                        • A Offline
                                          A Offline
                                          andre
                                          wrote on last edited by
                                          #20

                                          No, indeed, that's not very elegant at all.

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved