windows - Udskift TCustomEdit kontekstmenu med min egen

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg vil erstatte alle popupmenuerne, der vises af delphi i TCustomEdit-komponenterne som TEdit eller TMemo ved hjælp af min egen popup-menu (som har mange flere handlinger). Indtil videre har jeg erstattet PopUpMenu-ejendommen for hver komponent manuelt med min egen TPopUpMenu. men jeg spekulerer på, om jeg kan gøre dette uden at ændre denne egenskab manuelt for hver komponent i alle mine former.


Jeg vil gerne have noget som en krog for at aflytte opkaldene til denne systemmenu og erstatte til min egen menu. Er dette muligt?


Indtast billedbeskrivelse her

Bedste reference


I din hovedformular tilføjes følgende kode. Det bør gælde for alle dine formers brugerkontrol.


TForm2 = class(TForm)
  procedure FormCreate(Sender: TObject);
private
  procedure ActiveControlChanged(Sender: TObject);
end;

implementation

type
  TCustomEditAccess = class(TCustomEdit);
  TCustomGridAccess = class(TCustomGrid);

procedure TForm2.ActiveControlChanged(Sender: TObject);
begin
  if (Screen.ActiveControl is TCustomEdit) and not Assigned(TCustomEditAccess(Screen.ActiveControl).PopupMenu) then
    TCustomEditAccess(Screen.ActiveControl).PopupMenu := MyPopupMenu
  else if (Screen.ActiveControl is TCustomGrid) then
  begin
    TCustomGridAccess(Screen.ActiveControl).ShowEditor;
    if Assigned(TCustomGridAccess(Screen.ActiveControl).InplaceEditor) then
      TCustomEditAccess(TCustomGridAccess(Screen.ActiveControl).InplaceEditor).PopupMenu := MyPopupMenu;
  end;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  Screen.OnActiveControlChange := ActiveControlChanged;
end;


Det er kun en forenklet version (med henblik på kodning) af kobiks svar og vil også adressere enhver TCustomEdit, der oprettes af kode eller andre komplekse Controls, som ikke bruger Form som ejer.


Hans instruktion om, hvordan man bestemmer hvilken CustomEdit popup der skal anvendes.


Rediger: Tilføj Grid InplaceEditor Support

Andre referencer 1


Hvis dine Formularer stammer fra en fælles forfader (i stedet for standard TForm) for eksempel TMyBaseForm, hvilket betyder TForm1 = class(TMyBaseForm), kan det gøres nemt.
I TMyBaseForm.OnShow -hændelsen kan du gentage sig gennem dens kontrol, og hvis du finder en TEdit eller TMemo, sætter du deres PopupMenu ejendom dynamisk.


En anden måde er at bruge Screen.OnActiveFormChange (Screen.OnActiveControlChange brande for sent, hvis du højreklikker på den aktive kontrol - EDIT: Dette er sandt kun med D5 ) i dit hovedformular arrangement handler for at indfange den aktive form og iterere gennem Screen.ActiveForm kontrollerne og indstil TEdit eller TMemo ejendom PopupMenu til din brugerdefinerede MyPopupMenu:


procedure TForm1.FormCreate(Sender: TObject);
begin
  Screen.OnActiveFormChange := ActiveFormChange;
end;    

procedure TForm1.ActiveFormChange(Sender: TObject);
begin
  CustomEditControlsNormalize(Screen.ActiveForm);
end;

type
  TCustomEditAccess = class(TCustomEdit);

procedure TForm1.CustomEditControlsNormalize(F: TForm);
var
  I: Integer;
begin
  if not Assigned(F) then Exit;
  for I := 0 to F.ComponentCount - 1 do
    if F.Components[I] is TCustomEdit then
      TCustomEditAccess(F.Components[I]).Popupmenu := MyPopupMenu;
end;    





For at bestemme hvilken TCustomEdit kontrol, der forårsagede popupmenuen at pop-up, henvises til MyPopupMenu.PopupComponent (i MyPopupMenu.OnPopup hændelsen):


