Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Компоненты";
Текущий архив: 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.051 c
15-1190304543
Yegorchic
2007-09-20 20:09
2007.10.21
Недопустимое разрешение


15-1190294866
Azize
2007-09-20 17:27
2007.10.21
Новая среда разработки от CodeGear


2-1190516430
ggg
2007-09-23 07:00
2007.10.21
Windows уродует интерфейс


15-1190195376
Beastie Boys
2007-09-19 13:49
2007.10.21
у дизайнеров хорошая фантазия?


4-1176887783
ocean
2007-04-18 13:16
2007.10.21
Как развернуть раб. стол WinXP на 270 градусов?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский