kvv's home

Форма входа

Категории раздела

Лекции [14]
Разное [4]
Статьи на тему WM, не попавшие в лекции по разным причинам.

Поиск

Каталог статей

Главная » Статьи » Программирование под Windows Mobile » Разное

Пишем свой FileOpenDlg

Интро
Рано или поздно, но любой WinCE программер (впрочем как и программер пишущий под другие ОС) сталкивается с необходимостью использования диалога для выбора файлов. И вот тут начинаются проблемы. Стандартный диалог открытия файла в WM, мягко говоря, неудобный. нет, если вам надо выбирать файлы, лежащие только в стандартных папках My Pictures, My Documents и т.д., то подойдет и стандартный диалог, но если нужно дать пользователю возможность выбора файлов из любой папки с переходом по подкаталогам, то стандартный диалог нам в этом не товарищ. Как выходят из этой ситуации? Очень просто - пишут свой диалог выбора файлов. =) Вот чем-то подобным мы сейчас и займемся.

Как там с этим у Windows?
Стандартный диалог вызывается следующим образом:

 TCHAR szFileName[MAX_PATH] ={0};
 OPENFILENAME ofn = {0};
 ofn.lStructSize = sizeof(ofn);
 ofn.hInstance = g_hInst;
 ofn.hwndOwner = hWnd;
 ofn.lpstrFile = szFileName;
 ofn.lpstrFilter = _T("All Files (*.*)\0*.*\0\0");
 ofn.nMaxFile = MAX_PATH;
 ofn.lpstrInitialDir = L"Windows\\";
 GetOpenFileName(&ofn);

в результате получаем следующее:

красиво, но не удобно. =)
Попробуем создать что-то более правильное.

Поехали...
Сначала определимся с функционалом.
Наш диалог должен уметь отображать файлы и каталоги по маске, давать возможность ходить по каталогам, выбирать файлы или каталоги, отображать необходимую информацию о них. Диалог должен легко интегрироваться в любой проект и не нести с собой лишних файлов и поддерживать любые разрешения экрана.
Диалог должен вызываться одной функцией, и иметь минимум входных параметров. Чтобы не передавать в функцию диалога кучу параметров, сведем их в единую структуру (что позволит нам ее расширять в дальнейшем)

typedef struct tagFSD {
 DWORD cbSize;
 HWND hwndOwner;
 TCHAR szFileName[MAX_PATH];
 TCHAR szTitle[32];
 TCHAR szInitialDir[MAX_PATH];
 DWORD Flags;
} FILESYSTEMDLGW, *LPFILESYSTEMDLG;
    Рассмотрим парамеры структуры:
  • cbSize - размер структуры (для будущего использования)
  • hwndOwner - хендл родительского окна (нужен для правильной организации диалога)
  • szFileName - буфер полученного имени файла
  • szTitle - заголовок окна (для будущего использования)
  • szInitialDir - начальный каталог сканирования (для будущего использования, пока ищем от корня)
  • Flags - флаги всякие (для будущего использования)

Перейдем непосредствено к диалогу. Для первой версии диалога нам достаточно двух дочерних контролов EDIT и LISTVIEW. Поскольку у нас стоит условие не использования лишних файлов, то придется отказаться от файла ресурсов. Само окно будем создавать с помощью WinAPI функции DialogBoxIndirect, структуру описания диалога для которой можно собрать руками в памяти. С помощью этой функции можно создавать диалоги с любым количеством дочерних контролов, но мы опишем только родительское окно, а дочерние контролы создадим с помощью CreateWindow. Это проще, чем разбираться с достаточно сложной структурой описания контролов.
Проделаем это.
1. Создадим буфер в памяти
 HGLOBAL membuf = GlobalAlloc(GMEM_ZEROINIT,1024);
 if (!membuf) return FALSE;
2. Заполним буфер данными
 DLGTEMPLATE* dt = (DLGTEMPLATE*)GlobalLock(membuf);
 dt->cdit = 0;
 dt->style = WS_POPUP | DS_MODALFRAME | DS_SETFOREGROUND ; // window styles
 dt->cx = dt->cy = 200; // window size
 LPWORD p = (LPWORD)(dt+1);
 *p++=0; // end of data
 *p++=0;
