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

Вниз

Сообщения в неклиентской области окна   Найти похожие ветки 

 
ProgRAMmer Dimonych ©   (2010-02-05 00:37) [0]

Окно WS_POPUP прорисовываю самостоятельно, в т.ч. свой заголовок с кнопками сворачивания/разворачивания/закрытия (дальше - СРЗ). Обработкой сообщения WM_NCHITTEST заставил систему поверить, что мой заголовок - это и есть заголовок окна. Теперь окно перетаскивается за "заголовок" без дополнительных телодвижений в программе.

Стоит задача: обработать случай, когда щелчок попадает по одной из нарисованных мной кнопок СРЗ.

Мои действия:
1. Пишу обработчик WM_NCLBUTTONUP. Обнаруживаю, что сообщение не приходит. MSDN+Google: нужно обработать WM_NCLBUTTONDOWN, чтобы система не перехватывала ввод от мыши и не думала, что пользователь начинает перетаскивать окно.
2. Добавляю обработчик WM_LBUTTONDOWN, возвращаю 0 в соответствии с MSDN, чтобы дать понять, что обрабатываю сам. Получаю закономерную реакцию: кнопки нажимаются, а окно становится неподвижным.
3. Изменяю обработчик WM_LBUTTONDOWN так, чтобы 0 возвращался только при условии, что мышь на одной из кнопок СРЗ, в противном случае передаю сообщение на растерзание DefWindowProc(). Кнопки нажимаются, окно перетаскивается. Но после того, как перетаскивание случилось, кнопки уже не реагируют.
4. MSDN+Google подсказывают красивое на первый взгляд решение: не дать системе опомниться и в обработчике WM_NCHITTEST для областей, соответствующих кнопкам, возвращать HTBORDER, а не HTCAPTION. Результат: в зависимости от того, что возвращается вместо HTCAPTION, поведение меняется, но желаемого добиться не удаётся. Как частный случай: если возвращать HTCLOSE - система при щелчке нагло прорисовывает стандартную кнопку закрытия окна поверх нарисованной мною.

Есть ли вообще шансы обойтись без ручной обработки перетаскивания окна? Каким способом вообще лучше всего реализовать такую функциональность?

P.S. По традиции, системы: все Win32.


 
Игорь Шевченко ©   (2010-02-05 01:14) [1]

Возвращай HTCAPTION только если ты находишься в области своего заголовка, но не своих кнопок, в случае кнопок возвращай HTCLIENT и обрабатывай нажатия самостоятельно (только SetCapture не надо делать)


 
Игорь Шевченко ©   (2010-02-05 01:28) [2]

Виноват, SetCapture надо делать


 
ProgRAMmer Dimonych ©   (2010-02-05 01:36) [3]

Упс, это ж тогда обрабатывать обычное WM_LBUTTONUP? Работает, спс.


 
ProgRAMmer Dimonych ©   (2010-02-05 01:36) [4]

Без SetCapture() почему-то %)


 
Игорь Шевченко ©   (2010-02-05 02:02) [5]

ProgRAMmer Dimonych ©   (05.02.10 01:36) [4]


> Без SetCapture() почему-то %)


Попробуй нажать левую клавишу мыши на кнопке и не отпуская, увести мышь в другую область своего окна, за область своего окна, на заголовок своего окна и понаблюдать за поведением.

Зачем нужно вызывать SetCapture - если ты нажмешь левой клавишей мыши в области кнопки управления окном и начнешь перемещать мышь, не отпуская нажатой клавиши, без SetCapture каждое мышиное событие будет посылать сообщения WM_NCHITTEST, WM_SETCURSOR, WM_(NC)MOUSEMOVE, пока курсор находится в области твоего окна. При уходе мыши из твоего окна, мышиные сообщения твоему окну не посылаются и у тебя останется состояние "зависшего WM_LBUTTONDOWN".

Если же при обработке WM_LBUTTONDOWN вызвать SetCapture, то во-первых, при движении мыши не будет посылаться WM_NCHITTEST, во-вторых, сообщения о перемещениях и состоянии клавиш мыши будут посылаться твоему окну, вне зависимости от того, где находится курсор мыши.

