4

QFileDialogを使用してディレクトリを選択しています。解決できない問題が発生しています。私はこれのためにグーグルで多くの時間を費やしましたが、zilchを思いつきました。

開始ディレクトリ(たとえば/ home / dhoti / downloads)を指定し、このディレクトリの上のナビゲーションを無効にします。たとえば、ユーザーが/ home/dhotiや/tmpなどに移動することを許可しないでください。これを実現するにはどうすればよいですか。

これが私のコードです:

QFileDialog dlg(this, "Select Firmware Version");
dlg.setDirectory("/home/dhoti/downloads");
dlg.setFileMode(QFileDialog::DirectoryOnly);
dlg.setOption(QFileDialog::ReadOnly, true);
dlg.setOption(QFileDialog::HideNameFilterDetails, true);
dlg.setViewMode(QFileDialog::List);
dlg.setAcceptMode(QFileDialog::AcceptOpen);
dlg.exec();
qDebug() << "selected files: " << dlg.selectedFiles();

助けてくれてありがとうDhoti

4

4 に答える 4

2

現在のディレクトリがいつ変更されたかを検出でき、制限を超えている場合は、ディレクトリを制限ディレクトリに戻します。

これを行うには、ダイアログのノンブロッキングを実行し、QFileDialog::directoryEntered(const QString& directory)信号をチェックを実行できる独自のスロットに接続します。チェックに失敗した場合は、現在のディレクトリを。で制限ディレクトリに設定しますQFileDialog::setDirectory(const QString& directory)

免責事項私はこれを試していませんが、うまくいかない場合は驚かれることでしょう。

于 2012-08-29T08:14:03.277 に答える
1

次のことを試してください。

filedialog.h

#ifndef FILEDIALOG_H
#define FILEDIALOG_H

class QEvent;

#include <QFileDialog>
#include <QString>

class FileDialog : public QFileDialog
{
    Q_OBJECT
public:
    explicit FileDialog(QWidget *parent = 0);
public:
    bool eventFilter(QObject *o, QEvent *e);
    void setTopDir(const QString &path);
    QString topDir() const;
private:
    bool pathFits(const QString &path) const;
private slots:
    void checkHistory();
    void checkGoToParent();
    void checkLineEdit(const QString &text);
private:
    QString mtopDir;
};

#endif // FILEDIALOG_H

filedialog.cpp

#include "filedialog.h"

#include <QString>
#include <QStringList>
#include <QFileDialog>
#include <QList>
#include <QToolButton>
#include <QDir>
#include <QLineEdit>
#include <QDialogButtonBox>
#include <QEvent>
#include <QKeyEvent>
#include <QAbstractButton>
#include <QCompleter>
#include <QAbstractItemView>
#include <QFileInfo>

FileDialog::FileDialog(QWidget *parent) :
    QFileDialog(parent)
{
    connect(this, SIGNAL(directoryEntered(QString)), this, SLOT(checkHistory()));
    connect(this, SIGNAL(directoryEntered(QString)), this, SLOT(checkGoToParent()));
    connect(findChild<QToolButton *>("backButton"), SIGNAL(clicked()), this, SLOT(checkGoToParent()));
    connect(findChild<QToolButton *>("forwardButton"), SIGNAL(clicked()), this, SLOT(checkGoToParent()));
    connect(findChild<QLineEdit *>("fileNameEdit"), SIGNAL(textChanged(QString)), this, SLOT(checkLineEdit(QString)));
    findChild<QLineEdit *>("fileNameEdit")->installEventFilter(this);
    findChild<QWidget *>("listView")->installEventFilter(this);
    findChild<QWidget *>("treeView")->installEventFilter(this);
    findChild<QLineEdit *>("fileNameEdit")->completer()->popup()->installEventFilter(this);
    setOption(DontUseNativeDialog, true);
}

