Как сделать все элементы управления в форме Delphi недоступными для редактирования / изменения, но при этом разрешить пользователю копировать содержимое - PullRequest
0 голосов
/ 30 октября 2018

У меня есть форма, отображающая данные из базы данных, она имеет несколько кнопок и несколько панелей. Панели содержат различные компоненты, в частности, TEdits, TComboBox, TDateTimePicker, TCheckBox, TListBox и TstringGrid.

Когда форма открыта таким образом, что пользователь может просматривать, но не редактировать данные, в настоящее время я отключаю все компоненты, кроме кнопок, использующих

for i := 0 to FrmAddNewMember.ComponentCount-1 do
    if FrmAddNewMember.Components[i] is TPanel then
      (FrmAddNewMember.Components[ i ] as TPanel).enabled := false;

Это работает нормально, за исключением того, что теперь я хотел бы, чтобы пользователь мог копировать в буфер обмена текст в TEdits, дату в TDateTimePicker, выбранный элемент в TComboBox и т. Д. И т. Д., Но при этом не изменять его.

Я изменил код на следующий, который устанавливает TEdits только для чтения. Это делает то, что я хочу для TEdits, но другие типы элементов управления не имеют свойства только для чтения, поэтому я отключил их, как и раньше.

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;

Есть ли способ сделать другие элементы управления недоступными для редактирования, но при этом разрешить копирование их содержимого в буфер обмена?

PS Я посмотрел на

Disable-редактирует-на-DataGridView-но все еще позволяют в обмен на выделение к копии и вставки

и

макияж все-управления-на-а-форма-только для чтения-на-один раз-без одной LinkButton

и искал в другом месте. Может быть, это нельзя сделать просто.

Ответы [ 3 ]

0 голосов
/ 30 октября 2018

Вы можете использовать этот код, чтобы сделать выпадающий список только для чтения. Также вы можете использовать тот же подход к другим изменениям, если можете получить дескриптор окна редактирования.

procedure MakeComboboxReadOnly(const ACombobox: TCombobox);
var cbi: TComboBoxInfo;
begin
    cbi.cbSize := SizeOf(cbi);
    GetComboBoxInfo(ACombobox.Handle, cbi);
    SendMessage(cbi.hwndItem, EM_SETREADONLY, 1, 0);
end;
0 голосов
/ 23 ноября 2018

Просто чтобы добавить закрытие к моему вопросу В конечном итоге я просто разместил кнопки скорости рядом с элементами управления, содержащими текст, который я хотел скопировать, и использовал обычный

.
uses ClipBrd;
...
Clipboard.AsText := MyControl1.text;

для копирования данных.

Хитрость заключалась не в том, чтобы поместить кнопки скорости как дочерние элементы панели, содержащей элемент управления (который отключен, следовательно, также отключены все элементы управления внутри него), а вместо этого просто поместить их в форму и затем переместить их так они расположены перед панелью рядом с соответствующим элементом управления.

Таким образом, кнопки скорости выглядят так, как будто они являются частью панели, но будут работать, когда панель и все ее элементы управления отключены.

0 голосов
/ 30 октября 2018

Я думаю, вы можете эмулировать всплывающее меню для ваших компонентов (потому что стандартное всплывающее меню не будет работать для отключенных).

Но если у вас будет всплывающее меню для формы и обработчик события FormMouseDown, вы можете проанализировать, где находится указатель мыши (под каким компонентом, я имею в виду), и вызвать всплывающее окно с элементом меню Copy.

Быстрый пример для списков:

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.

Здесь ListBox1 находится на компоненте TPanel. Обратите внимание, что вы должны назначить обработчик OnMouseDown формы для всех ваших панелей или других контейнеров. Также, если у вас есть вложенные контейнеры, вам нужно использовать рекурсивный алгоритм, чтобы найти parentX, parentY.

...