До тех пор, пока ты не отпустишь кнопку.


 
Игорь Шевченко ©   (2010-02-05 02:04) [6]

Я когда-то писал пример для самостоятельного рисования заголовка с кнопками:

unit Popup2;

interface
uses
 Windows, Messages, SysUtils,
 Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, ExtCtrls;

type
 TCapturedButton = (cbtNone, cbtClose, cbtMinimize);

 TfPopup2 = class(TForm)
   ClientPanel: TPanel;
   CloseButton: TButton;
   procedure FormPaint(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
   procedure CloseButtonClick(Sender: TObject);
   procedure FormCreate(Sender: TObject);
   procedure FormActivate(Sender: TObject);
   procedure FormDeactivate(Sender: TObject);
   procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
   procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
   procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
     Y: Integer);
 private
   FCaptionRect : TRect;
   FCapturedButton : TCapturedButton;
   FMouseInCloseButton : Boolean;
   FMouseInMinimizeButton : Boolean;
   FCloseButtonRect : TRect;
   FMinimizeButtonRect : TRect;
   FWindowActive : Boolean;
   FWindowMinimized : Boolean;
   FSavedHeight : Integer;
   procedure WMHCHitTest (var Message : TWMNCHitTest); message WM_NCHITTEST;
   procedure MinimizeButtonClick;
 end;

var
 fPopup2: TfPopup2;

implementation

{$R *.dfm}

procedure TfPopup2.FormPaint(Sender: TObject);
var
 ARect : TRect;
 CaptionFlags : UINT;
 MinButtonKind : UINT;
begin
 CaptionFlags := DC_GRADIENT OR DC_SMALLCAP OR DC_TEXT;
 if FWindowActive then
   CaptionFlags := CaptionFlags OR DC_ACTIVE;
 ARect := ClientRect;
{ DrawEdge рисует линию толщиной в 2 пикселя (Tnx, [MBo]) }
 DrawEdge(Canvas.Handle, ARect, BDR_RAISED, BF_RECT);
 DrawCaption(Handle, Canvas.Handle, FCaptionRect, CaptionFlags);
 if FWindowMinimized then
   MinButtonKind := DFCS_CAPTIONMAX
 else
   MinButtonKind := DFCS_CAPTIONMIN;
 if (FCapturedButton = cbtClose) AND (FMouseInCloseButton) then
   DrawFrameControl(Canvas.Handle, FCloseButtonRect, DFC_CAPTION, DFCS_CAPTIONCLOSE OR DFCS_PUSHED)
 else
   DrawFrameControl(Canvas.Handle, FCloseButtonRect, DFC_CAPTION, DFCS_CAPTIONCLOSE);
 if (FCapturedButton = cbtMinimize) AND (FMouseInMinimizeButton) then
   DrawFrameControl(Canvas.Handle, FMinimizeButtonRect, DFC_CAPTION, MinButtonKind OR DFCS_PUSHED)
 else
   DrawFrameControl(Canvas.Handle, FMinimizeButtonRect, DFC_CAPTION, MinButtonKind);
end;

procedure TfPopup2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action := caFree;
end;

procedure TfPopup2.CloseButtonClick(Sender: TObject);
begin
 Close();
end;

procedure TfPopup2.FormCreate(Sender: TObject);
begin
 SetRect(FCaptionRect, GetSystemMetrics(SM_CXSIZEFRAME), GetSystemMetrics(SM_CYSIZEFRAME),
         Width - GetSystemMetrics(SM_CXSIZEFRAME),
         GetSystemMetrics(SM_CYSMCAPTION)+GetSystemMetrics(SM_CYSIZEFRAME)-1);
 FCloseButtonRect := FCaptionRect;
 InflateRect(FCloseButtonRect, -1, -1);
 FCloseButtonRect.Left := FCloseButtonRect.Right -
                            (FCloseButtonRect.Bottom - FCloseButtonRect.Top);
 FMinimizeButtonRect := FCloseButtonRect;
 OffsetRect(FMinimizeButtonRect, - (FCloseButtonRect.Right - FCloseButtonRect.Left) - 2, 0);
end;

