Russian Qt Forum
Ноябрь 25, 2024, 03:42 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Установка фокуса на элемент в QFileDialog  (Прочитано 3944 раз)
Ground
Гость
« : Ноябрь 28, 2012, 09:29 »

Доброго дня!
Реализую следующее поведение QFileDialog: чтобы пользователь лишний раз не шарился по папкам, я хочу не дать ему открывать папки пустые и с определенным содержимым. Для чего прослушиваю сигнал directoryEntered. В коде это реализуется примерно так:
Код
C++ (Qt)
int FileDialog::slotDirectoryEntered(QString path)
{
   QDir newDirectory(path);
 
   // Получение списка файлов и директорий в папке
   QStringList objects = newDirectory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
 
   index = objects.indexOf(projectFileName);
   if (index >= 0)
       objects.removeAt(index);
 
   if (objects.size() == 0)
       this->setDirectory(mPath);
 
   return 0;
}
Другими словами, если пользователь пытается открыть папку, а в ней ничего нет, или лежит один только файлик, то мы принудительно его оставляем в текущей директории.
При таком подходе только одна проблема. Когда пользователь пытается открыть папку - он устанавливает фокус на эту папку (она выделяется и в текстовом поле появляется название этой папки). Так вот, когда мы перебрасываем пользователя с помощью setDirectory - данные о фокусе мы теряем.
И поэтому вопрос - как программно установить фокус на какую-нибудь папку? Или как сделать так, чтобы при попытке зайти в определенную директорию - QFileDialog не пытался ее открыть?
« Последнее редактирование: Ноябрь 28, 2012, 09:36 от Ground » Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #1 : Ноябрь 28, 2012, 10:34 »

Другими словами, если пользователь пытается открыть папку, а в ней ничего нет, или лежит один только файлик, то мы принудительно его оставляем в текущей директории.
А почему нельзя вообще запретить выбирать такие папки?
Записан

Qt 5.11/4.8.7 (X11/Win)
Ground
Гость
« Ответ #2 : Ноябрь 28, 2012, 10:46 »

А почему нельзя вообще запретить выбирать такие папки?
Что именно вы имеете ввиду: скрыть такие папки в окне QFileDialog или именно запретить выбирать? Если скрыть - этот вариант не подходит, т.к. у пользователя должна быть возможность выбрать эту папку для открытия. А если запретить выбирать - это то что нужно, как такое реализовать?
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #3 : Ноябрь 28, 2012, 13:35 »

Что именно вы имеете ввиду: скрыть такие папки в окне QFileDialog или именно запретить выбирать? Если скрыть - этот вариант не подходит, т.к. у пользователя должна быть возможность выбрать эту папку для открытия. А если запретить выбирать - это то что нужно, как такое реализовать?
Наверное всё-таки имеется в виду "вход" в выбранную папку.
После некоторого исследования могу констатировать, что к сожалению легальными средствами сделать это не получится Грустный
Т.е. сделать такой элемент невыбираемым или "засеренным" можно, но double-click отрабатывает всегда.
« Последнее редактирование: Ноябрь 28, 2012, 13:39 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
Ground
Гость
« Ответ #4 : Ноябрь 28, 2012, 14:07 »

Наверное всё-таки имеется в виду "вход" в выбранную папку.
После некоторого исследования могу констатировать, что к сожалению легальными средствами сделать это не получится Грустный
Т.е. double-click отрабатывает всегда.

Я тут покопался в исходниках немного, нашел следующий способ.
Код
C++ (Qt)
/*!
2901    \internal
2902
2903    This is called when the user double clicks on a file with the corresponding
2904    model item \a index.
2905 */

2906 void QFileDialogPrivate::_q_enterDirectory(const QModelIndex &index)
2907 {
2908    Q_Q(QFileDialog);
2909    // My Computer or a directory
2910    QModelIndex sourceIndex = index.model() == proxyModel ? mapToSource(index) : index;
2911    QString path = sourceIndex.data(QFileSystemModel::FilePathRole).toString();
2912    if (path.isEmpty() || model->isDir(sourceIndex)) {
2913        q->setDirectory(path);
2914        emit q->directoryEntered(path);
2915        if (fileMode == QFileDialog::Directory
2916                || fileMode == QFileDialog::DirectoryOnly) {
2917            // ### find out why you have to do both of these.
2918            lineEdit()->setText(QString());
2919            lineEdit()->clear();
2920        }
2921    } else {
2922        q->accept();
2923    }
2924 }

Прежде всего, коннектимся к сигналу currentChanged, где запоминаем имя выделенной директории и через SelectionModel получаем порядковый номер выделенного файла.
Еще нам нужно перехватить directoryEntered(QString), в котором будет сосредоточена основная работа. Проверяем, нужно ли нам открывать эту директорию. Если не нужно - оставляем пользователя в текущей директории: this->setDirectory(mOldPath), восстанавливаем ModelIndex и имя файла в lineEdit. Причем, чтобы обойти очистку lineEdit в исходниках (строка 2918-2919), подключим directoryEntered с режимом Qt::QueuedConnection.
Вот такой костыль получился. Вроде бы я пробежался по тексту QFileDialog, проблем с QueuedConnection быть не должно - там всего 2 вызова directoryEntered.

И все это в коде, может кому-нибудь пригодится:
Код
C++ (Qt)
FileDialog::FileDialog(QWidget* parent, const QString& caption, const QString& directory, const QString& filter) :
   QFileDialog(parent, caption, directory, filter)
{
   this->connect(this, SIGNAL(directoryEntered(QString)),
                 this, SLOT(slotDirectoryEntered(QString)),
                 Qt::QueuedConnection);
   this->connect(this, SIGNAL(currentChanged(QString)),
                 this, SLOT(slotCurrentChanged(QString)));
 
   mPath = qApp->applicationDirPath();
 
   modelView = this->findChild<QListView*>("listView");
   lineEdit = this->findChild<QLineEdit*>();
}
 
 
int FileDialog::slotDirectoryEntered(QString path)
{
   QDir newDirectory(path);
 
   // Получение списка файлов и директорий в папке
   QStringList objects = newDirectory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
 
   // Проверка элементов
   ...
 
   // Если заходить в директорию не нужно
   if (objects.size() == 0)
   {
       this->setDirectory(mPath);
 
       if (lineEdit && modelView)
       {
           modelView->setCurrentIndex(mModelIndex);
           lineEdit->setText(mSelectedFileName);
       }
   }
   else
   {
       mPath = path;
   }
 
   return 0;
}
 
 
int FileDialog::slotCurrentChanged(QString path)
{
   if (path.isEmpty())
       return 0;
 
   if (lineEdit && modelView)
   {
       mModelIndex = modelView->currentIndex();
       mSelectedFileName = QDir(path).dirName();
   }
 
   return 0;
}
 
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.106 секунд. Запросов: 22.