procedure TForm1.MyPopupMenuPopup(Sender: TObject);
begin
  if MyPopupMenu.PopupComponent is TCustomEdit then
  begin
    FEditPopupControl := TCustomEdit(MyPopupMenu.PopupComponent);
    Caption := FEditPopupControl.Name; // debug :-P
  end;
end;





EDIT: Screen.OnActiveControlChange var min første tanke. Jeg har testet det i D5. hvis Edit1 er fokuseret og jeg højreklikker på Edit2, vil det først pop-up standardmenuen, først bliver det den aktive kontrol.
Jeg testede endelig dette med D7 og D2009. begge fungerer fint. Dette er kun et D5-problem , så Justmade s svar er helt sikkert en bedre løsning end at bruge Screen.OnActiveFormChange.

Andre referencer 2


Du kan tildele en enkelt OnContextPopup hændelseshåndterer til alle redigeringskontrollerne, få den til at kalde Popup() -metoden til TPopupMenu og indstille begivenhedens s Handled parameter til True. Men det er ikke meget anderledes end blot at tildele TPopupMenu til alle redigeringskontrollerne direkte.


For at tage det et skridt videre, kan du tildele en enkelt OnContextPopup hændelseshåndterer til din forælder TForm i stedet for de enkelte redigeringsfunktioner. Arrangementet fortæller dig musekoordinaterne, når menuen påberåbes med musen. Du kan finde barnekontrollen under disse koordinater, og hvis det er en af ​​dine redigeringskonfiler, skal du ringe Popup() og indstille Handled til True. Brugeren kan påberåbe menuer ved hjælp af tastaturet, i hvilket tilfælde musekoordinaterne er {-1, -1}, så brug egenskaben TScreen.ActiveControl for at vide, hvilken kontrol der påberåbes.

Andre referencer 3


Du kan gøre Popup-opgaven direkte på en monteret krog i TEdit eller TMemo Class 'NewInstance metoden. Med denne teknik skal du kun medtage en ekstra enhed, der installerer krogen. Krogens kode vil tildele din brugerdefinerede TPopupMenu-objekt til PopupMenu -egenskaben for alle komponenter i klasse TEdit og TMemo, der er oprettet i din ansøgning.


Først skal du slippe et TPopupMenu objekt i en global TDatamodule eller dit hovedformular. Hovedpunktet her er, at PopupMenu forælder altid skal være tilgængelig og være den første, der er oprettet ved din initialisering af applikationen, eller i hvert fald før krogen er installeret.


Derefter opretter du en tom ny enhed. Ring det, hvad du vil. I mit tilfælde popup\_assignment.pas. Kilden er dette:


unit popup\_assignment;

interface

uses Windows, StdCtrls;


implementation

uses globaldatamodule; // Unit of global TPopupMenu parent

{------------------------------------------------------------------------------}

function TEditNewInstance(AClass: TClass): TObject;
begin
    Result := TEdit.NewInstance;
    TEdit(Result).PopupMenu := global\_datamodule.customedit\_popupmenu; // <- your global TPopupMenu component !!!
end;

function TMemoNewInstance(AClass: TClass): TObject;
begin
    Result := TMemo.NewInstance;
    TMemo(Result).PopupMenu := global\_datamodule.customedit\_popupmenu; // <- your global TPopupMenu component !!!
end;

function GetVirtualMethod(AClass: TClass; const VmtOffset: Integer): Pointer;
begin
    Result := PPointer(Integer(AClass) + VmtOffset)^;
end;

procedure SetVirtualMethod(AClass: TClass; const VmtOffset: Integer; const Method: Pointer);
var
    WrittenBytes: DWORD;
    PatchAddress: PPointer;
begin
    PatchAddress := Pointer(Integer(AClass) + VmtOffset);
    WriteProcessMemory(GetCurrentProcess, PatchAddress, @Method, SizeOf(Method), WrittenBytes);
