Лабораторна робота №4 Тема – стандартні класи вікон та їх типи. Мета – зрозуміти поняття вікна в операційній системі Windows. ТЕОРЕТИЧНІ ПОЛОЖЕННЯ Все, що бачить користувач на екрані в системі WINDOWS є вікном. Вікно – це графічна оболонка, через яку програма може спілкуватися з користувачем. Якщо програмі не потрібно спілкуватись, то вона може і не створювати вікна. Вікно може володіти набором інших вікон, які називаються дочірніми (кнопки, рядки вводу, і т.д.). Кожне вікно має власний набір властивостей який відрізнятися певною специфікою спілкування з користувачем. Такі специфічні особливості називаються класом вікна. Існують стандартні класи, наприклад, вікно–регулювач, вікно-кнопка, вікно для вводу тексту, вікно-підказка та інші. Кожний стандартний клас має унікальну назву, яка дійсна для всіх версій операційних систем WINDOWS. Нижче приведено перелік стандартних класів вікона: BUTTON Стандартна прямокутня кнопка COMBOBOX Комбінований список з полем редагування у верхній частині або випадний список вибору. EDIT Прямокутний елемент редагування для введення тексту користувачем. Може містити одну або декілька рядків. LISTBOX Елемент типу список. Елемент управління, що містить список рядків, які можуть бути вибрані. MDICLIENT Клієнтське вікно багатодокументного інтерфейсу (MD1 — multiple-document interface). Це вікно отримує повідомлення, які управляють дочірніми вікнами багатодокументного інтерфейсу в застосуванні. Для правильної роботи застосування багатодокументного інтерфейсу необхідно створити вікно MIDIСLIENT. RICHEDlT Елемент управління Rich Edit версії 1.0. Елемент управління такого типу дозволяє редагувати текст з багатьма шрифтами і стилями. У Windows 2000 елемент управління цього типу емулює версію 1.0 на основі версії 3.0. SCROLLBAR Елемент управління лінійкою прокрутки. STATIC Елемент управління статичним текстом. Застосовується для розміщення у вікні тексту або рамок.
Для створення вікна використовується функція CreateWindowEx. Опис функції можна знайти у довіднику. Це все добре, але як створити вікно з кнопками, рядками вводу і т.п., і заставити виконувати певну дію, наприклад, при натисненні кнопки або руханні мишки над вікном? Розберемося як будувати складні вікна. Першим кроком потрібно створити новий клас вікна, оскільки такого екземпляру у системі немає. Мається на увазі, є стандартні вікна, типу "кнопка", "рядок вводу", але немає стандартного вікна, який би містив в собі, наприклад, кнопку і рядок вводу. Для створення нового класу використовується процедура RegisterClassEx. Хоча документацію по функціям можна знайти у довіднику, для зрозумілості кожну функцію розглянемо детально. RegisterClassEx Функція RegisterClassEx реєструє віконний клас для подальшого використання у функції CreateWindowEx. ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx // Вказівник на структуру типу WNDCLASSEX ); Результат: Якщо функція має успіх, значення, що повертається - атом класу, який унікально ідентифікує клас, що реєструється. В структурі ми описуємо всі можливості та властивості нового класу вікна. Розглянемо детально структуру. WNDCLASSEX Структура для реєстрації класу вікна struct WNDCLASSEX ( UINT cbSize; // розмір WNDCLASSEX структури (48 байт) UINT style; // властивість вікна, допускаються всі можливі комбінації значень. Якщо це значення нуль (NULL), Windows встановлює властивість автоматично Див. стилі вікна CS_; WNDPROC lpfnWndProc; // адреса функції вікна, котра обробляє повідомлення вікна даного класу, або нуль, якщо у функції немає процедури обробки; int cbClsExtra; // число додаткових байт, для розміщення власних даних, що відносяться до класу. В основному значення рівне нуль (NULL); int cbWndExtra; // число додаткових байт, для розміщення всіх структур, що створюються спільно з даним класом, для зберігання власних даних, що використовуються у вікні. В основному значення рівне нуль (NULL); HINSTANCE hInstance; // хендл модуля програми Див. функ.GetModuleHandle; HICON hIcon; // хендл іконки, що буде відображуватися у панелі завдань. Іконку можна завантажити з власних ресурсів, або бути одною з констант Див. IDI_ HCURSOR> hCursor; // хендл курсору вікна. Може бути завантажене з власних ресурсів або з ресурсів системи Див. IDC_ HBRUSH hbrBackground; // хендл "замальовки", тобто колір фону для вікна. Для його визначення можна скористатися будь-яким з 20 системних констант кольору Див. COLOR_ LPCTSTR lpszMenuName; // вказівник на стрічку з іменем меню вікна, котре визначене у файлі ресурсів; LPCTSTR lpszClassName; // вказівник на стрічку з іменем класу нового вікна. Ім'я класу повинне бути унікальним, тобто щоб не було аналогій, наприклад "АВВА"; HICON hIconSm; // хендл іконки, що буде відображуватися у лівому куті програми. Іконку можна завантажити з ресурсів або вибрати одну з стандартних; ); На рахунок параметра lpfnWndProc, як було вище сказано це вказівник на процедуру обробки повідомлень. Навіщо він нам потрібен ?. Будь яка дія над вікном, генерує повідомлення у системі і передає на обробку нашій процедурі, при умові якщо вона є. Повідомлення можна вважати практично все, від натиснення кнопки на клавіатурі до зміни розмірів вікна. Тобто все що робиться з вікном, можна відслідковувати та налаштовувати під себе. Наприклад, стандартний колір вікна "сірий", ми можемо поміняємо на "червоний" або на комбінований, також можемо замість кольору фону поставити малюнок і т.п. Як створити, та описати реакції на повідомлення буде описано нижче. Другим кроком, потрібно на основі нового класу створити так зване "батьківське" вікно, тобто, вікно на якому будуть розташовані "дочірні" об’єкти (вікна). Дочірні - це вікна які розташовані на батьківському вікні та підпорядковані йому. Батьківське вікно обробляє всі повідомлення дочірнього вікна. Як вище було згадано, для створення вікна використовується функція CreateWindowEx. Нижче проведено опис функції. CreateWindowEx Функція CreateWindowEx створює основне "батьківське" вікно, спливаюче, або дочірнє з розширеним стилем HWND CreateWindowEx( DWORD dwExStyle, // розширений стиль вікна, може бути один або комбінація багатьох Див. WS_EX_ LPCTSTR lpClassName, // вказівник на стрічку з іменем класу вікна, якщо це батьківське вікно, то стрічка має містити ім’я новоствореного класу. LPCTSTR lpWindowName, // вказівник на стрічку, що характеризує заголовок вікна DWORD dwStyle, // стиль вікна, може бути один або комбінація багатьох Див. WS_,BS_,CBS_,DS_,ES_,LBS_,SBS_,SS_ (якщо вікно дочірнє, в комбінації стилів має бути присутній стиль WS_CHILD) int x, // горизонтальна координата початку вікна (або CW_USEDEFAULT) int y, // вертикальна координата початку вікна (або CW_USEDEFAULT) int nWidth, // ширина вікна (або CW_USEDEFAULT) int nHeight, // висота вікна (або CW_USEDEFAULT) HWND hWndParent, // хендл батьківського вікна (цей параметр використовується для дочірніх вікон), або NULL (0) якщо його немає HMENU hMenu, // хендл меню або інедефікатор батьківського меню. NULL - немає меню. HINSTANCE hInstance, // хендл модуля програми. Див. GetModuleHandle LPVOID lpParam // вказівник на MDI – структуру, або NULL (0) ); Результат: Якщо функція має успіх повертає хендл нового вікна. Якщо функція завершилися помилкою повертається значення рівне NULL (0). Деяка інформація про стилі: WS_ : Стиль вікна BS_ : Стиль кнопки CBS_ : Стиль комбінований список з полем редагування DS_ : Стиль діалогового вікна ES_ : Стиль рядка вводу LBS_ : Стиль вікна-списку SBS_ : Стиль лінійки прокрутки SS_ : Стиль статичного тексту Третім кроком, нам потрібно відфільтровувати повідомлення для нашої програми забирати з системи та відправляти їх на обробку у віконну процедуру. Цю дію виконує процедура GetMessage. GetMessage функція GetMessage відшукує у черзі потоку повідомлень і розміщує його у вказаній структурі. Ця функція може відшукати як повідомлення, пов'язані з вказаним вікном, так і повідомлення потоків, відіслані функцією PostThreadMessage. Функція відшукує повідомлення, які лежать в межах вказаного діапазону значень повідомлень. BOOL GetMessage( LPMSG lpMsg, // адреса структури повідомлення Див. структуру типу MSG HWND hWnd, // хендл віна від котрого очікується повідомлення UINT wMsgFilterMin, // Конкретизує ціле значення найнижчого значення повідомлення, яке відшукане. Зазвичай це параметр рівний нулю. UINT wMsgFilterMax // Конкретизує ціле значення самого верхнього значення повідомлення, яке відшукане. Зазвичай це параметр рівний нулю. ); Результат: Якщо функція відшукує будь-яке повідомлення, окрім значення WM_QUIT, результат - відмінне від нуля. Якщо функція відшукує WM_QUIT повідомлення, результат - нуль NULL (0). Якщо вікна не існує (було аварійно закрите) - повертає (-1). У функції задіяна структура типу MSG, розглянемо її. MSG struct MSG ( HWND hwnd // хендл вікна що отримало повідомлення UINT message // специфічне числове значення, що характеризує повідомлення WPARAM wParam // конкретизує додаткову інформацію про повідомлення. Точне значення залежить від значення елементу повідомлення. (перше значення) LPARAM lParam // конкретизує додаткову інформацію про повідомлення. Точне значення залежить від значення елементу повідомлення. (друге значення) DWORD time // час появи повідомлення POINT pt // конкретизує позицію курсору(координатах миші), коли повідомлення було прислане. ); Четвертим кроком буде перетворення віртуально-ключових повідомлень у повідомлення символів. Це робиться за допомогою процедури TranslateMessage. TranslateMessage Функція TranslateMessage переводить віртуальний-ключові повідомлення на повідомлення символів. Повідомлення символів переносяться до черги повідомлень потоку запиту, щоб читатися в наступний час, коли функції GetMessage або, PeekMessage будуть звертатися до потоку. BOOL TranslateMessage( CONST MSG *lpMsg // адреса структури повідомлення Див. структуру типу MSG ); Результат: Якщо повідомлення перетворено результат відмінне від нуля, в протилежному випадку нуль. Останнім п’ятим кроком буде відправлення повідомлення у процедуру вікна за допомогою процедури DispatchMessage. DispatchMessage Функція DispatchMessage посилає повідомлення процедури вікна. LONG DispatchMessage( CONST MSG *lpmsg // адреса структури повідомлення Див. структуру типу MSG ); Результат: Значення, що повертається, конкретизує значення, повернене процедурою вікна. Кроки 3,4,5 потрібно виконувати в циклі до тип пір поки функція GetMessage не поверне значення "0" або "-1". Наведемо приклад: .WHILE TRUE ; безкінечний цикл invoke GetMessage, ADDR msg,hWnd,0,0 ;очікуємо повідомлення .BREAK .IF (eax == 0) || (eax == -1) ;макрозвернення, що виходить з ;циклу, якщо еах рівний "0" або "-1" invoke TranslateMessage, ADDR msg ; перекладаємо повідомлення invoke DispatchMessage, ADDR msg ; відправляємо на обробку у віконну ;процедуру. .ENDW ; ознака кінця блоку циклу Де, Msg – змінна-структура типу системне повідомлення, туди функція GetMessage записує всю інформацію про повідомлення; hWnd - хенд вікна від якого очікуємо повідомлення. Тепер приступимо до найважливішої частини програми. Наступним кроком є створення процедури обробки повідомлень. Назва функції може бути довільна, але ця назва має фігурувати у коді програми при реєстрації класу(поле структури WNDCLASSEX – lpfnWndProc). Найчастіше процедура має назву WNDProc. Процедура обробки повідомлень має 4 параметри, і такий вигляд: WndProc proc hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD { тіло процедури } ret WndProc endp Пройдемося по параметрах: hWnd: хендл батьківського вікна. uMsg: повідомлення котре надійшло від батьківського вікна. wParam: перший параметр повідомлення lParam: другий параметр повідомлення Для передачі інформації батьківському вікну від дочірнього використовується повідомлення WM_NOTIFY. Це як сигналізатор що у дочірньому вікні щось щось відбулося. Інформацію про це повідомлення можна прочитати у довідці по АРІ функціям. Наведемо приклад процедури WndProc: WndProc proc hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
.IF uMsg == WM_DESTROY ; якщо вікно знищується Invoke PostQuitMessage,NULL ;передаємо повідомлення системі про закриття програми ret .ELSEIF uMsg == WM_CREATE ; якщо вікно створюється { тут ми описуємо все що хочемо. Дія відбувається при створенні вікна } .ELSE Invoke DefWindowProc,hWnd,uMsg,wParam,lParam ; в протилежному випадку опрацьовуємо повідомлення по-замовчування. ret .ENDIF xor eax,eax ret WndProc endp Більш детальнішу інформацію можна знайти у довідці по WinApi функціях. ПОРЯДОК ВИКОНАННЯ РОБОТИ Відкриваємо F:\asm\RаdAsm.exe. Закрити попередній проект за допомогою меню: Файл(Закрити Проект(Ctrl+Shift+C) Створюємо новий проект: Файл(Новий Проект (Ctrl+Shift+N) У вікні майстра створення проекту, вибираємо тип асемблеру „masm”, тип проекту “Win32 App”(це означає, що програма є 32 розрядною і використовує власні ресурси, тобто іконок, діалогових вікон, меню і т.д.), ім’я та опис проекту вводимо індивідуально. Обов‘язково перевірити шлях до папки у вікні „Директорія”, куди буде збережений ваш проект, як правило, це повинно бути „c:\Users\ВЛАСНА_ГРУПА\”. Натискаємо ”Next”. (Мал.1.) Після цього, висвічується список можливих шаблонів для Win32 програм. Вибираємо проект „WIN32EXE”. Натискаємо „Next”. (Мал. 2.) Наступним кроком висвічується перелік файлів і папок, які потрібно створити для нашого проекту. Вибираємо файли „asm”(файл коду), „inc” (файл заголовків), "rc" файл ресурсів а папки „bak”(резервні копії колишніх змін) та папку "Res" (для гберігіння ресурсів які ми будемо приєднувати до програми) Натискаємо „Next”.(Мал.3.) Наступним кроком висвічується перелік ключів та параметрів компіляції, програма встановлює параметри автоматично. Натискаємо „Готово” (“Finish”). (Мал.4.) В правій частині програмного вікна з’являється список створених файлів котрі відносяться до проекту. Клікаємо у вікні по файлу з розширенням „inc” (додатковий файл) – відкривається вікно з основними директивами коду, в котрий треба дописати необхідний текст представлений в лістінгу 1. В цьому файлі будуть зберігатися константи, змінні, структури, шаблони, описи макросів та ініціалізації файлів що підключаються. Наступним кроком в правій частині програмного вікна клікаємо по файлу з розширенням „asm” – відкривається вікно в яке треба дописати необхідний текст представлений в лістінгу 2. В цьому файлі міститься код програми. Зберігаємо всі файли за допомогою послідовності пунктів меню: Файл(Зберегти всі файли (Ctrl+Shift+S). Компілюємо проект за допомогою послідовності пунктів меню: Створити ( GO (F9). По експериментувати з демонстраційною програмою, по створювати на ній вікна типу ComboBox, Edit, ListBox, Message, ScrollBar, Static, SysAnimate32, SysHeader32, SysListView32, SysTabControl32, SysTreeView32, TTSubclass, ToolTips, ToolbarWindow32, msctls_hotkey32, msctls_progress32, msctls_statusbar32, msctls_trackbar32, msctls_updown32, tooltips_class32, #32768, #32769, #32770, #32771, ComboBoxEx32, SysPager, SysIPAddress32, NativeFontCtl.
Мал. 1. Мал.. 2.
Мал. 3. Мал. 4. Лістінг 1. include windows.inc include user32.inc include kernel32.inc
includelib user32.lib includelib kernel32.lib WinMain proto .data ClassName db "MainWinClass",0 ;ім’я класу нового вікна AppName db "Main Window",0 ; заголовок батьківського вікна szEdit db 'Edit',0 ;стандартний клас вікна (стрічка вводу) szEdit_text db 'My Text',0 ; вміст вікна szButton db 'Button',0 ;стандартний клас вікна (кнопка) szButton_title db 'Clik me',0 ; вміст вікна buf db MAX_PATH dup(0) ; буфер куди ми будемо писати вміст вікна-стрічки szCaptin db 'Title.....',0 ; заголовок MessageBox'а .data? hInstance dd ? ;змінна для хендлу модуля CommandLine dd ? ;змінна для хендл командного рядка hEdit dd ? ;змінна для хендлу рядка-стрічки hButton dd ? ; змінна для хендлу кнопки Лістінг 2. .486 .model flat,stdcall option casemap:none include Lb_tt.inc ; підключаємо файл з заголовками .code start: invoke GetModuleHandle, NULL ; визначаємо хендл модуля mov hInstance,eax ; збережемо
invoke GetCommandLine ; визначаємо командний рядок mov CommandLine,eax ;збережемо ;(попередня команда не є потрібна, використовується якщо ми хочемо брати параметри з командного рядка)
call WinMain ; викликаємо власну під-процедуру ;WinMain в ній ми будемо створювати вікна. invoke ExitProcess,eax ; виходимо з процесу WinMain proc LOCAL wc:WNDCLASSEX ; локальна структура-змінна типу WNDCLASSEX (інфа про нов. клас) LOCAL msg:MSG ; локальна структура-змінна типу MSG (повідомлення) LOCAL hwnd:DWORD ; локальна змінна хар-є хенд баківського вікна
; заповнюємо поля класу… mov wc.cbSize,SIZEOF WNDCLASSEX ; задаємо розмір структури mov wc.style, CS_HREDRAW or CS_VREDRAW ; стиль класу (див. довідник) mov wc.lpfnWndProc, OFFSET WndProc ; вказівник на проц. обробки mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInstance ; ну тут ми копіюємо значення хенду модуля pop wc.hInstance ; у відповідне поле mov wc.hbrBackground,COLOR_BTNFACE+1 ; хендл щитки (можна створити самому, або задати одну з стандартних) mov wc.lpszMenuName,NULL ; меню у нас немає mov wc.lpszClassName,OFFSET ClassName ; задаємо нову назву класу
mov eax,msg.wParam ret WinMain endp ; проц. обробки повідомлень WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
mov eax,uMsg ; запишемо повідомлення у регістр еах, для простоти .IF eax == WM_DESTROY ; якщо вікно знищується invoke PostQuitMessage,NULL ; відправити повідомлення системі про закриття прогами
.ELSEIF eax == WM_CREATE ; якщо вікно створюється
.elseif eax == WM_COMMAND ; якщо виконання якась команда mov eax,hButton .if lParam == eax ; перевіримо, якщо lParam = хендлу кнопки (кнопка натиснута) invoke GetWindowText,hEdit,addr buf,MAX_PATH ; візьмемо текст з вікна-стрічки і запишемо у буфер buf invoke MessageBox,0,addr buf,addr szCaptin,MB_OK ; виведемо .endif .ELSE invoke DefWindowProc,hWnd,uMsg,wParam,lParam ; якщо небуло виконано жодної дії виконати системну обробку повідомлення (тобто не реагувати, або так як в системі) ret .ENDIF
xor eax,eax ret WndProc endp end start результат програми
Мал..5 КОНТРОЛЬНІ ЗАПИТАННЯ Що таке вікно і як його створити ? Які параметри потрібно вказати щоб створити вікно ? Що таке віконна процедура і які параметри до неї передаються ? Що таке клас вікна та субкласування ? Що таке повідомлення і яка його структура? Для чого надсилаються повідомлення ? Які існують стандартні класи вікон ? Що таке тип (стиль) вікна ? ФОРМА ЗВІТУ ПО РОБОТАХ Звіт – це документ про те, що студент успішно виконав роботу. Мета, що ставиться перед роботою; Короткий зміст теоретичних відомостей; Тексти всіх відлагоджених програм із коментарями; Відповіді на контрольні запитання; Висновки по особливостях застосування отриманих знань або зауваження по виконанню роботи та методичному забезпеченню. ЛІТЕРАТУРА Эпплман Д. Win32 API и Visual Basic. Для профессионалов (+CD). – СПб.: Питер, 2001. – 1120 с.: ил. Юров В. Assembler: учебник. - СПб.: Питер, 2001. – 624 с.: ил. Win32 Developer’s References (файл документації WIN32.HLP). DelphiWord ДОДАТОК Простудіювати наступні функції. AdjustWindowRect AdjustWindowRecfEx AllowSetForegroundWindow AnimateWindow BeginDeferWindowPos BringWindowToTop ChildWindowFromPoint ChildWindowFromPointEx ChooseColor CloseWindow DeferWindowPos EnableWindow EndDeferWindowPos FindWindow FindWindowEx GetClassLong GetClassLongPtr GetClassName GetClassWord GetClientRect GetDesktopWindow GetFocus GetForegroundWindow GetLastActivePopup GetNextWindow GetParent GetProp GetTitleBarlnfo GetTopWindow GetWindow GetWindowInfo GetWindowLong GetWindowLongPtr GetWindowModuleFileName GetWindowPlacement GetWindowRect GetWindowText GetWindowTextLength GetWindowWord IsChild lslconic IsWindow IsWindowEnabled IsWindowUnicode IsWindowVisible IsZoomed LockSetForegroundWindowLoadLibrary MapWindowPoints MoveWindow OpenIcon RealChildWindowFromPoint RealGetWindowClass RemoveProp SetActiveWindow SetClassLongPtr SetCassWord SetFocus SetForegroundWindow SendMessage SystemParametersInfo LoadImage LoadIcon LoadCursor GetDC ReleaseDC BitBlt SetTimer KillTimer WM_ (WM_ - мається на увазі, розібратися з повідомленнями вікна) Індивідуальне Завдання Умови: Вісі дочірні вікна розмістити на самостійно створеному батьківському відповідно до завдань Створити вікно список, записати у нього назви всіх вікон у системі. При двійному кліканню мишкою над певним записом списку, вивести його зміст. Використати анімацію вікна (перехід з альфа-міксуванням). Створити 2 кнопки, рядок вводу, статичний текст. При натисненні кнопки №1 вивести діалог вибору файлів по фільтру "*.bmp". При виборі графічного файлу шлях до нього занести у рядок вводу. При натисненні кнопки №2, вивести зображення на вікно статичного тексту. Створити 10 вікон різних класів. Наводячи мишкою на створеному вікні витягнути з них назви класів та назви заголовків. Вивести результат у вікні рядку, при цьому вікно рядок не розпізнавати. Створити кнопку та статичний текст. При натисненні кнопки кнопка починається рухатися (наприклад по колу). При повторному натисненні рух зупиняється. В статичному вікні тексту виводити координати. Знайти всі вікна і поміняти в них іконки. Іконку вибрати через діалог вибору файлів з фільтром "*.ico". Примітка : Перевірити чи вікно яке ми знайшли є вікном верхнього рівня, якщо так то змінити ікону та звернути вікно. Створити вікно-рядок (багато рядковий) з різнокольоровим текстом. Кожне наступне слово має мати інший колір. Окрім цього створити кнопку. При її натисканні має вискочити діалог вибору кольору. Колір який був вибраний встановлюється на фон вікна-рядока. Знайти всі батьківські вікна та їх потомків та описати їх у вікні дереві. Створити 4 кнопки. №1 – натискає кнопку пуск. №2 – Приховує (показує) кнопку пуск. №3 - Приховує (показує) годинник. №4 - Приховує (показує) робочій стіл. Написати програму яка міняє малюнок на робочому столі. Вибір малюнка здійснювати за допомогою діалогу вибору файлів. Фільтр "*.BMP". Створити вікно SysAnimate32, msctls_trackbar32 і статичне вікно. У статичному вікні один раз на секунду виводити час у форматі "11:04:54". У вікні SysAnimate32 задати якусь анімацію. При зміщенні позиції у вікні msctls_trackbar32, змінювати координати вікна SysAnimate32 відносно горизонталі. Створити msctls_progress32, trackbar32, і полосу прокрутки. Міняючи позицію у trackbar32 змінити позиції у інших вікнах. Знайти всі вікна системи верхнього рівня та поміняти у них колір фону. Використати діалог вибору кольору. Викликати цю дію за допомогою кнопки.