C++ Eigenschaften mehrerer Bilder per Schleife anpassen

M

Marcel^

Gast
Hallo,

ich möchte bei einer Reihe von Bildern (32 Stück) per Schleife Werte ändern.

Bisher musste ich das immer mit einzelnen Befehlen machen, sprich z.B.:

Image1->Top+=100;
Image2->Top+=100;
[...]
Image32->Top+=100;

Ich habe natürlich herumexperimentiert, aber

for(int i=1; i<33;i++)
{
Image->Top+=100;
}

will so nicht funktionieren. Ich bin mir sicher, dass es für solche Fälle eine bessere Lösung gibt, besonders wenn es vorher eine Berechnung gibt und ich sonst riesige switch-case-Anweisungen schreiben müsste.

Danke schonmal. :)
 
Also eigentlich sollte dein Ansatz mit der Schleife schon funktionieren. Beachte aber, daß Array-Indizes in C++ bei 0 beginnen, also:

Code:
for ( std::size_t i = 0; i < 32; ++i )
{
    Image[i]->Top+=100;
}
 
Das mit dem Array stimmt. Aber ich will ja bloß eine integer-Variable hochzählen. Darum fange ich bei 1 (Image 1 ist das erste) an und höre bei 32 (Image 32 ist das letzte) auf.

++i müsste i doch schon hochsetzen, bevor die Schleife zum ersten mal läuft oder? Also gehts im Prinzip nur von 1 bis 31 bei Deiner Version, oder?

Kannst Du mir "std::size_t" bitte erklären? :)

Edit:

Image->Left+=540;

[C++ Fehler] Unit1.cpp(40): E2451 Undefiniertes Symbol 'Image'

Wenn ich "std::size_t" noch dazu schreibe, gibts noch ne Fehlermeldung. :D

[C++ Fehler] Unit1.cpp(38): E2176 Zu viele Typen in der Deklaration
 
Zuletzt bearbeitet von einem Moderator:
std::size_t muß nicht unbedingt sein. Ich persönlich verwende es bevorzugt als Schleifenzähler in Fällen, in denen der Schleifenzähler niemals negative Werte annehmen kann. In C++ muß man allerdings vorher ein

#include <cstddef>

absetzen, um dem Compiler std::size_t bekannt zu machen. Aber du kannst auch einfach weiter int verwenden ... wahrscheinlich hätte ich der Einfachheit halber lieber auf std::size_t verzichten sollen. :)

++i müsste i doch schon hochsetzen, bevor die Schleife zum ersten mal läuft oder? Also gehts im Prinzip nur von 1 bis 31 bei Deiner Version, oder?

Nee. ;) Debug doch einfach mal in die Schleife rein. Du wirst sehen, der erste Durchlauf passiert mit i == 0.

C++ Fehler] Unit1.cpp(40): E2451 Undefiniertes Symbol 'Image'

Na ja, das Array Image[] muß natürlich in Unit1.cpp auch bekannt sein.
 
Zuletzt bearbeitet:
antred schrieb:
std::size_t muß nicht unbedingt sein. Ich persönlich verwende es bevorzugt als Schleifenzähler in Fällen, in denen der Schleifenzähler niemals negative Werte annehmen kann. In C++ muß man allerdings vorher ein

#include <cstddef>

absetzen, um dem Compiler std::size_t bekannt zu machen. Aber du kannst auch einfach weiter int verwenden ... wahrscheinlich hätte ich der Einfachheit halber lieber auf std::size_t verzichten sollen. :)

Wozu ist es denn gut, wenn die Schleife keine negativen Werte annehmen kann? :)

Nee. ;) Debug doch einfach mal in die Schleife rein. Du wirst sehen, der erste Durchlauf passiert mit i == 0.

Nagut, ich benutze einfach weiter i++. :D Wenn mich ein Fehler irgendwann verzweifeln lässt, probier ich ++i.^^

Na ja, das Array Image[] muß natürlich in Unit1.cpp auch bekannt sein.

