Стандартна сторінка Палітри Компонент Компоненти, розташовані на сторінці "Standard", представляють із себе об'єктну оболонку для стандартних керуючих елементів Windows. Тому для них існують обмеження, що накладаються самою системою. Наприклад, 32Кб - максимальний розмір тексту в TMemo. TMainMenu, TPopupMenu Додавання картинки (BitMap) в меню. Щоб додати до меню картинки, можна використовувати функцію API Windows SetMenuItemBitmaps (), наприклад, таким чином: ... implementation ... var BMP1, BMP2: TBitMap; ... procedure TForm1.FormCreate (Sender: TObject); begin BMP1: = TBitMap.Create; BMP1.LoadFromFile ('c: \ images \ uncheck.bmp'); BMP2: = TBitMap.Create; BMP2.LoadFromFi le ('c: \ images \ check.bmp'); SetMenuItemBitmaps (File1.Handle, 1, MF_BYPOSITION, BMP1.Handle, BMP2.Handle); end; procedure TForm1.FormDestroy (Sender: TObject); begin BMP1.Free; BMP2.Free; end; File1 – це об'єкт класу TMenuItem - пункт меню "File". Значення параметрів при виклику функції можна подивитися в довіднику з Windows API. При знищенні меню звільнення пов'язаних з ним картинок не відбувається і їх треба знищувати вручну. Друга картинка BMP 2 відображається поруч з пунктом меню, коли він обраний (Checked = True). TMemo Компонент класу TMemo може містити до 32К тексту (для Windows 3.X) внаслідок обмеження Windows. У Delphi 2.0 межа збільшена до 64К. I.Визначення позиції каретки в TMemo. Можливо використовувати повідомлення Windows API EM_LINEFROMCHAR і EM_LINEINDEX для визначення поточної позиції каретки. procedure TForm1.ShowPosition; var LineNum: longint; CharNum: longint; begin LineNum: = Memo1.Perform (EM_LINEFROMCHAR, Memo1.SelStart, 0); CharNum: = Memo1.Perform (EM_LINEINDEX, LineNum, 0); Label1.Caption: = 'Line:' + IntToStr (LineNum +1); Label2.Caption: = 'Position:' + IntToStr ((Memo1.SelStart - Char Num) +1); end; Метод Perform, визначений у класі TControl, посилає повідомлення своєму ж об'єкту, тобто його використання має той же ефект, що і виклик функції API SendMessage (): SendMessage (Memo1.Handle, EM_LINEFROMCHAR, Memo1.SelStart, 0); II.Операція UnDo в TMemo. Відміна останнього редагування (операція UnDo) в об'єкті класу TMemo виконується так само за допомогою повідомлень, що посилаються в даний об'єкт: procedure TForm1.UnDoClick (Sender: TObject); begin if Memo1.Perform (EM_CANUNDO, 0, 0) <> 0 then Memo1.Perform (EM_UNDO, 0, 0); end; У довіднику з Windo ws API описані повідомлення, які можна надіслати в об'єкт TMemo для управління його поведінкою. Крім вищеназваних, є ще кілька корисних: EM_EMPTYUNDOBUFFER Скидає прапорець UnDo EM_GETHANDLE Отримує покажчик на буфер з текстом EM_LINESCRO LL Прокрутка тексту у вікні TMemo EM_SETHANDLE Установка покажчика на буфер з текстом EM_SETTABSTOPS Встановлює табуляцію у вікні з текстом T ListBox, TComboBox Windows накладає обмеження на кількість елементів у списку цих керуючих елементів. У разі Windows 3. X це кількість дорівнює 5440, в Windows '95 - 32767. I.Як отримати горизонтальну прокрутку (scrollbar) у ListBox? Так само як у випадку з TMemo, тут можна використовувати повідомлення. Наприклад, повідомлення може бути відіслано у момент створення форми: procedure TForm 1. FormCreate (Sender: TObject); begin ListBox1.Perform (LB_SETHORIZONTALEXTENT, 1000, Longint (0)); end; Другий параметр у виклику – ширина прокрутки в точках. II.Вставка графіки в ListBox. У класу TListBox (і TComboBox теж) є властивість Style, що визначає порядок малювання об'єкта. За замовчуванням воно встановлено в lbStandard і за зовнішній вигляд об'єкта відповідає Windows. Якщо встановити це значення в lbOwnerDrawFixed або lbOwnerDrawVariable, то можна дещо урізноманітнити зовнішній вигляд об'єкта. Давайте побудуємо для прикладу ListBox, що відображає назви файлів формату. BMP з якої-небудь директорії разом з їх картинками. Насамперед, виявляється, що зовсім не потрібно заповнювати ListBox вручну іменами файлів, для цього достатньо надіслати йому повідомлення: procedure TForm1.Button1Click (Sender: TObject); var s: String; begin s: = 'c: \ windows \ *. bmp' # 0; ListBox1.Perform (LB_DIR, DDL_READWRITE, Longint (@ s [1])); end; Тут ми вказали ListBox 'у, які файли потрібно відображати. Далі, як вже було сказано, властивість Style потрібно встановити в lbOwnerDrawFixed і створити обробник події OnDrawItem: procedure TForm1.ListBox1DrawItem (Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var Bitmap: TBitma p; Offset: Integer; BMPRect: TRect; begin with (Control as TListBox). Canvas do begin {Очищаємо прямокутник} FillRect (Rect); {Зчитуємо картинку} Bitmap: = TBitMap.Create; Bitmap.LoadFromFile ('c: \ windows \' + ListBox1.Items [Index]); i f Bitmap <> nil then begin {Обчислюємо квадрат для показу картинки} BMPRect: = Bounds (Rect.Left + 2, Rect.Top + 2, Rect.Bottom-Rect.Top-2, Rect.Bottom-Rect.Top-2); {Малюємо картинку} StretchDraw (BMPRect, BitMap); Offset: = Rect.Bottom-Rect.Top + 6; end; {Виводимо текст} TextOut (Rect.Left + Offset, Rect.Top, Listbox1.Items [Index]); {Не забути звільнити!} Bitmap. Free; end; end; Щоб картинки вийшли побільше, значення властивості ItemHeight можна збільшити. Є близько двох десятків повідомлень, які можна надіслати в об'єкти класу T ListBox і TComboBox. Детальніше про них можна дізнатися в довіднику з Windows API (on - line Help). Сторінка "Additional" Палітри Компонент Компоненти, розміщені на цій сторінці представляють із себе об'єктну оболонку для керуючих елементів, що з'явилися в пізніших версіях Windows. T SpeedButton I.Емуляція втрати фокусу. Особливість цієї кнопки в тому, що вона ніколи не отримує фокус і, отже, при натисканні на неї, поточний активний елемент фокус не втрачає. У деяких випадках буває необхідно емулювати втрату фокусу активним об'єктом. Приклад, при натисканні кнопки, дані з об'єктів типу TEdit записуються у файл, на подію OnExit для них (об'єктів) встановлено процедуру верифікації. У цьому випадку треба викликати обробник в явному вигляді: procedure TForm 1. SpeedButton 1 Click (Sender: TObject); begin if ActiveControl is TEdit then (ActiveControl as TEdit). OnExit (ActiveControl); end; Обробник події повинен бути визначений, інакше виникне GPF. II.Обробка подвійного клацання мишею. Якщо значення властивості GroupIndex дорівнює 0, то подвійне натискання буде сприйнято об'єктом як два одиночних. Якщо потрібно, щоб у результаті подвійного клацання контроль не фіксувалася в натиснутому стані, то її властивість AllowAllUp встановлюється в True, і в обробнику події кнопка повертається до попереднього стану: procedure TForm1.SpeedButton1DblClick (Sender: TObject); begin SpeedButton1.Down: = Not SpeedButton1.Down; Do _ Something; end; T TabSet, TNoteBook Обмеження за кількістю сторінок для цих об'єктів - 16364 (ще одне "магічне число" з класу TList). Але, насправді, не має сенсу створювати більше сотні сторінок. I.Перехід на сторінку по її імені. Якщо об'єкт типу TTabSet містить велику кількість сторінок, то перегортати їх у пошуках потрібної - справа обтяжлива. Простіше знайти її по імені. Припустимо, що ім'я сторінки вводиться в Edit 1: procedure TMultPageDlg.Edit1Change (Sender: TObject); var i: Integer; s1, s2: String; begin s1: = Edit1.Text; if s1 ='' then Exit; for i: = TabSet.Tabs.Count-1 downto 0 do begin s2: = Copy (TabSet.Tabs [i], 1, Ord (s1 [0])); if CompareText (s1, s2) <= 0 then TabSet.TabIndex: = i; end; end; T TabbedNoteBook I.Додавання нових об'єктів під час виконання програми. Після створення нового об'єкта, потрібно в його властивості Parent вказати необхідну сторінку TabbedNotebook: ... var Btn: TButton; begin Btn: = TButton.Create (Self); Btn.Parent: = TWinControl (TabbedNotebook1.Pages.Objec ts [1]); ... end; Вікна в Delphi Більшість видимих компонентів в Delphi (всі компоненти, що мають предком клас TWinControl) є для Windows повноцінними вікнами. При доступі до цих компонентів з Windows API використовується властивість Handle кожного компонента. Нижче наводиться кілька прийомів, які можна провести з вікнами компонентів, включаючи TForm. I."Перетягування" вікна без допомоги Caption. Досить відомий спосіб "перетягування" вікна програми без Caption (caption - поле заголовка вгорі форми). Для вирішення цього завдання потрібно перевизначити обробник події WM _ NCHITTEST для вікна таким чином: type TForm1 = class (TForm) . . . private procedure WMNCHitTest (var M: TWMNCHitTest); message wm_NCHitTest; . . . end; procedure TForm1.WMNCHitTest (var M: TWMNCHitTest); begin {Виклик успадкованого обробника події} inherited; {Якщо подія сталася в клієнтській області,} if M. Result = htClient then {То нехай Windows думає, що це сталося на Caption} M. Result: = htCaption; end; Тепер вікно можна буде перемістити на екрані, навіть якщо воно зовсім не має Caption. Однак, неприємно те, що для такого вікна не будуть викликатися обробники подій, пов'язаних з мишкою (OnClick, OnMouseMove і т.д.). Все, що було зараз пророблено з формою (об'єктом класу TForm) можна застосувати і до решти віконним компонентам. Нам ніхто не забороняє і для них перевизначити обробку події WM _ NCHITTEST. II.Об'єкти, що перетягуються під час роботи програми. Найпростіше було б вирішити це завдання перевизначенням відповідного обробника і додаванням нового властивості для класу TWinControl. Однак, після цього перекомпілювати бібліотеку буде важко, так як не всі модулі надані у вихідних текстах. Тому, наведу рішення задачі на прикладі класу TMemo. type TMoveMemo = class (TMemo) private FMoveable: Boolean; procedure WMNCHit Test (var M: TWMNCHitTest); message WM_NCHitTest; published property Moveable: Boolean read FMoveable write FMoveable; end; . . . procedure TMoveMemo.WMNCHitTest (var M: TWMNCHitTest); begin inherited; if (not (csDesigning in ComponentState)) and FMoveable then if M.Result = htClient then M.Result: = htCaption; end; Властивість Moveable визначає, чи можна об'єкт перетягувати. Якби всі віконні об'єкти мали такий обробник події і властивість Moveable, то було б дуже просто побудувати додаток із змінним під час роботи програми користувача інтерфейсом. III.Зовнішній вигляд вікна. Як відомо, зовнішній вигляд вікна в Windows визначається при його створенні параметром Style (тип Longint). Повний список можливих значень цього параметра можна знайти в довіднику з Windows API, всі вони починаються з префікса WS _ (наприклад, WS _ CAPTION, WS _ MAXIMIZED). Змінити зовнішній вигляд вікна під час виконання програми можна, якщо змінити значення його параметра Style. Для цього використовується виклик функції API SetWindowLong (). Звичайно, у разі форми (TForm) можна обійтися властивостями цього класу (але не завжди). Але у випадку із звичайними віконними компонентами виходить забавний ефект. Спробуйте змінити стиль звичайної кнопки (TButton): procedure TForm1.Button2Click (Sender: TObject); var Style: Longint; begin {Старий стиль вікна} Style: = GetWindowLong (Button1.Handle, GWL_STYLE); {Міняємо стиль вікна} Style: = Style or WS_OVERLAPPEDWINDOW; SetWindowLong (Button1.Handle, GWL_STYLE, Style); {Оновлення вікна (Invalidate не спрацює)} SetWindowPos (Button1.Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER or SWP_DRAWFRAME or SWP _ NOACTIVATE); end; Вказати свій стиль вікна під час його створення можна, якщо перевизначити для будь-якого віконного об'єкта (включаючи TForm) процедуру CreateParams: type TForm1 = class (TForm) . . . procedure CreateParams (var Params: TCreateParams); override; . . . end; . . . procedure TForm1.CreateParams (var Params: TCreateParams); begin inherited CreateParams (Params); Params.Style: = Params.Style and not WS_CAPTION; end; IV.Максимізація імінімізація вікон. Іноді потрібно, щоб вікно при натисканні кнопки "Maximize" розорювалися не на весь екран, а тільки на частину його. Згадайте редактор вихідних текстів в середовищі Delphi. Це завдання, як і багато інших, вирішується написанням обробника відповідної події – WM_GETMINMAXINFO. Це повідомлення надсилається системою у вікно при максимізації вікна або при зміні його розмірів за допомогою рамки. Вікно повертає необхідні розміри і положення. TForm 1 = class (TForm) . . . private procedure WMGetMinMaxInfo (var M: TWMGetMinMaxInfo); message WM_GETMINMAXINFO; . . . end; . . . procedure TForm1.WMGetMinMaxInfo (var M: TWMGetMinMaxInfo); begin inherited; {Вказуємо верхню межу вікна нижче іншого вікна} M.MinMaxInfo ^. PTMaxPosition.Y: = Form2.Top + Form2.Height; end; За допомогою обробника даної події встановлюється не тільки місце і розмір розкритого повністю вікна, а й мінімальні / максимальні розміри вікна при зміні їх за допомогою рамки. Приклад, установка в обробнику події WM _ GETMINMAXINFO m. minmaxinfo ^. ptMinTrackSize. y: = 100; m. minmaxinfo ^. ptMaxTrackSize. y: = 300; не дасть зробити вертикальний розмір вікна менше 100 і більше 300 точок. |