How to access QMainWindow from a QWidget which parent is not QMainWindow - c++

I am programming a GUI with Qt Creator (Qt5.10) under OSX. I have a QMainWindow for the main app's window. Inside this I have a QTab widget, in which I have entire widget (let's call it CaptureTabWidget which contains some additional widgets AND a QFrame (the parent of this QFrame is the QTab). In this last widget I will be drawing some stuff. The point is that I would like to write in the statusBar of the QMainWindow some values related to the position of the mouse in that QFrame, but I do not have any idea about how to access the main window from a method inside the CaptureTabWidget which contains the QFrame.
The whole picture goes like this:
X
+-----------+ XXX
|MainWindow | XXXXXXXXX
+-----+-----+ XXX XXXXXX
| X XXX
+-----v------------+ XX
|QTabWidget | XX
|No parent | XX
+-----+------------+ XX
| X
+-----v-------------+ ?? X
|CaptureTabQWidget | X
|Parent:QTabWidget | X
+-----+-------------+ X
| X
+-----v-------------+ XX
|QFrame | XXXXXX
|Parent:CaptureTab | XXX
+-------------------+
I have tried modifying the CaptureTabWidget's constructor in order to receive a QMainWindow* which points to the main window, but it seems Qt Creator doesn't allow custom constructors when promoting widgets in the Designer. I am wondering what is the right way to do this.

If you just aim to write to the statusBar of the parent QMainWindow, you can post a QStatusTipEvent to any child of your QMainWindow, and the event will keep propagating to the parent QWidgets until it reaches the main window where it gets handled by by changing the content in the status bar. In other words, something like this in your QFrame does the job:
QCoreApplication::postEvent(this, new QStatusTipEvent("your tip"));
// ^^^^
// assuming this is a pointer to your QFrame object
As a side note, this is the same way views in Qt (QTableView, QTreeView, QListView, ...) are able to change status tips (when their models provide a custom value for the role Qt::StatusTipRole) while they might be buried deep down in the QObject tree...
For purposes other than just writing to the statusBar of a parent QMainWindow, I would try to generalize the above approach by having a custom QEvent (i.e. one that has a value between QEvent::User and QEvent::MaxUser) and handle that event in my QMainWindow subclass appropriately. I find this way much cleaner and more maintainable than other solutions that depend on global variables/singletons (that keep track of your supposedly one QMainWindow instance).

Related

Sizing an embedded widget in QT

So I'm working on a QT5 based GUI and I have a main window that fills in an empty area depending on user input. The gui looks roughly like this
---------------------
|Qlabel 1 |Qlabel 2 |
|-------------------|
| |B1|
| MAIN |B2|
| |B3|
|-------------------|
B1,B2, and B3 are buttons which create popups that ask for user input. Main is the issue. In QT Creator I've set main to be a widget. I've also created a widget which has a layout (again in QT creator) which I'll call filler. On input an instance of filler, I add filler to a layout which I then set on main. The issue I'm having is that sizing seems to be totally dependent on the QT creator sizing of the layout inside of filler.
What I want is for filler to scale to the size of the encapsulating MAIN widget and I'm not sure how to go about this. Any input is helpful!
Edit:
The code which fills in main is roughly
fillerWidget* filler = new fillerWidget(ui->mainWidget, QString::fromStdString(input1), input2);
QGridLayout* fillerLayout = new QGridLayout();
fillerLayout->addWidget(filler, 0, 0);
ui->mainWidget->setLayout(fillerLayout);
ui->mainWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
filler->adjustSize();

QT always on top on windows7/8

I would like to know if it's possible to set my QMainWindow always on top .
I tried:
mainWindow.setWindowFlags(Qt::WindowStaysOnBottomHint);
mainWindow is a QMainWindow extended object.
But it doesn't work and my window disapear.
Yes, it is possible but there are two errors in your code:
You are clearing all flags but Qt::WindowStaysOnBottomHint which is set.
You're using Qt::WindowStaysOnBottomHint flag (which represent the opposite of what you want) instead of Qt::WindowStaysOnTopHint.
A correct way of doing that is:
Qt::WindowFlags flags = mainWindow.windowFlags();
mainWindow.setWindowFlags(flags | Qt::WindowStaysOnTopHint);
Note that on some window managers on X11 you also have to pass
Qt::X11BypassWindowManagerHint for this flag to work correctly.
In that case you should do:
Qt::WindowFlags flags = mainWindow.windowFlags();
mainWindow.setWindowFlags(flags | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint);
If you want to make a window as Dialog, there is another way. Just call setModal(true) or setWindowModality(), afterward show(). Unlike exec(), show() returns control to the caller instantaneously.It wont stuck as QDialog in exec().
i.e
setModel(true);//In Constructor
then while calling or invoking the new window,
MyWindow* myWindow = new MyWindow(this);
myWindow->show();

