How to call QMessageBox Static API outside of a QWidget Sub-Class - c++

I have a utility class in my Qt GUI application. However, in my convenience class I wanted to call a QMessageBox::critical(), warning(), etc. The class isn't a QWidget, and therefore I cannot pass this as the parent. My class is subclassed from QObject, however, so it can run things such as signals and slots. So to work around this--if it's possible to--should I maybe look at the property API instead of using the Static API?
Class declaration:
class NetworkManager : public QObject
And here's an example of a Static API call that fails:
QMessageBox::critical(this, tr("Network"), tr("Unable to connect to host.\n"),
QMessageBox::Ok | QMessageBox::Discard);
So, if I were to build a Property based API message box, would it be possible to call it in a QObject somehow? I haven't really used the Property Based API, but I understand from the documentation that it seems to use an event loop (i.e. exec()).

Just pass NULL for the first parameter:
QMessageBox::critical(NULL, QObject::tr("Error"), QObject::tr("..."));

A better way than passing nullptr is to use the qobject tree you are already using (assuming that the parent of the NetworkManager instance is a QWidget; adjust the number of parents according to whatever your qobject tree looks like)
QMessageBox::critical(qobject_cast<QWidget *> (parent()), "Title", "Message");
We use a qobject_cast<> instead of a C or C++ style cast is because it adds a little protection and will return 0 if it can't cast upward to the QWidget *.
If you use nullptr the QMessageBox will appear as centered over the topmost window (QWidget) rather than the window that actually appeared higher up in the qobject tree of your NetworkManager class. This really annoys people who have multiple monitors, lots of windows open, multiple windows from a single application spanning multiple monitors, etc.

Related

Qt Creator - GUI from designer vs. GUI from code - how to access element's functions

I am confused about some Qt architecture.
When I am designing the GUI in Qt Designer it is easy to put the elements in a layout (Grid, Box, what ever) and create a slot to connect elements (e.g. buttons) with a certain and action not much code in .cpp file.
In the related .cpp file I can access theses elements via ui->element->do_something even from different functions within the class;
When not using the designer, instead creating the whole GUI stuff within the .cpp (adding element objects, add those objects to a layout, creating a slot, etc...) I cannot access my e.g. Button like ui->Button->do_something.
I am stuck at ui->Layout->functions from layout and cannot access the single elements and their functions like ui->textEdit->text(); or like ui->Layout->textEdit->text() from other functions within the class.
So how can I access those elements?
I am afraid I am missing an important point of Qt's architecture here or something else.
When you use designer, an "Ui" file is auto-generated with the code of your layout, then you access through the Ui::Mainwindow which you can see auto-generated in your QMainWindow class.
You can see in the default constructor:
QMainWindow(parent), ui(new Ui::MainWindow)
So each component defined in the gui file is accessible through ui::nameofyourcomponent.
If you write the code manually you don't have any "access point" to your element so you have to build your hierarchy exactly like each other part of your code and classes.
Edit: A little snippet to answer to his comment.
In you header you can declare:
private slots:
void doSomething();
private:
QPushButton* mybutton;
QLabel* mylabel;
in your Cpp:
connect(myButton, SIGNAL(clicked()), this, SLOT(doSomething) );
MyClass::doSomething()
{
mylabel->setText("hello button!");
}
Of course you can use the connect chaining directly the components through their signal and slot.
All of the objects the designer creates are public members of the ui object, that's why you can use them. To be able to use a manually created object, you have to store a pointer or reference to it somewhere.

Switching app "states" using QMainWindow as superclass

I'm attempting to run different modes/states of my app, for example having a menu which can go to a game state then highscore and from those two back to menu.
A solution I tried was using the autogenerated class QMainWindow as a superclass for creating the classes Menu and Game to start with. In QMainWindow I later want to create a QMainWindow, fill it with a Menu or Game and in eg. QMainWindow.paintEvents() call Menu.paintEvent() through polymophfism.
Now I know that I can't create a QMainWindow in another QMainWindow but would this idea work with yet another subclass called states or somthing inbetween the existing super/subclass(es)?
I was able to run just Game by itself (instead of QMainWindow) so the inheritance is probably done right. But when trying to create and run only a Game in QMainWindow it gave me a sigsegv at QMainWindow's constructor (which I have not changed and runs completely fine bby itself if empty). I've solved the problem with the classes including themselves in one another so that's not the problem either.
I solved it by making a superclass "State" for menu and game (without making State a subclass to QMainWindow) which is called by QMainWindow for each operation.
This is essentially the "states" pattern which I realise existed after the implementation.

