Toon posts:

[Delphi 7] Dynamisch creëren van objecten

Pagina: 1
Acties:
  • 218 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Ik ben bezig met het maken van een programma dat formulieren, aan de hand van een bestand opmaakt. Zo'n bestand heeft bijvoorbeeld de volgende opmaak:

code:
1
2
3
4
<FORM caption="Image">
     <TAB caption="General" name="General">
     <TAB caption="Extra" name="Extra">
</FORM>


Bij het opstarten van het programma lees ik de waarden en zet ze in een string. Aan de hand van die string wil ik dus objecten maken. In bovenstaand voorbeeld dus twee tabs met de namen Extra en General.

Ik ben al een hele tijd op zoek hoe ik dit moet doen, maar ik kom er niet uit. Bijna alle tutorials geven aan dat ik in de source voor een dynamisch gegenereerd object een variable moet aanmaken. Maar dat kan niet omdat ik niet exact weet hoeveel tabs er gemaakt moeten worden. Wie weet ik welke richting ik moet zoeken?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:55

Creepy

Tactical Espionage Splatterer

Array's? TObjectList? etc?

Zie ook hier: [rml][ Delphi] Aangemaakt object[/rml]

[ Voor 68% gewijzigd door Creepy op 01-07-2004 15:30 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
Bedankt, hiermee ben ik een stuk verder gekomen! :)

Verwijderd

Topicstarter
Ik heb nu een aantal objecten geaakt:

code:
1
2
3
4
5
6
7
8
       TabSheet:=TTabSheet.Create(Self);
        with TabSheet do
        begin
        PageControl:=Tabs;
        Parent:=Tabs;
        Caption := TDLParser.Item[CounterII].Params[0].Value;
        Name:=TDLParser.Item[CounterII].Params[0].Value;
        end;


Vervolgens maak ik op ongeveer dezelfde manier een nieuw component aan. De naam van de parent heb ik in een string staan. Hoe zet ik deze string om naar een 'componentnaam' zoals bijvoorbeeld button1.name;?

  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 00:18

Delphi32

Heading for the gates of Eden

Heb je die TComponent.Name echt nodig dan? Bij dynamisch aangemaakte controls (ik heb een vergelijkbaar project als dat van jou) zet ik de Name property altijd op leeg ('' dus). Ik ga in mijn code er dan vanuit, dat de controls self-containing zijn (die hoeven de naam van de andere componenten dus niet te weten) en dat het form waarop ze komen te staan niet hoeft te weten welke controls er allemaal zijn (identificatie iig niet by name). Nog nooit problemen mee gehad, vandaar mijn wedervraag of je die Name wel nodig hebt.
Heb je het wel nodig, kijk dan eens of je de implementatie van IDesigner.UniqueName ergens kan vinden in de source van Delphi. (noot: zo heet dat ding in D5, heb hier ff geen recentere versies bij de hand..)

Verwijderd

Topicstarter
Ja, ik heb de name nodig. Ik wil bijv. een groupbox op een tabsheet zetten. Ik krijg dat niet voor elkaar zonder een parrent toe te wijzen. Dat gebeurt toch via een naam.

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Je moet de Name van een component nooit in code toewijzen. De Name is puur voor de designer in het leven geroepen, om makkelijker een variabele in de class van je form te zetten (Vóór het Delphi-tijdperk moest je dit allemaal handmatig doen).

Maar, als je een array of collection of whatever met je objecten hebt, dan kun je de objecten al benaderen. Geen noodzaak om dat ook nog bij naam te kunnen.

日本!🎌


Verwijderd

Lijkt het je niet slimmer om hiervoor XUL te gebruiken? :)

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:55

Creepy

Tactical Espionage Splatterer

Verwijderd schreef op 02 juli 2004 @ 01:22:
Lijkt het je niet slimmer om hiervoor XUL te gebruiken? :)
Lijkt me niet als je al de beschikking over de VCL hebt. Zeker niet als het ook nog eens een Windows only app is.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

_Thanatos_ schreef op 02 juli 2004 @ 01:20:
Je moet de Name van een component nooit in code toewijzen. De Name is puur voor de designer in het leven geroepen, om makkelijker een variabele in de class van je form te zetten (Vóór het Delphi-tijdperk moest je dit allemaal handmatig doen).

Maar, als je een array of collection of whatever met je objecten hebt, dan kun je de objecten al benaderen. Geen noodzaak om dat ook nog bij naam te kunnen.
Maar als ik me niet vergis moeten alle objecten/componenten toch wel een unieke naam hebben ?

Verwijderd

Ik gebruik een procedure om aan de hand van een componentlist een aantal componenten te maken.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
procedure TForm1.CreateComponents;
type TwcClass = class of TWinControl;
var i: integer;
    cc: TwcClass;
    c: TWinControl;
