[SOLVED] QWizard: Workaround for registerField function
-
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.
-
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.
-
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.
-
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
}
@ -
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?
-
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);@
-
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.
-
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.
-
Ok. Just checking. Are you sure want to ignore all QAbstractButtons? Including QCheckBox and QRadioButton?
-
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.
-
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));
}
}
@ -
No, indeed, that's not very elegant at all.
-
Sorry I have spend many years on C (some on Borland C++). Just getting back to higher level languages like Qt again. There is much I don't fully know. Just have a sense of what the questions are.