Qt QML: UI with dynamic number of images provided by c++ code - c++

I am designing an application that, in essence, gets a number of images (which change - think of several videos consisting of many images each, displayed in sequence) which I want to display in a grid pattern. This pattern should be extensible, I want to be able to control row and column count dynamically.
A C++ core application provides these images at varying speeds. It needs to know where to send them.
My team and I have already created a prototype which fits some of those requirements: we are able to instance a C++ based object, derived from QQuickPaintedItem, which paints its image in the overwritten paint(QPainter *painter) method. In QML, several of these are then instanced and they display their images as I would expect. However, the image content is hard-coded and as these objects are instanced in QML, I'm unsure as to how I would control their contents from my core application in C++. Furthermore, the way we dynamically arrange them is an extremely dirty hack derived from trial and error and works only marginally close to how it is intended: the instances are simply destroyed and recreated whenever the "add one more" button is pressed.
My question is probably a matter of design principle. Even after examining a few examples and further research I am unsure what's the best way to combine the core application and the QML code to achieve what I want.
What is the right approach here? I suspect Models and Views might be the way to go, as I believe I could be able to add the Player components to the model via C++ and therefore have access to them there, while QML would ... somehow ... handle the displaying and arranging.
I'm sorry for the rather vague question, I hope you can help me with a few pointers into the right direction, as to which mechanics I could use to combine QML and C++ for my purposes.

QPaintedItem is unnecessary and will likely constitute performance overhead.
As already mentioned, what you really need to do is implement a QQuickImageProvider which can allow you to do C++ / QML image interop.
Then regardless of whether you need rows, columns or grids, those are all driven by models, you don't necessarily have to implement a C++ mode, QML's ListModel will suffice, as all you really need is a list model of strings, representing the image sources for the custom image provider.
Every time you have a new image coming from C++, you can emit a signal from the C++ side with the image source string, to which you connect a handler on the QML side to add a list item to the model. Expose the emitting object to QML as a context property. As soon as a signal is emitted, the new image source is added to the model and automatically shown in the view. That's pretty much it.

Related

Idomatic QT architecture for simple forms?

I am currently working on a medium-sized project that will need to utilize many form-like dialogs. I am developing this application using Qt5 widgets. (I am trying to implement a debugging tool for a class-based network protocol). Most of the logic behind the forms is very simple.
The view for a form would look like this:
Basically, when send is pressed it just constructs a packet using the data in the form, and would insert it into the message buffer to be sent out when appropriate later in the program. I want to utilize proper coding idioms when I develop this because I'm using this project to familiarize myself with GUI programming.
What concerns me, is that I don't know how to idiomatically structure my code in a way that is extensible, testable, and robust. I don't want my dialog to be directly responsible for inserting the data into the send stream, nor should it have to handle any business logic associated with it.
Naively I would imagine that the view should do very little logic other than communicate to some other part of the process that the user has edited something or pressed a button, perhaps it could validate that the text is in a proper format. The other part of the process would be what I imagine to be the 'model', therefore (I believe) following an MV architecture. This leads to several questions:
Most tutorials like this seem to want the user to implement a QAbstractListModel or a QAbstractTableModel, or perhaps even a QAbstractItemModel, but none of these seem needed or relevant to the type of data I am working with, furthermore, their interface seems to be very heavy-handed for what I think is simple data flow -- do I need to subclass one of these in order to properly fulfill the MV architecture or could I just manage the connections myself? If I manage the connections myself, should I create a presenter class to handle this and therefore implement an MVP architecture?
How should data be passed from this form to the rest of the application? I would prefer to avoid any/all global/static designs if plausible/correct. On send a packet should be constructed and inserted into the send buffer, but should that be done in the model for this dialog? Should a reference to the buffer or its controlling interface be provided and manipulated by this model? Should the relevant data be passed or returned to some outside model that would handle the buffer manipulation?
The data in these forms are basically 1 to 1 with the information needed to construct the messages for the send buffer, to the point that you could reasonably use or adapt the existing interfaces to be a functional model, however, I feel that this would be a code smell -- is that correct? Should I create a new class that basically mirrors my message class in order to have better separation of concerns?
Thank you all for any insight or resources that can be provided. Much of this is me overthinking the problem, but I would like to be sure that my design philosophy is sound before I implement 60+ dialogs so that this application can fully cover the protocol's standard.
I don't want my dialog to be directly responsible for inserting the data into the send stream
Exactly. And it should only be responsible for passing the data on to some service which is responsible for sending the message i.e., Separation of concern and single responsibility.
Most tutorials like this seem to want the user to implement a QAbstractListModel or a QAbstractTableModel, or perhaps even a QAbstractItemModel, but none of these seem needed or relevant to the type of data I am working with,
Is your data going to be represented in a table / list / tree. If yes, then you can use one of these / subclass them. Alternatively, you can use the QListWidget / QTreeWidget etc which don't use the model-view design. If no, then these are not for you obviously. It depends on the data and how you want to present it, and only you know about the data so you have to make that decision.
How should data be passed from this form to the rest of the application?
Using signal / slot mechanism. Take the form in the picture for example. The send button above shouldn't send anything. It should just accept the data entered into the form and then pass that data via a signal to some other service for example a MessageSender service or a ValidationService. That is all the form should do.
I would prefer to avoid any/all global/static designs if plausible/correct.
That is good and you should avoid them unless there is no other way. For example, a logging service is something that is needed everywhere in the program throughout the lifetime of a program, I would make it a singleton.
On send a packet should be constructed and inserted into the send buffer, but should that be done in the model for this dialog? Should a reference to the buffer or its controlling interface be provided and manipulated by this model?
Use signal / slots. A dialog should just take input, it shouldn't be sending data around or doing other things. It should take input and pass it on. Design your classes / objects with this in mind.

