2017-06-05 3 views
3

Ich verwende eine alte Vorläufer der DevExpress QuantumGrid (MasterView) in Delphi XE2 und möchte bestimmte Zellen effektiv als Hyperlinks (den Mauszeiger aus crDefault zu crHandPoint, wenn sie über sie sind und eine Aktion bei Klick auslösen).Ändern Sie den Mauszeiger, wenn über bestimmte Komponenten ohne andere Cursor-Einstellung Code

Die Konfiguration der Rasterkomponente ist so, dass einzelne Zellen keine eigene Komponente sind, und ich muss die Zelle aus den Mauszeigerkoordinaten finden und den Cursor von dort setzen.

Ich denke, ich muss ein paar Ereignisse auf meinem Gitterobjekt festlegen, um dies zu erreichen, aber ich bin ein wenig unwohl darüber, wie diese Ereignisse mit Code interagieren, der den Cursor zu einer Sanduhr bei lang laufenden Operationen setzt (wird derzeit mit IDisposible gehandhabt, um den Cursor nach Fertigstellung auf das Original zurückzusetzen, und ich möchte noch einmal überprüfen, ob es einen besseren Weg gibt, bevor ich anfange, und dann eine Tonne Kantenfälle finden, die den Mauszeiger im falschen Zustand belassen .

Ich glaube, ich außer Kraft setzen müssen:

  • omMouseMove - erhalten XY-Koordinaten und setzen Sie den Cursor auf der Hand/Pfeil
  • onMouseDown - erhalten XY-Koordinaten und 'aktivieren' Hyperlink falls vorhanden (möglicherweise auf Pfeil umkehren? Der Hyperlink öffnet normalerweise ein neues Fenster und der aufgerufene Code kann den Cursor in eine Sanduhr verwandeln.)
  • onMouseLeave - Cursor auf Pfeil zurücksetzen (dieses Ereignis wird nicht wirklich angezeigt, also denke, ich brauche um Nachrichten manuell zu behandeln)

Diese Art von Funktionalität ist standardmäßig auf einem TButton, aber ich konnte nicht in der VCL sehen, wie es auf den ersten Blick erreicht wird, und möglicherweise eine Funktion der zugrunde liegenden Windows-Steuerelement.

+1

Griff [ 'WM_SETCURSOR'] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms648382.aspx) –

+0

Vielleicht wird dies helfen: https: // Paketüberfluss.com/questions/19257237/reset-cursor-in-wm-setcursor-handler-richtig –

+0

Oder diese https://stackoverflow.com/q/19570880/8041231 – Victoria

Antwort

0

Ich habe tatsächlich die Lösung beim Surfen in SO gefunden.

Ich hatte vergessen, dass die Komponenten in der Regel ihre eigenen Cursor-Eigenschaft haben, die ist, wie sie die richtige Maus-Cursor-Typ festgelegt, wenn sich der Mauszeiger über ihnen (dh Taste Verhalten)

Durch Mouseüberschreiben Sie den Cursor zu ändern crHandPoint Wenn es sich um eine Hyperlink-Zelle handelt und die alte Cursor-Eigenschaft gespeichert wird, zu der es zurückkehrt, wenn es nicht über einen Hyperlink geht, scheint es gut zu funktionieren (und separat zu screen.cursor, das im lang laufenden Code festgelegt ist). Ich muss den Code abschließen, um zu bestätigen, dass er richtig funktioniert, also lasse ich die Frage für jetzt unbeantwortet, bis ich bestätigen kann, dass alles wie erwartet funktioniert.

edit: Hinzufügen von Code. Ich habe mich dafür entschieden, eine Interceptor-Klasse zu verwenden, anstatt das Grid zu untergliedern und das Steuerelement zu registrieren - ich verwende es nur an ein oder zwei Orten in einer App und es erspart mir, die Maschinen aller anderen zu konfigurieren.

TdxMasterView = class(dxMasterView.TdxMasterView) 
private 
    FDefaultCursor: TCursor; 
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; 
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; 
public 
    constructor Create(AOwner: TComponent); override; 
end; 

constructor TdxMasterView.Create(AOwner: TComponent); 
begin 
    inherited create(AOwner); 
    FDefaultCursor := self.Cursor; 
end; 

procedure TdxMasterView.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
var 
    lvHitTestCode: TdxMasterViewHitTestCode; 
    lvNode : TdxMasterViewNode; 
    lvColumn: TdxMasterViewColumn; 
    lvRowIndex, lvColIndex: integer; 
begin 
    inherited; 
    lvHitTestCode := self.GetHitTestInfo(Point(X,Y), 
              lvNode, 
              lvColumn, 
              lvRowIndex, 
              lvColIndex); 
    if (lvHitTestCode = htContent) and (lvColumn is TMasterViewClickableColumn) then 
    begin 
    TMasterViewClickableColumn(lvColumn).onClickContentCell(lvNode); 
    end; 
end; 

procedure TdxMasterView.MouseMove(Shift: TShiftState; X, Y: Integer); 
var 
    lvHitTestCode: TdxMasterViewHitTestCode; 
    lvNode : TdxMasterViewNode; 
    lvColumn: TdxMasterViewColumn; 
    lvRowIndex, lvColIndex: integer; 
