- •Лекція №14
- •Тема 4. Розробка графічного інтерфейсу користувача (продовження) Обробка подій миші і клавіатури План
- •2. Розпізнавання джерела події, натиснутих кнопок і клавіш, координат курсору
- •3. Події клавіатури
- •4. Перетягування даних між об’єктами
- •5. Перетягування і вбудовування об'єктів — Drag&Doc. Плаваючі вікна
- •6. Буксування компонентів у вікні програми
6. Буксування компонентів у вікні програми
У ряді випадків в Windows - програмах використовується переміщення окремих компонентів в полі вікна або якоїсь панелі. Це переміщення може бути переміщенням в якісь певні позиції (це легко здійснюється завданням відповідних значень властивостям Left і Тор) або здійснюватися безперервним буксируванням компоненту за допомогою миші. Простий приклад цього — буксирування компонентів на площині форми в середовищі розробки C++Builder. Подібні завдання виникають достатньо часто в технічних програмах, пов'язаних з компоновкою якогось пристрою, з формуванням якихось схем (наприклад, електричних) і т.п.
Випробувати різні способи буксирування можна в наступному тестовому застосуванні. У ньому на формі розміщено чотири компоненти Image, в які завантажені якісь зображення або частини зображення. Якщо хочете відтворити приклад, в якому на окремих компонентах, як на дитячих кубиках, відтворені фрагменти єдиного зображення, то можете в обробник події форми OnCreate вставити наступний код:
TImage * Pict = new TImage(Form1);
Pict->AutoSize = true;
// В наступному операторі замість ... треба вказати ім'я файлу
Pict->Picture->LoadFromFile(“...”);
Image1->Canvas->CopyRect(Image1->ClientRect, Pict->Canvas,
Rect(0, 0, Pict->Width/2, Pict->Height/2));
Image2->Canvas->CopyRect(Image2->ClientRect, Pict->Canvas,
Rect(Pict->Width/2, 0, Pict->Width, Pict->Height/2));
Image3->Canvas->CopyRect(Image3->ClientRect, Pict->Canvas,
Rect(0, Pict->Height/2, Pict->Width/2, Pict->Height));
Image4->Canvas->CopyRect(Image4->ClientRect,Pict->Canvas,
Rect(Pict->Width/2, Pict->Height/2, Pict->Width, Pict->Height));
delete Pict;
У компонентах Image властивість AutoSize повинна бути встановлена в true.
Почнемо розгляд на цьому прикладі прийомів буксирування. Всі приведені далі обробники подій записані в загальному вигляді. Отже ви можете застосовувати їх одночасно до всіх ваших компонентів Image, а можете до різних компонентів застосувати різні методи, щоб легше було порівнювати них один з одним.
Всі методи використовують декілька глобальних змінних, оголошення яких треба помістити в модулі поза якими - набудь процедурами:
int X0, Y0;
bool move = false;
Змінна move визначає режим буксирування. Вона встановлюватиметься в true на початку буксирування і скидатися в false в кінці. Тому по значенню move можна буде розрізняти переміщення миші з буксируванням і без неї. Змінні Х0 і Y0 будуть потрібно нам для запам'ятовування координат курсору миші.
Один з можливих варіантів рішення нашої задачі — буксирування самого компоненту. Буксирування починається при натисненні лівої кнопки миші на відповідному компоненті Image. Тому початок визначається подією OnMouseDown, обробник якої має вигляд:
void __fastcall TForm1::Image1MouseDown(TObject *Sender,
TMouseButton Button,TShiftState Shift, int X, int Y)
{if (Button != mbLeft) return;
X0=X;
Y0=Y;
move = true;
((TControl *)Sender)->BringToFront() ;
}
Спочатку в цій процедурі перевіряється, чи натиснута саме ліва кнопка миші (чи рівний параметр Button значенню mbLeft, що позначає ліву кнопку). Потім в змінних Х0 і Y0 запам'ятовуються координати миші X і Y у цей момент часу. Задається режим буксування — змінна move встановлюється в true. Останній оператор містить метод BringToFront, для якого подія — ((TControl *)Sender), висуває на передній план відповідний компонент. Це дозволить йому надалі переміщатися поверх інших аналогічних компонентів. Даний оператор не обов'язковий, але якщо його не записати, то в процесі буксирування переміщуваний компонент може опинитися під іншими компонентами.
П6ід час буксирування компоненту працює його обробник події OnMouseMove, що має вигляд:
void __fastcall TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{if (move)
{TImage * Im = (TImage *)Sender;
Im->SetBounds(Im->Left + X – X0, Im->Top + У – Y0,
Im->Width, Im->Height);}
}
Він змінює за допомогою методу SetBounds координати лівого верхнього кута на величину зрушення курсору миші (X - Х0 для координати X і Y - Y0 для координати Y). Тим самим підтримується постійне розташування точки курсору в системі координат компоненту, тобто компонент зміщується услід за курсором. Ширина Width і висота Height компоненту залишаються незмінними.
Після закінчення буксирування, коли користувач відпустить кнопку миші, наступить подія OnMouseUp. Обробник цієї події повинен містити всього один оператор:
move = false;
який вказуює програмі на закінчення буксування. Тоді при наступних подіях OnMouseMove їх обробник, приведений раніше, перестане змінювати координати компоненту.
На закінчення відзначимо ще один спосіб буксування, мабуть, найбільш універсальний і простій. Він може бути застосований до будь-яких віконних компонентів, включаючи форми. Пошліться в подіях OnMouseMove всіх компонентів, які ви хочете буксирувати, на наступний універсальний обробник:
const int SC_DRAGMOVE = 0xF012;
ReleaseCapture();
((TControl *)Sender)->Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0);
Цей обробник звільняє курсор миші і посилає методом Perform джерелу події Sender повідомлення Windows, відповідне буксируванню.
Можете посилатися на подібний обробник в подіях панелей, кнопок, списків, вікон редагування. Всі подібні компоненти користувач зможе буксирувати, перебудовувавши таким чином інтерфейс програми. Якщо ви пошлетеся на подібний обробник в події форми, то користувач зможе переміщати її по екрану, узявшись за будь - яку її точку, а не тільки за точку в заголовку вікна, як це прийнято в звичайних вікнах Windows.
Контрольні питання:
-
Які події миші пов’язані із її пересуванням, а які із клацанням по кнопкам?
-
Із якими діями користувача може бути пов’язана подія OnClick?
-
Які події, пов’язані із мишею повертають координати положення курсору?
-
У чому полягає відмінність подій, пов’язаних із клавіатурою?
-
Яким чином можна перевіряти натиснену клавішу клавіатури?
-
Які властивості визначають пересування даних між компонентами?
-
Як у програмі можна реалізувати плаваючі інструментальні панелі?
-
Яким універсальним способом можна реалізувати буксування віконних компонентів?