My widget doesn't show on the mainwindow. qt

in my program the senario is like this, user opens a xml file, the program reads it. Show the units and tests and when the user clicks on the desired test, the program needs to show its step. Since the number of steps always change i need to add the widget by code and delete them. But when i try to add a widget by code and set its position it doesn't show up on the main window. ( i am doing this with a seperate class just make things look neater)
Here is my sample code;
void CStepPanel::addstep()
{
QLabel *label1 = new QLabel("step1");
label1->move(450,50);
}
Do you know doesnt it work ? And how can i do that. Since i am new to qt and programming i am having a hard time about this.
Your widget should have a parent to be shown in an other widget or dialog. You should set a parent for the label. If you want it to be displayed on the main window then a pointer to your QMainWindow should be kept in the class CStepPanel (It could be assigned in the constructor of CStepPanel) :
QMainWindow * mainWindow;
And the addstep is like :
QLabel *label1 = new QLabel("step1");
label1->setParent(mainWindow);
label1->move(450,50);

Floating sub QMainWindow (QMainWindow as child widget of main QMainWindow)

I use a QMainWindow as child of my main QMainWindow. By that I get an other area which I can use for dockable widgets (QDockWidget).
According to the following posts this is OK, it also works perfectly for me.
https://qt-project.org/forums/viewthread/17519
http://www.qtcentre.org/threads/12569-QMainWindow-as-a-child-of-QMainWindow
To make the QMainWindow behaving as a normal widget, I unset the window flag, this trick is mentioned in one of the posts above.
Now I also want to be able to float this child QMainWindow with all its docked widgets. In other words, I want to revert the step "making it a normal widget". Unfortunately, this does does not work. It is gone from the main window, but not visible at all.
Any way to resolve it?
// this is the child QMainWindow
if (this->m_infoAreaFloating)
{
// this should give me a floating window besides the main window
this->setWindowFlags(Qt::Desktop);
this->show();
}
else
{
// make this compliant as QWidget
this->setWindowFlags(this->windowFlags() & ~Qt::Window);
}
Related: a , b
The Qt::Desktop flag is not something you are supposed to set by yourself.
You need to set the Qt::Window flag:
setWindowFlags(m_infoAreaFloating ? Qt::Window : Qt::Widget);
show();
There's no point to this->windowFlags() & ~Qt::Window: you've cleared all other window flags when setting the lone Qt::Window flag. You're in full control of the flags, there's no need to preserve some "other" flags: there are none.

What is the recommended way of working with QActions in multiple level hierarchy of widgets?

I'm planning on using qActions for use globally in my application. The idea is to have an action to be available at any level in the widget parent/child hierarchy.
Let's say I have the following GUI:
+--------------+
| +----------+ |
| | +----+ | |
| | | W2 | | |
| | +----+ | |
| | W1 | |
| +----------+ |
| MainWindow |
+--------------+
W2 has a QPushButton which I want to use with a QAction defined in MainWindow. So the question is: What is the recommended way of working with QActions in multiple level hierarchy of widgets?
Here are my approaches:
Define the actions in a MainWindow singleton, and
access it from W2 to add the qaction
to the QPushButton.
Define the actions in MainWindow and add them to W1, which in turn
would add the qaction to W2, which
in turn would add the action to the
QPushButton (I don't like this one).
Create a Delegate singleton class to
hold qactions and access it from
MainWindow to make the global
connections of qactions' triggers to
the backend (model), and also access
it from W2 to add the action wanted
to the QPushButton.
Thanks
Personnally, I'd go with a modified version of the second option, in the other way, because it keeps the hierarchy of your program. I say the other way because I would make the w2 pushButton propagate the signal up to the mainWindow. An advantage to this option is that if you add another w2 in w1, you simply have to connect it to w1, your mainWindow will stay exactly the same (encapsulation). Same thing, if you add a w1 in your mainWindow, you only have to connect the new w1 to your mainWindow and you don't have to care with the pushButton in the w2 of the new w1.
Here is the code to make this solution works:
In your w2 class constructor:
connect(pushButton, SIGNAL(clicked(bool)), this, SIGNAL(buttonClicked(bool)));
In your w1 class constructor:
connect(widget2, SIGNAL(buttonClicked(bool)), this, SIGNAL(buttonClicked(bool)));
In your mainWindow class constructor:
connect(widget1, SIGNAL(buttonClicked(bool)), anyAction, SIGNAL(triggered(bool)));
connect(anyAction, SIGNAL(triggered(bool)), this, SLOT(onActionTriggered(bool)));
Obvisouly, you must define the correct signals/slot in your class definitions and be sure that whatever you connect has already been created.
Hope this helps.