Floating sub QMainWindow (QMainWindow as child widget of main QMainWindow) - c++

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.

Related

How to set parent window overtop child window in Qt

I want the parent window to always be on top of the child window.
QMainWindow a();
a.show();
QMainWindow b(&a);
mat.show();
How to set a over b?
Your setup seems a bit weird. The mainwindow B with A as its parent. If you want to have independants window, I think you should remove the inheritance link.
In this cas, you can change the order of the show calls to change the order of the window :
QMainWindow a;
QMainWindow b;
b.show();
a.show();
If you're sure that's the way you want to go, you have mlultiple solution.
May you can call the show method in an other order ? Untested.
Maybe you can set up the windows flags before calling the show. If you want to have A over everything, in a permanent way, you change the windows flags :
It would be something like:
QMainWindow a;
QMainWindow b;
a.setWindowsFlags(Qt::WindowStaysOnTopHint| Qt::X11BypassWindowManagerHint);
a.show();
b.show();
If you want to manipulate the "who is over who" in your app, maybe you should unite them in a stack, or giving them a common ancestor, or something like that.

How to resize a QLabel displayed by a QWidgetAction after changing it's text

I use a QWidgetAction to add a header to a context menu (that will also show up on Windows, no matter what style is used, in contrast to addSection(), which does not always actually display the title).
The action's widget is a QLabel. It's text is changed by each invocation of the context menu. The menu is setup in the constructor of my class, and the QWidgetAction is added like so (all m_ variables are member variables declared in the header):
m_contextMenu = new QMenu(this);
m_menuTitle = new QLabel;
m_menuTitle->setAlignment(Qt::AlignCenter);
m_menuTitle->setMargin(4);
QWidgetAction *titleAction = new QWidgetAction(m_contextMenu);
titleAction->setDefaultWidget(m_menuTitle);
m_contextMenu->addAction(titleAction);
m_contextMenu->addSeparator();
When the menu is requested, the text of the label is changed and the menu is displayed like so:
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
...
m_contextMenu->exec(place_to_display);
When the label's text is set for the first time (with a short text the label's text is set to), everything is fine:
but when it's set to some longer text, the size remains the same and the text is cropped:
I tried to fix this, but the only working solution I found was to define the QActions displayed in the menu in the constructor, owned by this, setting the label's text, clearing the menu and adding the actions again, like so:
m_contextMenu->clear();
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
m_contextMenu->addAction(m_menuTitleAction);
m_contextMenu->addSeparator();
m_contextMenu->addAction(m_editAction);
m_contextMenu->addAction(m_deleteAction);
m_contextMenu->exec(place_to_display);
Is there a way to resize the title without rebuilding the menu each time?
The solution is to send a resize event instead:
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
...
QResizeEvent re(new_size, m_contextMenu->size());
qApp->sendEvent(m_contextMenu, &re);
This will set the QMenu's internal itemsDirty flag and will force geometry recalculation when the menu is shown. Note that the new size in the event does not matter, as the menu will aways resize based on its sizeHint()!
The QResizeEvent solution didn't really work for me (with a more complex widget), I found the generic solution by reading the QMenu and QAction source code.
m_widget->installEventFilter(this);
// and in my case m_widget->layout()->setSizeConstraint(QLayout::SetFixedSize);
bool SomeClass::eventFilter(QObject* watched, QEvent* event)
{
if (watched == m_widget && event->type() == QEvent::Resize) {
// Force QMenu to recalculate the geometry of this item
QActionEvent e(QEvent::ActionChanged, this);
qApp->sendEvent(m_contextMenu, &e);
}
...
}
QActionEvent triggers everything we need in QMenu: recalculating geometries, resizing the menu to its new size (if it's visible), etc.
This answer extends user362515's answer.
There is little more effort required if you change the size of a hidden widget action (e.g., because of its menu is currently collapsed).
Create a new class ActionWidget which derives publicly from QWidget.
Then override the showEvent method and implement it like this:
void ActionWidget::showEvent(QShowEvent* event)
{
QResizeEvent resize_event(QSize(), parentWidget()->size());
parentWidget()->adjustSize();
qApp->sendEvent(parentWidget(), &resize_event);
QWidget::showEvent(event);
}
Notice that adjustSize must be called on the parent widget of the action widget and the event must be sent to the parent widget.
Of course, you must also reimplement QWidgetAction::createWidget such that it returns an instance of the ActionWidget-class and make sure that ActionWidget reports a proper (updated) size hint.

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();

How can I make a child widget standalone?

Suppose I have a main Widget, which is used to view some objects. The names of those objects are stored in a QListWidget. Now when a user selects one object (one item of the QListWidget), I want to open another widget in a separate window which takes the name of the object as an argument.
class MainWidget
{
Q_OBJECT
public slots:
void openSelection();
};
class ChildWidget
{
public:
ChildWidget(QString name, QWidget* parent = nullptr);
};
void MainWidget::openSelection()
{
QString selectedObjectName = ui->objectsNamesList->selectedItem()->text();
ChildWidget* detaildedWiew = new ChildWidget(selectedObjectName, this);
detaildedWiew->show();
}
When I do this, the child widget opens, but it has no space of its own. It is locked in the area of the parent. I need to set the children free, to run around the screen freely, independent of their parent. How can I do this? Is there some Qt way, or do I have to define some "pseudo child" relationship and develop a system to properly delete the pseudo children?
You can use QWidget::setWindowFlags(Qt::Window) to make your widget a separate window.
Also have a look at Qt::WindowFlags.
Not sure I got the question right...
The default constructor of QWidget may accept two arguments:
QWidget *parent = 0 is the parent of the new widget. If it is 0 (the default), the new widget will be a window. If not, it will be a child of parent, and be constrained by parent's geometry (unless you specify Qt::Window as window flag).
Qt::WindowFlags f = 0 (where available) sets the window flags; the default is suitable for almost all widgets, but to get, for example, a window without a window system frame, you must use special flags.
So, if you pass anything but NULL to parent, your wiget will not be a separate window, unless you set the second parameter as QT::Window. This is what's happening for you. So you'll need to either set the flag QT::Window, or make your own class, derive it from QWidget, and write a constructor that takes an additional argument which will be the pointer you need, while getting NULL as parent.

Close button only for some tabs in Qt

I am using Qt for an assignment I have for college, and I want to use QTabWidget to display a chat window much like Pidgin's. I want to make the "group chat" tab always open and impossible to close and the rest of the "private channel" tabs closable.
QTabWidget's setTabsClosable(bool) is not helping.
Any ideas?
I found an easier solution, I think.
Simply access the relevant close button and resize it.
tabWidget->tabBar()->tabButton(0, QTabBar::RightSide)->resize(0, 0);
Find the bar (it is private, so use findChild()) and remove the buttons. Documentation claims that close buttons may be placed on left side too.
QTabBar *tabBar = ui->tabWidget->findChild<QTabBar *>();
tabBar->setTabButton(0, QTabBar::RightSide, 0);
tabBar->setTabButton(0, QTabBar::LeftSide, 0);
Hallo,
I guess this post won't help the author of this thread but perhaps someone else wanders over here.
In most cases a non-closable tab should not only ignore the closevent it also should not show a close symbol in its corner. A nice way to reach this is to modify the QTabBar which is inside the QTabWidget.
Example:
// let tabWidget be a QTabWidget with at least one page
QPushButton *closeButton = new QPushButton();
// set icon and size for PushButton, ...
// connect Signal clicked() from closeButton with Slot closeCurrentTab(), ...
// next line sets closeButton in right corner on tab with index 0
tabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, closeButton);
Although tabBar() is indeed protected, Klaus pointed into the right direction. Simply subclass QTabWidget and implement a wrapper method.
You should reimplement your widget's event(Event *e) method, check the type of e, find out CloseEvents, and call parent class's event when you can allow tab to close, or e->ignore() when you do not want it.
Note, then you must parent's event() handle othr events, so do not accept(), reject() or forget them Ж)
I guess you can handle the tabCloseRequest signal and decide whether u'll close a given tab or not
http://doc.qt.io/archives/4.6/qtabwidget.html#tabCloseRequested
Edit: I created a small example to check it out. My example is a simple QtGui application with a mainwindow that has a tabwidget. I then added the tabCloseRequested slot. Here is the code
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
if(someCondition){
return;
} else if(anotherCondition){
ui->tabWidget->removeTab(index);
}
}
From this example only tabs where the condition doesn't apply will be closed.
The best way for adding a pushbutton to some tabs and not in other is to define a subclass of QTabWidget for taking the QTabBar that is a potected!
The code below is tested and it works:
//TabWidget.h
#ifndef TABWIDGET_H
#define TABWIDGET_H
#include <QTabWidget>
class TabWidget : public QTabWidget {
public:
TabWidget(QWidget *parent);
~TabWidget();
QTabBar *tabBar() const;
};
#endif /* TABWIDGET_H */
//TabWidget.cpp
#include "TabWidget.h"
TabWidget::TabWidget(QWidget * p=0) : QTabWidget(p) {}
TabWidget::~TabWidget() {}
QTabBar * TabWidget::tabBar() const {return QTabWidget::tabBar();}
For using this subclass and create a new tab with a custom button you have to following this instructions ( ui->tabWidget is a QTabWidget with setClosableTabs=false):
TabWidget *t = (TabWidget *) ui->tabWidget;
t->addTab(new QWidget, "empty");
QTabBar *tab = t->tabBar();
QPushButton *b = new QPushButton();
b->setText("x");
tab->setTabButton(tab->count() -1, QTabBar::RightSide, b);
connect(b,SIGNAL(...),this,SLOT(...));
Not sure, why nobody here mentioned the simplest working solution:
tabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, 0);
This completely removes the close button, and the space taken by it.
Documentation