I would like to have a TMemo which will always begin with the string 'SELECT c_name FROM ' and I want to lock it so users cannot remove or replace this string in the TMemo, they will have to write their text AFTER this string. Can someone help me with that ? I tried something with the onChange event but the problem is that users can click at the begining of the TMemo and edit it by the begining.
I'm using Delphi 6.
What you are asking for is not possible with TMemo. It is just a thin wrapper around a standard Win32 EDIT control, which does not support this kind of functionality.
You need to use TRichEdit instead. It supports protecting text like you have described. After adding the desired text, select it using the TRichEdit.SelStart and TRichEdit.SelLength properties and then set the TRichEdit.SelAttributes.Protected property to true. If the user tries to modify the protected text in any way, TRichEdit will reject the modification by default (you can override that decision by using the TRichEdit.OnProtectChange event to set the AllowChange parameter to true). For example:
RichEdit1.Text := 'SELECT c_name FROM ';
RichEdit1.SelStart := 0;
RichEdit1.SelLength := 19;
RichEdit1.SelAttributes.Protected := True;
Update: by default, protecting the text also prevents the user from copying it. If you want the user to be able to copy the protected text, you have to explicitly enable that. Although TRichEdit has a OnProtectChange event to allow access to protected text, it does not tell you WHY the text is requesting access. However, the underlying EN_PROTECTED notification does. So, you can subclass the TRichEdit to intercept EN_PROTECTED directly, and then return 0 (allow access) only when the user is copying the protected text.
interface
uses
...;
type
TMyForm = class(TForm)
RichEdit1: TRichEdit;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
DefRichEditWndProc: TWndMethod;
procedure RichEditWndProc(var Message: TMessage);
public
{ Public declarations }
end;
...
implementation
uses
Richedit;
procedure TMyForm.FormCreate(Sender: TObject);
begin
DefRichEditWndProc := RichEdit1.WindowProc;
RichEdit1.WindowProc := RichEditWndProc;
RichEdit1.Text := 'SELECT c_name FROM ';
RichEdit1.SelStart := 0;
RichEdit1.SelLength := 19;
RichEdit1.SelAttributes.Protected := True;
end;
procedure TMyForm.RichEditWndProc(var Message: TMessage);
begin
DefRichEditWndProc(Message);
if Message.Msg = CN_NOTIFY then
begin
if TWMNotify(Message).NMHdr.code = EN_PROTECTED then
begin
if PENProtected(Message.lParam).Msg = WM_COPY then
Message.Result := 0;
end;
end;
end;
Alternatively:
interface
uses
...;
type
TRichEdit = class(ComCtrls.TRichEdit)
private
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
end;
TMyForm = class(TForm)
RichEdit1: TRichEdit;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
...
implementation
uses
Richedit;
procedure TMyForm.FormCreate(Sender: TObject);
begin
RichEdit1.Text := 'SELECT c_name FROM ';
RichEdit1.SelStart := 0;
RichEdit1.SelLength := 19;
RichEdit1.SelAttributes.Protected := True;
end;
procedure TRichEdit.CNNotify(var Message: TWMNotify);
begin
inherited;
if Message.NMHdr.code = EN_PROTECTED then
begin
if PENProtected(Message.NMHdr).Msg = WM_COPY then
Message.Result := 0;
end;
end;
Well it is possible, but I don't know, if you like the solution.
As already said TMemo has not that that kind of behaviour implemented. So you have to program this behaviour.
Use the application OnIdle event and a memento for the content. On each Idle message validate memo content. If the memo content did not start with 'SELECT c_name FROM ' then assign the memento value, otherwise store the memo content to memento.
Here is an example for that validation and cursor protection
type
TMainForm = class( TForm )
Memo1: TMemo;
ApplicationEvents1: TApplicationEvents; // OnIdle = ApplicationEvents1Idle
procedure ApplicationEvents1Idle( Sender: TObject; var Done: Boolean );
private
FMemo1StartWith: string;
FMemo1Memento : string;
procedure ValidateMemo( AMemo: TMemo; const AStartWith: string; var AMemento: string );
public
procedure AfterConstruction; override;
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.AfterConstruction;
begin
inherited;
FMemo1StartWith := 'SELECT c_name FROM ';
end;
procedure TMainForm.ApplicationEvents1Idle( Sender: TObject; var Done: Boolean );
begin
ValidateMemo( Memo1, FMemo1StartWith, FMemo1Memento );
end;
procedure TMainForm.ValidateMemo( AMemo: TMemo; const AStartWith: string; var AMemento: string );
var
lCurrentContent: string;
begin
// protect content
lCurrentContent := AMemo.Text;
if Pos( AStartWith, lCurrentContent ) = 1
then
AMemento := lCurrentContent
else if Pos( AStartWith, AMemento ) = 1
then
AMemo.Text := AMemento
else
AMemo.Text := AStartWith;
// protect cursor position
if ( AMemo.SelLength = 0 ) and ( AMemo.SelStart < Length( AStartWith ) )
then
AMemo.SelStart := Length( AStartWith );
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With