Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Глюк с Align у панели [D6, Win2k, WinXP]


Страницы:   1 2

--= Eagle =-- ©   (2006-09-11 11:53:00) 

Вобщем, есть наследник от 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, но это мне, увы, не подходит...


--= Eagle =--   (2006-10-26 15:12:00) [1]

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


DimaBr   (2006-10-06 10:44:00) [2]

Вот как я занимаюсь той же фигнёй. Контрол с двумя панелями и сплитером между ними. Каждая панель (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-05 22:36:00) [3]

Нашёл вопросик для спросить :)
Вобщем, попробовал перехватить 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


--= Eagle =--   (2006-10-05 14:41:00) [4]

DimaBr, к этому же решению пришёл и я :-) Сейчас вот пытаюсь реализовать... Там просто есть ещё некоторые мелкие заминки связанные со спецификой реализации компонента. Вобщем, если будут ещё вопросы - спрошу обязательно. А пока спасибо за оказанную помощь :)


DimaBr   (2006-10-05 13:43:00) [5]

Травла в том что нужно хранить либо панели и лежашие на них компоненты или список что на чём лежит.
1. Храним Панели. Они не должны создаваться самостоятельноиначе получаем дубликаты после чтения из ресурса.
2. Храним Списки. Что хотим то и творим.


> Дело в том, что эта панелька не может использоваться без TMultiPanel

Не регистрируем панель в палитере и её нельзя будет добавить на форму, Copy/Paste предотвращаем в методе SetParent.


--= Eagle =--   (2006-10-05 13:10:00) [6]


> Пишем класс панели у которого в SetParent проверяется является
> ли Parent - TMultiPanel. Если нет, то генерим ошибку. В
> редактор компонента (по правой кнопке на компоненте) TMultiPanel
> добавляем пункт Add SubPanel.

Дело в том, что эта панелька не может использоваться без TMultiPanel... А трабла состоит в том, что мне нужно, чтобы TMultiPanel сама создала эти панельки, а я при загрузке из DFM только поназначал правильно эти панельки парентами для других контролов...


DimaBr   (2006-10-05 12:38:00) [7]

Самый простой вариант.
Пишем класс панели у которого в SetParent проверяется является ли Parent - TMultiPanel. Если нет, то генерим ошибку. В редактор компонента (по правой кнопке на компоненте) TMultiPanel добавляем пункт Add SubPanel.


--= Eagle =--   (2006-10-05 11:37:00) [8]

Естественно, "главная" нанелька - это TMultiPanel, содержащиеся в ней панельки - в массив FPanels, они должны создаваться главной панелькой, и не иначе...


--= Eagle =--   (2006-10-05 11:35:00) [9]

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


DimaBr   (2006-10-05 10:43:00) [10]

Объясните пожалуйста какой в итоге компонент вы хотите получить.


--= Eagle =--   (2006-10-05 10:38:00) [11]

DimaBr, именно... Вот и думаю, что бороться прийдётся этим способом:

> Вариант 1. Завести списоки контролов которые лежат на каждой
> панели (на каждую панель свой список).

Вобщем, буду бороться :-)


DimaBr   (2006-10-04 10:28:00) [12]

Это происходит потому, что при чтении из ресурса создаются две панельки, а Вы ещё создаёте две в конструкторе.


--= Eagle =--   (2006-10-03 18:45:00) [13]

Вобщем, походу тут что-то не то получается... При переключении View as Form / View as Text происходит создание компоненты. А при создании компоненты происходит создание новых панелек. А у старых панелек, похоже, больше не вызываются процедуры перерисовки, т.к. этим частично занимается компонента. Вобщем, они лежат на моём компоненте, но уже НЕ являются его составной частью...


--= Eagle =--   (2006-10-03 17:03:00) [14]

Я имел в виду попросить помощи.
Вобщем, я сделал так:

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 пустые панельки. Кстати, корректная отрисовка старых панелек не производится...


DimaBr   (2006-10-03 16:50:00) [15]


> можно ещё разок запросить бекап? :-)

?????? непонял


--= Eagle =--   (2006-10-03 16:01:00) [16]

точнее, сохранито-то удалось, а вот со считыванием страблы пока были... :(


--= Eagle =--   (2006-10-03 15:53:00) [17]

Хмм... Я вот только что тоже пришёл к этому же выводу, т.к. паренты реально нигде не хранятся... А как же тогда сохранить всю панельку, а не просто её компоненты?
З.Ы. Всё-таки я понял, что не всё ещё понял, т.к. у меня что-то это не получается... DimaBr, можно ещё разок запросить бекап? :-)


DimaBr   (2006-10-03 15:48:00) [18]

Вариант 1. Завести списоки контролов которые лежат на каждой панели (на каждую панель свой список). (TRzSplitter)
Вариант 2. Хранить в DFM сами панели и сответственно всё что на них расположено.


--= Eagle =--   (2006-10-03 14:58:00) [19]

Вот, предстала предо мной ещё одна задача: теперь нужно сохранять несколько панелек (допустим, две), на которых лежат разные компоненты. Как бы им правильно поставить парентов?
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;


--= Eagle =--   (2006-09-11 18:01:00) [20]

Последний вопрос снимается - не заметил что class(TCustomPanel)
=)


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо