Как предотвратить взаимозависимость времени разработки с TFrame в качестве компонента

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

RegisterSprigType должным образом не позволяет дизайнеру выбирать, случайно перемещать или удалять элементы управления внутри вашего фрейма, но только напрямую. Элементы управления внутри по-прежнему принимают элементы управления, которые нужно удалить.

В моей ситуации у меня есть панели внутри рамки. Я могу нажать кнопку на панели. Если я удалю кнопку, то родительский элемент будет выбран (который будет панелью), а затем я смогу удалить панель.

Я попытался удалить csAcceptsControls из фрейма ControlStyle. Это предотвратило падение элементов управления непосредственно на фрейме, но панель внутри все еще принимала элементы управления.

Итак, я закончил удаление csAcceptsControls из всех элементов управления, содержащихся в моем фрейме, в процедуре "Загруженный".

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

Итак, мой вопрос: есть ли лучший способ добиться того же результата (запретите разработчику добавлять элементы управления внутри кадра, зарегистрированного как компонент). "Регистр" говорит разработчику игнорировать класс рамки и его дочерние элементы в качестве контейнеров, возможно?

Если этот метод уже самый оптимальный, я что-то пропустил?

Есть ли какие-либо "gotchas", о которых я должен знать при таком подходе? (Любые побочные эффекты - как дизайн, так и время выполнения).

Ответ 1

Я копаюсь, но нет хорошего решения для вашей проблемы потому что все методы работают в контексте Frame, а не его дочерние компоненты как DesignWndProc, WM_NCHITTEST...

но у меня есть solusion (не приятно), посмотрите ниже, но я не знаю, лучше ли это решение для удаления csAcceptsControls.

Вы можете создать во время разработки только Panel (прозрачный) и удалить только из него csAcceptsControls. При изменении размера рамки вы можете установить ширину и высоту панели, чтобы съесть всю рамку. Но вы должны поместить все элементы управления в панель верхнего уровня (parent - Frame) с выравниванием alClient, и каждый элемент управления будет на нем. Затем вы создаете свою панель времени разработки (parent is Frame), и она будет второй панелью верхнего уровня на вашем фрейме. И вы можете вывести его на фронт только один раз после создания. Это удаление необходимо изменить каждое свойство, создающее новые элементы управления.

Что-то вроде этой структуры Frame {PanelTopLevel {любые другие элементы управления}} {DesignPanel}:

object FrameTestDisableFrame: TFrameTestDisableFrame
  object PanelTopLevel: TPanel
    object Panel1: TPanel
      Left = 96
      Top = 56
      Width = 201
      Height = 105
      Caption = 'Panel1'
      TabOrder = 0
      object Button1: TButton
        Left = 48
        Top = 24
        Width = 75
        Height = 25
        Caption = 'Button1'
        TabOrder = 0
      end
    end
end

код панели проектирования

TDesignPanel = class(TWinControl)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  public
    constructor Create(AOwner: TComponent); override;
  end;

реализация

{TDesignPanel}

constructor TDesignPanel.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle:= ControlStyle - [csAcceptsControls];
  Color:= clBackground;
end;

procedure TDesignPanel.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle:= Params.ExStyle or WS_EX_TRANSPARENT;
end;

procedure TDesignPanel.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
  Message.Result:= 1;
end;

и в вашем фрейме

private
    DesignPanel: TDesignPanel;

...

constructor TFrameTestDisableFrame.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle:= ControlStyle - [csAcceptsControls];
  if csDesigning in ComponentState then
    begin
      DesignPanel:= TDesignPanel.Create(Self);
      DesignPanel.Parent:= Self;
      DesignPanel.BringToFront;
    end;
end;



procedure TFrameTestDisableFrame.Resize;
begin
  inherited;
  DesignPanel.BringToFront;
  DesignPanel.SetBounds(0, 0, Width, Height);
end;

Я тестировал это и работал нормально

Совет

В моей ситуации у меня есть панели внутри рамки. Я могу нажать кнопку на панели. Если я удалю кнопку, то родительский элемент будет выбран (который будет панелью), а затем я смогу удалить панель.

В delphi Seattle, когда я удаляю такую ​​кнопку, весь кадр выбран не родительской панелью.