GUI Composition in Qt

I have experience building GUIs in Java, C#, and C++ using the WinAPI. I'm attempting my first GUI in C++ using Qt and I have a bit of a transition problem. In any of the other three GUI paradigms, I could create my own GUI components, extend existing JPanels, etc. and end up with a custom-made GUI element that I could add to other GUI windows. C# is particularly good at this as anything I create automatically shows up in the Toolbox after it compiles.
From what I can see there are only two options in Qt and I'm hoping there is something I'm missing. The options are:
Create a custom Widget which may then be imported using a widget container promoted to the right widget.
Build what I like and drag it to scratchpad, from where I can replicate it to my heart's content.
The problem is that I want dynamically add/remove GUI elements at run time. For example, I have a Model-View-Control pattern. The view and control are two different panels in the GUI. When I switch to a different view in one panel, I want to remove the control from the other panel and replace it with the right control for the new view.
From what I can tell, I could do this using custom widgets, but it seems extremely heavy handed to do this for tons of minor widgets in composition to a greater capability. And although I can do the kind of composition I want in scratchpad, I can't figure out how to dynamically add something I have saved in scratchpad.
It is also possible that there is a Qt way of doing things which I have not found. For instance, I have some friends that have successfully created the effects above using different tabs. That seems like a cheap answer, which I could use, but I'd like to believe that Qt has sufficient flexibility to let me build any kind of GUI.
Any suggestions would be helpful
---------------------Improved example--------------------
Let me use the example code that #m7913d gave. (http://doc.qt.io/qt-5/qtwidgets-layouts-basiclayouts-example.html) Suppose that I want to make this portion of the gui into a reusable component which i can add to any GUI I want. How do I do that?
If this was C# I would create a new user control, add the GUI elements, set up the code that makes the unit work as a whole and possibly set up event listeners or properties of the user control as a whole. then I can instantiate, add, and remove them at will from the rest of the GUI. That is what I want.

I don't understand how QAbstractItemModel works