end;


{$IFOPT W+}{$DEFINE WARN}{$ENDIF}{$WARNINGS OFF} // no compiler warning
const
    vmtNewInstance = System.vmtNewInstance;
{$IFDEF WARN}{$WARNINGS ON}{$ENDIF}

var
    orgTEditNewInstance: Pointer;
    orgTMemoNewInstance: Pointer;

initialization
    orgTEditNewInstance := GetVirtualMethod(TEdit, vmtNewInstance);
    orgTMemoNewInstance := GetVirtualMethod(TMemo, vmtNewInstance);

    SetVirtualMethod(TEdit, vmtNewInstance, @TEditNewInstance);
    SetVirtualMethod(TMemo, vmtNewInstance, @TMemoNewInstance);

finalization
    SetVirtualMethod(TEdit, vmtNewInstance, OrgTEditNewInstance);
    SetVirtualMethod(TMemo, vmtNewInstance, orgTMemoNewInstance);

end.

Andre referencer 4


Tilføj en TApplicationEvents-komponent til din delphi-applikation.
Lav din egen popupmenu (popupmenu1)?
I den onMessage af komponenten TApplicationEvents tilføj følgende kode:


procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var
  ctrl: TWincontrol;

begin
  if (msg.Message = WM\_RBUTTONUP) or (msg.Message = WM\_KEYUP ) then begin
     ctrl := FindControl(Msg.hwnd);
     if ctrl <> nil then begin
       if ((ctrl is TEdit))  then begin
        (ctrl as TEdit).PopupMenu := Popupmenu1;
       end;
       if ((ctrl is TMemo))  then begin
        (ctrl as TMemo).PopupMenu := Popupmenu1;
       end;
     end;
   end;
end;


Dette vil aflytte rightclick, og hvis der på den tid er en TEdit eller TMemo under din mousecursor, vil den forbinde popupmenu til den komponent og slukke den.

Andre referencer 5


Andre muligheder:



  1. Brug tilgængelige eksperter funktionaliteter:



    • Brug CnPack Property Corrector og definer handling, der beder dig om specificerede komponentdråber.

    • Brug GExperts Omdøb/Udskift komponenter futures (påkrævet implementering af dine brugerdefinerede kontroller)



  2. Mest komplicerede - implementere TForm efterkommere heks design tid dra og slip og modificer droppe kontroller PupupMenu ejendom. [44]

  3. Ugly men fleksibel og uden nogen efterkommer kontrollerer implementering - brug nedenstående procedure:




    • CustomizePopupMenu (Formular, [[TEdit, TMemo]], MyPopupMenu)

    • TilpasPopupMenu (AnyForm, [[TEdit, TMemo]], AnyPopupMenu)








procedure CustomizePopupMenu(
  const aCtrl: TWinControl;
  const aClasses: array of TControlClass;
  const aPopUp: TPopupMenu);

  procedure Process(const aCtrl: TWinControl;
    const aClasses: array of TControlClass; const aPopUp: TPopupMenu);

    procedure Match(const aCtrl: TControl;
      const aClasses: array of TControlClass; const aPopUp: TPopupMenu);
    var
      Ix: Integer;
    begin
      for Ix := Low(aClasses) to High(aClasses) do
      begin
        if aCtrl.InheritsFrom(aClasses[Ix]) then
           aCtrl.PopupMenu:= aPopUp;
      end;
    end;

  var
    Ix: Integer;
    Ctrl: TControl;
  begin
    for Ix := 0 to Pred(aCtrl.ControlCount) do
    begin

      if aCtrl.Controls[Ix] is TWinControl then
         Process(TWinControl(aCtrl.Controls[Ix]), aClasses, aPopUp);
      Match(aCtrl.Controls[Ix], aClasses, aPopUp)

    end;
  end;


begin
  if (aCtrl <> nil) and (Length(aClasses) > 0) and (aPopUp <> nil) then
     Process(aCtrl, aClasses, aPopUp)
end;