2010-10-20 4 views
5

Je voudrais avoir ma propre barre de légende et donc j'utilise essentiellement un panneau (Nom: pnCaption) et supprimer la barre de légende d'origine dans CreateParams. Mais la possibilité de déplacer la fenêtre par MouseDown-MouseMove dans le nouveau panneau est un problème.Déplacement d'une fenêtre sans légende en utilisant une "zone de glissement"

Normalement, vous utiliseriez le message NCHITTEST. MAIS ceci n'est pas signalé si la souris est sur le panneau (ma propre légende). Voir code ...

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; 

J'apprécierais tous les conseils pour accomplir cette tâche.

Christian

Répondre

13

Vous pouvez toujours faire glisser un fenêtre par n'importe quel contrôle qui a un événement mousedown en utilisant le numéro "Magic" $ F012 avec un message WM_SYSCOMMAND. C'est quelque chose que j'ai appris de Ray Kanopka (auteur des excellents composants raize), mais je ne me rappelle plus comment cela m'a été communiqué.

C'est aussi un moyen simple et facile de permettre aux utilisateurs de déplacer des formulaires sans bordure en leur donnant une étiquette de panneau qui ressemble à une légende. Par exemple, je l'utilise pour permettre aux utilisateurs de se déplacer d'un dialogue sur les frontières:

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 est 'SC_MOVE' avec $ 0002 OR avec. Les 4 bits de poids faible ($ 0000- $ 000F) de 'WM_SYSCOMMAND' sont utilisés par le système d'exploitation en interne. Dans ce cas, $ 0002 signifie que le bit Drag est activé. –

+0

Super - c'est exactement ce que je cherchais. Je vous remercie. – Christian

+0

@Remy: merci. C'est le peu d'information de fond que je n'ai jamais eu :-) –

5

Comme je suis à la recherche dans notre ancien code pour le composant StatusBar personnalisé, qui est descendant de TWinControl, de fournir sous forme de redimensionnement en utilisant la poignée de StatusBar nous traitons WM_NCHITTEST dans le contrôle, pas sous la forme et de retour HTBOTTOMRIGHT:

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; 

Cela signifie que vous devez mettre en œuvre descendant de votre composant de panneau (ou accrochez est la gestion des messages) et la poignée WM_NCHITTEST là.

En outre, j'utiliserais la procédure de gestion des messages WM_NCCALCSIZE et WM_NCPAINT dans le formulaire afin de fournir votre propre zone de légende et d'éviter d'utiliser TPanel ou un autre contrôle. Mais ce n'est que ma préférence.

+0

Hmm, je pensais, que je vais lui donner un essai et descendent d'un TPanel où je l'utilise WM_NCHITTEST de celui-ci. Mais maintenant, je suis en mesure de déplacer le panneau lors de l'exécution :(pas la chose que je voulais;) Je remarque que votre procédure de WMNCHitTest n'a pas de paramètres ... Type TasCaptionPanel = class (TPanel) protégée procédure WM_NCHITTEST (var Msg: TWMNcHitTest); message WM_NCHITTEST; fin; mise en œuvre procédure TasCaptionPanel.WM_NCHITTEST; commencer si TForm (parent).WindowState = wsNormal puis Msg.Result: = HTCAPTION sinon hérité; fin; – Christian

+0

JE SUIS STUCK .. COMMENT PUIS-JE PORTER LE TEXTE COMME CODE DANS LE MESSAGE ORIGINAL – Christian

+0

Pas de paramètres - ce n'est que l'implémentation (qui permet de ne pas copier les paramètres déjà déclarés dans l'interface) Il se peut que le système gère HTBOTTOMRIGHT dans certains cas manière spécifique. –

2

La méthode la plus simple est probablement d'utiliser un composant qui n'a pas de handle de fenêtre HWND et ne peut donc pas recevoir de messages. Ils seront transmis à votre formulaire, où ils peuvent être traités comme vous le montrez dans votre question.

remplaçant simplement le TPanel avec un haut aligné TPaintBox, TImage ou similaire descendant TGraphicControl rendrait votre travail de code. Vous conservez à la fois la gestion des messages du formulaire et la prise en charge de l'alignement de la VCL.

+0

Oui, en utilisant un TBevel ou quelque chose de similaire. La bonne chose avec le TPanel aurait été que je peux laisser tomber d'autres composants en utilisant des techniques VCL simples. – Christian

+0

@Christian: Vous ne l'avez pas spécifié comme exigence dans votre question. Seuls les descendants 'TWinControl' peuvent être parents d'autres contrôles, cette solution ne fonctionnera donc pas. – mghie

2

Pas exactement ce que vous cherchez, mais pour d'autres intéressés par une technique similaire, le code est ici pour un composant TLabel-descendu du ciel qui peut servir de barre de légende:

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

Que va-t-il se passer si je laisse tomber votre contrôle sur un 'TFrame'? Ou si je crée votre composant à l'exécution, en passant un propriétaire qui n'est pas un 'TForm', ou' nil'? – mghie

+1

Sheesh, je ne cherchais pas d'argument; Je publiais juste du code lié à la question qui pourrait être utile à quelqu'un. De votre question, vous avez évidemment compris que le contrôle était destiné à remplacer la légende sur un TForm. En rester là. –

Questions connexes