Qt Creator: AlwaysStaysOnTop blocks open file prompt - c++

I have a push button on my main window that allows the user to select a file to open.
std::fstream infile;
std::string filename = QFileDialog::getOpenFileName(this, tr("TXT file"), qApp->applicationDirPath (),tr("TXT File (*.txt)")).toStdString();
if (filename.empty())
return;
infile.open(filename, std::fstream:: in | std::fstream::out | std::fstream::app);
if (true) {
//Does stuff with the data
}
infile.close();
This normally works fine, and I've used it in previous gui qt applications. However, for this application the mainwindow (upon its setup) sets its windowsflags as follows:
setWindowFlags(Qt::FramelessWindowHint| Qt::WindowStaysOnTopHint);
This creates a problem as the main window attempts to always stay on top (and thus prevents the open file window from appearing). Without the staysontop flag the file dialog works correctly.
Is there a way to temporarily disable this flag (so I can disable when the push button is clicked and then reenable when the file dialog is complete)?
setWindowFlags(Qt::FramelessWindowHint| ~Qt::WindowStaysOnTopHint);
This seems to be the most common suggested solution, but doesn't work for me. I believe this is because the window has to be recreated for the changes to the window flag to be registered -- however, I believe that if I killed the main window the file dialog would go out of scope too?
In summary, I am trying to find a work around to have the main window always on top except for when I am trying to select a file to open (the file dialog being triggered by a push button).

The problem was not the flags but rather a timer emitting signals which updated the window position:
QTimer* timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update_pos()));
timer->start(50);
Where the update_pos function is as follows:
void MainWindow::update_pos(){
RECT rect;
if (GetWindowRect(target_window, &rect)) {
SetWindowPos((HWND)this->winId(), HWND_TOPMOST, rect.left, rect.top, 0, 0, SWP_NOSIZE);
} else {
//maybe window was closed
qDebug() << "GetWindowRect failed";
QApplication::quit();
}
}
Whenever the update_pos function was called it would push the main window to the top (and thus above the open file dialog).

Related

how do I call primary window using pushbutton c++

I'm trying to create a C++ Widget Application in QT with multiple windows where you can return to the mainwindow by clicking a Pushbutton.
I'm a complete noobie so I try to follow YouTube tutorial and for opening windows by pushbuttons I watched this one (minute 8:00): https://youtu.be/tP70B-pdTH0
It works when opening secondary windows from the main one but if I try to do the same from a secondary windows to the mainwindow it doesn't. It appears an error "cannot initialize object parameter of type 'Widget' with an expression of type 'MainWindow'"
in the source file I wrote:
void Crediti::on_pushButton_clicked()
{
close();
mainwindow = new MainWindow(this);
mainwindow->show();
}
mainwindow->show(); is the incriminated part
I also included mainwindow in the header of the secondary window and specified the class
MainWindow *mainwindow
in the header so It recognizes mainwindow initially in the source.
I'm doubting if doing this thing is possible at all, and if not so how can I make a pushbutton that, when clicked, can redirect me to the mainwindow?
Please I need this for a school application, thanks
So here you're creating a new main window each time you click on the button. From your description that's not the behaviour you want. I understand you have an application with a main window and other secondary windows and want to bring up the main window when clicking on the button, assuming the main window still exists somewhere and hasn't been deleted.
What I would try is to find the main window when hitting the push button and show / raise it, something along the line of:
#include <QApplication>
#include "MainWindow.h" // Adapt that one to you main window header
// ... some code of your secondary window
void SecondaryWindow::on_pushButton_clicked()
{
for(auto widget : QApplication::topLevelWidgets())
{
// This will return a nullptr if the widget is not the main window
auto mainWindow = dynamic_cast<MainWindow*>(widget);
// skip if not the main window
if(!mainWindow)
continue;
// Show it if hidden
if(mainWindow->isHidden())
mainWindow->show();
// raise it, as in bring it forward, over all other windows
mainWindow->raise();
}
// eventually close the current window if that's what you want
close();
// if you close it and don't need it any more you might also want to delete it
deleteLater();
}
Note that this function won't do anything if the main window has been deleted in the meantime, which might be the case if you closed it and the Qt::WA_DeleteOnClose attribute is set.
Hope that helps.

Why does the QMessageBox opened from QFileDialog::accept() does not stay on top on macOS?

