简体   繁体   中英

QFileDialog: force file name

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?

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 in QFileDialog .

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:

testQFileDialogQLineEditReadOnly 的快照

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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM