Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.08.27;
Скачать: CL | DM;

Вниз

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

 
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;
Скачать: CL | DM;

Наверх




Память: 0.49 MB
Время: 0.101 c
3-1149146961
vadim14
2006-06-01 11:29
2006.08.27
copy tables with metadata


2-1154779776
AlexanderMS
2006-08-05 16:09
2006.08.27
Убрать прямоугольную рамку фокуса в ListBox.


4-1146841864
Георгий А.
2006-05-05 19:11
2006.08.27
Запуск программы из консольного приложения


2-1154672198
Reng
2006-08-04 10:16
2006.08.27
Прогммма сервер не отвечает


6-1144412093
Квэнди
2006-04-07 16:14
2006.08.27
Добавить Ip на интерфейс