Delphi - Ссылки на компоненты, созданные во время выполнения
Я использую Delphi 5 и создаю несколько панелей во время выполнения, затем создаю кнопки на панелях, очевидно, снова во время выполнения. Мне нужно сделать это таким образом, потому что в будущем мне может понадобиться динамически создавать больше комбинаций панелей / кнопок.
Я могу сделать все это, но я не знаю, как ссылаться на созданные мной панели, потому что не могу найти способ доступа к имени компонента панелей. Охота по Интернету Я обнаружил, что могу использовать FindComponent, чтобы найти компоненты панели по имени, но я все еще не знаю, как использовать это имя, потому что я не могу использовать строковую переменную для ссылки на него - например, StringVar:= Panel.Name. Я получаю несоответствие типов, TComponentName и String.
Я создал кнопки для каждой панели, как я создал панели. Упрощенно это выглядит так:
With TypeQuery do begin // Create Panels
First;
While (not eof) do begin // create the actual panel
panelno := FieldByName('Product_type_id').AsInteger;
pnl := Tpanel.Create(Self);
pnl.name := FieldByName('PanelName').AsString;
pnl.color := clInactiveCaption;
pnl.parent := MainForm;
pnl.width := 365;
pnl.Height := 551;
pnl.left := 434
pnl.top := 122;
pnl.caption := '';
With ButtonQuery do begin
Close;
Parameters.parambyname('PanelID').Value := PanelNo;
Open;
First;
While (not eof) and (FieldByName('Product_type_id').AsInteger = PanelNo) do begin //put the buttons on it.
btnName := FieldByName('ButtonName').AsString;
BtnText := FieldByName('ButtonText').AsString;
BtnGroup := FieldByName('Product_Group_ID').AsString;
GrpColour := FieldByName('ButtonColour').AsString;
btn := TColorButton.Create(Self);
btn.Parent := pnl;
btn.Name := BtnName;
Btn.backcolor := HexToTColor(GrpColour);
btn.Font.Name := 'Arial Narrow';
btn.Font.Style := [fsBold];
btn.Font.Size := 10;
. . .
end;
. . .
end;
end;
Я читал на нескольких форумах (включая этот), что нет возможности напрямую ссылаться на панели по названию. Я попытался использовать массив компонентов, но столкнулся с той же проблемой - мне нужно ссылаться на компонент по назначенному имени компонента.
Хорошо, я не программист оружия - я годами использовал Delphi для создания простых программ, но эта намного сложнее. Я никогда не работал с созданием компонентов во время выполнения.
Могу ли я использовать FindComponent, чтобы сделать панели видимыми или невидимыми? Если так, учитывая то, что я показал вам выше, можете ли вы дать мне подход, который я должен использовать в шагах ребенка?
Заранее спасибо...
4 ответа
Я не уверен, что вы подразумеваете под: "Я не могу использовать строковую переменную для ссылки на нее - например, StringVar: = Panel.Name."
Попробуй это:
procedure TForm1.FormCreate(Sender: TObject);
var
p: TPanel;
begin
p := TPanel.Create(Self); // create a TPanel at run-time
p.Name := 'MyPanel'; // set a unique name
p.Parent := Self;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
p: TPanel;
StringVar: string;
begin
p := FindComponent('MyPanel') as TPanel;
if Assigned(p) then // p has reference to MyPanel
begin
// use that reference
p.Caption := 'Foo';
StringVar := p.Name;
ShowMessage(StringVar);
end;
end;
Или я что-то пропустил?
Вы связываете имя компонента с именем переменной. Delphi IDE стремится оставить эти два одинаковыми для созданных IDE компонентов, но они не обязательно равны. У вас нет имен переменных, потому что вы создаете компоненты динамически, и вы не знаете, сколько переменных вам понадобится. Тем не менее, у вас все еще есть контроль над именами компонентов: просто назначьте Name
свойство компонента, и затем вы можете использовать его так же, как вы используете любые другие имена компонентов, вызывая FindComponent
, Просто убедитесь, что имена уникальны для каждого экземпляра панели.
Помните также, что способ работы с переменными, когда во время компиляции вы не знаете, сколько вам понадобится, состоит в использовании массивов или списков. Вы можете использовать простые старые массивы или более сложную структуру данных, такую как TComponentList
или же TDictionary
,
Наконец, чтобы упростить обращение к элементам управления на панелях, которые вы создаете, вы можете обойтись без панелей и использовать вместо них фреймы. Вы можете визуально оформить TFrame
в IDE и присваивайте имена кнопкам, а во время выполнения вы можете создать экземпляр класса фрейма, и он автоматически создаст все кнопки для вас, как при создании экземпляра формы или модуля данных. Вам нужно только дать имя новому объекту фрейма, но этот объект уже будет иметь именованные поля, ссылающиеся на кнопки.
Не должно быть необходимости создавать дополнительный список элементов, которые вы создали для отображения в экземпляре tForm.
AFAIK, всякий раз, когда вы создаете новую панель, которая использует форму или другой контейнер вместо себя
pnl := Tpanel.Create(Self);
вам не нужно заботиться об уничтожении нового pnl, потому что он обрабатывается компонентом self.
Это означает, что должна быть любая конструкция, которая будет содержать дочерние компоненты родительского компонента.
Я ожидаю, что вы найдете, либо ComponentCount, либо список компонентов, либо метод FindComponent в родительском объекте. Предполагая, что объект "Self", на который ссылаются, является Tform.
for i := 0 to tForm(self).ComponentCount -1 do
if tForm(self).Components[i] is tPanel then
tPanel(tForm(self).Components[i]).Caption := intToStr(i) ;
изменит все подписи tPanels в вашем приложении. Чтобы различать Панели, созданные кодом и дизайнером, вы можете использовать свойство TAG каждого созданного tPanel и использовать его в приведенном выше примере.
Вы можете добавить компоненты, на которые вам нужны ссылки, в TList|Container... и затем использовать ваш список |container для доступа к ним.
var
slPanels: TStringList;
...
With TypeQuery do begin // Create Panels
First;
While (not eof) do begin // create the actual panel
panelno := FieldByName('Product_type_id').AsInteger;
pnl := Tpanel.Create(Self);
pnl.name := FieldByName('PanelName').AsString;
slPanels.AddObject(FieldByName('PanelName').AsString, pnl);
когда вам это нужно:
TPanel(slPanels.Objects[slPanels.IndexOf(FieldByName('PanelName').AsString)]) ...
Мне не нравится код выше (есть лучший контейнер... но это должно сделать работу: о))