begin
  for i := 0 to pred(ComponentList.Count) do
  begin
    case ComponentList.Item[i].GetMetaType of
      mtID:       begin
                    cc := TLabel;
                    c := cc.Create(Panel1);
                    c.Name := ComponentList.Item[i].FldName;
                    if IsNew then
                      TLabel(c).Caption := 'New'
...

Greetinx,

Jos

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:55

Creepy

Tactical Espionage Splatterer

Verwijderd schreef op 02 juli 2004 @ 09:11:
[...]

Maar als ik me niet vergis moeten alle objecten/componenten toch wel een unieke naam hebben ?
* Creepy zet nooit de name property bij het dynamisch aanmaken van componenten.
Dus nee, dat hoeft niet ;)

@designtime wel (naampje dat je geeft is ook het naampje van de variabele). @runtime heeft dat naampje vrij weinig nut.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Tenzij je m met FindComponent via de naam op wilt zoeken.

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

Topicstarter
Ik ben grotendeels uit het probleem. Ik geef de objecten een naam. Om ze vervolgens uit de ComponentList op te roepen gebruik ik de volgende functie:

code:
1
2
3
4
5
6
7
8
9
function TTAgFrm.GiveListNumber(Name: String): integer;
var CounterI: integer;
begin
   for CounterI := 0 to DynObjects.Count - 1 do
   begin
      if DynObjects.Items[CounterI].Name = Name then
         Result := CounterI
      end
end;

Verwijderd

Verwijderd schreef op 02 juli 2004 @ 00:35:
Ja, ik heb de name nodig. Ik wil bijv. een groupbox op een tabsheet zetten. Ik krijg dat niet voor elkaar zonder een parrent toe te wijzen. Dat gebeurt toch via een naam.
Nee hoor. Ik zie niet in waarom je daar een naam voor nodig hebt?

Delphi:
1
2
3
4
5
6
7
procedure TForm1.Button1Click(Sender: TObject);
var
  oGrpBx: TGroupBox;
begin
  oGrpBx:=TGroupbox.Create(self);
  PageControl1.ActivePage.InsertControl(oGrpBx);
end;


Ik durf rustig te zeggen dat je de .name property NOOIT nodig hebt.

Post eens wat meer code, ik wil wel proberen uit te leggen hoe het dan werkt.. want hoe je het nu doet klinkt als via aken en keulen van amsterdam naar rotterdam reizen.. :P

//edit

Zo'n 'objectvariabele' is niets meer dan een pointer naar een bepaald object. Je kunt 'm dus herbruiken. Stel ik zou 10 groupboxen willen toevoegen, dan kan ik gewoon een for next loop om de bovenstaande code zetten.

[ Voor 33% gewijzigd door Verwijderd op 02-07-2004 16:58 ]


Verwijderd

Topicstarter
Op die manier had ik het nog niet bekeken. InsertControl werkt prima. Dat is voldoende om de name propety te vervangen en alle controls op de juiste plaats in te voegen.

De source van het bestandje waaruit het formulier wordt opgebouwd ziet er nu als volgt uit:
code:
1
2
3
4
5
6
7
8
9
10
<FORM caption="Image">
    <TAB  name="GeneralTab" caption="General">
        <GROUPBOX name="GeneralGbx" caption="" height="800" left="8" top="8" width="433">
            <ATTRIBUTE name="align" caption="Align:" type="combobox" left="8" top="16" width="417"> 
            <ATTRIBUTE name="alt" caption="Alt:" type="textbox" left="8" top="64" width="417"> 

        </GROUPBOX>

    </TAB>
</FORM>


Ik heb de zaak nu aangepast: Er is een ParentControl variable van het type TWinControl. Zodra de Formtag gelezen wordt wordt ParentControl:=Form1; zodra de groupbox gelezen wordt wordt ParentControl:=GroupBox1 enz. Voor ieder attribuut gebruik ik nu ParentControl.Insert. Dat werkt allemaal prima.

Als de gebruiker echter op het Ok knopje klinkt (die niet gegenereerd wordt via bovenstaand bestand :P ) wil ik een lijstje van strings maken waarvoor ik alle objecten weer wil aanroepen. Nu moet ik echter weten welk object bij welk attribute hoort. Hoe doe ik dat zonder van de naam gebruik te maken?

[ Voor 15% gewijzigd door Verwijderd op 02-07-2004 18:38 ]


Verwijderd

waarom zit je eigenlijk een soort van runtime DFM's te maken?

Maar goed, dat is een ander verhaal.

Ik begrijp weinig van je applicatie en kan je daarom niet zo direct antwoord geven op je vraag. Post anders even een stukje van je code, misschien dat ik dan beter begrijp wat je eigenlijk probeert te doen.

Wat wil je met die objecten doen?

Om even iets te noemen.. als je bv. gewoon al je 'zelf gegenereerde' objecten wilt hebben.. leid een eigen klasse af en controleer op het type.

dus bv.:

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type
  Mijn1337Object = class (TObject)
    private
      FString: String;
    public
       Property WeetIkVeel: String read FString write FString;
  end;

