Results 1 to 8 of 8

Thread: Create a dialog on the fly dynamically based on an input xml file

  1. #1
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    652
    Thanks
    40
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Create a dialog on the fly dynamically based on an input xml file

    Hi Qt community,

    I need to read an xml custom file and based on its content I have to create and show a dialog showing what has been described in the xml file.
    A small example of part of the content of the file:

    Qt Code:
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <HMI>
    3. <Parameter type=[COLOR="#008000"]"textfield"[/COLOR]>
    4. <Label>DS ID</Label>
    5. <Size>80</Size>
    6. <Value>-1</Value>
    7. <ToolTip>Enter DS_ID. For all use -1</ToolTip>
    8. </Parameter>
    9. <Parameter type=[COLOR="#008000"]"textfield"[/COLOR]>
    10. <Label>RT Number</Label>
    11. <Size>80</Size>
    12. <Value>-1</Value>
    13. <ToolTip>Track number. For all use -1</ToolTip>
    14. </Parameter>
    15. <Parameter type=[COLOR="#008000"]"textfield"[/COLOR]>
    16. <Label>Sigma Value</Label>
    17. <Size>80</Size>
    18. <Value>2</Value>
    19. <ToolTip>Sigma value. For for which AA will be performed</ToolTip>
    20. </Parameter>
    21. </HMI>
    To copy to clipboard, switch view to plain text mode 

    This will be translated in a dialog having 3 couples of QLabel and QLineEdit respectively.
    Each couple of <Label>labelText</Label> tags identifies the QLabel (having labelText as text) and each Parameter type="textfield" identifies the QLineEdit widgets with the text between the tags <Value> and </Value>. I have no problem in parsing an xml file, but I'm not very clear on how to create dialog on the fly.

    Any help will be appreciated.
    Franco
    Last edited by d_stranz; 25th November 2021 at 17:59. Reason: missing [code] tags
    Franco Amato

  2. #2
    Join Date
    Jul 2008
    Location
    Germany
    Posts
    477
    Thanks
    11
    Thanked 65 Times in 63 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Create a dialog on the fly dynamically based on an input xml file

    Hi, I would try it like this:
    - create a new widget with a QGridLayout
    - loop over all labels, create a new QLabel for each label, and put it into first column of the layout
    - loop over all lineedits, create a new QLineEdit for each lineedit, and put it into the second column of the layout

    Hope this helps,

    Ginsengelf

  3. The following user says thank you to Ginsengelf for this useful post:

    franco.amato (26th November 2021)

  4. #3
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,065
    Thanks
    286
    Thanked 832 Times in 819 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Create a dialog on the fly dynamically based on an input xml file

    Adding to Ginsengelf's reply, I have a very simple helper class derived from QDialog which allows hosting of any widget inside of a QDialog. I create the widget first, hook up all of its signals, then add it to the helper dialog class and call exec(). This saves me the work of having to repeat the same code over and over for every custom dialog, and allows me to use the same widgets in other, non-dialog parts of the UI. Maybe this can help in your case, especially if you devise a custom QWidget class that builds itself from XML and provides a generic set of signals that are emitted when things are edited.

    I assume you realize that Qt's UI files are just fancier versions of the XML file that you have devised, right? And that there is a QUiLoader class that will load and build a GUI from a UI file at runtime?

    Qt Code:
    1. /*
    2. QtWidgetHostingDialog
    3.  
    4. This is a generic QDialog class designed to host a single composite widget.
    5. The dialog has a vertical layout with the hosted widget on top and a
    6. standard QDialogButtonBox below. The button box's accepted and rejected
    7. signals are connected to the QDialog accept and reject slots.
    8.  
    9. The pointer to the hosted widget is passed during construction and
    10. ownership is passed to the QDialog. The hosted widget may not be replaced
    11. once the dialog is constructed.
    12.  
    13. Convenience methods are provided to retrieve the hosted widget and button box
    14. pointers.
    15.  
    16. Example:
    17.  
    18. MyWidget * pWidget = new MyWidget;
    19. // configure pWidget, connect signals, etc.
    20.  
    21. CQtWidgetHostingDialog dlg( pWidget, this );
    22. dlg.setWindowTitle( "Edit My Parameters" );
    23. if ( QDialog::Accepted == dlg.exec() )
    24. // retrieve edited information from pWidget
    25.  
    26. */
    27.  
    28. #include <QDialog>
    29.  
    30.  
    31. class CQtWidgetHostingDialog : public QDialog
    32. {
    33. Q_OBJECT
    34.  
    35. public:
    36. CQtWidgetHostingDialog( QWidget * pHostedWidget, QWidget * pParent = nullptr );
    37. virtual ~CSAQtWidgetHostingDialog();
    38.  
    39. QWidget * hostedWidget() const;
    40. QDialogButtonBox * buttonBox() const;
    41.  
    42. protected:
    43. QWidget * mpHostedWidget = nullptr;
    44. QDialogButtonBox * mpButtonBox = nullptr;
    45. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "QtWidgetHostingDialog.h"
    2.  
    3. #include <QDialogButtonBox>
    4. #include <QVBoxLayout>
    5.  
    6. #include <cassert>
    7.  
    8. CQtWidgetHostingDialog::CQtWidgetHostingDialog( QWidget * pHostedWidget, QWidget * pParent /*= nullptr */ )
    9. : QDialog( pParent )
    10. , mpHostedWidget( pHostedWidget )
    11. {
    12. assert( mpHostedWidget != nullptr );
    13.  
    14. QVBoxLayout * pLayout = new QVBoxLayout;
    15. setLayout( pLayout );
    16.  
    17. pLayout->addWidget( mpHostedWidget );
    18.  
    19. mpButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
    20. pLayout->addWidget( mpButtonBox );
    21.  
    22. connect( mpButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
    23. connect( mpButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
    24. }
    25.  
    26. CQtWidgetHostingDialog::~CQtWidgetHostingDialog()
    27. {
    28. }
    29.  
    30. QWidget * CQtWidgetHostingDialog::hostedWidget() const
    31. {
    32. return mpHostedWidget;
    33. }
    34.  
    35. QDialogButtonBox * CQtWidgetHostingDialog::buttonBox() const
    36. {
    37. return mpButtonBox;
    38. }
    To copy to clipboard, switch view to plain text mode 

    Access to the QDialogButtonBox is provided so you can customize by adding additional buttons and connect to their signals.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  5. The following 3 users say thank you to d_stranz for this useful post:

    franco.amato (26th November 2021), Ginsengelf (26th November 2021), ^NyAw^ (30th November 2021)

  6. #4
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    652
    Thanks
    40
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Create a dialog on the fly dynamically based on an input xml file

    Qt Code:
    1. void ReportParametersDialog::processXmlFile(const QString &xmlFile, QGridLayout *layout)
    2. {
    3. QDomDocument document("parameters");
    4. QFile file(xmlFile);
    5. if (!file.open(QIODevice::ReadOnly))
    6. {
    7. return;
    8. }
    9. if (!document.setContent(&file))
    10. {
    11. file.close();
    12. return;
    13. }
    14. QDomElement root = document.documentElement();
    15. QDomNode node = root.firstChild();
    16. while (!node.isNull())
    17. {
    18. QDomElement param = node.toElement();
    19. if (!param.isNull())
    20. {
    21. if (param.tagName() != "Parameter")
    22. {
    23. continue;
    24. }
    25. if (param.attribute("type") == "textfield")
    26. {
    27. QDomElement labelElem = node.firstChildElement("Label");
    28. QLabel *label = new QLabel(labelElem.text());
    29. QDomElement value = node.firstChildElement("Value");
    30. QDomElement size = node.firstChildElement("Size");
    31. QDomElement toolTip = node.firstChildElement("ToolTip");
    32.  
    33. QLineEdit *lineEdit = new QLineEdit(value.text());
    34. lineEdit->setMaximumWidth(size.text().toInt());
    35. lineEdit->setToolTip(toolTip.text());
    36.  
    37. int row = layout->rowCount();
    38. layout->addWidget(label, row, 0);
    39. layout->addWidget(lineEdit, row, 1);
    40. }
    41. }
    42. node = node.nextSibling(); }
    43. }
    To copy to clipboard, switch view to plain text mode 

    I thought about using QSignalMapper but I don't see how to detect if the value of any widget has changed without storing the value somewhere.
    Do you have any better idea?
    Regards,
    Franco
    Franco Amato

  7. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,065
    Thanks
    286
    Thanked 832 Times in 819 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Create a dialog on the fly dynamically based on an input xml file

    In your loop that creates the QLineEdit, you can use the QObject::setProperty() method to associate a unique value with the widget (as a QVariant). You can also connect the QLineEdit::editingFinished() signal to a slot. In the slot, call sender() to retrieve the QLineEdit pointer, then use the QObject::property() method to retrieve the unique value you have stored for the widget. You can also use QLineEdit::text() to retrieve whatever the user has changed the text to.

    You are going to have devise some way of connecting the widgets you create via XML to fields in a data structure, otherwise you will end up with widgets connected to slots that don't have any idea what to do with the data they have retrieved.

    But there are a lot of problems with your design. How are you going to prevent users from entering incorrect values, for example? How will you enforce required fields (i.e. a field that cannot be left empty)? How can you set the tab order so that the tab key doesn't just take the user to random places in the grid each time it is pressed? What you will be creating is a dialog with no way to control what happens between the time the dialog is displayed until the time the user clicks OK or Cancel.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  8. #6
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    652
    Thanks
    40
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Create a dialog on the fly dynamically based on an input xml file

    Sorry d_stratz,
    it seems that some text has been lost in my previous answer.

    Regarding what you said, so far I am assuming that the xml has correct values.
    But you are right, I will follow your advice and do the checks at the moment of parsing the file.

    To replace the edited value of the QLineEdit in the xml, I was thinking of using the position in the grid of the widget (basically the row number) and associating it with the position of the tag in the xml file. What do you think?
    Franco Amato

  9. #7
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,065
    Thanks
    286
    Thanked 832 Times in 819 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Create a dialog on the fly dynamically based on an input xml file

    To replace the edited value of the QLineEdit in the xml, I was thinking of using the position in the grid of the widget (basically the row number) and associating it with the position of the tag in the xml file. What do you think?
    I think it would be better to add a new field to the XML element - a "key" or "id" that you can use as the unique property the you can assign to the QLineEdit. When the edited value changes, you get the property from the widget, find the same key or id in your XML, and use that to change the value.

    Using the location of the widget in the grid to find it in the XML is fragile - if you add a new widget or change the order of the widgets in the XML, then the mapping between the grid and the XML is no longer correct. Adding a "key" that uniquely maps between widget and XML makes your layout independent of the number and placement of the widgets in the XML.

    To make it easy, you could use a QMap< QString, QDomElement * > data structure to give you a quick way to look up the XML element that gets changed whenever the QLineEdit with that key (the QString):

    Qt Code:
    1. void MyDialog::onEditingFinished()
    2. {
    3. QLineEdit * pEdit = qobject_cast< QLineEdit * >( sender() );
    4. if ( pEdit )
    5. {
    6. QString text = pEdit->text();
    7. QString key = pEdit->property( "key" ).toString();
    8.  
    9. // QMap< QString, QDomElement * > mKeyMap is a member of MyDialog
    10. QDomElement * pXML = mKeyMap[ key ];
    11. pXML->setAttribute( "myAttr", text );
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 

    You build the QMap when you read the XML to create the GUI. And of course you would add error checking to the code above to make sure that the "key" exists in the map, and that the map lookup has returned a non-null pointer.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  10. #8
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    652
    Thanks
    40
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Create a dialog on the fly dynamically based on an input xml file

    Yours is a good idea, but unfortunately I can't change the xml files.
    However, giving a look at the xml, I noticed that the label names are unique and I can add these names as properties of the QLineEdit widgets
    Qt Code:
    1. QLineEdit::setProperty("id", labelName);
    To copy to clipboard, switch view to plain text mode 

    Then, I can use the labelName as information to retrieve the correct modified tag (even if I don't know how yet). It is the first time that I work with xml files
    Franco Amato

Similar Threads

  1. Replies: 1
    Last Post: 12th March 2015, 07:41
  2. Replies: 0
    Last Post: 25th March 2014, 07:24
  3. Replies: 7
    Last Post: 5th February 2014, 12:20
  4. Replies: 3
    Last Post: 19th October 2011, 14:08
  5. Replies: 2
    Last Post: 28th September 2010, 11:34

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.