Reset / Clear every item within TabWidget Page - c++

Is it possible to reset / clear every QTabWidgets Pages Items?
I have created the UI using the Designer.
I would hate to statically code a clear mask function since we all now UIs can get quite complex and it would take quite the maintenance work for every item that gets added later on.
If this is not possible I would also be okay with looping over each child item and invoking the clear( ) function if someone could give me a hint as to how I can get the pointer / address of them.

All pages of a QTabWidget are of the type QWidget which is a QObject. The latter has the function
const QObjectList & QObject::children() const
so you can get all children, iterate over them and invoking the clear(). You should probably check isWidgetType() to make sure you only have widgets and probably also design this function recursively if you plan on having widgets with children of their own (i.e QGroupBox).

Related

Is there a way to check if QLabel pixmap is set to something particular?

I am creating an Qt application and I have a part where I can drag QLabel's from one frame to another and I need to know which label is dragged but I don't know how to check that. Is there function or method to do that ?
Assuming that you are handling drop-actions by overriding the dropEvent(QDropEvent *) method in a subclass of some type of QWidget, you can call QDropEvent::source() to get a pointer to the widget that the user clicked on to start the drag. You can then use that pointer to do a lookup in a table/list of pointers of known drag-sources, or use dynamic_cast<QLabel*>() on it to try and get a QLabel pointer out of it that so that you can call QLabel methods on it, or etc.
Note that this technique only works if the drag-operation started in your own application. It won't work if the drag-operation came from some other application, of course, because in that case the source-widget is not in your program's process space and therefore there is no way to get a pointer to it.
A slightly-more-elegant alternative method would be to have the source-widget add some identifying data to a QMimeData object, and then call setMimeData() on the QDrag object before it calls exec() on it. Then the receiving widget could look at the QMimeData object returned by QDropEvent::mimeData() to retrieve that information. This is a bit nicer since it will work across process boundaries, and is safer since you don't have unrelated widgets dereferencing pointers to each other or trying to downcast QObject-pointers.

Adding an object to a vector

