フォームのサイズを変更するには?


ポルン  2006-01-06 17:51:49  No: 19498

目的は、フォーム上にマウスカーソルが移動するとフォームのサイズを
大きくし、フォーム外にマウスカーソルが移動するとフォームのサイズを
元に戻すようにしたいのです。

以下のようにしてみたのですが、まったく動作しません。
条件判断をなくしてみると、動作したりしなかったりまた、
フォーム上の他のコンポーネント等を移動させると
メニューが大きくなったり小さくなったりと表示されるため
フラッシュ状態?になります。

どうすればよいのでしょうか?

type
  TForm1 = class(TForm)
      :
  private
      :
    procedure CMMouseEnter(var Msg: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
      :
  end;

procedure TForm1.CMMouseEnter(var Msg: TMessage);
begin
  if TComponent(Msg.LParam) = Form1 then begin
    Width  := 500;
    Height := 500;
  end;
end;

procedure TForm1.CMMouseLeave(var Msg: TMessage);
begin
  if TComponent(Msg.LParam) = Form1 then begin
    Width  := 100;
    Height := 100;
  end;
end;


ん?  2006-01-06 20:02:24  No: 19499

難しい説明はコレ
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=060434

メッセージ処理が停止するらしいので、WM_MOUSEHOVER を使うのがいいのかもしれない。


ん?  2006-01-06 20:05:50  No: 19500

WM_MOUSEHOVER じゃなくて、TrackMouseEventのほうかな?


ポルン  2006-01-08 01:49:42  No: 19501

お恥ずかしい
まったく動きません。

>WM_MOUSEHOVER じゃなくて、TrackMouseEventのほうかな?
これを参考に検索して、サンプルみたいなのがあったので
作ってみたのですが、(すみません。理解せず作ってます)
やはり、まったく動きません。

どうすればよいのでしょうか?
ちなみに以下ソースです。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
  private
  public
  end;

var
  Form1: TForm1;
  LPTRACKMOUSEEVENT: tagTRACKMOUSEEVENT;

implementation

{$R *.dfm}

procedure TrackMouseTimerProc(hWnd: HWND; uMsg: UINT; idEvent: UINT; dwTime: DWORD);
var
  rect:  TRect;
  pt:    TPoint;
begin
  GetClientRect(hWnd, rect);
  MapWindowPoints(hWnd, NULL, rect, 2);

  GetCursorPos(pt);
  if (not PtInRect(rect, pt) or (WindowFromPoint(pt) <> hWnd)) then begin
    if ( not KillTimer(hWnd,idEvent)) then begin
      // エラーのためタイマー停止
    end;
    PostMessage(hWnd,WM_MOUSELEAVE,0,0);
  end;
end;

function TrackMouseEvent(ptme: PTRACKMOUSEEVENT): Boolean;
begin
  if ( (ptme <> Nil) or (ptme.cbSize < sizeof(tagTRACKMOUSEEVENT)) ) then begin
    Result := False;
    Exit;
  end;

  if ( not IsWindow(ptme.hwndTrack) ) then begin
    Result := False;
    Exit;
  end;

  if ( (ptme.dwFlags and TME_LEAVE) = 0 ) then begin
    Result := False;
    Exit;
  end;

  Result := (SetTimer(ptme.hwndTrack, ptme.dwFlags, 100, @TrackMouseTimerProc) <> 0);
end;

var
  fInWindow:  Boolean;
  fInMenu:    Boolean;

function MainWndProc(hWnd: HWND; uMsg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT;
var
  tme:  tagTRACKMOUSEEVENT;
begin
  case uMsg of
  WM_CREATE:
    begin
      fInWindow := FALSE;
      fInMenu := FALSE;
      Result := 0;
      Exit;
    end;
  WM_MOUSEMOVE:
    begin
      if not fInWindow then begin
        fInWindow := TRUE;
        tme.cbSize := sizeof(tagTRACKMOUSEEVENT);
        tme.dwFlags := TME_LEAVE;
        tme.hwndTrack := hWnd;
        if TrackMouseEvent(@tme) then begin
          MessageBox(hWnd, 'TrackMouseEvent Failed', 'Mouse Leave', MB_OK);
        end;
      end;
    end;
  WM_MOUSELEAVE:
    begin
      fInWindow := FALSE;
      if not fInMenu then begin
         MessageBox(hWnd, 'Elvis has left the building', 'Mouse Leave', MB_OK);
      end;
    end;
  WM_ENTERMENULOOP:
    begin
      fInMenu := TRUE;
    end;
  WM_EXITMENULOOP:
    fInMenu := FALSE;
  else
    Result := DefWindowProc( hWnd, uMsg, wParam, lParam);
    Exit;
  end;
  Result := 0;
end;

end.


ママん  2006-01-08 02:29:13  No: 19502

あけおめことよろ。
こんな感じでどーでしょう。
すみませんが上のソースは見てません。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Menus;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    FTME:TTRACKMOUSEEVENT;
    TrackLeave:boolean;
    TrackHover:boolean;
    procedure NewWndProc(var AMsg:TMessage);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;
  OldWndProc:TWndMethod;
implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 TrackLeave:= false;
 TrackHover:= true;
 FTME.cbSize      := sizeof(TTRACKMOUSEEVENT);
 FTME.dwFlags     := TME_LEAVE;
 FTME.dwHoverTime := HOVER_DEFAULT;
 FTME.hwndTrack   := Application.Handle;
 TrackMouseEvent(FTME);

 OldWndProc  := WindowProc;
 WindowProc  := NewWndProc;
end;

procedure TForm1.NewWndProc(var AMsg:TMessage);
  procedure leaveCheck;
    var cPos:TPoint;
  begin
    cpos:=Point(0,0);
    GetCursorPos(cpos);
    if ((cpos.X <= Left) or (cPos.X >= Left+Width )) or
       ((cpos.Y <= Top ) or (cPos.Y >= Top +Height)) then
    begin
      Width :=200;
      Height:=100;
    end;
    TrackLeave := false;
    TrackHover := true;
  end;
begin
 case AMsg.Msg of
  WM_NCMOUSELEAVE :leaveCheck;
  WM_MOUSELEAVE   :leaveCheck;
  WM_MOUSEMOVE :
                begin
                  if not TrackLeave then
                  begin
                    TrackLeave      := true;
                    FTME.cbSize     := sizeof(TTRACKMOUSEEVENT);
                    FTME.dwFlags    := TME_LEAVE;
                    FTME.dwHoverTime:= HOVER_DEFAULT;
                    FTME.hwndTrack  := Handle;
                    TrackMouseEvent(FTME);
                  end;
                  if TrackHover then
                  begin
                    Width :=300;
                    Height:=300;
                    TrackHover := false;
                  end;

                end;
 end;
 OldWndProc(AMsg);
end;

end.


わからんちん  2006-01-08 04:23:00  No: 19503

ママんさんのソース、実行レポ

マウスを高速で出入りするとOK。
スロー・スピードではNG。

フォームが全面パネルとかに覆われているとNG。

・・・こんな感じでした。

乗ってるコントロールすべてにディスバッチしないと・・・
な感じなんですけどね、初心者なのでよくわかりません。

Variants をインクルードするとエラーが出るので削除しました。(D4)
それと  WM_NCMOUSELEAVE :leaveCheck; の部分と。
これのせい?


Mr.XRAY  URL  2006-01-08 10:11:52  No: 19504

JournalHook(ジャーナルフック)を使用した例です.
なお,他の方のコードは試していません.解説コードの中の説明ということで
省略させていただきます.

var
  Form1       : TForm1;
  ALeft       : Integer;
  ATop        : Integer;
  AWidth      : Integer;
  AHeight     : Integer;
  TargetWin   : HWND;
  JournalHook : HHOOK = 0;
  MsgID       : Integer;

implementation

{$R *.DFM}

//=============================================================================
//  フック関数のメッセージを受取る
//  ここではマウスの移動のみ処理
//  マウスがFormを離れるとFormのサイズが小さくなる.小さくなったFormは,必ず元
//  のFormの中に収まらなければならない.何故なら,元のFormの外側になると,
//  (1) 小さくなったFormの中にマウスがくる
//  (2) これはFormの中なので大きくなる
//  (3) ところが,現在のマウスの位置は大きくなったFormの外側である
//  (4) そこでFormは小さくなろうとする
//  以上を繰り返すので,大きいFormと小さいFormが交互に表示されることになる.
//=============================================================================
function WatchProc(nCode: Integer; wPara: WPARAM;lParam:LPARAM):LRESULT;
stdcall;
var
     event : pEVENTMSG;
     Pos   : TPOINT;
begin
    if nCode < 0 then begin
      Result := CallNextHookEx(JournalHook,nCode,wPara,lParam)
    end else begin
      Result := 0;
      if nCode = HC_ACTION then begin
        event := pEVENTMSG(lParam);
        case {p}Event^.Message of
          WM_MOUSEMOVE:   MsgID := 1;
        else
          MsgID := 0;
        end;
        if MsgID = 1 then begin
          GetCursorPos(Pos);
          if PtInRect(Form1.BoundsRect,Pos) then begin
            Form1.SetBounds(ALeft,ATop,AWidth,AHeight);
          end else begin
            Form1.SetBounds(ALeft,ATop,AWidth div 2,AHeight div 2);
          end;
        end;
      end;
    end;
end;
//=============================================================================
//  フックの開始
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
     TargetWin := FindWindow(nil, pchar('Form1'));
    if TargetWin <> 0 then begin
      JournalHook :=SetWindowsHookEx(WH_JOURNALRECORD,
                                     Addr(WatchProc),
                                     MainInstance,
                                     0);
      ALeft   := Self.Left;
      ATop    := Self.Top;
      AWidth  := Self.Width;
      AHeight := Self.Height;
    end;
end;
//=============================================================================
//  フック終了
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  if JournalHook <> 0 then begin
    UnhookWindowsHookEx(JournalHook);
    JournalHook := 0;
  end;
end;
//=============================================================================
//  Formがなくなるときはフック終了
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
begin
     Button2Click(Sender);
end;

end.


ママん  2006-01-09 03:30:40  No: 19505

WM_NCMOUSELEAVE :leaveCheck;
これがスロースピードの時の検出メッセージです。
CM_MOUSELEAVEで代用可能です。
ちなみに私の例はTrackMouseEventの使用例っぽいものですので、
あくまでTrackMouseEventを使うならこんな感じ的のものです。

私はコントロール上にマウスがあるかの判断はTrackMouseEventが作法的に礼儀正しい気がしますが、タイマーやJournalHookでももちろん可能です。
初心者だったらタイマーでいいんでないっすか?


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加