qt prevent qdialog/window from moving with mainwindow - c++

Env
OS X 10.6.8 ... and later, Windows XP ... and later.
Qt 4.7 (has to be, legacy issues, OS X 10.6.8 must be supported, Qt5 won't do it)
Problem
I have opened a second window in my application. It behaves as I want it to, except that if the MainWindow in the application moves, so does this window. That behavior is unwanted (actually more like "toxic and user-unfriendly").
The Qt docs say not to call move() from within moveEvent(), and anyway moveEvent() only shows up after window has stopped moving, not even while moving, which would, even if I did use it successfully, result in second window moving and snapping back, which would be pretty awful.
I thought to try overriding move() and not calling QDialog::move(), but that didn't work, it seems it cannot be overridden; rfview window still follows mainwindow around.
Perhaps I am opening the window wrong:
void MainWindow::xrfview()
{
ttrfview = new rfview(this);
uiframePlot = ttrfview->ui->framePlot;
ttrfview->show();
ttrfview->raise();
}
Or perhaps I have defined the window wrong:
class rfview: public QDialog
{
Q_OBJECT
public:
explicit rfview(QWidget *parent = 0);
~rfview();
}
Or both?
Basically, if the user drags/re-positions MainWindow, I do not want the rfview window to follow.

Change ttrfview = new rfview(this) to ttrfview = new rfview()

Related

Application with multiple windows in Qt

What is a good way to create application with multiple windows in Qt? Something like GIMP. I have already read this answer and it is not what I need.
I have two windows, one with controls and one with OpenGL inside. Right now I have something like this:
int main()
{
// some code
MainWindow mw;
mw.show();
GLWindow gw;
gw.show();
// ...
}
I don't like this for two reasons. First reason is when I start my application, window with OpenGL will be on top (because it is last to call show()) but MainWindow will be buried somewhere under all opened windows. What I need is both windows in front of everything (like GIMP), preferably with focus on MainWindow (I guess I can bring them to front, so that is minor issue). Second reason I don't like this is that my application will be closed completely only when I close both windows.
So I was thinking of having a reference to GLWindow inside MainWindow, and creating it from MainWindow.
Would that be a good way to create application with several windows?
EDIT: GLWindow inherits from QOpenGLWindow.
You are doing right, but with the following simple tricks, you can resolve both issues that cause you do not like your right method:
To activate both windows, just do as follows:
MainWindow mw;
mw.show();
mw.activateWindow();
GLWindow gw;
gw.show();
gw.activateWindow();
To resolve the quit problem, you have to override the closeEvent in both windows. To do that, add the following code into the header file of your both windows:
protected:
void closeEvent(QCloseEvent *event) override;
and in the implementation of the closeEvent, just write qApp->quit();. This way once you close either window, your application will terminate completely.
MainWindow.cpp
void MainWindow::closeEvent(QCloseEvent *event)
{
qApp->quit();
}
and
GLWindow.cpp
void GLWindow::closeEvent(QCloseEvent *event)
{
qApp->quit();
}
I'm not sure I completely understand the situation but, typically, you can make the 'secondary' widgets child dialogs of the QMainWindow. Given your example code that would be something like...
int main ()
{
// some code
MainWindow mw;
mw.show();
/*
* Secondary windows should be created with the QMainWindow mw
* as their parent.
*/
GLWindow gw(&mw);
/*
* Set the Qt::Dlaog window flag to `encourage' the QMainWindow
* and its children to behave as a group.
*/
gw.setWindowFlags(gw.windowFlags() | Qt::Dialog);
gw.show();
// ...
}
Now all widgets behave as a group (possibly subject to the window manager being used) and closing the QMainWindow will, by default, close the application.

QDialog flash back after create

I have a QListWidget on my QMainWindow, and I connect the itemDoubleClicked(QListWidgetItem*) signals to a slot like the following code:
connect(listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(popUpMyDialog(QListWidgetItem*)));
My popUpMyDialog(QListWidgetItem*) function is like:
QMyDialog *myDialog = new QMyDialog(this);
myDialog->show();
QMyDialog is a class which I inherent from QDialog, and no operation except ui->setupUi(this); was done.
But when I try to double click on the item of QListWidget, the myDialog flashed and disappear very soon.
So I had tried to write some code to judge if the myDialog is deleted like that:
QMyDialog *myDialog = new QMyDialog(this);
connect(myDialog, SIGNAL(destroyed(QObject*)), this, SLOT(handleQMyDialogClose(QObject*)));
myDialog->show();
and the slots function handleQMyDialogClose(QObject*) just do:
qDebug() << "myDialog is closed";
When I double click on the item of item of QListWidget, the console print myDialog is closed, which means the myDialog object is deleted, but I don't delete the pointer, so I feel confused.
I Googled it and tried to setModal attributes to myDialog , but it take no effect.
I tried to copy the same code to my Mac, the strange thing is that it runs perfect.
I tried to add a for loop in my popUpMyDialog(QListWidgetItem*) like that:
QMyDialog *myDialog = new QMyDialog(this);
connect(myDialog, SIGNAL(destroyed(QObject*)), this, SLOT(handleQMyDialogClose(QObject*)));
myDialog->show();
for(int i = 0; i < 100; ++i) {qDebug() << i;}
to block the thread, and find that the myDialog window work prefect, but if I comment the for loop code, it flash back again.
So, I want to know what error happened to my code, and how I can try to handle it.
My coding environment is:
Windows 10 and Mac OS X 10.10.4 Yosemite, the version of Qt is Qt5.5.0, and on my Windows , the Qt runs with mingw.
So, you have the following method:
void Foo::popUpMyDialog(QListWidgetItem*) {
QMyDialog *myDialog = new QMyDialog(this);
myDialog->show();
}
The only reason why the dialog would get prematurely destroyed is if the instance of Foo, that the dialog is a child of, got destructed.
To troubleshoot the issue, first try to create a parentless dialog:
void Foo::popUpMyDialog(QListWidgetItem*) {
QMyDialog *myDialog = new QMyDialog;
myDialog->show();
}
If that dialog remains visible, then you know that you gave it a wrong, short-lived parent. The solution would be to find another parent. To avoid leaking the dialogs, you can give the dialog a Qt::WA_DeleteOnClose attribute.
QDialog has an exec() function that "blocks" the execution (as you do with your loop), to use instead of show() so your dialog can stay visible. Isn't it what you are looking for?

QWinTaskbarProgress won't show

I'm using windows7 and Qt5.3.0
I added below to my MainWindow's constructor but nothing shows on my taskbar. Did I miss something?
QWinTaskbarProgress * pTaskbarProgress = new QWinTaskbarProgress(this);
pTaskbarProgress->setMinimum(0);
pTaskbarProgress->setMaximum(100);
pTaskbarProgress->setValue(50);
pTaskbarProgress->show();
In fact, it seems like calling
button->setWindow(widget->windowHandle());
in QMainWindow constructor doesn't work and QWinTaskbarProgress won't show at all even after calling setVisible(true) or show().
If created in the QMainWindow constructor it has to be called once the Window is shown like in:
void MainWindow::showEvent(QShowEvent *e)
{
#ifdef Q_OS_WIN32
m_button->setWindow(windowHandle());
#endif
e->accept();
}
See the example in the documentation:
QWinTaskbarButton *button = new QWinTaskbarButton(widget);
button->setWindow(widget->windowHandle());
button->setOverlayIcon(QIcon(":/loading.png"));
QWinTaskbarProgress *progress = button->progress();
progress->setVisible(true);
progress->setValue(50);
Seems to me like you have to set this as part of a QWinTaskbarButton.
The history behind this class is that it was part of QWinTaskbarButton, thus it was inherently tightly coupled with that class. You can see the relevant upstream commit that began the refactoring and hence decoupling:
Refactor QWinTaskbarProgress out of QWinTaskbarButton
You are right that it is not too explicit in QWinTaskbarProgress' documentation, so this could be potentially improved upstream, but the QWinTaskbarButton example as well as the Music Player example shows the point, namely you have to replace this line:
QWinTaskbarProgress * pTaskbarProgress = new QWinTaskbarProgress(this);
with:
QWinTaskbarButton * pTaskbarButton = new QWinTaskbarButton(this);
pTaskbarButton->setWindow(windowHandle());
QWinTaskbarProgress * pTaskbarProgress = pTaskbarButton->progress();
You may wish to set the overlay icon as well for the taskbar button with either a custom image or something like what the Music Player examples does:
pTaskbarButton->setOverlayIcon(style()->standardIcon(QStyle::SP_MediaPlay));

Embed QWidget into Other Application

Recently I stumbled upon QMacNativeWidget (src and header) which basically makes it possible to use Qt widgets in native Cocoa applications without having to use QApplication.
Now I was wondering whether it is possible to adapt this technique to embed Qt widgets into other GUI kits, say I want to place QWidget Foo inside CoolUIKit Bar. At a glance this seems pretty straightforward, e.g. the main functionality is to adapt getEmbeddableView correctly:
NSView *getEmbeddableView(QWindow *qtWindow)
{
// Make sure the platform window is created
qtWindow->create();
// Inform the window that it's a subwindow of a non-Qt window. This must be
// done after create() because we need to have a QPlatformWindow instance.
// The corresponding NSWindow will not be shown and can be deleted later.
extern QPlatformNativeInterface::NativeResourceForIntegrationFunction resolvePlatformFunction(const QByteArray &functionName);
typedef void (*SetEmbeddedInForeignViewFunction)(QPlatformWindow *window, bool embedded);
reinterpret_cast<SetEmbeddedInForeignViewFunction>(resolvePlatformFunction("setEmbeddedInForeignView"))(qtWindow->handle(), true);
// Get the Qt content NSView for the QWindow from the Qt platform plugin
QPlatformNativeInterface *platformNativeInterface = QGuiApplication::platformNativeInterface();
NSView *qtView = (NSView *)platformNativeInterface->nativeResourceForWindow("nsview", qtWindow);
return qtView; // qtView is ready for use.
}
But: how do I get from NSView to CoolUIKit? Or is there a completely alternative approach?

Fullscreen for QDialog from within MainWindow only working sometimes

(Testing with C++ on Qt 4.8 and Ubuntu 12.10 unity)
I've got a main window which displays a QDialog. When I put the Dialog window full-screen it does not seem to always work even though it seems to be a proper window.
Meaning, the window can appear full-screen, though only sometimes.
Anyone got an idea? I know Qt states it might not work for all X environments, but it can't be that bad, can it?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QDialog* d = new QDialog();
d->setModal(false);
d->show();
qDebug() << d->isWindow();
// works most of the times, though not always:
// d->showFullScreen();
// sometimes works, sometimes it doesn't:
QTimer::singleShot(2000, d, SLOT(showFullScreen()));
}
DomTomCat here at stackoverflow showed a way to detect Ubuntu and the QDialog problem is related to a bug in Metacity (Ubuntu's default window manager).
Metacity doesn't manage the same way dialogs and main windows and it has to be tricked making it think that a QDialog is a normal window. In order to do so using QDialog class it's window flags have to be changed.
Instead of doing all the steps DomTomCat says, you can detect the session and then just
//example inside the QDialog
this->setWindowFlags(Qt::Window);
this->showFullScreen();
The bug was reported (and ignored) before but as far as I know this is the first simple workaround.
https://bugreports.qt.io/browse/QTBUG-16034
https://git.gnome.org/browse/metacity/tree/src/core/window.c#n6326
Ubuntu can also use compiz. This can be seen at:
grep DefaultProvider-windowmanager /usr/share/gnome-session/sessions/*
Best regards,
Iker De Echaniz.
I came to a method, which works. I don't know why it works compared to just calling showFullScreen(). I guess this is not the perfect and clean solution. This can surely be adapted to other environmental variables and X sessions.
QDialog* d = new QDialog();
d->setModal(false);
d->show();
const QString session = QString(getenv("DESKTOP_SESSION")).toLower();
QByteArray geometry;
if (session == "ubuntu") {
geometry = _d->saveGeometry();
d->setFixedSize(qApp->desktop()->size());
d->setWindowFlags(Qt::FramelessWindowHint);
d->setWindowState( d->windowState() | Qt::WindowFullScreen);
d->show();
d->activateWindow();
} else {
d->showFullScreen();
}
For restoring from the fullscreen state, this has worked
if (session == "ubuntu") {
d->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
d->setMinimumSize(0,0);
d->restoreGeometry(geometry);
d->setWindowFlags(Qt::Dialog);
d->show();
d->activateWindow();
} else {
d->showNormal();
}