this is my first question on this website, but I will try to cover everything that is needed. Apologies if I forgot something. I encountered the problem using QT Creator, but I suppose it would be the same using Visual Studio, or just C++ in general.
I've got a couple of classes: Mainwindow, Track and AddForm. Mainwindow is what it is called. The main form. Track is a custom class based on QObject which contains just a single QString variable (just for now, since I am still experimenting with QT). And AddForm is a class for another form that can be created by clicking a button in my MainWindow form. That form only contains a single line-edit to fill the string and a button that says "Add". Whenever that button is pressed the text from the line-edit will be put into the QString variable from the Track-class. That QString variable is called "artist".
Apart from assigning the text from the line-edit to the variable "artist" for the Track-object, the form will also emit a signal that sends that entire object. A slot within my mainwindow will react to that signal and collect the Track-object. So far so good.
Here is my question. Within my mainwindow-header I have created a private QVector named trackVector, which I can then call within my mainwindow.cpp. What I want to do is append / push_back the QVector with that Track-object. Sort of like this:
trackVector.push_back(trackObject);
I get the following error message when building the application:
click here for a screenshot
Now ofcourse with an integer or any other variable this is very straightforward. You would just do something like this I suppose:
QVector<int> myVector;
myVector.push_back(3);
I think that whenever you append a QVector (or a standard non-QT vector) you need to do so with the constructor of that class. But how can I make a constructor in which you can just put an already existing object?
Please explain with as much simple words as possible since I am no native English speaker :) Thanks a lot in advance!
You've posted insufficient code (so your post is liable to be closed as off topic -- a classical beginners error on SO), but I guess the appropriate solution here is to use some auto pointer type. If your TrackVector is to keep ownership of the Track objects, then the best solution is have std::unique_ptr<Track> elements:
std::vector<std::unique_ptr<Track>> TrackVector;
// filled like
TrackVector.emplace_back(new Track(args));
If, on the other hand ownership lies somewhere else, you may either use std::shared_ptr or even raw pointers (provided your layout guarantees that the pointed to Track objects' lifetime exceeds that of the TrackVector).

How to structure signals/slots?

I am creating a UI with Qt and there are two elements which may or may not be present. Additionally, their parents are different elements as well. However, one affects the other.
How should I structure the signals/slots (or should I not even use that pattern) in the best way?
The methods that come to mind all seem like hacks:
create a signal/slot in all parents and pass up and then back down the signal
create a signal/slot in the closest common parent of both then have the children connect their signals/slots to the parents'
on creation of one navigate the structure of the other to get the element and then connect signals/slots directly. Any guidance here is greatly appreciated.
Edit: "present" means that there is a button that the user may press that creates an element and adds it to the layout. So depending on the combination of button presses, an element may be present or not.
"affect" means it changes its state. for example, there is a list of items and a button elsewhere which adds an element to the list.
For an example, imagine a tabbed pane which contains a todo list. There is a button not in the tabbed pane which adds an item to the list. The tabbed pane does NOT create all the elements of the pane. It creates only the elements of the visible pane and deletes them when the pane is switched away. Therefore, the list may or may not exist.
The UI elements are QWidgets. All QWidgets are QObjects. Any QObject's signals can be connect()ed to any other object's slots. The hierarchy of parent/child relationships is entirely immaterial.
You seem to be confusing signal-slot connections with events, which can be in fact passed up the object hierarchy if they remain ignored by given object.
It's also worth noting that signal-slot connections are safe in spite of QObjects being destroyed. When an object with connected signals or slots gets destroyed, the connections are safely torn down. The only thing you can't do is deleting the sender nor receiver object within a slot - use object->deleteLater() instead.

Getting notified when a list box has an item removed?

I use CListBox::SetItemData to store a pointer to some data in my ownerdrawn CListBox-derived class, and I'd like the listbox itself to keep track of it and free the memory when its no longer needed.
For that I'd need to be notified each time an item is deleted (including LB_RESETCONTENT and every possible other case where an item is deleted). Is there an event or events that I can handle to achieve that?
As its owner drawn with one of the LBS_OWNERDRAW* styles you can look out for WM_DELETEITEM;
Sent to the owner of a list box or combo box when the list box or
combo box is destroyed or when items are removed by the
LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT
message. The system sends a WM_DELETEITEM message for each deleted
item
No. A ListBox only generates notifications for things that the user does. The user cannot remove or add or empty a list box, that can only be done by your own code. So the philosophy here is that the control doesn't have to tell you about something you already know. You can arbitrarily generate your own message in the code that modifies the content. But of course inheriting your own class from CListBox and adding your own virtual methods would be better.
Since you're subclassing the listbox already anyway, the 'proper' design would (IMO) be to add data management functionality to the listbox, which would then know when items are removed and can delete the data as required. What I mean is, let's say your list keeps track of people, you'd add AddPerson(Person p) and RemovePerson(Person p) methods to your class. The implementation of RemovePerson would remove the respective entry from the list, and delete all data related to it. So don't use CListBox::DeleteString to remove things, use the higher-level API that you implement yourself.
It's easy - just subclass the list box and add message handlers for LB_DELETESTRING and LB_RESETCONTENT
See here for details:
http://www.codeguru.com/cpp/controls/listbox/article.php/c4759/CListBox-with-the-Horizontal-Scroll-Bar-that-Works.htm

Qt-GUI with several "pages", how to synchronize the size of several QWidgets

I am currently writing a wizard-style application using Qt4. I am not using the wizard class however, since going next/back does not make sense from every step in the process.
The user starts off at a "hub"-window with five buttons, each of which take him to another window at a different stage of the process. At the beginning all but the first button of the hub are disabled. After clearing each stage, the user will be directed back to the hub and one new button/stage will get enabled.
Since every stage has significantly differing objectives, I coded every single stage as a single QWidget that gets instantiated in the main() function. To switch between the widgets, I simply hide() the one I am leaving and show() the one I am going to.
However, this leads to problems if the user resized or moved one widget, since the next widget will always show up at its default position instead of the new one.
Is there a way to synchronize the widgets' sizes and positions?
Or, better yet, is there a more elegant way to deal with those different windows than switching between several hidden widgets?
Thank you in advance!
Create one top-level widget that holds the others.
I suggest that you either use QStackedWidget, or, if you want more control, create your own widget and use QStackedLayout directly.
Why not just have one main QWidget as a container for your pages? That way if the user moves the main QWidget and then goes to the next page, it will still open in the new position inside the main widget.
Generally, I've never had occasion to create multiple widgets inside my main method. Don't quite see the point.
I'm beginning on something similar - with different views (perspectives) for different tasks along the way. Using toolbar icons and file menu, not buttons, to move between views. Similar to how MS Outlook allows you to have the window display email, or a calendar, or contacts, etc.
My intent (haven't started yet) is to have one QMainWindow as the application window, containing my various QWidgets that offer the various views. Depending on what task the user is doing, one composite widget will be visible, and the others hidden.