procedure TfPopup2.FormActivate(Sender: TObject);
begin
 FWindowActive := true;
 InvalidateRect(Handle, @FCaptionRect, false);
end;

procedure TfPopup2.FormDeactivate(Sender: TObject);
begin
 FWindowActive := false;
 InvalidateRect(Handle, @FCaptionRect, false);
end;

procedure TfPopup2.WMHCHitTest (var Message : TWMNCHitTest);
begin
 if PtInRect (FCaptionRect,
        ScreenToClient(SmallPointToPoint(Message.Pos))) and NOT
    PtInRect (FCloseButtonRect,
        ScreenToClient(SmallPointToPoint(Message.Pos))) and not
    PtInRect (FMinimizeButtonRect,
        ScreenToClient(SmallPointToPoint(Message.Pos))) then
   Message.Result := HTCAPTION
 else
   inherited;
end;

procedure TfPopup2.FormMouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
begin
 if Button <> mbLeft then
   Exit;
 if NOT PtInRect(FCaptionRect, Point(X,Y)) then
   Exit;
 if PtInRect(FCloseButtonRect, Point(X,Y)) then begin
   FCapturedButton := cbtClose;
   SetCapture(Handle);
   FMouseInCloseButton := true;
 end else if PtInRect(FMinimizeButtonRect, Point(X,Y)) then begin
   FCapturedButton := cbtMinimize;
   FMouseInMinimizeButton := true;
   SetCapture(Handle);
 end;
 if FCapturedButton <> cbtNone then
   InvalidateRect(Handle, @FCaptionRect, false);
end;

procedure TfPopup2.FormMouseUp(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
var
 OldButton : TCapturedButton;
begin
 if Button <> mbLeft then
   Exit;
 if FCapturedButton = cbtNone then
   Exit;
 OldButton := cbtNone;
 if PtInRect(FCloseButtonRect, Point(X,Y)) then
   OldButton := cbtClose
 else if PtInRect(FMinimizeButtonRect, Point(X,Y)) then
   OldButton := cbtMinimize;
 ReleaseCapture();
 FCapturedButton := cbtNone;
 if OldButton <> cbtNone then begin
   InvalidateRect(Handle, @FCaptionRect, false);
   case OldButton of
   cbtClose:
     Close();
   cbtMinimize:
     MinimizeButtonClick;
   end;
 end;
end;

procedure TfPopup2.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
 Y: Integer);
begin
 if FCapturedButton = cbtNone then
   Exit;
 FMouseInCloseButton := PtInRect(FCloseButtonRect, Point(X,Y));
 FMouseInMinimizeButton := PtInRect(FMinimizeButtonRect, Point(X,Y));
 InvalidateRect(Handle, @FCloseButtonRect, false);
 InvalidateRect(Handle, @FMinimizeButtonRect, false);
end;

procedure TfPopup2.MinimizeButtonClick;
begin
 if NOT FWindowMinimized then begin
   FSavedHeight := Height;
   Height := GetSystemMetrics(SM_CYSIZEFRAME)*2 +
         FCaptionRect.Bottom - FCaptionRect.Top;
 end else
   Height := FSavedHeight;
 FWindowMinimized := NOT FWindowMinimized;
 Invalidate;
end;

end.


 
ProgRAMmer Dimonych ©   (2010-02-05 02:27) [7]

Спасибо за пример, сейчас попробую вчитаться. Мне, наверное, показалось, что всё работает нормально, потому что пока что никакой визуально наблюдаемой реакции на нажатие (без отпускания) и наведение для этих кнопок не реализовано... Так что надо будет действительно покопаться как следует.



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

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

Наверх





Память: 0.49 MB
Время: 0.005 c
15-1359516511
Кто б сомневался
2013-01-30 07:28
2013.06.02
Как запускать игру)


15-1359173042
Студент
2013-01-26 08:04
2013.06.02
Сломался USB-Разъём.


15-1359029346
Студент
2013-01-24 16:09
2013.06.02
Колонка и микрофон.


2-1351922003
alexdn
2012-11-03 09:53
2013.06.02
Расширение формы


15-1358803496
N.Cage
2013-01-22 01:24
2013.06.02
Защита приложений





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский