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.
Related
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.
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?
I've followed instructions given on previous questions like this
so now if I put a link to a regular page it opens fine with the default browser. But if I want to open a mailto link from QT QLabel 4.8.6 the link does nothing.
What am I doing wrong?
here is the code:
UpgradeMessageDialog* umd = new UpgradeMessageDialog();
umd->ui->label->setOpenExternalLinks(true);
umd->ui->label->setTextInteractionFlags(Qt::TextBrowserInteraction);
umd->ui->label->setText("<a href='mailto:user#foo.com?subject=Test&body=Just a test'>My link</a>");
umd->exec();
umd->ui->label->connect(umd->ui->label,
SIGNAL(linkActivated(const QString&)), umd,
SLOT(linkOpen(const QString&)));
(this is defined as a public slot in the appropriate h file)
void UpgradeMessageDialog::linkOpen(const QString &link)
{
QDesktopServices::openUrl(QUrl(link));
}
Just to clarify: I have a default mail program set up in my computer, and when I type mailto:a#b.c in the browser that program opens fine.
First, there are two ways to handle link activation in QLabel. You should use one of them, but I see you are trying to use both.
This two ways are:
Call openExternalLinks(true), so that QLabel will automatically open links using QDesktopServices::openUrl() instead of emitting the linkActivated() signal.
Connect to the linkActivated() signal and then manually open link in the connected slot (by calling QDesktopServices::openUrl() for example).
Also you use the exec() function wrong. You should put the exec() call after the connect() call, because exec() is blocking so the signal connection will actually happened after the dialog is closed.
So your code should be like this:
umd->ui->label->setText("<a href='mailto:user#foo.com?subject=Test&body=Just a test'>My link</a>");
connect(umd->ui->label, SIGNAL(linkActivated(QString)), umd, SLOT(linkOpen(QString)));
umd->exec();
or like this:
umd->ui->label->setTextFormat(Qt::RichText);
umd->ui->label->setTextInteractionFlags(Qt::TextBrowserInteraction);
umd->ui->label->setOpenExternalLinks(true);
umd->ui->label->setText("<a href='mailto:user#foo.com?subject=Test&body=Just a test'>My link</a>");
And a little advise: put the label initialization code into the UpgradeMessageDialog constructor.
UpgradeMessageDialog::UpgradeMessageDialog(QDialog* parent) : QDialog(parent)
{
ui->label->setTextFormat(Qt::RichText);
ui->label->setTextInteractionFlags(Qt::TextBrowserInteraction);
ui->label->openExternalLinks(true);
ui->label->setText("<a href='mailto:user#foo.com?subject=Test&body=Just a test'>My link</a>");
}
And then you can use your dialog this way:
QScopedPointer<UpgradeMessageDialog> umd = new UpgradeMessageDialog;
umd->exec();
#include <QUrl>
#include <QDesktopServices>
myLabel = new QLabel(this);
myLabel->setTextFormat(Qt::RichText);
myLabel->setText("Email:href='mailto:serge#essetee.be'>serge#essetee.be</a>");
myLabel->setOpenExternalLinks(true);
Now you just have to click the link and the standard mail client will be launched.
I would like to allow the user to drag a file path from a QTableWidget cell and drop this in a file manager (e.g. Windows Explorer) to create a link (Windows file shortcut).
I assume this requires modifying the dragged object data in place?
To start with, I have tried subclassing QTableWidget to reimplement the events
#include <QTableWidget>
#include <QEvent>
class tableWidget : public QTableWidget
{
Q_OBJECT
public:
tableWidget(QWidget *parent = 0);
~tableWidget();
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dropEvent(QDropEvent *event);
};
and "promoted" QTableWidget in Qt Designer to my tableWidget (be sure not to have the objectName identical to the class) and set dragEnabledto true.
However, the event handlers seem not to be executed.
So I thought I might be looking in the wrong place, but QTableWidgetItem does not appear to have Drag and Drop events implemented, although its documentation says
By default, items are enabled, editable, selectable, checkable, and can be used both as the source of a drag and drop operation and as a drop target.
What do I need to do in order to create this behaviour? Is it necessary to create a QDrag object manually as shown in Drag and Drop?
To answer my own question: Yes - it seems that installing an object with eventFilter method allows handling the widget's viewport()'s QMouseEvent's, where a QDrag object is set up according to the documentation linked in the question.
Then use
QTableWidgetItem *twi = ui->tWidget->itemAt( mouseEvent->pos() );
QString dirname( twi->text() );
to retrieve the dragged table cell data
However, passing the link file contents in QDrag object MIME data does not seem to work, as also noted here. Instead, passing the url ("file:///...") of an existing .lnk file works with Windows Explorer.
This does not really make a difference, as the link file needs to be created with e.g. QFile::link() anyway. Remove it after operation is completed.
While several Mime data segments can be passed (see Qt\Examples\Qt-5.5\widgets\draganddrop\dropsite) I have not yet figured out what the order of preference is - e.g. the target application uses either the plain text target path or the reference url to the link file.
When using right mouse button for a drag-n-drop action, a context menu will be shown on release, depending on the DropActions specified as supportedActions in exec(). The dropAction returned by exec then might also be TargetMoveAction and IgnoreAction. Not sure if the context menu can be disabled.
I am a student programmer using Qt to build a reader Table for my company. This reader is both an editor and converter. It reads in a .i file allows table editing of a text document and then puts out a .scf file which is essentially a separated value file stacked under a legend built with headers. I digress... Basically the file format imported is really hard to scan and read in(mostly impossible) so what I'd like to is modify the open file preBuilt QFileDialog to include an additional drop down when older file types are selected to declare their template headers.
When the user selects .i extension files(option 2 file type) I would like to enable an additional drop down menu to allow the user to select which type of .i file it is(template selected). This way I don't have to deal with god knows how many hours trying to figure out a way to index all the headers into the table for each different type. Currently my importFile function calls the dialog using this:
QString fileLocation = QFileDialog::getOpenFileName(this,("Open File"), "", ("Simulation Configuration File(*.scf);;Input Files(*.prp *.sze *.i *.I *.tab *.inp *.tbl)")); //launches File Selector
I have been referencing QFileDialog Documentation to try and find a solution to what I need but have had no avail. Thanks for reading my post and thanks in advance for any direction you can give on this.
UPDATE MAR 16 2012;
First I'd like to give thanks to Masci for his initial support in this matter. Below is the connect statement that I have along with the error I receive.
//Declared data type
QFileDialog openFile;
QComboBox comboBoxTemplateSelector;
connect(openFile, SIGNAL(currentChanged(const &QString)), this, SLOT(checkTemplateSelected()));
openFile.layout()->addWidget(comboBoxTemplateSelector);
I also noticed that it didn't like the way I added the QComboBox to the modified dialog's layout(which is the second error). I really hope that I'm just doing something dumb here and its an easy task to overcome.
In response to tmpearce's comment heres my header code;
#include <QWidget>
namespace Ui {
class ReaderTable;
}
class ReaderTable : public QWidget
{
Q_OBJECT
public:
explicit ReaderTable(QWidget *parent = 0);
~ReaderTable();
public slots:
void checkTemplateSelected();
void importFile();
void saveFile();
private:
Ui::ReaderTable *ui;
};
Thanks for reading and thanks in advance for any contributions to this challenge!
Instance a QFileDialog (do not call getOpenFileName static method), access its layout and add a disabled QComboBox to it.
// mydialog_ and cb_ could be private fields inside MyClass
mydialog_ = new QFileDialog;
cb_ = new QComboBox;
cb_->setEnabled(false);
connect(mydialog, SIGNAL(currentChanged(const QString&)), this, SLOT(checkFilter(const QString&)));
mydialog_->layout()->addWidget(cb_);
if (mydialog_->exec() == QDialog::Accepted) {
QString selectedFile = mydialog_->selectedFiles()[0];
QString cbSelection = cb_->currentText();
}
the slot would be something like:
void MyClass::checkFilter(const QString& filter)
{
cb_->setEnabled(filter == "what_you_want");
}
returning from the dialog exec(), you could retrieve selected file and cb_ current selection.
Notice you could add something more complex than a simple QComboBox at the bottom of the dialog, taking care of gui cosmetics.
Actually I don't like very much this approach (but that was what you asked for :-). I would make a simple dialog like this:
and enable the combo only if the selected file meets your criteria. The "browse" button could call getOpenFileMethod static method in QFileDialog.
You can handle item selection by this signal:
void QFileDialog::fileSelected ( const QString & file )
Then it occurs, call setFilter with type you want.
Sorry, if i don't understand your task.