Reputation: 3902
I want to create a QFileDialog
set to QFileDialog::AnyFile
in which the file name is fixed (but the location can be changed).
So far I found the question QFileDialog - Saving a file with specified file name, which was not answered.
There is the pseudo-answer of choosing the directory directly instead, which is what I did so far in my project. However, by people testing the program, this was found to be confusing, thus is not an acceptable answer.
What I tried so far is to derive QFileDialog
and then enforce this, but I don't know what to try anymore. I managed to reset the file name when a different file is clicked by reacting to the appropriate signal:
FixedFileDialog::FixedFileDialog(QWidget* parent) : QFileDialog(parent)
{
connect(this, SIGNAL(currentUrlChanged(const QString&)), this, SLOT(current_changed(const QString&)));
}
void FixedFileDialog::current_changed(const QString&)
{
selectFile(_filename);
}
(With _filename
being a member set at the beginning.)
This works so far, but it does not prevent the user from entering a different name in the line edit. And I haven't found any signal which is emitted in this case.
Another attempt was trying to access the QLineEdit
widget itself to disable it, but I don't know how. I tried
QLineEdit* line_edit = dialog.d_func()->lineEdit();
(With dialog
being of the derived class.)
This does not work, as d_func()
is private in QFileDialog
.
Does somebody have any other idea what to do?
Upvotes: 1
Views: 580
Reputation: 20151
I must admit that this what I got in mind is a dirty hack. On the other hand, the OP appeared somehow desperate to me. So, I post it (with some doubts in mind).
My idea raised due to the statement of OP:
QLineEdit* line_edit = dialog.d_func()->lineEdit();
(With dialog being of the derived class.)
This does not work, as
d_func()
is private inQFileDialog
.
While d_func()
is private, Qt widgets provide a kind of back-door due to their owner-ship management which can be exploited:
Each QObject
provides a list of its children. So, a simple traversal of this children tree should pass the QLineEdit
in quest (which is the only one in the current implementation of QFileDialog
I have in Qt 5.13).
This is what I tried in a sample:
/ Qt header:
#include <QtWidgets>
QLineEdit* findFirstQLineEdit(QWidget *pQWidget)
{
//qDebug() << "Inspect" << pQWidget;
const QObjectList pQObjs = pQWidget->children();
for (QObject *pQObj : pQObjs) {
if (QLineEdit *pQLineEdit = dynamic_cast<QLineEdit*>(pQObj)) {
qDebug() << "Found:" << pQLineEdit;
return pQLineEdit;
} else if (QWidget *pQWidget = dynamic_cast<QWidget*>(pQObj)) {
if (QLineEdit *pQLineEdit = findFirstQLineEdit(pQWidget)) {
return pQLineEdit;
}
}
}
return nullptr;
}
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QFileDialog qFileDlg(nullptr,
QString::fromUtf8("Choose Dir. to Save File"),
QDir::currentPath());
qFileDlg.show();
// manipulate the file name input
qFileDlg.selectFile("CMakeLists.txt");
QLineEdit *const pQEdit = findFirstQLineEdit(&qFileDlg);
pQEdit->setReadOnly(true);
// runtime loop
return app.exec();
}
Output:
The file name line editor is read-only. Neither editing nor deleting is allowed but the contents may still be copied and changed from outside. (For this case, OP seems to have found another solution, already.)
Note:
My first idea was to call findFirstQLineEdit()
in the constructor of a class derived from QFileDialog
. This didn't work! The debug output proofed that the QFileDialog
hasn't any children after construction. I came to the conclusion that the children of the QFileDialog
are created at a later time – but surely have to be already created after show()
.
To embed this hack into a derived class, it might be sufficient to do the manipulation in an override of QFileDialog::showEvent()
. (I didn't test it.)
Upvotes: 3