2010-10-20 7 views
5

Mi piacerebbe avere la mia barra di didascalia e quindi sto usando fondamentalmente un pannello (Nome: pnCaption) e rimuovere la barra dei sottotitoli originale in CreateParams. Ma la possibilità di spostare la finestra con MouseDown-MouseMove nel nuovo pannello è un problema.Spostamento di una finestra senza didascalie utilizzando una "area di trascinamento"

Normalmente si utilizzerà il messaggio NCHITTEST. MA questo non è segnalato se il mouse è sopra il pannello (la mia didascalia). Vedi codice ...

procedure TForm1.CreateParams(var params: TCreateParams); 
begin 
    inherited Createparams(Params); 
    with Params do 
    Style := (Style or WS_POPUP) and (not WS_DLGFRAME); 
end; 

procedure TForm1.WM_NCHitTest(var Msg: TWMNcHitTest); 
begin 
    inherited; 
    if PtInRect(pnCaption.BoundsRect, ScreenToClient(Point(Msg.XPos, Msg.YPos))) 
     then Msg.Result := HTCAPTION; 
end; 

Apprezzerei qualsiasi suggerimento su come eseguire tale compito.

Christian

risposta

13

si può sempre trascinare un finestra da qualsiasi controllo che ha un evento falso usando il numero F012 $ "Magic" con un messaggio WM_SYSCOMMAND. È qualcosa che ho raccolto da Ray Kanopka (autore degli eccellenti componenti per il raize), ma non ricordo più come mi è stato impartito questo.

È anche un modo pulito e semplice per consentire agli utenti di spostare i moduli senza bordi dando loro un'etichetta di pannello che sembra una didascalia. Ad esempio, lo uso per consentire agli utenti di spostare un senza bordi su finestra:

