I have a form displaying data from a database, It has a few buttons and several panels. The panels contain a variety of components, specifically TEdits, TComboBox, TDateTimePicker, TCheckBox, TListBox and TstringGrid.
When the form is opened such that the user can view, but not edit, the data I currently disable all the components except for the buttons using
for i := 0 to FrmAddNewMember.ComponentCount-1 do
if FrmAddNewMember.Components[i] is TPanel then
(FrmAddNewMember.Components[ i ] as TPanel).enabled := false;
This works fine except that I would now like the user to be able to copy to the clipboard the text in the TEdits, the date in the TDateTimePicker, the selected item in the TComboBox etc etc. but still not change it.
I altered the code to the following which sets the TEdits to Read Only. This does what I want for TEdits but the other type of controls do not have a read only property, so I disabled them as before.
for i := 0 to FrmAddNewMember.ComponentCount-1 do
if not (FrmAddNewMember.Components[i] is TButton) then //(keep buttons working)
case FrmAddNewMember.Components[i] of
TEdit: (FrmAddNewMember.Components[ i ] as TEdit).readonly := true; //allows copying but not editing
TComboBox: (FrmAddNewMember.Components[ i ] as TComboBox).enabled := false; //no read only propert?
TDateTimePicker: (FrmAddNewMember.Components[ i ] as TDateTimePicker).enabled := false; //ditto
TCheckBox: (FrmAddNewMember.Components[ i ] as TCheckBox).enabled := false;
TListBox: (FrmAddNewMember.Components[ i ] as TListBox).enabled := false;
TstringGrid: (FrmAddNewMember.Components[ i ] as TstringGrid).enabled := false;
end;
Is there a way to make the other controls non editable but still allow their contents to be copied to the clipboard?
PS I have looked at
disable-edits-on-datagridview-but-still-allow-for-highlighting-to-copy-and-paste
and
make-all-controls-on-a-form-read-only-at-once-without-one-linkbutton
and searched elsewhere. Maybe it cannot be done simply.
I think, you can emulate a popup menu for your components (because standard popup menu will not work for disabled ones).
But if you will have popup menu for the form and FormMouseDown
event handler, you can analyze where mouse pointer is (under which component, I mean) and call popup with Copy
menu item.
Quick example for listboxes:
unit Unit6;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus, Vcl.StdCtrls, Vcl.ExtCtrls, Clipbrd;
type
TForm6 = class(TForm)
Panel1: TPanel;
ListBox1: TListBox;
ListBox2: TListBox;
PopupMenu1: TPopupMenu;
miCopy: TMenuItem;
procedure miCopyClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
selectedText: string;
public
{ Public declarations }
end;
var
Form6: TForm6;
implementation
{$R *.dfm}
procedure TForm6.FormCreate(Sender: TObject);
begin
ListBox1.ItemIndex := 1;
ListBox2.ItemIndex := 1;
Panel1.OnMouseDown := FormMouseDown;
end;
procedure TForm6.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
i, parentX, parentY: integer;
p: TPoint;
lb: TListBox;
begin
if Button <> mbRight then
exit;
selectedText := '';
for i := 0 to ComponentCount - 1 do
if Components[i] is TListBox then
begin
lb := TListBox(Components[i]);
begin
p := lb.ParentToClient(Point(X, Y));
if lb.ClientRect.Contains(p) then
begin
parentX := 0;
parentY := 0;
if Assigned(lb.Parent) then
begin
parentX := lb.Parent.ClientOrigin.X;
parentY := lb.Parent.ClientOrigin.Y;
end;
if lb.ItemIndex > -1 then
begin
selectedText := lb.Items[lb.ItemIndex];
PopupMenu1.Popup(lb.Left + parentX + p.X, lb.Top + parentY + p.Y);
end;
break;
end;
end;
end;
end;
procedure TForm6.miCopyClick(Sender: TObject);
begin
if selectedText = '' then
exit;
Clipboard.AsText := selectedText;
end;
end.
Here ListBox1
is placed on the TPanel
component. Please note you should assign form's OnMouseDown
handler to all your panels or other containers. Also, if you have nested containers, you need use recursive algorithm to find parentX, parentY
.
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