I try to have with Qt a file dialog, which asks the user for confirmation if the chosen file does not exist. So basically the same you get with the Windows API via IFileDialog::SetOptions(FOS_CREATEPROMPT).
So I derived a new class from QFileDialog to overwrite QFileDialog::accept().
The new QFileDialogEx::accept() opens a QMessageBox when the user clicks on Open, but the file does not exist. If the user chooses "No", the file dialog will not be accepted and keeps open.
That works fine on Linux, but on macOS, the QMessageBox does not stay on top of the QFileDialog. So if the user clicks on the QFileDialog under the QMessageBox, it will come to the top, hiding the QMessageBox.
Here is my code:
class QFileDialogEx : public QFileDialog
{
public:
QFileDialogEx(QWidget *parent, const QString &caption, const QString &directory)
: QFileDialog(parent, caption, directory) {
this->setOption(QFileDialog::DontUseNativeDialog);
}
void accept(void) {
QString selectedFilePath = this->selectedFiles().value(0);
QFileInfo selectedFileInfo(selectedFilePath);
if (!selectedFileInfo.exists()) {
// File does not exist => Ask if file should be created
QMessageBox msgBox(this);
msgBox.setWindowFlags(msgBox.windowFlags() | Qt::WindowStaysOnTopHint);
msgBox.setText(selectedFileInfo.fileName() + "\nThis file doesn't exist.\n\nDo you want to create this file?");
msgBox.setWindowTitle("Create Prompt");
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
if (msgBox.exec() == QMessageBox::No)
return; // Keep file dialog open
}
QFileDialog::accept();
}
};
I've searched a lot about keeping a QMessageBox box on top. Normally the point is: "Set the parent". But as you can see, I did that already. I also desperately tried Qt::WindowStaysOnTopHint and msgBox.setWindowModality(Qt::ApplicationModal) without success.
Just to be clear: I am not using the native file dialogs here. (QFileDialog::DontUseNativeDialogs)
Any idea how to let the QMessageBox stay on top of the QFileDialog also on macOS?
Or any other idea, on how to implement a prompt when the user clicks on Open, but the chosen file does not exist?

QFileDialog causes my application to become less responsive

Firstly, for context, I am connecting a signal from triggered from QAction to a slot called fileOpen in this, and other similar connections are done in a method in my main window class like the following:
void MainWindow::createActions()
{
m_fileNew = new QAction("&New", this);
m_fileOpen = new QAction("&Open", this);
m_fileExit = new QAction("E&xit", this);
connect(m_fileNew, SIGNAL(triggered(bool)), this, SLOT(fileNew()));
connect(m_fileOpen, SIGNAL(triggered(bool)), this, SLOT(fileOpen()));
connect(m_fileExit, SIGNAL(triggered(bool)), this, SLOT(fileExit()));
}
To show the file dialog, the static method QFileDialog::getOpenFileName is used in MainWindow::fileOpen:
void MainWindow::fileOpen()
{
QString filename = QFileDialog::getOpenFileName(this, tr("Open Audio File"),
"", tr("WAVE Files (*.wav);;All Files (*.*)"));
if (filename != QString::null) {
m_fileName = filename;
}
}
The signal-slot connection between m_fileOpen and fileOpen works and displays the file dialog, but after closing the dialog the window takes longer to redraw while resizing.
Why is that happening, and how can I fix it?
All I had to do was build my Qt application in release mode, which means removing the "CONFIG+=debug" argument from the qmake call.
In release mode the performance degradation is gone, which is great, although I don't understand what differences between the debug and release versions of the Qt libraries allow this to occur.

Open a new Qt window with a slot

