Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.08.27;
Скачать: [xml.tar.bz2];

Вниз

Прилипание форм   Найти похожие ветки 

 
Robin Hood   (2006-08-05 18:42) [0]

надо чтоб побочная форма прилипала к верхнему краю главной, скажем по нажатию на кнопку? Помогите зелёному!


 
Kolan ©   (2006-08-05 18:53) [1]

одноимённой статьи с сайта delphi.about.com

В статье рассматривается приём создания обработчиков сообщений, которые позволяют форме при перетаскивании "прилипать" к краям экранной области.

Конечно же в Win API такой возможности не предусмотрено, поэтому мы воспользуемся сообщениями Windows. Как нам извесно, Delphi обрабатывает сообщения через события, генерируя его в тот момент, когда Windows посылает сообщений приложению. Однако некоторые сообщения не доходят до нас. Например, при изменении размеров формы, генерируется событие OnResize, соотвествующее сообщению WM_SIZE, но при перетаскивании формы никакой реакции не происходит. Конечно же форма может получить это сообщение, но изначально никаких действий для данного сообщения не предусмотрено.

Итак, при перемещении, окну посылается сообщение WM_MOVING. Обрабатывая данной сообщение, приложение может отслеживать размер и расположение перетаскиваемого квадрата и, при необходимости, изменять их.

Так же существует сообщение WM_WINDOWPOSCHANGING, которое посылается окну, в случае, если его размер, расположение или место в Z порядке собираются измениться, как результат вызова функции SetWindowPos либо другой функции управления окном.

Чаще всего с сообщением передаются дополнительные параметры, которые сообщают нам необходимую информацию. Например, сообщение WM_MOVE, указывающее на то, что форма изменила своё местоположение, так же передаёт в параметре LPARAM новые координаты X и Y.

Сообщение WM_WINDOWPOSCHANGING передаёт нам ТОЛЬКО один параметр - указатель на структуру WindowPos, которая содержит информацию о новом размере и местоположении окна. Вот как выглядит структура WindowPos:

TWindowPos = packed record
 hwnd: HWND; {Identifies the window.}
 hwndInsertAfter: HWND; {Window above this one}
 x: Integer; {Left edge of the window}
 y: Integer; {Right edge of the window}
 cx: Integer; {Window width}
 cy: Integer; {Window height}
 flags: UINT; {Window-positioning options.}
end;

Наша задача проста: нам необходима, чтобы форма прилипла к краю экрана, если она находится на определённом расстоянии от окна (допустим 20 пикселей).

Пример
К новой форме добавьте Label, один контрол Edit и четыре Check boxes. Измените имя контрола Edit на edStickAt. Измените имена чекбоксов на chkLeft, chkTop, и т.д... Для установки количества пикселей используем edStickAt, который будет использоваться для определения необходимого расстояния до края экрана достаточного для приклеивания формы.

Нас интересует только одно сообщение WM_WINDOWPOSCHANGING. Обработчик для данного сообщения будет объявлен в секции private. Ниже приведён полный код этого процедуры "прилипания" вместе с комментариями. Обратите внимание, что Вы можете предотвратить "прилипание" формы к определённому краю, путё снятия нужной галочки.

Для получения рабочей области декстопа (минус панель задач, панель Microsoft и т.д.), используем SystemParametersInfo, первый параметр которой SPI_GETWORKAREA.

...

 private
  procedure WMWINDOWPOSCHANGING
           (Var Msg: TWMWINDOWPOSCHANGING);
            message WM_WINDOWPOSCHANGING;

...

procedure TfrMain.WMWINDOWPOSCHANGING
         (var Msg: TWMWINDOWPOSCHANGING);
const
 Docked: Boolean = FALSE;
var
 rWorkArea: TRect;
 StickAt : Word;