procedure TAbout_Dlg.LblTitleMouseDown(Sender: TObject; 
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
const 
    sc_DragMove = $F012; 
begin 
    ReleaseCapture; 
    Perform(wm_SysCommand, sc_DragMove, 0); 
end; 
+3

$ F012 è 'SC_MOVE' con $ 0002 OR'ed con esso. I 4 bit di ordine inferiore ($images. $ 000F) di 'WM_SYSCOMMAND' sono utilizzati dall'OS internamente. In questo caso, $ 0002 significa che il bit di trascinamento è abilitato. –

+0

Grande - questo fa esattamente quello che stavo cercando. Grazie. – Christian

+0

@Remy: grazie. Questo è un po 'di informazioni di base che non ho mai ricevuto :-) –

5

Come Sto cercando nel nostro vecchio codice per il componente StatusBar personalizzato, che è discendente di TWinControl, per fornire forma ridimensionamento tramite la presa di StatusBar gestiamo WM_NCHITTEST nel controllo, non nella forma e HTBOTTOMRIGHT ritorno:

procedure TElStatusBar.WMNCHitTest; 
var 
    P : TPoint; 

    function InGrip(Point : TPoint) : boolean; 
    var 
    r : TRect; 
    begin 
    R := ClientRect; 
    R.Left := R.Right - R.Bottom + hMargin; 
    result := PtInRect(R, Point); 
    end; 

begin 
    if not FSizeGrip then 
    begin 
    inherited; 
    exit; 
    end; 
    P := ScreenToClient(Point(Message.XPos, Message.YPos)); 
    if InGrip(P) and (TForm(Parent).WindowState = wsNormal) 
    and (TForm(Parent).BorderStyle in [bsSizeable, bsSizeToolWin]) then 
    Message.Result := HTBOTTOMRIGHT 
    else 
    inherited; 
end; 

Questo significa che è necessario implementare discendente del componente del pannello (oppure agganciarlo è gestione dei messaggi) e gestire WM_NCHITTEST lì.

Inoltre, sceglierei il percorso di gestione dei messaggi WM_NCCALCSIZE e WM_NCPAINT nel modulo per fornire la propria area didascalia ed evitare l'uso di TPanel o altri controlli. Ma questa è solo la mia preferenza.

+0

Hmm, ho pensato, che darò una prova e discendo da una TPanel cui uso il WM_NCHITTEST di esso. Ma ora sono in grado di spostare il pannello durante il runtime :(non è la cosa che volevo;) ho notato che la vostra procedura WMNCHitTest non ha parametri ... tipo TasCaptionPanel = class (TPanel) protetto procedura WM_NCHITTEST (var Messaggio: TWMNcHitTest); messaggio WM_NCHITTEST; fine; implementazione procedure TasCaptionPanel.WM_NCHITTEST; iniziare se TForm (Parent).WindowState = wsNormal then Msg.Result: = HTCAPTION else ereditato; fine; – Christian

+0

I AM STUCK .. COME POSSO BANDIERE IL TESTO COME CODICE COME NEL MESSAGGIO ORIGINALE – Christian

+0

Nessun parametro - questa è solo implementazione (che consente di non copiare i parametri, già dichiarati nell'interfaccia) Può essere che il sistema gestisca HTBOTTOMRIGHT in alcuni modo specifico. –

2

Il modo più semplice è probabilmente quello di utilizzare un componente che non ha un handle di finestra HWND e pertanto non può ricevere messaggi. Verranno passati al tuo modulo, dove possono essere gestiti come ti mostri nella tua domanda.

semplicemente sostituendo il TPanel con un top-allineato TPaintBox, TImage o simili TGraphicControl discendente renderebbe il vostro lavoro codice. Si mantiene sia la gestione dei messaggi del modulo sia il supporto di allineamento del VCL.

+0

Sì, utilizzando un TBevel o qualcosa di simile funziona. La cosa bella con il TPanel sarebbe stata la possibilità di far cadere altri componenti su di essa usando semplici tecniche VCL. – Christian

+0

@Christian: non l'hai specificato come requisito nella tua domanda. Solo i discendenti di 'TWinControl' possono essere genitore di altri controlli, quindi questa soluzione non funzionerà allora. – mghie

2

Non è esattamente quello che stai cercando, ma per gli altri interessati a una tecnica simile, ecco il codice per un componente TLabel di discendenza che può servire come una barra didascalia:

unit Draglbl; 

interface 

uses 
    WinTypes, WinProcs, Classes, Graphics, Controls, Forms, StdCtrls; 

type 
    TDragWindowTitle = class(TCustomLabel) 
    private 
    { Private declarations } 
    _lastx, 
    _lasty : integer ; 
    protected 
    { Protected declarations } 
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override ; 
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override ; 
    public 
    { Public declarations } 
    constructor Create(AOwner: TComponent); override; 
    published 
    { Published declarations } 
    property Alignment; 
    property Caption; 
    property Color; 
    property DragCursor; 
    property DragMode; 
    property Enabled; 
    property FocusControl; 
    property Font; 
    property ParentFont; 
    property ParentShowHint; 
    property PopupMenu; 
    property ShowHint; 
    property Visible; 
    property WordWrap; 
    property OnClick; 
    property OnDblClick; 
    property OnDragDrop; 
    property OnDragOver; 
    property OnEndDrag; 
    property OnMouseDown; 
    property OnMouseMove; 
    property OnMouseUp; 
    end; 

procedure Register; 

implementation 
constructor TDragWindowTitle.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner) ; 
    color := clActiveCaption ; 
    font := TForm(AOwner).Font ; 
    font.color := clCaptionText ; 
    Align := alTop ; 
    AutoSize := false ; 
    ShowAccelChar := false ; 
    Transparent := false ; 
end ; 

procedure TDragWindowTitle.MouseMove(Shift: TShiftState; X, Y: Integer); 
begin 
    if ssLeft in Shift then begin 
    TForm(owner).left := TForm(owner).left+(x-_lastx) ; 
    TForm(owner).top := TForm(owner).top+(y-_lasty) ; 
    end ; 

    inherited MouseMove(shift,x,y) ; 
end ; 

procedure TDragWindowTitle.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
begin 
    if Button=mbLeft then begin 
    _lastx := x; 
    _lasty := y ; 
    end ; 
end ; 

procedure Register; 
begin 
    RegisterComponents('MYCOMPONENTS', [TDragWindowTitle]); 
end; 

end. 
+0

Cosa succederà se cancello il tuo controllo su un 'TFrame'? O se creo il tuo componente in fase di runtime, passando un proprietario che non è un 'TForm', o' nil'? – mghie

+1

Sheesh, non stavo cercando un argomento; Stavo semplicemente postando del codice relativo alla domanda che potrebbe essere utile a qualcuno. Dalla tua domanda hai ovviamente capito che il controllo era inteso a sostituire la didascalia su un TForm. Lascia fare a quello. –

Problemi correlati