2016-09-23 3 views
2

OnDblClick 이벤트에서 TStatusPanel (Panel of a TStatusBar)의 인덱스를 얻으려는 시도가 있는데, 예를 들어 ShowMessage()과 함께 사용하려고하지만 인덱스를 얻는 방법을 모르겠습니다.TStatusPanel (StatusBar - Delphi)의 색인을 얻는 방법은 무엇입니까?

나는 OnDrawPanel 같은 이벤트가 Panel: TStatusPanel 매개 변수가 있음을 알지만, OnDblClick에서 같은 일을 필요로하지만, 하나의 매개 변수, Sender: TObject이있다.

예를 들어 if StatusBar.Panel = 1과 같은 명령이 없습니다. StatusBar.Panels[0]을 사용할 수는 있지만 내 메시지를 표시하기 위해 클릭 한 인덱스를 비교하는 방법을 모릅니다.

글쎄, 그건 내가 쉬운 방법에 필요한 작업은 다음과 같습니다

if StatusBar.Panel = 0 then 
    showmessage('0') 
else if StatusBar.Panel = 1 then 
    showmessage('1'); 

내가 위의 코드는 작동하지 않습니다 알고, 그냥 예입니다.

if StatusBar.Panels[0].'SOMETHING' = 0 then 
    showmessage('0') 
else if StatusBar.Panels[0].'SOMETHING' = 1 then 
    showmessage('1'); 
+0

GetMessagePos를 호출하여 어떤 패널을 클릭했는지 확인합니다. –

+0

David Heffernan, 답변 주셔서 감사합니다.하지만 StatusBar는 크기를 조정할 수있는 형식이므로 GetMessagePos는 다른 위치를 반환합니다. – SisMaster

+0

그래서 뭐. 패널 위치를 알아야합니다. 그리고 당신이 속한 운동을 찾으십시오. –

답변

4

당신은 더블 클릭 핸들러를가 터 WM_LBUTTONDBLCLK 메시지가 검색되는 마우스 위치를 얻을 수 OnDblClick 이벤트 처리기에서 GetMessagePos를 사용하고 클라이언트 좌표로 변환 할 수 있습니다 :이 같은해야한다. 그런 다음 상태 막대의 패널을 반복하여 마우스가 있던 부분을 찾을 수 있습니다. 예 :

procedure TForm1.StatusBar1DblClick(Sender: TObject); 
var 
    Pt: TPoint; 
    i, w: Integer; 
begin 
    Pt := SmallPointToPoint(TSmallPoint(DWORD(GetMessagePos))); 
    MapWindowPoints(HWND_DESKTOP, StatusBar1.Handle, Pt, 1); 
    w := 0; 
    for i := 0 to StatusBar1.Panels.Count - 1 do begin 
    w := w + StatusBar1.Panels[i].Width; 
    if Pt.X < w then begin 
     ShowMessage(IntToStr(i)); 
     Break; 
    end; 
    end; 
end; 

선택적으로 대신 이벤트 처리기에서 더블 클릭의 OnMouseDown 이벤트 핸들러, 마우스가 이미 전달 클릭 할 경우 좌표하는 클라이언트 및 테스트를 사용하여 다음 패널을 찾습니다. 더블 클릭이있을 때 WM_LBUTTONDBLCLK에서 해고되었으므로 OnMouseDown 핸들러를 사용할 때 부작용이 없습니다.

procedure TForm1.StatusBar1MouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
var 
    i, w: Integer; 
begin 
    if (Button = mbLeft) and (ssDouble in Shift) then begin 
    w := 0; 
    for i := 0 to StatusBar1.Panels.Count - 1 do begin 
     w := w + StatusBar1.Panels[i].Width; 
     if X < w then begin 
     ShowMessage(IntToStr(i)); 
     Break; 
     end; 
    end; 
    end; 
end; 
1

거의 동일한 로직이지만 상태 표시 줄에서 실제 패널 경계를 가져옵니다. 즉, 패널 사이의 구분 기호를 클릭하면 -1이 반환됩니다.

uses 
    Winapi.CommCtrl; 

procedure TForm1.StatusBar1DblClick(Sender: TObject); 
var 
    LClickPos: TPoint; 
    LIndex: Integer; 

    function GetPanelIndex: Integer; 
    var 
    I: Integer; 
    LRect: TRect; 
    begin 
    for I := 0 to StatusBar1.Panels.Count - 1 do 
    begin 
     if SendMessage(StatusBar1.Handle, SB_GETRECT, I, LPARAM(@LRect)) <> 0 then 
     begin 
     if PtInRect(LRect, LClickPos) then 
      Exit(I); 
     end; 
    end; 

    Result := -1; 
    end; 