bool FileDialog::eventFilter(QObject *o, QEvent *e)
{
    if (e->type() != QEvent::KeyPress)
        return false;
    int key = static_cast<QKeyEvent *>(e)->key();
    if (o->objectName() == "listView" || o->objectName() == "treeView")
    {
        return (Qt::Key_Backspace == key && !pathFits(directory().absolutePath()));
    }
    else
    {
        if (Qt::Key_Return != key && Qt::Key_Enter != key)
            return false;
        QString text = findChild<QLineEdit *>("fileNameEdit")->text();
        QString path = QDir::cleanPath(directory().absolutePath() + (text.startsWith("/") ? "" : "/") + text);
        bool a = QDir(text).isAbsolute();
        return !((!a && pathFits(path)) || (a && pathFits(text)));
    }
}

void FileDialog::setTopDir(const QString &path)
{
    if (path == mtopDir)
        return;
    mtopDir = (!path.isEmpty() && QFileInfo(path).isDir()) ? path : QString();
    if (!pathFits(path))
    {
        setDirectory(mtopDir);
        checkHistory();
        checkLineEdit(findChild<QLineEdit *>("fileNameEdit")->text());
    }
    else
    {
        QLineEdit *ledt = findChild<QLineEdit *>("fileNameEdit");
        ledt->setText(ledt->text());
    }
    findChild<QWidget *>("lookInCombo")->setEnabled(mtopDir.isEmpty());
    findChild<QWidget *>("sidebar")->setEnabled(mtopDir.isEmpty());
    checkGoToParent();
}

QString FileDialog::topDir() const
{
    return mtopDir;
}

bool FileDialog::pathFits(const QString &path) const
{
    return mtopDir.isEmpty() || (path.startsWith(mtopDir) && path.length() > mtopDir.length());
}

void FileDialog::checkHistory()
{
    QStringList list = history();
    for (int i = list.size() - 1; i >= 0; --i)
        if (!pathFits(list.at(i)))
            list.removeAt(i);
    setHistory(list);
}

void FileDialog::checkGoToParent()
{
    findChild<QToolButton *>("toParentButton")->setEnabled(pathFits(directory().absolutePath()));
}

void FileDialog::checkLineEdit(const QString &text)
{
    QAbstractButton *btn = findChild<QDialogButtonBox *>("buttonBox")->buttons().first();
    QString path = QDir::cleanPath(directory().absolutePath() + (text.startsWith("/") ? "" : "/") + text);
    bool a = QDir(text).isAbsolute();
    btn->setEnabled(btn->isEnabled() && ((!a && pathFits(path)) || (a && pathFits(text))));
}

このコードは魔法のように見えるかもしれません。完璧ではありませんが、機能します。QtソースでQFileDialog子オブジェクト名を検索して使用しました

findChild()

それらにアクセスする方法。必要なのは使用するだけです

setTopDir()

それを超えるとユーザーが移動できないディレクトリを指定するメソッド。

このクラスを使用したプロジェクトの例を次に示します。https ://docs.google.com/file/d/0B3P3dwuDIZ1-Q19FbkFMY2puUE0/edit?usp = Sharing

于 2013-07-17T22:10:06.757 に答える
1

@ololoepepeのソリューションを使用できます。そして、これで上部のコンボボックスの不要なエントリをクリーンアップします。

connect(findChild<QComboBox *>("lookInCombo"), static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &FileDialog::checkComboBox);

void FileDialog::checkComboBox(int index) {
    int i;
    QComboBox *cb = findChild<QComboBox *>("lookInCombo");

    if (index == 0 && cb->model()->rowCount() > 1) {
        for (i = 0; i < cb->model()->rowCount(); ++i) {
            if (!pathFits(cb->model()->index(i, 0).data().toString() + "/")) {
                cb->model()->removeRow(i);
                --i;
            }
        }
    }
}
于 2015-06-23T07:46:59.767 に答える
1

これが最も簡単な解決策であり、ディレクトリトラバーサルを制限するために必要な最小限の手順があります。

アイデア:ディレクトリが変更される可能性がある場合に通知を受け取るためにパブリックシグナルdirectoryEntered(const QString &)を使用QFileDialogし、クラスの1つにそのスロットを実装し、ディレクトリが必要なものであることを確認するためのロジックを配置します。

QFileDialog dialog(this);
    connect(&dialog, SIGNAL(directoryEntered(const QString &)), this, SLOT(onFileDialogDirectoryChanged(const QString &)));
于 2016-11-15T11:20:22.503 に答える