Handling Qt C++ events in QML context

The C++ API has QEvent along with multiple other classes derived from it (QMouseEvent, QGestureEvent etc.). QML on the other hand has events too. However I am struggling to find an elegant way of directly processing C++ events in QML.
Usually what I do is I create a custom QQuickWidget (or similar including QQmlEngine), override the QWidget::event(QEvent* event) and upon receiving a specific C++ event I propagate it through signals to QML slots with the QML code being loaded through that widget. This seems like a lot of work and I'm wondering if there is some sort of QML built-in event handling for events that come from C++ context.
In particular I'm interested in handling QGestureEvents in QML but I guess what works for this type of events should also work for any other type of event.
There is no direct support for event handling in QML, even keyboard and mouse are accessible through auxiliary objects.
QEvent itself is not a QObject derived, and as such, the same applies to all the derived events as well. That means no meta-information and no easy way to use from QML.
Since you are interested in a particular type of events, it would be easiest to create your own auxiliary object for those type of events, implement it in C++ and interface it to QML via signals you can attach handlers to.
If QGestureEvent can be copy-constructed you could simply create a Q_GADGET based adapter:
class QmlGestureEvent : public QGestureEvent
{
Q_GADGET
Q_PROPERTY(...) // for the things you want to access from QML
public:
QmlGestureEvent(const QGestureEvent &other) : QGestureEvent(other) {}
};
If it is not copy-constructable you'll have to add data members to the adapter and copy the values from the event.

Propagate QML events to C++

I would like to propagate event from a QML signal handler to C++ procedure but don't know how to pass the "event object". Take a look at this situation and pay particular attention to SomeType.
First I create a custom QML item with a slot that can be called from QML:
class Tool : public QQuickItem
{
. . .
public slots:
virtual void onMousePositionChanged(SomeType *event);
}
Then, in QML, I create a MouseArea and an instance of my custom object to which I wanto to propagate events to.
MouseArea {
hoverEnabled: true
onPositionChanged: {
var event = . . .
tool.onMousePositionChanged(event);
}
}
Tool {
id: tool
}
And there is the problem. I don't know how to assemble an instance of SomeType to pass to the method. Actually I don't know what should I choose as SomeType. Ideally this would be QQuickMouseEvent so i could just call tool.onMousePositionChanged(mouse), but for some reason this type is not available for use in C++ code.
I've also considered QMouseEvent so I would just have to rewrite the properties, but this class in turn seems to be unavailable to QML code.
I'm new to Qt Quick so maybe I'm misusing it altogether. What I want to achieve is to have this base Tool class that has those virtual event handlers for mouse and keyboard and then create a collection of different tools that override them as necessary. They are to be displayed in some kind of toolbox, i.e. a grid with icons, from which the user can choose the current tool. The chosen tool is the one that receives the events. Any design suggestions are welcome.
Try QEvent, then use event->type() for filtering the event type.

Is there a way to determine if a top level Qt window has been moved?

I am trying to determine when the main window of my application has been moved. The main window is a standard QMainWindow and we've installed an eventFilter on the QApplication to look for moveEvents for the QMainWindow, but none are being triggered. For a variety of reasons, subclassing the QMainWindow isn't really an option.
Any thoughts on this, aside from starting a QTimer tto constantly check the position, would greatly be appreciated.
I guess it's better to install the event filter at the top-level window, instead of the application. However, if you still do not get QMoveEvents and you're working on Windows, you probably can override winEventFilter() and wait for WM_MOVE. Similar functionality might be available for Linux and Mac.
I usually do not recommend to break the platform-independence, but sometimes it might make sense.
Subclassing is really the best solution :-/
In the class that implements your top level windows you just overload this function:
virtual void moveEvent ( QMoveEvent * event )
From the documentation:
This event handler can be
reimplemented in a subclass to receive
widget move events which are passed in
the event parameter. When the widget
receives this event, it is already at
the new position.
The old position is accessible through
QMoveEvent::oldPos().
This should allow you to detect if your main window has moved. Why can't you subclass? Are you using an instance of QMainWindow directly? The usual use case is to subclass it anyway.