3. Запустим диалог
 GlobalUnlock(membuf);
 BOOL bResult = FALSE; 
 if (IDOK == DialogBoxIndirect(GetModuleHandle(NULL),(LPDLGTEMPLATE)membuf,g_pFSData->hwndOwner,WndProc))
 {
 lstrcpy(Data->szFileName, g_szSelectedPath);
 bResult = TRUE;
 } 
 GlobalFree(membuf); 
 return bResult;

Теперь нужно разобраться с диалоговой функцией окна (у нас она зовется WndProc).
Берем станндартный шаблон диалоговой функции и добавляем реакцию на WM_INITDIALOG:
 // Create a Done button and size it. 
 SHINITDLGINFO shidi;
 shidi.dwMask = SHIDIM_FLAGS;
 shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU;
 shidi.hDlg = hDlg;
 SHInitDialog(&shidi);
 // Create controls
 g_hwndInfo = CreateWindow(L"STATIC",0,WS_CHILD | WS_VISIBLE | SS_LEFT | WS_BORDER,0,0,100,10,hDlg,0,GetModuleHandle(NULL),NULL);
 ::SetWindowText(g_hwndInfo,L"Select file");
 g_szCurrentPath[0] = 0;
 g_szSelectedPath[0] = 0;
 g_hwndList = CreateWindow(L"LISTBOX",0,WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY | WS_BORDER,0,10,100,10,hDlg,0,GetModuleHandle(NULL),NULL);//::GetDlgItem(hDlg,8001);
 BuildFilesList(g_hwndList);

и на WM_SIZE:
 RECT rt;
 ::GetClientRect(g_hwndInfo,&rt);
 int nHeight = 16;
 ::GetClientRect(hDlg,&rt);
 ::SetWindowPos(g_hwndInfo,NULL,0,0,rt.right-rt.left,nHeight,SWP_NOZORDER);
 ::SetWindowPos(g_hwndList,NULL,0,nHeight,rt.right-rt.left,rt.bottom-rt.top-nHeight,SWP_NOZORDER);