Stimmt. :p Wie mache ich das dann? Der Compiler legt die Bilder ja automatisch an:

Code:
TImage *Image1;   TImage *Image2;   TImage *Image3;   TImage *Image4;
TImage *Image5;   TImage *Image6;   TImage *Image7;   TImage *Image8;
TImage *Image9;   TImage *Image10;  TImage *Image11;  TImage *Image12;
TImage *Image13;  TImage *Image14;  TImage *Image15;  TImage *Image16;
TImage *Image17;  TImage *Image18;  TImage *Image19;  TImage *Image20;
TImage *Image21;  TImage *Image22;  TImage *Image23;  TImage *Image24;
TImage *Image25;  TImage *Image26;  TImage *Image27;  TImage *Image28;
TImage *Image29;  TImage *Image30;  TImage *Image31;  TImage *Image32;
TImage *Image33;

Ich lege das Array Image[32] an. Aber wo? Dort, wo der Compiler ("__published:"-Bereich) alles deklariert?

Welchen Typ hat das Array? Und was schreibe ich anschließend rein, damit ich direkt auf die Images zugreifen kann?

Tut mir leid für die dummen Fragen aber sowas haben wir in den 3 Jahren Schule nicht gemacht und die Eigeninitiative kommt leider erst jetzt zum Studium hin. :rolleyes:

Vielen Dank bis hierhin schonmal! :)
 
Du verwendest also Borland C++ Builder, oder?

Deine TImage Bilder stammen von deiner IDE und werden auch von dieser automatisch generiert ( nicht vom Compiler! )

Ich weiß nicht wie deine IDE die ganzen TImage Pointer füllt, aber ich schätze da wird es irgendwo auch einen automatisch generierten Code dazu geben, der sich in deiner Unit1.cpp befindet. Wenn du den findest, dann kannst du die ganzen TImage Pointer durch ein Array aus TImage Pointern ersetzen und das dann über eine Schleife füllen, so wie du es geplant hattest.

BTW:
In einer Schleife spielt es keine Rolle ob du "i++" oder "++i" verwendest, das Resultat ist genau das gleiche! Möglicherweise ist "++i" schneller, wobei das vom Compiler abhängig ist und wie sehr der Code optimiert wird!

Gruß
BlackMark
 
Zuletzt bearbeitet:
Genau den benutze ich.

Tut mir leid, natürlich die IDE.