begin 
    inherited; 
    lvHitTestCode := self.GetHitTestInfo(Point(X,Y), 
              lvNode, 
              lvColumn, 
              lvRowIndex, 
              lvColIndex); 
    if (lvHitTestCode = htContent) and (lvColumn is TMasterViewClickableColumn) then 
    begin 
    self.cursor := TMasterViewClickableColumn(lvColumn).cursorOnMouseOver; 
    end 
    else 
    begin 
    self.cursor := self.FDefaultCursor; 
    end; 
end; 
+0

Ich wette, das Gitter selbst behandelt die 'WM_SETCURSOR'-Nachricht gefolgt von einige Hit-Test-Tests, wenn der 'HitTest' -Parameter des Message-Handlers' HTCLIENT' ist. Wenn ja, würde ich diesen Weg folgen, nur die Hit-Test-Methode erweitert und so etwas in Pseudocode 'if (Msg.HitTest = HTCLIENT) und (GetHitTest () = htLinkHover) dann ChangeToMyCursor sonst geerbt;'. – Victoria

+0

@Victoria scheint die 'Cursor' -Eigenschaft, die vom TControl-Vorfahren stammt, nur ein Wrapper um die WM_SETCURSOR-Windows-Nachricht zu sein. Die Eigenschaft verfügt über einen Setter, der die Aufrufe von WM_SETCURSOR verarbeitet, wenn es sich ändert. Ich habe gerade eine spezielle FOriginalCursor-Eigenschaft gemacht, um den alten Cursor zu halten und die VCL einfach die erforderlichen Anrufe behandeln zu lassen. Ich bearbeite meine Antwort, um Code einzublenden, aber ich denke, es ist die einfachere Lösung. –

+0

Ich dachte, Sie ändern den ursprünglichen Gittercode. Wenn ja, könntest du dem folgen, was ich geschrieben habe (so etwas könnte dort möglicherweise existieren). Wie ich bereits in meiner Antwort erwähnt habe, wird beim Aufruf von 'geerbt' im' WM_SETCURSOR'-Message-Handler standardmäßig der 'Cursor' verwendet. Und es ist kein Wrapper. Das Nachrichtensystem fragt nach dem Cursor und Sie legen ihn dort selbst fest, oder rufen Sie 'geerbt' auf, damit VCL seinen Standardjob ausführen kann. – Victoria

1

Dies ist ein Szenario, das ich bevorzugen würde. Der Cursor wird vom Meldungshandler WM_SETCURSOR gesetzt, und die Back-End-Arbeit wird durch ein Flag signalisiert. Link-Klick wird dann von der Methodenüberschreibung MouseDown behandelt. Beachten Sie, dass der Cursor nur für dieses Steuerelement geändert wird (wenn der Mauszeiger das Steuerelement bewegt). In Pseudo-Code:

type 
    THitCode = 
    (
    hcHeader, 
    hcGridCell, 
    hcHyperLink { ← this is the extension } 
); 

    THitInfo = record 
    HitRow: Integer; 
    HitCol: Integer; 
    HitCode: THitCode; 
    end; 

    TMadeUpGrid = class(TGridAncestor) 
    private 
    FWorking: Boolean; 
    procedure DoStartWork; 
    procedure DoFinishWork; 
    procedure UpdateCursor; 
    procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR; 
    protected 
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; 
    public 
    function GetHitTest(X, Y: Integer): THitInfo; override; 
    end; 

implementation 

procedure TMadeUpGrid.DoStartWork; 
begin 
    FWorking := True; 
    UpdateCursor; 
end; 

procedure TMadeUpGrid.DoFinishWork; 
begin 
    FWorking := False; 
    UpdateCursor; 
end; 

procedure TMadeUpGrid.UpdateCursor; 
begin 
    Perform(CM_CURSORCHANGED, 0, 0); { ← triggers WM_SETCURSOR handler if needed } 
end; 

procedure TMadeUpGrid.WMSetCursor(var Msg: TWMSetCursor); 
var 
    P: TPoint; 
    HitInfo: THitInfo; 
begin 
    { the mouse is inside the control client rect, inherited call here should 
    "default" to the Cursor property cursor type } 
    if Msg.HitTest = HTCLIENT then 
    begin 
    GetCursorPos(P); 
    P := ScreenToClient(P); 
    HitInfo := GetHitTest(P.X, P.Y); 
    { if the mouse is hovering a hyperlink or the grid backend is working } 
    if FWorking or (HitInfo.HitCode = hcHyperLink) then 
    begin 
     { here you can setup the "temporary" cursor for the hyperlink, or 
     for the working grid backend } 
     if not FWorking then 
     SetCursor(Screen.Cursors[crHandPoint]) 
     else 
     SetCursor(Screen.Cursors[crHourGlass]); 
     { tell the messaging system that this message has been handled } 
     Msg.Result := 1; 
    end 
    else 
     inherited; 
    end 
    else 
    inherited; 
end; 

procedure TMadeUpGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
var 
    HitInfo: THitInfo; 
begin 
    if Button = mbLeft then 
    begin 
    HitInfo := GetHitTest(X, Y); 
    { the left mouse button was pressed when hovering the hyperlink, so set 
     the working flag, trigger the WM_SETCURSOR handler "manually" and do the 
     navigation; when you finish the work, call DoFinishWork (from the main 
     thread context) } 
    if HitInfo.HitCode = hcHyperLink then 
    begin 
     DoStartWork; 
     DoSomeNavigation(HitInfo.HitRow, HitInfo.HitCol); 
    end; 
    end; 
end; 

function TMadeUpGrid.GetHitTest(X, Y: Integer): THitInfo; 
begin 
    { fill the Result structure properly } 
end; 
Verwandte Themen