begin 
    LClickPos := SmallPointToPoint(TSmallPoint(GetMessagePos())); 
    LClickPos := StatusBar1.ScreenToClient(LClickPos); 
    LIndex := GetPanelIndex; 

    Application.MessageBox(PChar(Format('Panel %d', [LIndex])), 'Test'); 
end; 
+2

SB_RECT로 더 정확 해졌지만 GetCursorPos로 정확성을 포기했습니다. –

+0

GetMessagePos를 사용하는 것이 중요합니다. –

+0

고마워요. GetMessagePos에 고정되었습니다. –

2

나는 SB_GETPARTS 대신 SB_GETRECT의를 사용하는 것이 좋습니다 것입니다. 그런 식으로, 당신은 TStatusBar에 적은 메시지를 보내는 :

uses 
    ..., Winapi.CommCtrl; 

function GetStatusPanelAt(StatusBar: TStatusBar; X, Y: Integer): TStatusPanel; overload; 
function GetStatusPanelAt(StatusBar: TStatusBar; const P: TPoint): TStatusPanel; overload; 

... 

function GetStatusPanelAt(StatusBar: TStatusBar; X, Y: Integer): TStatusPanel; 
begin 
    Result := GetStatusPanelAt(StatusBar, Point(X, Y)); 
end; 

function GetStatusPanelAt(StatusBar: TStatusBar; const P: TPoint): TStatusPanel; 
var 
    index: Integer; 
    arr: array of Integer; 
    Panel: TStatusPanel; 
begin 
    Result := nil; 

    if not PtInRect(StatusBar.ClientRect, P) then 
    Exit; 

    SetLength(arr, SendMessage(StatusBar.Handle, SB_GETPARTS, 0, 0)); 
    SendMessage(StatusBar.Handle, SB_GETPARTS, Length(arr), LPARAM(PInteger(arr))); 

    index := 0; 
    while index < Length(arr) do 
    begin 
    if (P.X <= arr[index]) or (arr[index] = -1) then 
    begin 
     Result := StatusBar.Panels[index]; 
     Exit; 
    end; 
    Inc(index); 
    end; 
end; 

그럼 당신은이 작업을 수행 할 수 있습니다

uses 
    ..., System.Types, Winapi.Windows; 

procedure TForm5.StatusBar1DblClick(Sender: TObject); 
var 
    Pt: TPoint; 
    Panel: TStatusPanel; 
begin 
    Pt := SmallPointToPoint(TSmallPoint(GetMessagePos())); 
    Pt := StatusBar1.ScreenToClient(Pt); 

    Panel := GetStatusPanelAt(StatusBar1, Pt); 
    if Panel <> nil then 
    ShowMessage('Click on Panel ' + IntToStr(Panel.Index)) 
    else 
    ShowMessage('No click on a Panel'); 
end; 

Alternativly, 당신은 D2006 이상을 사용하는 경우, 당신은 클래스로 논리를 포장 할 수 있습니다 대신 도우미 :

uses 
    ..., Winapi.CommCtrl; 

type 
    TStatusBarHelper = class helper for TStatusBar 
    public 
    function GetPanelAt(X, Y: Integer): TStatusPanel; overload; 
    function GetPanelAt(const P: TPoint): TStatusPanel; overload; 
    end; 

... 

function TStatusBarHelper.GetPanelAt(X, Y: Integer): TStatusPanel; 
begin 
    Result := GetPanelAt(Point(X, Y)); 
end; 

function TStatusBarHelper.GetPanelAt(const P: TPoint): TStatusPanel; 
var 
    index: Integer; 
    arr: array of Integer; 
    Panel: TStatusPanel; 
begin 
    Result := nil; 

    if not PtInRect(Self.ClientRect, P) then 
    Exit; 

    SetLength(arr, SendMessage(Self.Handle, SB_GETPARTS, 0, 0)); 
    SendMessage(Self.Handle, SB_GETPARTS, Length(arr), LPARAM(PInteger(arr))); 

    index := 0; 
    while index < Length(arr) do 
    begin 
    if (P.X <= arr[index]) or (arr[index] = -1) then 
    begin 
     Result := Self.Panels[index]; 
     Exit; 
    end; 
    Inc(index); 
    end; 
end; 

uses 
    ..., System.Types, Winapi.Windows; 

procedure TForm5.StatusBar1DblClick(Sender: TObject); 
var 
    Pt: TPoint; 
    Panel: TStatusPanel; 
begin 
    Pt := SmallPointToPoint(TSmallPoint(GetMessagePos())); 
    Pt := StatusBar1.ScreenToClient(Pt); 

    Panel := StatusBar1.GetPanelAt(Pt); 
    if Panel <> nil then 
    ShowMessage('Click on Panel ' + IntToStr(Panel.Index)) 
    else 
    ShowMessage('No click on a Panel'); 
end; 
,