begin
 StickAt := StrToInt(edStickAt.Text);
 
 SystemParametersInfo
    (SPI_GETWORKAREA, 0, @rWorkArea, 0);

 with Msg.WindowPos^ do begin
   if chkLeft.Checked then
    if x <= rWorkArea.Left + StickAt then begin
     x := rWorkArea.Left;
     Docked := TRUE;
    end;

   if chkRight.Checked then
    if x + cx >= rWorkArea.Right - StickAt then begin
     x := rWorkArea.Right - cx;
     Docked := TRUE;
    end;

   if chkTop.Checked then
    if y <= rWorkArea.Top + StickAt then begin
     y := rWorkArea.Top;
     Docked := TRUE;
    end;

   if chkBottom.Checked then
    if y + cy >= rWorkArea.Bottom - StickAt then begin
     y := rWorkArea.Bottom - cy;
     Docked := TRUE;
    end;

   if Docked then begin
     with rWorkArea do begin
     // не должна вылезать за пределы экрана
     if x < Left then x := Left;
     if x + cx > Right then x := Right - cx;
     if y < Top then y := Top;
     if y + cy > Bottom then y := Bottom - cy;
     end; {ширина rWorkArea}
   end; {}
 end; {с Msg.WindowPos^}

 inherited;
end;
end.

Теперь достаточно запустить проект и перетащить форму к любому краю экрана.

А также можно взять готовый пример (~6Kb)

Вот собственно и всё.

Комментарии:

Автор: Nashev

а так короче... И, ИМХО, лучше:

procedure TCustomGlueForm.WMWindowPosChanging1(var Msg: TWMWindowPosChanging);
var
WorkArea: TRect;  

StickAt : Word;  

 
begin
StickAt := 10;  

SystemParametersInfo(SPI_GETWORKAREA, 0, @WorkArea, 0);  

with WorkArea, Msg.WindowPos^ do  

 
begin  

 
// Сдвигаем границы для сравнения с левой и верхней сторонами  

Right:=Right-cx;  

Bottom:=Bottom-cy;  

if abs(Left - x) <= StickAt then x := Left;  

if abs(Right - x) <= StickAt then x := Right;  

if abs(Top - y) <= StickAt then y := Top;  

if abs(Bottom - y) <= StickAt then y := Bottom;  

 
end;  

 
inherited;  

 
end;

Скачать демонстрационный проект с исходниками - 167Kb

В проекте осталось 2 глюка:

1) Если у формы, к которой прицепили другую форму за правую/нижнюю границы попробовать переместить эти границы, прицепленная форма останется на месте но все равно будет прикрепленной.

2) Иногда 3 формы прикрепляются друг к другу, и иначе, как воспользовавшись 1-ым глюком, их не расцепить.

Состав проекта:
сам проект, uCustomGlueForm - форма с добавленной липкостью 3 формы - пустышки, наследники TCustomGlueForm

Для использования сделанного в своих проектах надо добавить в проект, и свои формы создавать, наследуя от него, например, через мастер "File/New..."
В принципе, если липкость нужна без прилипания (а это уже работает без глюков) можно выкинуть все методы, кроме
procedure WMWindowPosChanging(var Msg: TWMWindowPosChanging);message WM_WINDOWPOSCHANGING;
и все переменные, а в самом WMWindowPosChanging удалить все упоминания этих переменных.

Взято с Исходников.ru http://www.sources.ru

Не проверял...


 
Robin Hood   (2006-08-05 18:57) [2]

Хотя бы это.


 
Kolan ©   (2006-08-05 19:29) [3]

В BDS2006 у форм это уже есть...


 
Eraser ©   (2006-08-05 19:31) [4]

> [0] Robin Hood   (05.08.06 18:42)
> надо чтоб побочная форма прилипала к верхнему краю главной,
> скажем по нажатию на кнопку?

в обработчике кнопки впиши
SecondForm.Top := MainForm.Top + SecondForm.Height;



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2006.08.27;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.47 MB
Время: 0.042 c
15-1154593000
ALEXD31
2006-08-03 12:16
2006.08.27
Мультизагрузочный диск


3-1150890703
Mishenka
2006-06-21 15:51
2006.08.27
Создание динамического поля


2-1154945702
Spectrum2
2006-08-07 14:15
2006.08.27
Декодировать string фХФ ЧУЕ ДЕМП Ч БУУПГЙБГЙСИ


3-1150381411
Urvin
2006-06-15 18:23
2006.08.27
Счетчик (?) в Firebird


5-1138368717
De
2006-01-27 16:31
2006.08.27
Как выполнить событие предка?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский