Скрещиваем элемент
управления Edit и кнопку просмотра
Автор: PJ Arends
Описание
Обычно, для того, чтобы позволить пользователю
выбрать файл и директорию, создаётся два
элемента управления: Edit и кнопка просмотра,
которая вызывает обычный диалог выбора файла.
Здесь же представлен класс, совмещающий эти два
контрола.
Возможности
- Элемент управления наследуется от класса CEdit.
Все функции-члены CEdit естевственно доступны в
CFileEditCtrl .
Создавать его можно со всеми возможными стилями ES_* .
Команды EM_* и сообщения EN_* работают
точно так же как и в обычном контроле Edit.
- Элипсы кнопки рисуются в неклиентской области
контрола. Кнопку можно размещать как справа так и
слева от текстового блока.
- Элемент управления имеет свои собственные
DDX_FileEditCtrl
и DDV_FileEditCtrl функции обмена данными.
Настройка контрола довольно проста.
- Используя функцию
Create() , можно создать
данный элемент управления в любом окне, т.е. не
только в диалоге или форме.
- Основная цель контрола - это просмотр списка
выбираемых файлов или директорий. Когда
открывается
CFileDialog или SHBrowseForFolder то
текущей становится та директория, которая введа
в данном контроле.
- Элемент управления позволяет использовать
относительные пути, т.е. пользователи могут
вводить
"..\..\любая папка " и контрол
вернёт абсолютный путь относительно текущей
рабочей директории. Если ввести ". " ,
то получим текущую рабочую директорию.
- Элемент управления поддерживает технологию Drag
and Drop файлов и директорий. Для этого его
достаточно создать с расширенным стилем
WS_EX_ACCEPTFILES .
- Размеры контрола можно изменять. Кнопка всегда
сохраняет свою высоту относительно общей высоты
элемента управления.
- При нажатии на кнопку, элемент управления
посылает сообщение
WM_NOTIFY родительскому
окну, давая возможность родительскому окну
закрыть SHBrowseForFolder или CFileDialog .
Комбинация <Ctrl><.> равносильна нажатию на
кнопку.
Использование контрола
Чтобы ключить данный элемент управления в своё
приложение, добавьте в проект файлы FileEditCtrl.h и
FileEditCtrl.cpp. Затем рекомендуется добавить
следующие строки как ресурсы в таблицу строк с
идентификаторами FEC_IDS_* .
// FEC_IDS_ALLFILES будет определён в resource.h если будет находиться
// в ресурсе таблицы строк
#if !defined FEC_IDS_ALLFILES
#define FEC_NORESOURCESTRINGS so this class knows how to handle these strings
#define FEC_IDS_ALLFILES _T"All Files (*.*)|*.*||")
#define FEC_IDS_BUTTONTIP _T("Browse")
#define FEC_IDS_FILEDIALOGTITLE _T("Browse for File")
#define FEC_IDS_SEPERATOR _T(";")
#define FEC_IDS_NOFILE _T("Enter an existing file.")
#define FEC_IDS_NOTEXIST _T("%s does not exist.")
#define FEC_IDS_NOTFILE _T("%s is not a file.")
#define FEC_IDS_NOTFOLDER _T("%s is not a folder.")
#define FEC_IDS_OKBUTTON _T("OK")
#endif
Чтобы использовать контрол в диалоговом окне с
установками поумолчанию, создайте улемент
управления edit в шаблоне диалога, добавьте
переменную CString в класс диалога и в DoDataExchange()
добавьте функции DDX_FileEditCtrl() и DDV_FileEditCtrl() .
В данном примере используется: для контрола edit
идентификатор IDC_EDIT1 и CString m_String .
void CFileEditDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFileEditDlg)
//}}AFX_DATA_MAP
DDX_FileEditCtrl(pDX, IDC_EDIT1, m_String, FEC_FOLDER |
FEC_TRAILINGSLASH | FEC_BUTTONTIP);
DDV_FileEditCtrl(pDX, IDC_EDIT1);
...
}
Поскольку эти функции не поддерживаются класс
визардом, то они должны быть помещены за
пределами блока AFX_DATA_MAP .
Если Вам потребуется разместить несколько
таких контролов в диалоге (например для выбора
нескольких файлов), то добавьте переменную CFileEditCtrl
в Ваш диалоговый класс. В DoDataExchange()
добавьте вторую функцию DDX_FileEditCtrl() . Вот
как это будет выглядеть:
void CFileEditDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFileEditDlg)
//}}AFX_DATA_MAP
...
DDX_FileEditCtrl(pDX, IDC_EDIT2, m_FileEditCtrl,
FEC_FILE | FEC_BUTTONLEFT | FEC_BUTTONTIP | FEC_CLIENTTIP);
DDV_FileEditCtrl(pDX, IDC_EDIT2);
}
Затем в OnInitDialog() , получаем указатель на
структуры OPENFILENAME либо BROWSEINFO , и
устанавливаем их соответствующим образом. В
демо-проекте установлена m_FileEditCtrl для
обеспечения выбора нескольких файлов.
BOOL CFileEditDlg::OnInitDialog()
{
CDialog::OnInitDialog();
...
// Изменяем контрол для выбора нескольких файлов
if (OPENFILENAME *ofn = m_FileEditCtrl.GetOpenFileName())
{
ofn->Flags |= OFN_ALLOWMULTISELECT;
buffer = new TCHAR[2000];
::ZeroMemory(buffer, 2000);
ofn->lpstrFile = buffer;
ofn->nMaxFile = 2000;
}
m_FileEditCtrl.SetClientTipText("Files");
return TRUE; // возвращаем TRUE, если на контроле не установлен фокус
}
Для получения имён файлов из контрола,
используем функции-члены GetStartPosition() и GetNextPathName() .
В демо-проекте это сделано в функции InitInstance() ,
а TRACE позволяет просмотреть, какой файл
был выбран пользователем.
BOOL CFileEditApp::InitInstance()
{
...
CFileEditDlg dlg;
m_pMainWnd = &dlg
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
int n = 1;
TRACE ("\nFiles entered :\n");
POSITION pos = dlg.m_FileEditCtrl.GetStartPosition();
while (pos)
{
CString x = dlg.m_FileEditCtrl.GetNextPathName(pos);
TRACE ("%03d - %s\n",n, x);
n++;
}
TRACE ("Directory entered :\n %s\n\n",dlg.m_String);
}
...
return FALSE;
}
Элемент управления посылает сообщение WM_NOTIFY
с уведомляющим кодом FEC_NM_POSTBROWSE после
того как диалог вернёт управление и текст в окне
контрола обновится. Указатель NMHDR*
указывает на структуру FEC_NOTIFY , но параметр
LRESULT будет игнорироваться.
typedef struct tagFEC_NOTIFY {
NMHDR hdr;
CFileEditCtrl* pFEC; // указатель на контрол, который
// отсылает уведомляющее сообщение
tagFEC_NOTIFY (CFileEditCtrl *FEC, UINT code);
} FEC_NOTIFY;
#define FEC_NM_PREBROWSE 1 // уведомляющий код, отправляемый
// до появления диалога
#define FEC_NM_POSTBROWSE 2 // уведомляющий код, отправляемый
// после появления диалога
Постоянное обновление данного контрола
доступно сдесь.
|