When you uses an Edit control like a TMemo or TEdit component a context menu pops up with options to undo, copy, paste, select all, etc.
Unfortunally the TSynEdit component doesn’t include a menu like this, so you must write you own. You can fix this in a few lines of code using a interposer class. Check this unit which implements a standard context menu for a TSynEdit component, based on a TActionList (only be sure to include the uSynEditPopupEdit unit after of the SynEdit unit in your uses list).
unit uSynEditPopupEdit;
interface
uses
ActnList,
Menus,
Classes,
SynEdit;
type
TSynEdit = class(SynEdit.TSynEdit)
private
FActnList: TActionList;
FPopupMenu : TPopupMenu;
procedure CreateActns;
procedure FillPopupMenu(APopupMenu : TPopupMenu);
procedure CutExecute(Sender: TObject);
procedure CutUpdate(Sender: TObject);
procedure CopyExecute(Sender: TObject);
procedure CopyUpdate(Sender: TObject);
procedure PasteExecute(Sender: TObject);
procedure PasteUpdate(Sender: TObject);
procedure DeleteExecute(Sender: TObject);
procedure DeleteUpdate(Sender: TObject);
procedure SelectAllExecute(Sender: TObject);
procedure SelectAllUpdate(Sender: TObject);
procedure RedoExecute(Sender: TObject);
procedure RedoUpdate(Sender: TObject);
procedure UndoExecute(Sender: TObject);
procedure UndoUpdate(Sender: TObject);
procedure SetPopupMenu_(const Value: TPopupMenu);
function GetPopupMenu_: TPopupMenu;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property PopupMenu: TPopupMenu read GetPopupMenu_ write SetPopupMenu_;
end;
implementation
uses
SysUtils;
const
MenuName='uSynEditPopupMenu';
procedure TSynEdit.CopyExecute(Sender: TObject);
begin
Self.CopyToClipboard;
end;
procedure TSynEdit.CopyUpdate(Sender: TObject);
begin
TAction(Sender).Enabled :=Self.SelAvail;
end;
procedure TSynEdit.CutExecute(Sender: TObject);
begin
Self.CutToClipboard;
end;
procedure TSynEdit.CutUpdate(Sender: TObject);
begin
TAction(Sender).Enabled :=Self.SelAvail and not Self.ReadOnly;
end;
procedure TSynEdit.DeleteExecute(Sender: TObject);
begin
Self.SelText := '';
end;
procedure TSynEdit.DeleteUpdate(Sender: TObject);
begin
TAction(Sender).Enabled :=Self.SelAvail and not Self.ReadOnly;
end;
procedure TSynEdit.PasteExecute(Sender: TObject);
begin
Self.PasteFromClipboard;
end;
procedure TSynEdit.PasteUpdate(Sender: TObject);
begin
TAction(Sender).Enabled :=Self.CanPaste;
end;
procedure TSynEdit.RedoExecute(Sender: TObject);
begin
Self.Redo;
end;
procedure TSynEdit.RedoUpdate(Sender: TObject);
begin
TAction(Sender).Enabled :=Self.CanRedo;
end;
procedure TSynEdit.SelectAllExecute(Sender: TObject);
begin
Self.SelectAll;
end;
procedure TSynEdit.SelectAllUpdate(Sender: TObject);
begin
TAction(Sender).Enabled :=Self.Lines.Text<>'';
end;
procedure TSynEdit.UndoExecute(Sender: TObject);
begin
Self.Undo;
end;
procedure TSynEdit.UndoUpdate(Sender: TObject);
begin
TAction(Sender).Enabled :=Self.CanUndo;
end;
constructor TSynEdit.Create(AOwner: TComponent);
begin
inherited;
FActnList:=TActionList.Create(Self);
FPopupMenu:=TPopupMenu.Create(Self);
FPopupMenu.Name:=MenuName;
CreateActns;
FillPopupMenu(FPopupMenu);
PopupMenu:=FPopupMenu;
end;
procedure TSynEdit.CreateActns;
procedure AddActItem(const AText:string;AShortCut : TShortCut;AEnabled:Boolean;OnExecute,OnUpdate:TNotifyEvent);
Var
ActionItem : TAction;
begin
ActionItem:=TAction.Create(FActnList);
ActionItem.ActionList:=FActnList;
ActionItem.Caption:=AText;
ActionItem.ShortCut:=AShortCut;
ActionItem.Enabled :=AEnabled;
ActionItem.OnExecute :=OnExecute;
ActionItem.OnUpdate :=OnUpdate;
end;
begin
AddActItem('&Undo',Menus.ShortCut(Word('Z'), [ssCtrl]),False,UndoExecute, UndoUpdate);
AddActItem('&Redo',Menus.ShortCut(Word('Z'), [ssCtrl,ssShift]),False,RedoExecute, RedoUpdate);
AddActItem('-',0,False,nil,nil);
AddActItem('Cu&t',Menus.ShortCut(Word('X'), [ssCtrl]),False,CutExecute, CutUpdate);
AddActItem('&Copy',Menus.ShortCut(Word('C'), [ssCtrl]),False,CopyExecute, CopyUpdate);
AddActItem('&Paste',Menus.ShortCut(Word('V'), [ssCtrl]),False,PasteExecute, PasteUpdate);
AddActItem('De&lete',0,False,DeleteExecute, DeleteUpdate);
AddActItem('-',0,False,nil,nil);
AddActItem('Select &All',Menus.ShortCut(Word('A'), [ssCtrl]),False,SelectAllExecute, SelectAllUpdate);
end;
procedure TSynEdit.SetPopupMenu_(const Value: TPopupMenu);
Var
MenuItem : TMenuItem;
begin
SynEdit.TSynEdit(Self).PopupMenu:=Value;
if CompareText(MenuName,Value.Name)<>0 then
begin
MenuItem:=TMenuItem.Create(Value);
MenuItem.Caption:='-';
Value.Items.Add(MenuItem);
FillPopupMenu(Value);
end;
end;
function TSynEdit.GetPopupMenu_: TPopupMenu;
begin
Result:=SynEdit.TSynEdit(Self).PopupMenu;
end;
destructor TSynEdit.Destroy;
begin
FPopupMenu.Free;
FActnList.Free;
inherited;
end;
procedure TSynEdit.FillPopupMenu(APopupMenu : TPopupMenu);
var
i : integer;
MenuItem : TMenuItem;
begin
if Assigned(FActnList) then
for i := 0 to FActnList.ActionCount-1 do
begin
MenuItem:=TMenuItem.Create(APopupMenu);
MenuItem.Action :=FActnList.Actions[i];
APopupMenu.Items.Add(MenuItem);
end;
end;
end.
And this is the final result.


December 8, 2011 at 2:55 am
How about the CUA shortcuts?
December 8, 2011 at 12:37 pm
That does not include the unicode and IME menu items!
;.)
December 8, 2011 at 12:46 pm
No for now, but you can expand the unit as you wish.
January 28, 2016 at 8:54 pm
I know this topic is quite old. But since it’s still a valid solution I’d like to add an improvement that I implemented after running into some irritating problems. Your current implementation creates “global” hotkeys that grab all normal keyboard actions (like Ctrl+V) to the SynEdit, even if the focus is in a totaly different control. Also it pastes inside a disabled SynEdit.
So to solve this I’ve set FActnList.State := asSuspended; in CreateActns and added:
procedure TSynEdit.DoEnter;
begin
FActnList.State := asNormal;
inherited;
end;
procedure TSynEdit.DoExit;
begin
FActnList.State := asSuspended;
inherited;
end;
That way the hotkeys become only active if the focus is inside the SynEdit.
Just wanted to give something back to you. Thanks for all your Delphi work!
May 25, 2016 at 7:30 am
I use your solution with Lazarus (fpc)
Thanks.
November 29, 2017 at 6:38 pm
Thank you RRUZ. That was a great help to me.