Jacek Surazski (перевод Racheengel) |
Эта статья представляет FileBrowser, подкласс QListBox, позволяющий пользователю просматривать каталоги и файлы.В отличие от FileDialog, который работает как модальное окно, элемент FileBrowser может быть встроен в главное окно приложения или в диалог, предоставляя больше удобств для просмотра.
Компонент FileBrowser отображает содержимое каталога. Если пользователь дважды кликнет имя подкаталога, FileBrowser загрузит в себя содержимое этого подкаталога (как показано ниже). По двойному щелчку на "..", пользователь может вернуться в родительский каталог.
-> |
Когда пользователь подсвечивает новый файл, FileBrowser активирует сигнал, к которому может быть подключена другая чать приложения. Например, на рисунке ниже представлено приложения, комбинирующее FileBrowser с QTextBrowser для получения простого браузера HTML.
Самый обычный путь реализовать FileBrowser - наследоваться от QListBox и добавить несколько новых членов:
class FileBrowser : public QListBox { Q_OBJECT public: FileBrowser(const QString &filter, QWidget *parent = 0, const char *name = 0); void setDir(const QString &path); signals: void picked(const QString &fileName); private slots: void itemHighlighted(int index); void itemSelected(int index); private: QString nameFilter; QString basePath; };
(Альтернативой может быть наследование от QWidget и использование потомка QListBox, но это требует несколько больше кода.)
Конструктор FileBrowser'а получает строку с фильтром имен в дополнение к обычным параметрам QWidget parent и name. Эта строка должна содержать список шаблонов имен файлов (например, "*.jpg *.gif *.png"), и FileBrowser будет отображать только файлы, подпадающие под один из шаблонов.
Функция setDir() устанавливает начальный каталог для просмотра. Сигнал picked(const QString &) активируется, когда новая запись становится подсвеченной (кроме каталогов). В типичных приложениях, этот сигнал должен быть присоеденен к слоту, отображающему содержимое файла.
Далее идут два "закрытых" слота. Они присоединяются к сигналам QListBox'а highlighted(int) и selected(int). Сигнал highlighted(int) активируется, только когда пользователь дважды щелкнул запись или нажал Enter. Для элемента FileBrowser, мы должны использовать оба сигнала - одиночный щелчок на файле вызовет его просмотр, но двойной щелчок (или нажатие Enter) необходимо для входа в каталог.
Наконец, FileBrowser имеет два "закрытых" члена данных: nameFilter хранит аргумент конструктора filter (фильтр), а basePath содержит путь к каталогу, который отображен в данное время в списке.
FileBrowser::FileBrowser(const QString &filter, QWidget *parent, const char *name) : QListBox(parent, name) { nameFilter = filter; setDir(QDir::currentDirPath()); connect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int))); connect(this, SIGNAL(selected(int)), this, SLOT(itemSelected(int))); }
Конструктор сохраняет параметр nameFilter для дальнейшего использования. Затем он вызывает setDir() для заполнения себя содержимым текущего рабочего каталога и присоединяет два сигнала, наследованных от QListBox, к соответствующим "закрытым" слотам FileBrowser.
void FileBrowser::setDir(const QString &path) { QDir dir(path, nameFilter, QDir::DirsFirst); dir.setMatchAllDirs(true); if (!dir.isReadable()) return; clear(); QStringList entries = dir.entryList(); QStringList::ConstIterator it = entries.constBegin(); while (it != entries.constEnd()) { if (*it != ".") insertItem(*it); ++it; } basePath = dir.canonicalPath(); }
Функция setDir() использует объект QDir для получения списка содержимого каталога, указанного в path. Мы передаем nameFilter в конструктор QDir, так что он вернет только файлы, имя которых совпадает с шаблоном. Мы также передаем флаг DirsFirst для указания того, чтобы QDir вначале возвращал каталоги. Потом мы вызываем setMatchAllDirs(true), чтобы QDir вывел все подкаталоги, а не только те, что совпадают с фильтром.
Перед чтением каталога, надо убедится, что он существует и доступен для чтения. Если каталог нечитаем, setDir() сразу выполнит возврат, оставляя список неизмененным.
Далее мы очищаем QListBox и заполняем его содержимым каталога, которое вернул QDir::entryList()--- но пропускаем каталог ".". Мы сохраняем текущий путь в "закрытом" члене basePath для дальнейшего использования.
void FileBrowser::itemHighlighted(int index) { QString path = basePath + "/" + text(index); if (QFileInfo(path).isFile()) emit picked(path); }
Whenever a list box entry is highlighted (single-clicked), the itemHighlighted() slot is called with the entry's index. We pass it to QListBox::text() to retrieve the file name. We use a QFileInfo object to find out whether the selected entry is a regular file. If it is, we emit the picked() signal.
void FileBrowser::itemSelected(int index) { QString path = basePath + "/" + text(index); if (QFileInfo(path).isDir()) setDir(path); }
Когда запись в списке выбрана (дважды кликнута), слот itemSelected() вызывается со значением индекса записи. Если выбранная запись является каталогом, FileBrowser обновляет себя содержимым этого каталога.
Напишем мальнькую программу, которая позволяет это использовать:
int main(int argc, char *argv[]) { QApplication app(argc, argv); QSplitter win(Qt::Horizontal); QString filter = "*.htm *.html *.txt *.xml"; FileBrowser *fileBrowser = new FileBrowser(filter, &win); QTextBrowser *textBrowser = new QTextBrowser(&win); QObject::connect(fileBrowser, SIGNAL(picked(const QString &)), textBrowser, SLOT(setSource(const QString &))); app.setMainWidget(&win); win.show(); return app.exec(); }
Эта программа создает FileBrowser с левой стороны и QTextBrowser с правой, с разделителем между ними. Мы инициализируем FileBrowser фильтром имен, который совпадает с форматами, поддерживаемыми QTextBrowser.
Возможным усовершенствованием может быть отображение каталогов в отличном от файлов стиле, чтобы было легче их различать. Это потребует использования QListBoxPixmap или подкласса QListBoxItem для отображения записей каталогов.
Copyright © 2004 Trolltech | Trademarks |