PDA

View Full Version : Passing handles to widgets



GDI
7th December 2011, 16:31
I have a general question concerning widgets.

I am working on a computational program. The user selects a widget that is then added to a tabwidget. Each selected widget "form" has user added input and computed output. Depending on the type of widget selected the input can vary, but the output is mostly the same. Each widget "form" has a corresponding class that performs the computation. Currently I copy the contents of the widget to a structure and pass the structure to the computation class. The computation class modifies the output contents of the structure and then I copy the results to the output portion of the original widget.

Rather than copy the widget contents to a structure and passing the structure I would like to simply pass a handle to the widget itself. So far I haven't had any luck with this. Is this allowed in Qt? Can anyone point me to a forum, article or example similar to this?

d_stranz
7th December 2011, 17:28
"Handles" tends to be a Windoze concept. Qt basically uses pointers to the widgets themselves.

But I question a design where the computational parts are dependent on details of the GUI (like pointers to widgets and their contents). In almost all the computational software I write, the algorithmic parts are completely independent of the GUI. Communication between the two is by way of data structures which are known to both, as per your original implementation. This allows changes to either side without affecting the other. Copying and passing a data structure is almost certainly cheap compared to the cost of the computation, so you aren't gaining anything by directly accessing widget contents.

GDI
7th December 2011, 17:50
Okay, I'm showing my age referring to "handles".

Thanks for the reply. Although it wasn't what I really wanted to find out I'm rather in agreement with it.

Looking back at the problem I've been using a SIGNAL/SLOT to update each structure element as the user changed the input data. Passing the form (widget) would have eliminated this.

It appears that my best bet is to keep the data structure and work on improving how I pass data to and from the structure.

Thanks again. You're response has helped me re-focus on the problem.

d_stranz
7th December 2011, 18:03
In my GUI designs where I use a dialog or similar GUI element to change parameters, I usually pass a reference to the structure into the dialog widget, with a "setParameters()" call. The dialog makes a copy of the data structure and modifies that, using slots / signals connected to the various editing widgets in the dialog. After the dialog is dismissed with accept(), the caller retrieves the modified structure with a "parameters()" call. In my apps, there is generally no need for live updates, so a simple set/get mechanism works. If you implement an "Apply" button for the dialog, then you can add a signal "applyParameters( const DataStruct & )" to notify the app. Passing and storing a copy of the parameters in the dialog allows you to easily implement "Undo" as well: setParameters() actually makes two copies, one of them for modification, the other to serve as the backup if the user wants to undo changes.

Typically, the parameter setting dialog has no direct connection to the computational part. The communication is handled via a slot (e.g. a QAction::triggered() handler) that creates the dialog, sets initial parameters, then posts it. If the user clicks OK to accept, then the modified parameters are retrieved and passed into the computational part for execution.

There are variations on this theme; as a long-time MFC developer, I grew to like the CDocument idea, so in general I use a document-like class as the glue between the GUI part and the computational part. When the GUI is used to edit parameters, these are then sent to the document (via a signals/slots or direct function calls), and the document is then responsible for orchestrating what computation occurs next. This really decouples the app, to the point where I can make massive changes to the GUI without affecting the computational parts of it at all.

GDI
7th December 2011, 19:25
I'm usually a proponent of the Document/View concept as well. In fact, in this program I started using a structure array as a document and the GUI as a view. Then I realized that the GUI was the only view so the separation didn't make much sense.

The problem I have run into with the structure array is the size. In the program there are eight possible forms (widgets) that the user can select to place on a tabwidget. The user can add as many forms as needed. Each form contains six to sixty input/output boxes. So, the array was getting a bit out of hand. What might be more practical is to use the GUI as both the document and view. I can make up eight structures (one for each form) and pass the data from individual forms for computation and record the results back into the form. This solution might make a purist faint, but I'm looking for practical solutions.

The dialog concept is interesting. The program does not currently have undo/redo features. I once used a program that used a popup dialog for all inputs to the form. When the user clicked on an input box a dialog appeared. The input was entered into a box on the dialog and the user clicked accept to update the form. It was probably the most annoying programs I have ever used. It might work if the dialog appeared as an exact overlay of the form. In this case the only change the user would see is the appearance of a accept/cancel button pair. I may try that.

Thanks again.

d_stranz
7th December 2011, 20:07
I once used a program that used a popup dialog for all inputs to the form.

Oh, yeah, that would get really old, really quickly. When the US Postal Service first offered an online postage calculator, the original version (obviously written under a lucrative contract according to a specification written by an administrator who knew nothing about web development) posted a new web page for every single entry. (How big is your package? Enter the length and click submit. Enter the width and click submit, ...) Took about 30 pages to learn that it would cost $1.50 to send your package. It very quickly disappeared to be replaced with a form-based entry version.

I wasn't implying that you would post a dialog for every parameter. In one of my apps, I have a multi-page tabbed dialog, each tab representing a collection of individual parameters for a certain category; the main dialog that manages these pages has a setParameters() method that accepts a "struct of structs" (similar to your array). Inside this setParameters method, the wrapping struct is taken apart, and the sub-structs are parceled out to each appropriate page, calling their setParameters() methods. Thus, there is only a loose connection between the main tab dialog and each page, and in fact the individual pages know nothing about the facts that they belong to a tabbed dialog or that their parameters are part of a larger data structure. The widgets on the dialog pages themselves are encapsulated inside of generic QWidget-derived widgets, so the "page" could be hosted anywhere, not restricted to a dialog.

This decoupling has allowed me to change parts of the GUI from tabbed dialog to docking window by simply reparenting the "page", or to reuse pages in a different app. I hate rewriting GUI code; making all the connections between signals and slots is the most tedious and error-prone part of app development. By encapsulating things in generic widgets, it minimizes the rewriting and errors.