Пытливый взгляд заметит неопознанную функцию BuildFilesList. Ага, как видно из названия, функция строит список файлов.
Поглядим, что она делает:
void BuildFilesList(HWND hItem, LPTSTR szInitDir = NULL)
{
 ::SendMessage(hItem,LB_RESETCONTENT,0,0);
 TCHAR szDir[MAX_PATH] = {0};
 lstrcpy(szDir,g_szCurrentPath);
 if (NULL != szInitDir)
 {
 lstrcat(szDir,szInitDir);
 } 
 if (szDir[lstrlen(szDir)] != L'\\')
 {
 lstrcat(szDir,L"\\"); 
 }
 lstrcpy(g_szCurrentPath,szDir);
 lstrcat(szDir,L"*.*");
 WIN32_FIND_DATA fd ={0};
 HANDLE hFind = FindFirstFile(szDir,&fd);
 if (INVALID_HANDLE_VALUE != hFind)
 {
 do 
 {
 TCHAR szFile[MAX_PATH] = {0};
 lstrcpy(szFile,fd.cFileName);
 if (0 != (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
 {
 ::SendMessage(hItem,LB_INSERTSTRING,0,(LPARAM)szFile);
 ::SendMessage(hItem,LB_SETITEMDATA,0,1);
 } else
 {
 ::SendMessage(hItem,LB_ADDSTRING,0,(LPARAM)szFile);
 int cnt = (int)::SendMessage(hItem,LB_GETCOUNT,0,0);
 if (cnt>0)::SendMessage(hItem,LB_SETITEMDATA,cnt-1,0);
 }
 }while (FindNextFile(hFind,&fd)>0);
 }
 FindClose(hFind);
 if (lstrcmp(g_szCurrentPath,L"\\"))
 {
 ::SendMessage(hItem,LB_INSERTSTRING,0,(LPARAM)L"..");
 ::SendMessage(hItem,LB_SETITEMDATA,0,2);
 }
 ::SendMessage(hItem,LB_SETCURSEL,0,0);
}
Вобщем-то ничего особенного, стандартный поиск файлов с заполнением ListBox. В будущем расширим эту функцию для поска только каталогов или поиска файлов по маске, пока же будет так, как есть.
Теперь осталось сделать навигацию по каталогам и вывести информацию о текущем файле.
Снова идем в WndProc и добавляем обработку событий ListBox
case WM_COMMAND:
 // select OK button
 if (LOWORD(wParam) == IDOK)
 {
 EndDialog(hDlg, LOWORD(wParam));
 return (INT_PTR)TRUE;
 }
 // select file by stylus 
 if (LBN_DBLCLK == HIWORD(wParam))
 {
 HWND hList = (HWND)lParam;
 TCHAR szFileName[MAX_PATH] = {0};
 int idx = (int)::SendMessage(hList,LB_GETCURSEL,0,0);
 ::SendMessage(hList,LB_GETTEXT,idx,(LPARAM)szFileName);
 int Data = ::SendMessage(hList,LB_GETITEMDATA,idx,0);
 if (Data == 2)
 {
 OneDirUp(g_szCurrentPath);
 BuildFilesList(hList);
 } else if (Data == 1) BuildFilesList(hList,szFileName);
 SetFileInfo(g_hwndInfo);
 }
 // select file by keyboard 
 if (LBN_SELCHANGE == HIWORD(wParam))
 {
 HWND hList = (HWND)lParam;
 TCHAR szFileName[MAX_PATH] = {0};
 int idx = (int)::SendMessage(hList,LB_GETCURSEL,0,0);
 ::SendMessage(hList,LB_GETTEXT,idx,(LPARAM)szFileName);
 lstrcpy(g_szSelectedPath,g_szCurrentPath);
 lstrcat(g_szSelectedPath,szFileName);
 SetFileInfo(g_hwndInfo);
 }
 break;
Текущий каталог мы храним в глобальной переменной g_szCurrentPath. Функция OneDirUp предназначена для перехода в родительский каталог:
void OneDirUp(LPTSTR szPath)
{
 int MaxCnt = lstrlen(szPath);
 TCHAR *p = szPath + MaxCnt-2;
 while ((--MaxCnt >0)&&(*p != L'\\'))p--;
 *p = 0;
}
Функция SetFileInfo заполняет StaticText информацией о выбранном файле/каталоге:
void SetFileInfo(HWND hInfo = NULL)
{
 TCHAR szFileInfo[300] = {0};
 HANDLE hFile = CreateFile(g_szSelectedPath,GENERIC_READ,0,0,OPEN_EXISTING,0,0);
 DWORD dwSize = 0;
 DWORD dwAttr = GetFileAttributes(g_szSelectedPath);
 if (INVALID_HANDLE_VALUE != hFile)
 {
 BY_HANDLE_FILE_INFORMATION hfi = {0};
 if (GetFileInformationByHandle(hFile,&hfi))
 {
 dwSize = hfi.nFileSizeLow;
 } else
 {
 dwSize = GetFileSize(hFile,NULL);
 }
 }
 CloseHandle(hFile);
 TCHAR pref = L' ';
 if (dwSize>1000)
 {
 dwSize = dwSize / 1024;
 pref = L'K';
 }
 if (dwSize>1000)
 {
 dwSize = dwSize / 1024;
 pref = L'M';
 }
 TCHAR *p = g_szSelectedPath + lstrlen(g_szSelectedPath)-1;
 while ((p > g_szSelectedPath)&&(*p!=L'\\')) p--;
 p++;
 if (0 == (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
 {
 wsprintf(szFileInfo,L"%s %d%cb",p,dwSize,pref);
 } else
 { if (!lstrcmp(p,L".."))
 lstrcpy(szFileInfo,g_szCurrentPath);
 else
 wsprintf(szFileInfo,L"\\%s",p);
 }
 if (NULL != hInfo)
 ::SetWindowText(hInfo,szFileInfo);
 else
 ::MessageBox(0,szFileInfo,L"File info",MB_ICONINFORMATION | MB_OK);
}
Ну вот, простой диалог выбора файла готов. Теперь можно подумать над расширением функционала диалога. Для начала, выводить расширенную информацию об объектах.

продолжение следует...

Категория: Разное | Добавил: kvv (14.12.2007) | Автор: Владимир Кошелев E W
Просмотров: 10649 | Комментарии: 6 | Рейтинг: 5.0/2
Всего комментариев: 6
6 kisxlque  
0
From being able to see when you aren't at home through your thermostat perhaps to controlling your refrigerator to altering the your lights already there are apps that can be used to access the lights and temperature in the home from afar petty criminals have an almost endless slate of mischief to choose from. http://www.umts-total.de/ - montblanc online shop is Ali getting ready to film her second attempt at finding love on the spring version on The Bachelorette next year? Wetpaint Entertainment caught up with Ali Fedotowsky and of course. why don't the hijackers notice a laptop screen that's been conveniently left open to give authorities a clear view of the train? Its teenage owner uses it to convey his love to his needy girlfriend. http://www.singing-exercises.com/ - red wing shoes sale and mules a convenient shoe if you are taking of and putting on your shoes regularly but it does change the way you walk making them less ideal if you plan to be walking long distances. History of the SuperstitionSome authorities claim that Friday the 13th's reputation as an omen of ill fortune begins with the persecution byKing Philip the Fairof France not to be confused withPhilip the Handsomeof theKnights Templarson trumped-up charges. http://www.w-bdesigns.co.uk/ - mbt uk Spend a few minutes reflecting on what the holiday is really about can help you feel a deeper sense of peace and will provide a cherished memory for your children because in the end. The Pope's own record on gay rights was marred late last year after the Bishop of Malta said the pontiff was shocked by gay adoption in an interview with The Sunday Times of Malta. http://www.theater-im-loft.com/ - clarisonic mia Increasingly many small businesses and professionals are realizing it is not necessary for them to have a physical presence where they must meet always meet customers and clients. From the early days when the religious zealots hunted down all people who did not go "with the flow" to the current generation who is fortunate enough in most places to be able to publicly embrace the religion of Wicca. http://www.1to1datingdirectory.co.uk/ - fred perry barrel bag sale Fadden pointed out that the Chicago Rockford International Airport is a big selling point to the selection committee making the decision on where to locate the company's next campus.

5 reizeKerb  
0
[color=color_url - Водонепроницаемая экшен-камера. Всецело новая, компактная и в своём роде уникальная http://www.centroline.ru видеокамера[color=color_url - ради экстремальных видов спорта и активного отдыха.Она представляет собой мини-камеру, которая позволят вам посылать записанное фото и видео стойком на принадлежащий айфон, смартфон alias планшетный компьютер, а также позволяет воззриться в режиме реального времени сообразно каналу беспроводной связи Wi-Fi.

4 SashaTravel  
0
Всегда перед командировкой или отпуском встаёт вопрос покупки билетов на самолет или Ж\д билетов. Поделитесь кто и как покупает http://xn--80acmldkekdf7c.xn--p1ai/ - авиабилеты дешево или ж\д билеты? Покупаете ли вы http://xn--80acmldkekdf7c.xn--p1ai/ - билеты на самолет онлайн или пользуетесь кассами у метро?

3 Piotr  
0
Haha, suhdoln't you be charging for that kind of knowledge?!

2 components  
0
Купим комплектующие:

В упаковках
Покупаем с хранения оптом разъемы шр, 2рм, 2рмдт, 2рмд, 2ртт, двигатели рд-09, дши-200, лампочки и многое другое.

Ждем ваших предложений.
ICQ 177-211-010 tel:+38 (066) 239-82-50
Руслан
[url=http://raritet-komplekt.com]Электронные компоненты и электротехника

1 XroM  
0
А вы не могли бы выложить проект с этим диалогом, и еще был бы рад увидеть продолжение статьи, спасибо.

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Друзья сайта

  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Облако тэгов