Форум: "Компоненты";
Текущий архив: 2007.10.21;
Скачать: [xml.tar.bz2];
ВнизГлюк с Align у панели Найти похожие ветки
← →
--= Eagle =-- © (2006-09-11 11:53) [0]Вобщем, есть наследник от TPanel, на котором лежит сплиттер (не стандартный, но всё же...). Сплиттер постоянно имеет какой-то Align. И если сплиттер у меня alLeft, а я бросаю на компоненту какую-то другую компоненту и ставлю ей Align=alTop, то сплиттер... правильно, располагается ПОД компонентой, т.к. выравнивание сверху/снизу имеет более высокий приоритет, чем выравнивание слева/справа. Как эту радость обойти? Я пытался создать на панели ещё одну панельку, на которую собственно и будут кидаться все остальные компоненты в режиме конструктора (и создаваться в рантайме), но почему-то компоненты, которые я кидаю в дизайн-тайме, не записываются как находящиеся на этой панели и не отображаются (в DFM их НЕ видно как будто они НЕ находятся на форме; при чём если выйти из режима просмотра DFM то получим сообщение о том, что этой панельки типа вообще-то и нима, и не стоит ли её убрать).
Как повлиять на ситуацию? Нужно чтобы если я установил сплитер справа, то он и занимал ВСЮ правую часть панели, игнорируя то, что какие-то компоненты могут быть заалигнены alTop/alBottom?
Как создаю панельку? А вот так:FContainer := TPanel.Create(Self);
FContainer.Parent := Self;
FContainer.BevelInner:=bvNone;
FContainer.BevelOuter:=bvNone;
FContainer.Align := alClient;
FContainer.Name := "Container";
FContainer.SetSubComponent(True);
Если сделатьFContainer := TPanel.Create(AOwner);
то оно тоже будет глючить, хотя компоненты будут регаться... Но зато Container будет зареган в классе формы, что далеко не есть хорошо... :(
в ControlStyle флаг csAcceptControls установлен (по умолчанию)
В нете нарыл кусок нерабочего под D6 кода:
unit RzPnlPnl;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, ExtCtrls;
type
TSubPanel = class(TPanel)
protected
procedure ReadState(Reader: TReader); override;
end;
TPanelPanel = class(TPanel)
private
FSubPanel: TSubPanel;
protected
procedure WriteComponents(Writer: TWriter); override;
procedure ReadState(Reader: TReader); override;
public
constructor Create(AOwner: TComponent); override;
end;
procedure Register;
implementation
procedure TSubPanel.ReadState(Reader: TReader);
var
OldOwner: TComponent;
begin
OldOwner := Reader.Owner;
{ Сохраняем старого владельца, что необходимо для PanelPanel }
Reader.Owner := Reader.Root; { Задаем в качестве владельца форму }
try
inherited ReadState(Reader);
finally
Reader.Owner := OldOwner;
end;
end;
constructor TPanelPanel.Create(AOwner: TComponent);
const
Registered: Boolean = False;
begin
inherited Create(AOwner);
FSubPanel := TSubPanel.Create(Self);
FSubPanel.Parent := Self;
FSubPanel.SetBounds(20, 20, 200, 100);
FSubPanel.Name := "SomeName";
if not Registered then
begin
Classes.RegisterClasses([TSubPanel]);
{ так TSubPanel может храниться в файле формы }
Registered := True;
end;
end;
procedure TPanelPanel.ReadState(Reader: TReader);
var
OldOwner: TComponent;
I: Integer;
begin
for I := 0 to ControlCount - 1 do
Controls[0].Free;
OldOwner := Reader.Owner;
Reader.Owner := Self;
{Для чтения субкомпонентов, установите данный экземпляр в качестве родителя}
try
inherited ReadState(Reader);
finally
Reader.Owner := OldOwner;
end;
end;
procedure TPanelPanel.WriteComponents(Writer: TWriter);
var
I: Integer;
begin
for I := 0 to ControlCount - 1 do
Writer.WriteComponent(Controls);
end;
procedure Register;
begin
RegisterComponents("Samples", [TPanelPanel]);
end;
end.
Переименовал WriteComponents в WriteState, но это не привело ни к каким хорошим результатам... Оно просто начало компилиться... Вобщем, чего бы ему такого сделать хорошего, чтобы оно решилось работать?
З.Ы. Я понимаю, что компонента будет нормально работать, если в дизайн-тайме на неё кинуть панель или фрейм с alClient, но это мне, увы, не подходит...
← →
DimaBr (2006-09-11 12:07) [1]Внимательно изучаем GetChildten, ваш код должен быть приблизительно таким
TPanelPanel = class(TPanel)
private
FSubPanel: TSubPanel;
protected
procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
procedure Loaded;override;
constructor Create(AOwner: TComponent); override;
end;
procedure TPanelPanel.GetChildren(Proc: TGetChildProc; Root: TComponent);
var i: integer;
Control: TControl;
begin
inherited GetChildren(Proc,Root);
for i := 0 to ControlCount - 1 do begin
if Controls[i].Owner = Owner then Proc( Controls[i] );
end;{for}
end;
procedure TPanelPanel.Loaded;
var i: integer;
begin
inherited Loaded;
for i := 0 to ControlCount-1 do
if (Controls[i] <> FSubPanel) then
Controls[i].Parent := FSubPanel;
end;
← →
--= Eagle =-- © (2006-09-11 12:48) [2]
> Внимательно изучаем GetChildten, ваш код должен быть приблизительно
> таким
DimaBr, прошу прощения, но такая задача стоит предо мной впервые при написании компонентов... Я немного "поигрался" с этим кодом, но мне и его тоже не удалось заставить правильно работать...
Можно попросить минимально рабочий пример, плиз?
← →
DimaBr (2006-09-11 14:29) [3]
unit Panels;
interface
uses Classes, ExtCtrls,Controls;
type
TMyPanel = class(TCustomPanel)
private
fPanel: TPanel;
public
constructor Create(AOwner: TComponent);override;
destructor Destroy;override;
procedure GetChildren(Proc: TGetChildProc; Root: TComponent);override;
procedure Loaded;override;
procedure SetParent(AParent: TWinControl);override;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents("Standard",[TMyPanel]);
end;
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fPanel := TPanel.Create(self);
Width := 200;
Height := 200;
end;
destructor TMyPanel.Destroy;
begin
FreeAndNil(fPanel);
inherited;
end;
procedure TMyPanel.GetChildren(Proc: TGetChildProc; Root: TComponent);
var i: integer;
begin
inherited GetChildren(Proc,Root);
for i := 0 to fPanel.ControlCount - 1 do begin
Proc( fPanel.Controls[i] );
end;{for}
end;
procedure TMyPanel.Loaded;
var i: integer;
begin
inherited Loaded;
for i := ControlCount-1 downto 0 do begin
if (Controls[i] <> fPanel) then Controls[i].Parent := fPanel;
end;{for}
end;
procedure TMyPanel.SetParent(AParent: TWinControl);
begin
inherited;
if fPanel <> nil then fPanel.Parent := self;
end;
end.
← →
DimaBr (2006-09-11 14:32) [4]Забыл, единственное НО. Так как саму встроенную панель мы в ресурс не сохраняем, то всё что мы броаем на панель-родитель перенесётся на на встроенную.
← →
--= Eagle =-- © (2006-09-11 16:33) [5]
> Забыл, единственное НО. Так как саму встроенную панель мы
> в ресурс не сохраняем, то всё что мы броаем на панель-родитель
> перенесётся на на встроенную.
Огромное спасибо! Это работает. Хотя, правда говоря, неудобно, что компоненты, которые я кидаю в дизайнтайме не отображаются как находящиеся на панели (т.е. в Object TreeView они располагаются не в ветке моей компоненты, а являются как бы её sibling-ами). Это можно полечить? :)
← →
--= Eagle =-- © (2006-09-11 17:36) [6]Кстати, заметил ещё одну вещь, это уже немного серьёзнее - бОльшая часть свойств теперь не видна в инспекторе объектов...
← →
--= Eagle =-- © (2006-09-11 18:01) [7]Последний вопрос снимается - не заметил что class(TCustomPanel)
=)
← →
--= Eagle =-- © (2006-10-03 14:58) [8]Вот, предстала предо мной ещё одна задача: теперь нужно сохранять несколько панелек (допустим, две), на которых лежат разные компоненты. Как бы им правильно поставить парентов?
procedure TMyPanel.Loaded;
var i: integer;
begin
inherited Loaded;
for i := ControlCount-1 downto 0 do begin
//?? if (Controls[i] <> fPanel) then Controls[i].Parent := fPanel;
end;{for}
end;
← →
DimaBr (2006-10-03 15:48) [9]Вариант 1. Завести списоки контролов которые лежат на каждой панели (на каждую панель свой список). (TRzSplitter)
Вариант 2. Хранить в DFM сами панели и сответственно всё что на них расположено.
← →
--= Eagle =-- © (2006-10-03 15:53) [10]Хмм... Я вот только что тоже пришёл к этому же выводу, т.к. паренты реально нигде не хранятся... А как же тогда сохранить всю панельку, а не просто её компоненты?
З.Ы. Всё-таки я понял, что не всё ещё понял, т.к. у меня что-то это не получается... DimaBr, можно ещё разок запросить бекап? :-)
← →
--= Eagle =-- © (2006-10-03 16:01) [11]точнее, сохранито-то удалось, а вот со считыванием страблы пока были... :(
← →
DimaBr (2006-10-03 16:50) [12]
> можно ещё разок запросить бекап? :-)
?????? непонял
← →
--= Eagle =-- © (2006-10-03 17:03) [13]Я имел в виду попросить помощи.
Вобщем, я сделал так:procedure TMultiPanel.GetChildren(Proc: TGetChildProc; Root: TComponent);
var
I: Integer;
begin
inherited GetChildren(Proc, Root);
for I := 0 to FPanels.Count - 1 do
Proc(FPanels[I]);
end;
procedure TMultiPanel.Loaded;
begin
inherited Loaded;
end;
procedure TMultiPanel.SetParent(AParent: TWinControl);
var
I: Integer;
begin
inherited;
for I := 0 to FPanels.Count - 1 do
if FPanels[I] <> nil then FPanels[I].Parent := Self;
end;
Компоненты сохраняются, но наступают глюки: допустим, у меня есть 2 панели, которые создаются вместе с компонентой. Кидаю на одну понельку кнопочку, перехожу в просмотр формы "как текст" и проверяю - всё красиво, в компоненте сохраняются панельки, на одной панельке есть кнопочка. Жизнь прекрасна... до тех пор, пока я не выхожу из режим "как текст". После этого у меня количество формочек увеличивается на 2 (все прописаны в DFM, на одной из 4-х лежит кнопка). И так каждый раз - добавляется по 2 пустые панельки. Кстати, корректная отрисовка старых панелек не производится...
← →
--= Eagle =-- © (2006-10-03 18:45) [14]Вобщем, походу тут что-то не то получается... При переключении View as Form / View as Text происходит создание компоненты. А при создании компоненты происходит создание новых панелек. А у старых панелек, похоже, больше не вызываются процедуры перерисовки, т.к. этим частично занимается компонента. Вобщем, они лежат на моём компоненте, но уже НЕ являются его составной частью...
← →
DimaBr (2006-10-04 10:28) [15]Это происходит потому, что при чтении из ресурса создаются две панельки, а Вы ещё создаёте две в конструкторе.
← →
--= Eagle =-- © (2006-10-05 10:38) [16]DimaBr, именно... Вот и думаю, что бороться прийдётся этим способом:
> Вариант 1. Завести списоки контролов которые лежат на каждой
> панели (на каждую панель свой список).
Вобщем, буду бороться :-)
← →
DimaBr (2006-10-05 10:43) [17]Объясните пожалуйста какой в итоге компонент вы хотите получить.
← →
--= Eagle =-- © (2006-10-05 11:35) [18]Есть панелька, на которой размещено произвольное количество других панелек, расположеных произвольно с произвольными размерами. Каждая из этих панелек может содержать какие-то компоненты.
← →
--= Eagle =-- © (2006-10-05 11:37) [19]Естественно, "главная" нанелька - это TMultiPanel, содержащиеся в ней панельки - в массив FPanels, они должны создаваться главной панелькой, и не иначе...
← →
DimaBr (2006-10-05 12:38) [20]Самый простой вариант.
Пишем класс панели у которого в SetParent проверяется является ли Parent - TMultiPanel. Если нет, то генерим ошибку. В редактор компонента (по правой кнопке на компоненте) TMultiPanel добавляем пункт Add SubPanel.
← →
--= Eagle =-- © (2006-10-05 13:10) [21]
> Пишем класс панели у которого в SetParent проверяется является
> ли Parent - TMultiPanel. Если нет, то генерим ошибку. В
> редактор компонента (по правой кнопке на компоненте) TMultiPanel
> добавляем пункт Add SubPanel.
Дело в том, что эта панелька не может использоваться без TMultiPanel... А трабла состоит в том, что мне нужно, чтобы TMultiPanel сама создала эти панельки, а я при загрузке из DFM только поназначал правильно эти панельки парентами для других контролов...
← →
DimaBr (2006-10-05 13:43) [22]Травла в том что нужно хранить либо панели и лежашие на них компоненты или список что на чём лежит.
1. Храним Панели. Они не должны создаваться самостоятельно иначе получаем дубликаты после чтения из ресурса.
2. Храним Списки. Что хотим то и творим.
> Дело в том, что эта панелька не может использоваться без TMultiPanel
Не регистрируем панель в палитере и её нельзя будет добавить на форму, Copy/Paste предотвращаем в методе SetParent.
← →
--= Eagle =-- © (2006-10-05 14:41) [23]DimaBr, к этому же решению пришёл и я :-) Сейчас вот пытаюсь реализовать... Там просто есть ещё некоторые мелкие заминки связанные со спецификой реализации компонента. Вобщем, если будут ещё вопросы - спрошу обязательно. А пока спасибо за оказанную помощь :)
← →
--= Eagle =-- © (2006-10-05 22:36) [24]Нашёл вопросик для спросить :)
Вобщем, попробовал перехватить Notification для того чтобы заполнять список компонент, которые добавляются на панельки внутри TMultiPanel. Одна беда - я могу правильно узнать и парента, и имя самой компоненты только при Operation = opRemove ввиду того, что при opInsert у AComponent ещё нет ни имени, ничего толком нету вобщем. Как бы это красиво так отловить все эти компоненты...
Ах, да... Пробовал в перекрытой процедурке WriteComponentsParents (перекрывал как в этом примере: http://www.rsdn.ru/article/Delphi/makecomponents.xml , там процедурка только называется WriteTextHistory) сделать такую фишку:FComponentsParents.Clear;
for I := 0 to ControlCount - 1 do
if (Components[I].ClassName <> "TMPanel") and (Components[I].Name <> "") then
try
FComponentsParents.Add(Format("%s=%s,", [Components[I].Name, (Components[I] as TControl).Parent.Name]));
except
beep;
end;
{$IFDEF DBUGINTF} SendDebugFmt("%s", [FComponentsParents.Text]); {$ENDIF}
Бипов нет, а FComponentsParents.Text = "" Как бороться дальше пока не решил, ушёл спать :D
← →
DimaBr (2006-10-06 10:44) [25]Вот как я занимаюсь той же фигнёй. Контрол с двумя панелями и сплитером между ними. Каждая панель (fPanels: array[0..1]) имеет TStrings (fControlList) - список контролов лежащий на ней.
procedure TBrSplitter.DefineProperties( Filer: TFiler );
begin
fReadControls := 1;
Filer.DefineProperty("FirstControls", ReadControls, WriteControls, True );
fReadControls := 2;
Filer.DefineProperty("SecondControls", ReadControls, WriteControls, True );
end;
procedure TBrSplitter.ReadControls( Reader: TReader );
begin
fPanels[ fReadControls ].fControlList.Clear;
Reader.ReadListBegin;
while not Reader.EndOfList do
fPanels[ fReadControls ].fControlList.Add( Reader.ReadIdent );
Reader.ReadListEnd;
end;
procedure TBrSplitter.WriteControls( Writer: TWriter );
var I: Integer;
begin
Writer.WriteListBegin;
for I := 0 to fPanels[ fReadControls ].ControlCount - 1 do
Writer.WriteIdent( fPanels[ fReadControls ].Controls[ I ].Name );
Writer.WriteListEnd;
end;
procedure TBrSplitter.Loaded;
var I, P: Integer;
C: TComponent;
SaveActiveControl: TWinControl;
begin
Inc( fLoadCount );
try
inherited Loaded;
SaveActiveControl := nil;
if Owner <> nil then
if Owner is TCustomForm then
SaveActiveControl := TCustomForm( Owner ).ActiveControl;
ManualPosition := Position;
ResizePanes;
DisableAlign;
try
if Owner <> nil then
for P := 1 to 2 do begin
for I := 0 to fPanels[ P ].fControlList.Count - 1 do begin
C := Owner.FindComponent( fPanels[ P ].fControlList[ I ] );
if C <> nil then TControl( C ).Parent := fPanels[ P ];
end;
fPanels[ P ].FixupTabList;
end;{for}
finally
EnableAlign;
end;{try}
if Owner <> nil then
if Owner is TCustomForm then
TCustomForm( Owner ).ActiveControl := SaveActiveControl;
finally
Dec( fLoadCount );
end;{try}
end;
← →
--= Eagle =-- © (2006-10-26 15:12) [26]Сегодня опять вернулся к этой теме и добил её до конца. И хотя тут была ситуёвина немного более другая, но тем не менее этот код помог решить одну возникшую проблемму. Спасибо за помощь, вопрос можно считать закрытым.
Страницы: 1 вся ветка
Форум: "Компоненты";
Текущий архив: 2007.10.21;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.044 c