[..]

procedure tform1.button1click(sender: TObject);
var
  nLus: Integer;
begin
  for nLus:=0 to ControlCount-1 do
    if Controls[nLus] is Mijn1337Object then ...
end;


Dit type ik haastig even in, zal wel niet helemaal kloppen, maar het idee is denk ik wel duidelijk :P

Verwijderd

Topicstarter
Ik ben bezig met het schrijven van versie 4.0 van Internet Evolutions, m'n HTML editor. In de vorige versies had ik voor een aantal HTML tags een dialoogvenster gemaakt.

Er zijn heel veel tags, met steeds meer verschillende eigenschappen. Nu kan ik wel 60 verschillende formulieren maken, maar dat schiet niet echt op. Daarom maak ik voor iedere tag een bestandje waarin gedefinieert is welke eigenschappen die tag heeft, en doe dat "vertaalt" moet worden naar een formulier. Gebruikers kunnen zo ook hun eigen tags definieeren.

Aan de hand van bovenstaand bestandje genereer ik dus een control voor iedere tag eigenschap. Als de gebruiker op ok klikt moet ik daaruit een string genereren in de vorm van
code:
1
<tagnaam attribute1="waarde1" attribute2="waarde2">


Om dit te doen moet ik weten welk van de 6 gegenereerde comboboxen de waarde bevat die hoort bij attribute1.

[ Voor 27% gewijzigd door Verwijderd op 02-07-2004 18:54 ]


Verwijderd

Kijk dat bedoel ik. Waarom maak je voor elke tag een bestandje, waarom stop je dat in losse bestandjes, imo kun je dan beter gaan werken met eigen objecten. Veel tags zullen dezelfde eigenschappen hebben. Op jouw manier zul je toch voor elke tag afzonderlijk die eigenschap moeten gaan definieren, met een objectmodel hoef je dat maar 1 maal te doen ..

Voor de rest kan ik je nog geen antwoord geven op je vraag.. ok je hebt dus een tabsheet met daarop controls welke corrosponderen met 'tags' welke je opgeslagen had in een bestandje. Nu klikt de user op OK, en wil je iets met die controls gaan doen, maar wat?

Post anders een stukje pseudo-code ofzo, want je vraag mij iig een beetje onduidelijk zo.. :P

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 21-02 23:50
Als je die source zelf onder controle hebt, is het misschien handig om er valid XML van te maken. Dan heb je denk ik vast wel componenten beschikbaar die dat zo inlezen.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Verwijderd

Topicstarter
Het maken van een objectmodel is voor mij helemaal nieuw. Ik zal eens rondsnuffelen op internet om te kijken of ik ergens een tutorial kan vinden.

Verwijderd

Topicstarter
Nu klikt de user op OK, en wil je iets met die controls gaan doen, maar wat?
Die controls corresponderen met eigenschappen van een tag. Nu wil ik de waarden van controls uitlezen en deze verwerken in een string om zo uiteindelijk een tag te genereren.

Voordat ik de formulieren dynamisch maakte had ik dat alsvolgt gedaan:
code:
1
2
3
Tag:='<a';
if HrefBox.Text<>'' then
  Tag:=Tag+'href="'+HrefBox.Text;


Nu kan ik uit een bestand alle eigenschappen van een tag (zoals href) lezen. Alleen moet ik nu de control vinden die bij die eigenschap hoort.

Ik ben ook aan het kijken naar een object model. Met wat ik tot nu toe gevonden heb kom ik nog niet veel verder.

  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 00:18

Delphi32

Heading for the gates of Eden

Ik snap je probleem nu en dit is wat ik ervan zou maken:
maak een class TTagPartEditor of iets van die naam. Instantieer voor elke control die je volgens je form-definitie wilt hebben, 1 object van type TTagPartEditor. Laat dat object weten bij welk control hij hoort (TTagPartEditor krijgt een property Control, die je set bij aanmaken van je control) en stop je object in een lijstje. Bij sluiten van het form loop je het lijstje TagPartEditors af en vraag je aan elke instantie de TagPart.AsString (function TTagPartEditor.AsString dus; deze function leest dan de waarde van de Control uit die aan de instantie gehangen is). Die plak je dan allemaal achter elkaar en je hebt een complete html-tag.
Om de positie van je tagpart in de uiteindelijke tag-string te bepalen, zou je een Position op kunnen nemen in je form-definitie. Die Position laat je dan weten aan de TagPartEditor-instantie en bij het aflopen van je lijstje sorteer je de lijst op Position.

[ Voor 5% gewijzigd door Delphi32 op 03-07-2004 00:22 . Reden: Kleine verduidelijking ]


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 22-05 23:32

alienfruit

the alien you never expected

Peter, ik denk dat ik nog wel ergens mijn kloon van VTML heb liggen, ik zal eens zoeken voor je.
Pagina: 1