I've been using this class somewhat successfully thus far but I feel like I don't have a good conceptual understanding of what I'm doing. I'm missing something basic about the Qt model/view architecture which prevents me from making full use of it. Qt doc doesn't seem to be addressing my questions. Much of my lack of understanding seems to be centered around the data() method.
For example:
1) The doc doesn't properly explain (or I missed it) what the data() method is and how to properly use it. I just have this vague idea that it is some kind of callback or slot function for when there are any changes to my model. But architecturally speaking what is its role? Why is it needed and what problem is it solving?
2) Speaking of roles, what is the point of the role parameter in the data method. Again, why did the designers choose to implement the data() method this way?
I hope my questions aren't too abstract. If they are it might be because I don't fully understand what I don't understand about the model/view architecture. Therefore not quite sure how to formulate my question.
Anyway, anyone who has some decent understanding of these concepts is welcome to chime in. Also if anybody knows other places that explains this better than the Qt doc that would be great as well.
Thanks much for any feedback.
As the function name hints the `QAbstractItemModel::data()' is for providing the information that should be visualized by the view. View doesn't need to cache all the data (in some cases thousands of elements) at once, but incrementally queries it from this function as soon as it should be shown on the screen.
When I talk about the data, I assume that it could be item's text, text color, background color, icon etc. All these types of data represented by Qt::ItemDataRole enum and the data itself represented by QVariant.
For example, if you have a tree view and corresponding model. When you scroll the tree down, it should paint, say 20 nodes. Tree view calls model's data() function for each of these 20 nodes to paint their texts, icons, backgrounds etc.
And finally, for better understanding roles. Instead of having textData(), colorData(), iconData() function in the model, Qt provides one single function data() with ability to conditionally chose which data to return depending on the role. This is much convenient design wise.
Did you read about Model/View Programming?
http://doc.qt.io/qt-4.8/model-view-programming.html

QTableWidget vs QTableView

I am new to this Model/View Framework of Qt. In my application I want to have 1000 X 1000 cells. There should be minimum memory requirement & it should be fast. I don't know what this Model terminology is for. But I have my own class which knows how to deal with the double variables stored in the table. Currently I am using QLineEdit's with a Validator to create the array of cells. But it was way too slow for cells > 50 X 50. So I decided to go the good old MS Excel way.
So which Widget should I use: QTableWidget or QTableView?
And can anybody please explain in short what this Model/View framework is? I am not a Computer Science guy hence I am finding it tough to understand...
cmannett85's recommendation is a good one. Read the docs about a dozen times.
Then, if performance and memory issues are your primary concern and you think you can out-perform the QTableWidget implementation, then a QTableView interface on top of a QAbstractTableModel or QStandardItemModel is what you're looking for.
Since you're new to Qt's model-view architecture, I'd recommend using the QStandardItemModel until you feel like you're getting the hang of it. If your performance still isn't good enough, avoid a lot of the memory duplication and wasted objects by implementing your custom model. Plus, get yourself a good textbook and read its chapter on the model-view framework about 12 times. That section alone was worth its weight in gold, imho.
Here are the basics for Qt's custom model-view framework:
Your actual data is stored in a list/tree somewhere
The model provides a standard framework for queries to and edits for your data
Proxy models allow you to sort/filter your data without affecting the original model
The view provides a means to visually observe and interact with your data
Delegates (often optional) tweak the appearance of your data and provide custom editors to the data
If you're feeling both cheap and brave, check out this excerpt on implementing your own custom model. Work at it one function at a time and play with it as you go.
To understand the framework, start off with the documentation about it. It starts slow, but becomes moderately extensive and covers most of the classes involved.
QTableWidget or QTableView?
Once you have read the documentation you will see why this question doesn't really make any sense: a QTableWidget uses a QTableView to display the data. QTableWidget (along with QTreeWidget, etc.) uses the MVC framework, but it encapsulates it all to a handy package useful for most purposes, but if you need to do something different, you will have to crack it into it's component parts and reimplement the bits you need.

Creating a professional-looking (and behaving!) form designer

When I began programming (some 10+ years ago), three things amazed me:
Compilers/interpreters (back then I knew them as "programs that make my programs work", often followed by the qualifier "whatever they are")
Code editors
Form designers
Back then, I accepted all of them as facts of life. I was able to make my own special-purpose programs, but "programs that made my programs work", code editors and form editors were made by the Gods and there was no way I could mess with them.
Then I went to university, and took a course on formal language processing. After learning formal grammars, parsers, abstract syntax trees, etc.; all the magic about compilers, interpreters and code editors was soon gone. Compilers and interpreters could be written in sane and simple ways, and the only non-sane thing a syntax highlighting code editor could require were Windows API hacks.
However, to this day, form editors remain a mystery to me. Either I lack the technical knowledge required to make a form designer, or I have such knowledge, but cannot find a way to use it to implement a form designer.
Using Visual C++ and the MFC, I would like to implement a form designer inspired by the best form designer ever:
In particular, I would like to imitate its two features that I like the most:
The form being designed is inside a container. Thus, an arbitrarily large form may be designed without wasting too much screen real estate, by simply resizing the container to an appropriate size.
The "Align to Grid" option makes designing professional-looking user interfaces a lot less
frustrating. In fact, I would go as far as saying creating professional-looking user interfaces using Visual Basic's form designer is actually easy, fun and enjoyable. Even for left-brained programmers like me.
So, I have the following questions:
How do I make a form designer, in which the form being designed is inside a container? Is the form being designed an actual window contained inside another window? Or is it just a mockup "manually" painted by the form designer?
Do the Windows API and/or the MFC contain functions, classes, whatever that make it easy to create "selectable" items (surrounded by little white or blue boxes when they are selected, resizable when they are "grabbed" by one of these "edges")?
How do I implement the "Align to Grid" functionality?
Both the answers here are good, but left out what I consider to be the really interesting bits (including a couple that you didn't ask directly, but you might find of interest anyhow), so here's my 2c:
Drawing the controls
Ideally, you just go ahead and create a regular instance of the control. You want something that looks like a button? Create a real button. The tricky thing is stopping it from behaving like a button: you want clicks to activate it for moving, not actually 'click' it.
One way of dealing with this - assuming that the controls in question are 'HWND-based' (eg. the standard windows set of button, edit, static, listbox, treeview, etc.) - is to create the control, and then subclass it - ie. override the wndproc with SetWindowLongPtr(GWLP_WNDPROC, ...), so that the designer code can intercept mouse and keyboard input and use it to initiate a move, for example, instead of having the mouse input go through to the actual button code, which would instead interpret it as a 'click' event.
An alternative approach to subclassing is to place an invisible window above the button to capture the input. Same idea of intercepting input, just different implementation.
The above applies to both managed (VB.Net, C#) and unmanaged (C/C++) controls; they're both essentially stock windows HWNDs; the managed versions just have a managed wrapper code handing off to the underlying unmanaged control.
The old (pre-managed code) ActiveX controls, as used in pre-.Net VB, were a whole different ball game. There's a fairly complex relationship between an ActiveX container and the ActiveX controls within it, with many COM interfaces handling things like negotiation of properties, events, painting, and so on. (There's event a set of interfaces that allows an ActiveX control to receive input and draw itself without having its own HWND.) One benefit you get from this complexity, however, is that ActiveX controls have an explicit 'design mode'; so a control knows to respond appropriately in that case and can cooperate with the whole procedure.
The Form Itself...
So basically the controls are just regular controls. So you'd expect the form itself to be a regular form? - Almost. As far as I know, its just another HWND-based window, that's a child of the designer (so it gets clipped, and can be scrolled within it); but I think the designer is doing a bit of 'cheating' here, because usually Windows only draws frames like - with titlebar and min/max buttons that for actual top-level windows. I don't know offhand the exact technique that they're using here, but some options could include: painting it manually to mimic the Windows look; using the Windows "theme" APIs, which allow you to access the graphic elements used for the bits and pieces of titlebars and paint them wherever you want to; or, perhaps less likely, setting the window up as a "MDI Child window" - this is one exception case where windows will draw a frame around a nested window.
Draggable Handles
Simplest approach here is for the designer to create eight small square title-bar-less popup windows that sit above all the other elements - which initiate the appropriate resize code when they are clicked. As the user clicks from control to control, just move the drag handle windows to the currently active control. (Note that in all the above, Windows itself is figuring out who's been clicked, you never have to actually compare mouse coords against element rectangle coordinates and work it out yourself.)
Saving & Recreating
For plain windows system controls that are used by unmanaged C/C++, it's relatively easy: there's a well-known text-based file format - .rc - that describes the controls and locations. Have the designer spit out that (and likely a resource.h file also) and you're done: any C/C++ project can pick up those files and compile them in. Managed code (C#, VB.Net) has a somewhat more complex scheme, but it's still the same basic idea: write out a description in the style that the managed tools expect, and they'll happily compile it and use it.
(ActiveX controls are - you've guessed it - a whole 'nother story. There isn't a standard format that I'm aware of, so the form editor and runtime that consumes the data would be closely tied together - eg. the form editor from pre-.Net VB6 produces forms that only VB can use. - I think. It's been some time ago...)
As for recreating the form: if you have a .rc file, it gets compiled into a dialog resource, Windows has built in support to recreate those. Likewise, the managed code support libraries know how to recreate a form from its particular format. Both basically parse the description, and for each item, create elements of the appropriate classes, and set the appropriate style, text, and other properties as specified. It's not doing anything you can't do yourself, its just helper utility code.
Handling Focus
For a collection of HWNDs in any container, whether in 'test' mode or actually running in the real app, and regardless of whether you let Windows or Winforms handle the form creation or whether you created each HWNDs yourself, you can add tabbing support by calling IsDialogMessage in your message loop: see the MSDN page remarks section for details. (While WinForms could do this, I think it actually does its own focus handling, so that it can have tab order independent from visual stacking Z-Order.)
Other Things To Explore...
Make friends with the Spy++ app (part of the SDK, installs with Visual Studio). If you're going to do anything with HWNDs, managed or unmanaged, it's a real good idea to know how to use this tool: you can point it at any piece of UI on Windows, and see how it's constructed out of a tree of different types of HWNDs. Point it at the VB designer and see what's really happening for yourself. (Click the 'binoculars' icon on the toolbar, then drag the crosshairs the the window you're interested in.)
Also take a look at the resource files that the designer spits out. Everything that you can tweak or move or edit in the forms designer corresponds to some item somewhere in one of those resource files. Make a copy of them, tweak some settings, and then file-compare the two sets, and see what's changed. Try changing some things in the files by hand (I think they're nearly all text), reload, and see if the designer picked up your changes.
Other Things To Note...
Much of the above is specific to Windows - notably the fact that since we're using Window's own building blocks - HWNDs - we can get Windows itself to do some of the hard work for us: it gives us the facilities to reuse the controls themselves at design time so we don't have to draw mock-ups; to intercept input on other controls so we can make a click into a move or whatever other action we want, or figure out which control is clicked without having to do the location math ourselves. If this was a designer for some other UI framework - say Flash - which doesn't use HWNDs internally, it would likely instead use that framework's own internal facilities to do similar work.
Also, it's far easier if you limit the number of controls in the palette to a small finite set, at least at first. If you want to allow any control at all to be dragged in - eg. a 3rd party one, or one you've used in another project; you typically first need some way for that control to be 'registered' so that the designer knows that it's available in the first place. And you may also need some way to discover what icon it uses in the toolbar, what its name is, what properties it supports - and so on.
Have fun exploring!
You implement a form designer almost like a normal GUI. You have stuff you can drag (your widgets), you have stuff you can click (your buttons) and you have stuff you can select (your placed widgets) and that's really about it.
Q: Now, how do you display a window in a GUI?
A: You paint it, simple as that.
Q: And how do you keep stuff inside that window?
A: You check against the bounds of the "parent" object. You could almost say that a form designer is like a little game and you have a scene graph holding all your widgets, connected by parent-child-relations.
Q: Then, how do you select stuff in a GUI?
A: Check the current mouse position on-click against the bounds of all (near) widgets (a scene graph only helps here, like a quadtree).
Q: How do you align widgets on a grid?
A: For the grid alignment, let's have a simple example: Say your real resolution is 100px on the x-axis, but you want your grid to only have a resolution of 10px on x. Now say you move your widget by 28px in real resolution. To get the grid resolution, you simply divide by 10, get 2.8, round that, and finally move the widget 3 tiles on x. The rounding is the key here. only if the grid movement is >= ?.5, you snap to the next tile. Otherwise you simple stay at the old one.
Hope this can give you a general hint on how to start a form designer. Have fun. :)
(PS: Don't know about any specific WinAPI/MFC functions/class to help you along, sorry.)
Just to add a point or two to what #Xeo has already said:
First of all, no, you don't always draw all the content yourself. During normal design phase you're basically just drawing something that looks like the control, but (at least IIRC) it also lets you "run" a form in test mode (certainly the VC++ dialog designer does, and even though VB's was more primitive, I think it did have that particular capability as well). Test mode was when you can "run" a form before you've (necessarily) attached any code to it -- even though clicking a button (for example) doesn't do anything in the surrounding program, the control itself works as normal -- a button clicks normally, an edit control will let you edit, etc.
That is done by actually instantiating a control, telling it the correct position, size, and properties. ActiveX controls do quite a bit to support this, and the previous "Windows custom controls" did as well, though with considerably less sophistication. From the viewpoint of the control, it's working just about exactly like it normally would, receiving input, sending notification to its parent, etc. The only thing that's changed is that the parent most ignores most of the notifications it receives, but the control doesn't really know that.
There are two basic ways to do this. One is to create a collection of controls yourself, along with their positions, sizes, etc., and use CreateWindow (or CreateWindowEx, etc.) to create window of the correct class. While relatively easy to handle, this has the disadvantage that it leaves all the tab-handling to you.
The other possibility is to create a DLGTEMPLATE structure to hold data about the dialog box, and a some DLGITEMTEMPLATES for the individual controls, and finally use CreateDialogIndirect to create a dialog box with those specs, holding those controls. It's tedious, but it works, and when you're done it handles tabbing between controls automatically (and works the same as any other dialog, since it's the same Windows code creating it either way).
Second, since you've tagged this C++, you might want to take a look at some code on CodeProject that actually implements a dialog editor. Although it isn't quite as sophisticated as some of the commercial ones, this is a reasonably complete form/dialog editor, complete with most of what you've asked about.