Bin da gerade etwas ratlos. Außer den oben im Code-Feld zitierten Zeigern ist da nichts vorhanden. :(
 
Dann wird es schwierig, weil deine IDE die Bilder wahrscheinlich über eine Art resource Datei den Pointern zuweist. Wie gesagt, ich weiß es nicht genau, weil ich keinen Borland C++ Builder habe.

Was du aber auf jeden fall machen kannst:
Du kannst die ganzen Image Variablen in einem Array zusammenfassen. Das geht indem du ein Array mit Pointern auf die TImage Pointer machst.

Also so in etwa:
Code:
TImage** appImage[33];

appImage[0] = &Image1;
appImage[1] = &Image2;
appImage[2] = &Image3;
// ...
appImage[32] = &Image33;

Das kannst du direkt unter den ganzen TImage Pointern einfügen. Dadurch dass du im Array jetzt einen Pointer auf einen Pointer hast, bekommst du über das Array auch immer den Wert, auf den die TImage Pointer gerade zeigen.
In der Schleife kannst du dann auf die einzelnen Bilder mit "(*appImage)->Top += 100;" zugreifen!

Ob das wirklich die beste Lösung ist wage ich stark zu bezweifeln, aber es sollte funktionieren!

Gruß
BlackMark
 
Ich nehme mal an, dass die VCL des C++ Builders mit der von Delphi weitestgehend identisch ist, was den Funktionsumfang angeht.
Dementsprechend würde ich folgendes Vorgehen vorschlagen:

Da die Images alle auf einem Formular liegen, werden sie wahrscheinlich dieses Formular (ggf. ein darauf liegendes visuelles Control) als Owner haben.
Das ermöglicht es dir, über Components des Owners zu laufen, und für jedes Element dieses Arrays zu überprüfen, ob das Objekt zu denne gehört, die du anpassen willst: zB alle Bilder via Components->ClassNameIs('TImage').

Einfacher wäre es natürlich, wenn du einfach alle betroffenen Bilder auf ein Panel legst, und dann über Panel->Controls auf die darauf liegenden Elemente zugreifst.

So dürftest du dir in einem gewissen Rahmen Code-Anpassungen (das Array) sparen, wenn du ein paar Bilder löscht oder hinzufügst.
 
@pcw:

Ja, die Bilder liegen alle auf TForm1, dessen Owner TForm ist.

Allerdings sollten die Bilder schon per Array direkt ansprechbar sein. :(

@BlackMark:

Wenn ich das dort hinkopiere, wird gemeckert:

Fehler im Modul Unit1: Falsche Felddeklaration in Klasse TForm1.

Kopiere ich das in den Private-Bereich, funktioniert der Zeigerzeiger. Aber ab

appImage[0] = &Image1;

sagt er mir:

[C++ Fehler] Unit1.h(48): E2303 Typname erwartet
[C++ Fehler] Unit1.h(48): E2238 Bezeichner 'TForm1::appImage' mehrfach deklariert
[C++ Fehler] Unit1.h(47): E2344 'TForm1::appImage' bereits deklariert
[C++ Fehler] Unit1.h(48): E2233 Klassenelement kann hier nicht initialisiert werden.
 
Das sieht sehr nach einem Fehler mit deiner TForm1 Klasse aus. Du musst "appImage" im Header der Klasse deklarieren, sonst kommen diese Fehler. Sofern die C++ Builder Klassen mit den normalen C++ Klassen identisch sind, kannst du "appImage" einfach im "private" Bereich deiner Klasse deklarieren!

Gruß
BlackMark
 
Im Header der Klasse? Die Klasse wird ja sowieso komplett in der Header-Datei konstruiert.

Die Fehlermeldungen stehen ja schon unten, sowohl für published als auch für private. :(
 
Ich hab zwar mit dem C++ Builder selber noch nie gearbeitet, aber warum definierst du deinem Form nicht einfach eine public property, die Array-artig ansprechbar ist und auf die Images zugreift?

Code:
//Form1Unit.h
class TForm1
{
private:
...
public:
...
  TImage *GetImageFromControls(int Index);
  __property TImage *Images[int Index]= {read = GetImageFromControls};
}
Code:
//Form1Unit.cpp
TIMage * TForm1::GetImageFromControls(int Index)
{
  for(int i = 0;i < self->ControlCount; i++)
  {
    if(self->Controls[i].ClassNameIs('TImage'))
    {
      if(Index-- == 0)
      {
        return (TImage *)(self->Controls[i]);
      }
    }
  }
  return NULL;
}

Aber wie gesagt, ich hab keinen C++ Builder und noch nie mit C++ an sich ernsthaft gearbeitet, deswegen ist das Code weder geprüft noch sonstirgendwie qualitativ hochwertig. Ich stell mir nur vor, dass es so in etwa funktionieren könnte. *g*

Falls es funktionieren sollte, kannst du dann einfach Form1->Images benutzen, um auf die Bilder zuzugreifen. Die Property für den Count müsstest du dir analog selber anlegen.
 
Die Klasse wird im Header deklariert und auch definiert?

Ok, dann machst du die Definition "TImage** appImage[33];" in den Header und die Definition in den Konstruktor der Klasse. Somit solltest du keine Fehlermeldung von doppelter Deklaration mehr bekommen!

Edit:
@pcw: Interessanter Ansatz, wenn der C++ Builder so etwas zulässt, dann würde ich diese Lösung auch bevorzugen!

Gruß
BlackMark
 
Zuletzt bearbeitet:
Ihr seid die besten. :)

Der Borland Builder handhabt das so:

Klassendefinition und -rumpf in der Header-Datei, die "Innereien" bekommen die Funktionsrümpfe aber erst in der .cpp-Datei.

Habe jetzt erstmal den Ansatz von BlackMark umgesetzt, der war schon halb reinkopiert und die Variante von pcw wirft bei stumpfen kopieren, kurzen anpassen und Ausführen noch zu viele Fehler aus. :D

Hab das jetzt soweit alles eingebaut, die Definition schluckt er ohne zu murren.

Allerdings führt nun

Code:
appImage[i]->Visible=true;

zu folgendem Fehler:

Code:
[C++ Fehler] Unit1.cpp(81): E2288 Zeiger auf Struktur auf linker Seite von -> oder von ->* erforderlich

Wenn der Zeiger wirklich ein Muss ist, ist der Plan so nicht umsetzbar, oder? :confused_alt:
 
Wie ich schon vorher geschrieben habe, kannst du auf die einzelnen Pointer im Array so zugreifen:
Code:
(*appImage[i])->Visible = true;

So wie du es machst bekommst du nur den Pointer auf den Pointer, wenn du aber den Pointer auf das Bild haben willst, dann musst du mit dem "*" Operator arbeiten!

Edit:
Klassendefinition und -rumpf in der Header-Datei, die "Innereien" bekommen die Funktionsrümpfe aber erst in der .cpp-Datei.
Das ist ja auch das Prinzip von Header Dateien!

Gruß
BlackMark
 
Zuletzt bearbeitet:
Super, so klappt es! :) Vielen Dank für eure Bemühungen!

BlackMark schrieb:
Wie ich schon vorher geschrieben habe, kannst du auf die einzelnen Pointer im Array so zugreifen:
Code:
(*appImage[i])->Visible = true;

So wie du es machst bekommst du nur den Pointer auf den Pointer, wenn du aber den Pointer auf das Bild haben willst, dann musst du mit dem "*" Operator arbeiten!

Ich hab es nur ohne Klammern versucht, das hat nicht funktioniert. Es mangelt eben fast immer an Kleinigkeiten. :D

Das ist ja auch das Prinzip von Header Dateien!

Wollte Dir nur den Aufbau im Borland Builder erklären. Da Du gefragt hattest, nahm ich an, dass es in anderen Buildern vielleicht anders strukturiert ist.
 
Gut, dass du es zum laufen bekommen hast!

Wollte Dir nur den Aufbau im Borland Builder erklären. Da Du gefragt hattest, nahm ich an, dass es in anderen Buildern vielleicht anders strukturiert ist.
Normalerweise schreibt man die Klassen selber und lässt sie nicht von der IDE erstellen, aber es wäre auch ziemlich schlecht, wenn deine IDE nicht die gängige Art des Programmierens einhalten würde, oder?

Gruß
BlackMark
 
Dieser Kniff wird mir bestimmt noch oft von nutzen sein, habs direkt notiert. :cool_alt:

Wir haben nur mit dem Borland Builder gelernt und das war meine bisher einzige Erfahrung mit C++. Da das beigebrachte leider sehr lückenhaft ist (nicht nur im Fach Programmieren :rolleyes:), hätte es nach meinem Wissen genauso bei jedem Builder verschieden sein können. :)

Die Borland IDE erstellt nur die Klasse der Unit1 selbst. Mein Programm enthält zusätzlich noch drei eigens geschriebene Klassen.
 
Dieser Kniff wird mir bestimmt noch oft von nutzen sein, habs direkt notiert.
Der Pointer ist der größte Feind und Freund des Programmierers :D

C++ ist sehr umfangreich und deshalb kann man schwer alles lehren, was es zu dieser Sprache gibt!

Ich wünsche dir noch viel Spaß beim programmieren ;)

Gruß
BlackMark
 
Zurück
Oben