In my Qt Program, there is a menu bar where one of the menu options is Settings. When the user click on the Settings window, it should open a Settings window. The settings window gets opened with a openSettingsWindow() function. This is how I made the Settings menu in the main window:
QMenu settingsMenu("&Settings");
QAction *settings = toolsMenu.addAction("&Settings");
Window::connect(settings,&QAction::triggered,&mainWindow,[&mainWindow](){
openSettingsWindow();
});
menuBar.addMenu(&toolsMenu);
mainWindow is the main window and Window is the class used to create windows which inherits from QWidget. Its constructor takes two arguments: the title of the window and the icon of the window. This is the openSettingsWindow() function:
void openSettingsWindow(){
Window settingsWindow("Settings","icon.png");
settingsWindow.show();
}
The problem is that when I click ont he Settings option in the Settings menu, the Settings window opens as it should, but it closes directly after less than a second. What should I do to keep the Settings window opened?
The local variable settingsWindow gets destructed when your function openSettingsWindow goes out of scope, you need to keep the object valid as long as you want to show your settingsWindow.
one solution would be to allocate the Window object on the heap, and use the Qt::WA_DeleteOnClose to make Qt delete the Window object for you when it is closed, here is how your openSettingsWindow would look like:
void openSettingsWindow(){
Window* settingsWindow = new Window("Settings","icon.png");
settingsWindow->setAttribute(Qt::WA_DeleteOnClose);
settingsWindow->show();
}
You need to return a reference to that Window and keep it until you're no longer using it.
Window *openSettingsWindow() {
Window *settingsWindow = new Window("Settings, "icon.png");
settingsWindow.show();
return settingsWindow;
}
QMenu settingsMenu("&Settings");
QAction *settings = toolsMenu.addAction("&Settings");
Window *settingsWindow = null;
Window::connect(settings,&QAction::triggered,&mainWindow,[&mainWindow, &settingsWindow](){
settingsWindow = openSettingsWindow();
});
menuBar.addMenu(&toolsMenu);
You might want to find a better way of storing the settingsWindow pointer in the main function if you're going to have many possible open windows but this will work.
Remember to call delete() on that pointer when you're done with the settings window (likely on the window close event)

Close QFileDialog only when click "open"

Whenever I select a file in my QFileDialog the accepted signal is fired and the window closes. I want to keep the window open so I can select multiple files and then capture the signal fired when "open" is clicked.
QFileDialog* myDialog = new QFileDialog(this);
myDialog->setFileMode(QFileDialog::ExistingFiles);
myDialog->setVisible(true);
What signals should I be connecting here to achieve this effect?
The QFileDialog::ExistingFiles should guarantee that multiple files can be selected. Given that, you can connect to the signal:
void QFileDialog::filesSelected(const QStringList & selected)
Directly from the documentation:
When the selection changes for local operations and the dialog is accepted, this signal is emitted with the (possibly empty) list of selected files.
However, if you are only interested in collecting such files, you can totally avoid signal-slot and write (taken again from the documentation):
QStringList fileNames;
if (dialog.exec())
fileNames = dialog.selectedFiles();
Note that in this case dialog object has been created on the stack (which is the common approach for such objects).
Your code looks fine to me. I believe you are double clicking on the file inside the dialog instead of holding on the Ctrl and single clicking on all the files you need.
You can optionally use an event filter and ignore the double click event.
Once you click on Open, you can get a list of all the file paths in the QStringList given by QFileDialog::selectedFiles(). Also it's better to use a stack variable here and use exec method to launch it as pointed out by BaCaRoZzo.
QFileDialog myDialog(this);
myDialog.setFileMode(QFileDialog::ExistingFiles);
if(myDialog.exec())
{
qDebug() << myDialog.selectedFiles();
}
Whenever I select a file in my QFileDialog the accepted signal is fired and the window closes. I want to keep the window open so I can select multiple files
All other answers is just solution for selection many files one time and CLOSE window after Open button pressing. Get my solution, it is not very simple because it required lot of work:
I used lamda expressions and new signals and slots syntax in my answer, but you can use old syntax or add
CONFIG += c++11
to the .pro file and use lambdas.
Subclass QFileDialog:
Header:
#ifndef CUSTOMFILEDIALOG_H
#define CUSTOMFILEDIALOG_H
#include <QFileDialog>
#include <QDebug>
class CustomFileDialog : public QFileDialog
{
Q_OBJECT
public:
explicit CustomFileDialog(QWidget *parent = 0);
void setDefaultGeo(QRect);
signals:
void newPathAvailable(QStringList list);
public slots:
private:
bool openClicked;
QRect geo;
};
#endif // CUSTOMFILEDIALOG_H
When you click open, you hide your dialog, not close! Cpp:
#include "customfiledialog.h"
CustomFileDialog::CustomFileDialog(QWidget *parent) :
QFileDialog(parent)
{
openClicked = false;
connect(this,&QFileDialog::accepted,[=]() {
openClicked = true;
qDebug() << openClicked;
this->setGeometry(geo);
this->show();
emit newPathAvailable(this->selectedFiles());
});
}
void CustomFileDialog::setDefaultGeo(QRect rect)
{
geo = rect;
}
Usage:
CustomFileDialog *dialog = new CustomFileDialog;
QStringList fileNames;
dialog->setFileMode(QFileDialog::ExistingFiles);
dialog->show();
dialog->setDefaultGeo(dialog->geometry());
connect(dialog,&CustomFileDialog::newPathAvailable,[=](QStringList path) {
qDebug() << path;
});
Why do you need setDefaultGeo? Without this method, your window will move after Open pressing.
What we get?
I open filedialog and select two files:
I clicked Open, but window didn't close! You can choose new files again and again!
One more file and so on:
Window will closed only when user press Close button, but you will have all path which user choose.
As you said:
I want to keep the window open so I can select multiple files
You get this.
I don't think anyone has understood the question (or it could be just me looking for my own solution)...
I had the same issue. As soon as I clicked a file the dialog would close. I couldn't ever select a file and then click "Open" because the dialog instantly closed as soon as I single clicked a file.
related: qtcentre.org/threads/48782-QFileDialog-single-click-only
It turns out it was my linux os settings (under mouse). File opening was set to single-click. I still feel like something external might have toggled this but that is just speculation. It appears Qt was going the right thing. Check another application, like kate on KDE and see if it has the same behavior. That is what clued me in to the source of my issue.