Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Лабораторна робота №6.
Тема роботи: Створення дочірніх елементів керування: смуги прокручування, списки.
Ціль роботи: Придбання досвіду створення прикладного програмного забезпечення для Windows з використанням дочірніх елементів керування.
ТЕОРЕТИЧНА ЧАСТИНА
Існує два способи створення смуг прокручування у вікні додатка.
Перший спосіб створення смуг прокручування ґрунтується на тому, що при створенні свого власного вікна чи дочірнього вікна керування додаток може вказати, що вікно повинне мати смуги прокручування.
Цей метод дуже простий, але з його допомогою можна створити тільки одну горизонтальну й одну вертикальну смуги прокручування. Для того щоб у вікна з'явилися ці смуги прокручування, при створенні вікна в третьому параметрі функції CreateWindow необхідно вказати стиль вікна WS_VSCROLL чи WS_HSCROLL.
По-друге, можна створити смугу прокручування дочірнє вікно керування за допомогою функції CreateWindow. Для цього в першому параметрі потрібно вказати клас вікна “scrollbar”.
У цій лабораторній буде розглянутий перший спосіб створення смуг прокручування.
С допомогою класу “listbox” можна створювати одноколоночні і багатоколоночні списки, що мають вертикальну (для одноколоночних списків) і горизонтальну (для многоколоночних списків) смугу перегляду.
Список може бути як з одиночним вибором, так і з множинним. Останній дозволяє користувачу вибирати більш одного пункту списку.
Для створення списку додаток повинний викликати функцію CreateWindow, передавши їй як перший параметр покажчик на рядок “listbox”.
Вікно списку посилає повідомлення WM_COMMAND своєму батьківському вікну, коли в списку вибирається який-небудь пункт. Батьківське вікно може визначити, який пункт списку обраний.
Розглянемо стилі вікон списків
При стилі, що задається по умовчанню, вікна списку (тільки стиль WS_CHILD) повідомлення WM_COMMAND батьківському вікну не посилаються. Це означає, що програмі варто опитувати вікно списку за допомогою передачі йому повідомлень щодо обраних у списку пунктів.
В вікна списку майже завжди включають ідентифікатор стилю LBS_NOTIFY, що дозволяє батьківському вікну одержувати від вікна списку повідомлення WM_COMMAND.
Якщо додаток бажає мати можливість сортувати елементи списку, йому необхідно використовувати у вікні списку й інший часто використовуваний ідентифікатор стилю LBS_SORT.
По умовчанню, у списку допускається вибір тільки одного пункту. Якщо необхідно створити список з можливістю вибірки відразу декількох пунктів, то варто використовувати стиль LBS_MULTIPLESEL.
По умовчання, віконна процедура вікна списку виводить тільки список елементів без якої-небудь рамки навколо. Рамку можна додати за допомогою стилю WS_BORDER.
Для прокручування вмісту за допомогою миші і вертикальної смуги прокручування варто використовувати стиль WS_VSCROLL.
В заголовних файлах Windows визначається стиль списку, що називається LBS_STANDARD. Стиль LBS_STANDARD містить у собі найбільше часто використовувані стилі списку. Він визначається як комбінація
(LBS_NOTIFY|LBS_SORT|WS_VSCROLL|WS_BORDER)
Розглянемо повідомлення, що можуть посилати батьківські вікна вікнам списків для їхнього заповнення і подальшої роботи з ними
Після створення вікна списку в нього варто додати рядки тексту елементи списку. Це робиться за допомогою функції SendMessage за допомогою відправлення повідомлень вікну списку. Посилання на рядок тексту (на елемент) звичайно здійснюються через індекс, що починається з 0, що відповідає самому верхньому елементу списку.
Специфічних повідомлень, що батьківське вікно може послати вікну списку за допомогою функції SendMessage, досить багато. Розглянемо найбільше часто уживані:
Самим могутнім повідомлення для вікон списку є повідомлення LB_DIR. Наступний оператор заповнює список переліком файлів каталогу, іноді з підкаталогами й іменами доступних дисків:
SendMessage(hWndList, LB_DIR, iAttr,(LPARAM)szFileSpec);
Параметр iAttr це код атрибута файлу, він визначає атрибути відображуваних у списку файлів.
Параметр szFileSpec це покажчик на рядок, що задає специфікацію файлів. Така специфікація не впливає на підкаталоги, що містяться в списку.
Розглянемо, які значення, об'єднані порозрядовим АБО, можна використовувати для завдання атрибутів файлів:
Як молодший байт використовується звичайний атрибут файлу: DDL_READWRITE звичайний файл; DDL_READONLY файл тільки для читання, DDL_HIDDEN схований файл; DDL_SYSTEM системний файл; DDL_DIRECTORY підкаталог; DDL_ARCHIVE файл із встановленим архівним бітом.
Старший байт забезпечує деякий додатковий контроль над виведеними іменами: DDL_DRIVES включення імен дисків; DDL_EXCLUSIVE включати тільки файли з зазначеними атрибутам.
От як буде, наприклад, виглядати виклик, що виводить у список імена усіх файлів поточного каталогу й імена всіх підкаталогів цього каталогу (у виді [subdir]):
SendMessage(hWndList,LB_DIR,
DDL_READWRITE| // звичайний файл
DDL_READONLY| // файл тільки для читання
DDL_HIDDEN| // схований файл
DDL_SYSTEM| // системний файл
DDL_DIRECTORY| // підкаталог
DDL_ARCHIVE, // файл із встановленим архівним бітом
(LPARAM) "*.*");
Якщо для списку не використовується стиль LBS_SORT, то імена файлів і каталогів виводяться упереміш, а імена доступних дисків виявляються наприкінці списку.
Зауваження. Коли користувач клацає мишею над вікном списку, вікно списку одержує фокус уведення. Якщо вікно списку має фокус уведення, то для вибору пунктів можна користатися як мишею, так і клавіатурою.
Розглянемо повідомлення, що можуть посилати списки батьківським вікнам.
Вікно списку посилає батьківському вікну повідомлення WM_COMMAND, у старшому слові параметра wParam цього повідомлення міститься код повідомлення:
Зауваження. Вікно списку посилає коди повідомлення LBN_SELCHANGE і LBN_DBLCLK тільки в тому випадку, якщо в стиль дочірнього вікна включений ідентифікатор LBS_NOTIFY.
Для обробки повідомлення від списку віконна функція батьківського вікна може містити код наступного виду:
case WM_COMMAND:
{ UINT idCtl=LOWORD(wParam); // ідентифікатор дочірнього вікна
UINT code=HIWORD(wParam); // код повідомлення
HWND hChild=(HWND)lParam; // дескриптор дочер. вікна
If(idCtrl==ID_listbox&&code==LB_SELCHANGE)
{
// поточний вибір у списку змінився
. . .
}
};
return 0;
Для приклада створимо додаток CONTROLS, що використовує такі дочірні елементи керування як списки і смуги прокручування, що є частиною вікна редагування. Створюваний додаток буде аналогом відомої в операційній системі UNIX утиліти head, що виводить на екран початкові рядки файлу. Однак, завдяки смугам прокручування, на екран буде виводитися файл цілком якщо його розмір не перевищує 8 кілобайт.
Зовнішній вигляд програми буде наступним:
Рисунок 2.8 Зовнішній вигляд програми CONTROLS.
Створення додатка, що використовує списки і смуги прокручування.
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = " Head" ;
MSG msg ;
WNDCLASS wndclass ;
…
RegisterClass (&wndclass) ;
hWnd = CreateWindow (szAppName, " File Head ", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ;
…
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
TEXTMETRIC tm ;
switch (iMsg)
{
case WM_CREATE :
hdc = GetDC (hwnd) ;
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
GetTextMetrics (hdc, &tm) ;
ReleaseDC (hwnd, hdc) ;
rect.left = 20 * tm.tmAveCharWidth ;
rect.top = 3 * tm.tmHeight ;
…
При малюванні на екрані (у вікні) додатку не потрібно створювати контекст пристрою, використовуючи CreateDC. Замість цього воно може одержати дескриптор контексту пристрою, що представляє робочу область вікна за допомогою функції GetDC чи ціле вікно за допомогою функції GetWindowDC.
Потім вибираємо шрифт SYSTEM_FIXED_FONT у контекст відображення.
#include <windows.h>
#include <direct.h>
#define MAXPATH 256
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
…
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
RECT rect ;
HDC hdc ;
PAINTSTRUCT ps ;
TEXTMETRIC tm ;
UINT ID_edit1=1;
static HWND hwndList, hwndText, hWndEdit;
switch (iMsg)
{
case WM_CREATE :
…
rect.left = 20 * tm.tmAveCharWidth ;
rect.top = 3 * tm.tmHeight ;
hwndList = CreateWindow ("listbox", NULL,
WS_CHILDWINDOW | WS_VISIBLE | LBS_STANDARD,
tm.tmAveCharWidth, tm.tmHeight * 3,
tm.tmAveCharWidth * 13,
tm.tmHeight * 10,
hwnd, (HMENU) 1,
(HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
NULL) ;
hwndText = CreateWindow ("static", getcwd (szBuffer, MAXPATH),
WS_CHILDWINDOW | WS_VISIBLE | SS_LEFT,
tm.tmAveCharWidth, tm.tmHeight,
tm.tmAveCharWidth * MAXPATH, tm.tmHeight,
hwnd, (HMENU) 2,
(HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
NULL) ;
hWndEdit=CreateWindow("edit",NULL, WS_CHILDWINDOW|ES_MULTILINE| WS_VISIBLE|WS_BORDER|WS_HSCROLL|WS_VSCROLL|ES_AUTOVSCROLL| ES_AUTOHSCROLL,
150,50,470, 400, hwnd,(HMENU)ID_edit1,
((LPCREATESTRUCT) lParam) -> hInstance,
NULL);
Кожне дочірнє вікно має дескриптор вікна і його ідентифікатор, що є унікальним серед інших. Знання одного з цих елементів дозволяє вам одержати іншиї. Якщо ви знаєте дескриптор дочірнього вікна, то можете одержати його ідентифікатор у такий спосіб:
id = GetWindowLong (hwndChild, GWL_ID);
Тут, при створенні статичного елемента керування, використовується функція getcwd(), що служить для одержання поточного робочого каталогу. Т.е. повний шлях до поточного робочому каталогу виводиться в статичному елементі керування.
Створення смуг прокручування у вікні редагування, здійснюється шляхом додавання наступних значень у завданні стилю вікна: WS_HSCROLL| WS_VSCROLL.
…
hWndEdit=CreateWindow("edit",NULL, WS_CHILDWINDOW|ES_MULTILINE|
WS_VISIBLE|WS_BORDER|WS_HSCROLL|WS_VSCROLL| ES_AUTOVSCROLL|ES_AUTOHSCROLL,
150,50,470, 400, hwnd,(HMENU)ID_edit1,
((LPCREATESTRUCT) lParam) -> hInstance,
NULL);
SendMessage (hwndList, LB_DIR, DDL_READWRITE|DDL_READONLY| DDL_HIDDEN|DDL_SYSTEM|DDL_DIRECTORY, (LPARAM) "*.*") ;
return 0 ;
…
SendMessage (hwndList, LB_DIR, DDL_READWRITE|DDL_READONLY| DDL_HIDDEN|DDL_SYSTEM|DDL_DIRECTORY, (LPARAM) "*.*") ;
return 0 ;
case WM_SIZE :
rect.right = LOWORD (lParam) ;
rect.bottom = HIWORD (lParam) ;
return 0 ;
…
rect.bottom = HIWORD (lParam) ;
return 0 ;
case WM_SETFOCUS :
SetFocus (hwndList) ;
return 0 ;
…
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static char szFile[MAXPATH], szBuffer[MAXPATH + 1] ;
static HWND hwndList, hwndText, hWndEdit;
static OFSTRUCT ofs ;
static BOOL bValidFile ;
case WM_SETFOCUS :
SetFocus (hwndList) ;
return 0 ;
case WM_COMMAND :
if (LOWORD (wParam) == 1 && HIWORD (wParam) == LBN_DBLCLK)
{
if (LB_ERR == (i = SendMessage (hwndList,
LB_GETCURSEL, 0, 0L)))
break ;
SendMessage (hwndList, LB_GETTEXT, i, (LPARAM) szBuffer) ;
if (-1 != OpenFile (szBuffer, &ofs, OF_EXIST | OF_READ))
{
bValidFile = TRUE ;
strcpy (szFile, szBuffer) ;
getcwd (szBuffer, MAXPATH) ;
if (szBuffer [strlen (szBuffer) - 1] != '\\')
strcat (szBuffer, "\\") ;
SetWindowText (hwndText, strcat (szBuffer, szFile)) ;
}
else
{
bValidFile = FALSE ;
szBuffer [strlen (szBuffer) - 1] = '\0' ;
chdir (szBuffer + 1) ;
getcwd (szBuffer, MAXPATH) ;
SetWindowText (hwndText, szBuffer) ;
SendMessage (hwndList, LB_RESETCONTENT, 0, 0L) ;
SendMessage (hwndList, LB_DIR, 0x37, (LONG) "*.*") ;
}
InvalidateRect (hwnd, NULL, TRUE) ;
}
return 0 ;
При обробці в WndProc повідомлення WM_COMMAND, для контролю обраного пункту, використовується функція Windows OpenFile. Ця функція в загальному виді виглядає так:
HFILE OpenFile(
LPCSTR lpFileName, // покажчик на ім'я файлу
LPOFSTRUCT lpReOpenBuff, // покажчик на буфер інформації про файл
UINT uStyle // режим відкриття
);
Якщо функція OpenFile повертає помилку, значить обраний не файл, а, можливо, підкаталог і змінна bValidFile встановлюється в FALSE. Потім для зміни підкаталогу в програмі HEAD використовується функція chdir. Програма посилає вікну списку повідомлення LB_RESETCONTEXT для відновлення контексту і повідомлення LB_DIR для заповнення вікна списку переліком файлів нового підкаталогу.
#include <windows.h>
#include <direct.h>
#define MAXPATH 256
#define MAXREAD 8192
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
…
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static char sReadBuffer[MAXREAD] ;
int iHandle, i ;
case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT)) ;
SetBkColor (hdc, GetSysColor (COLOR_BTNFACE)) ;
if (bValidFile && -1 != (iHandle =
OpenFile (szFile, &ofs, OF_REOPEN | OF_READ)))
{
i = _lread (iHandle, sReadBuffer, MAXREAD) ;
_lclose (iHandle) ;
SetWindowText(hWndEdit, sReadBuffer);
}
else
bValidFile = FALSE ;
EndPaint (hwnd, &ps) ;
return 0 ;
При обробці повідомлення WM_PAINT у віконній процедурі відкривається файл із використанням функції Windows OpenFile. Значенням функції, що повертається, є дескриптор файлу MS-DOS, що може бути переданий функціям Windows _lread і _lclose. Вміст файлу виводиться у вікно редагування за допомогою функції SetWindowText().
ПРАКТИЧНА ЧАСТИНА
2. Створіть програму, аналогічну програмі завдання 2 Лабораторної роботи №5, але замість радіокнопок використовуйте список. Результат визначається в залежності від обраного рядка списку.
Контрольні питання: