Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Timage.onclick TNotifyEvent??


galikor - Do 19.02.09 18:18
Titel: Timage.onclick TNotifyEvent??
Hallo Community,

es gab 5 relevante Themen, da hab ich aber keine Lösung gefunden.
Falls ich etwas übersehen haben sollte, dann verzeiht mir bitte.

Habe folgendes Anliegen, ich erzeuge dynamisch ein Array of TImage
und dann werden diese Bilder auf meiner Tform1 zugeordnet und plaziert.
Dies passiert hier:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
     while not eof(f) do
        begin
          readln(f,str);
          pics[i]:=TImage.create(form1);
          pics[i].Parent:=form1;
          pics[i].Visible:=true;
          pics[i].Picture.LoadFromFile(str);
          pics[i].Stretch:=true;
          pics[i].Left:=a;
          pics[i].Top:=b;
          a:=a+110;
        if a > 700 then begin a:=10;b:=b+110;
        end;
     end;


Ich weiß das man mit dem Befehl ( ShellExecute(Application.Handle, 'open', PChar('Project1.exe'),NilNil, SW_NORMAL); ) eine Datei öffnen kann.

Mein Anliegen ist nun, dass wenn man dann auf einen der Bilder klickt, es sich das Original öffnet.
Mit pics[i].Onclick:=ShellExecute(Application.Handle, 'open', PChar(str),   NilNil, SW_NORMAL);
geht es allerdings nicht. 'str' ist der Pfad der Datei aus ner anderen Datei genommen.

Bin über jeden hinweis dankbar.

Moderiert von user profile iconmatze: Delphi-Tags hinzugefügt


Yogu - Do 19.02.09 19:05

Hallo und :welcome: im Delphi-Forum, user profile icongalikor!

Du musst irgendwie die Dateinamen der Grafiken speichern. Das kannst du auf verschiedene Arten tun:


Entscheide selber, welche der genannten Varianten für dich am günstigsten ist :idea:

Manche Programmierer mögen das Speichern größerer Daten in einem Tag nicht, und das auch begründet: Du musst die Strings auch irgendwie wieder freigeben. Ist zwar logisch, aber ich weiß gerade nicht, wie das gehen soll :?

Grüße,
Yogu


galikor - Do 26.02.09 18:00

Stimmt das mit dem Namen speichern war der Punkt. ;)

Habe erstmal rausgefunden, wie das mit dem TNotifyEvent für OnClick funktioniert.
Meinem createten Image weise ich dann ne Procedur zu:

Delphi-Quelltext
1:
pics[i].OnClick := Click;                    
Und dies ist die Procedure dann:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure tpics.Click(Sender: TObject);
var str,str_aktiv:string;i:integer;
begin
str:=TImage(Sender).Name; //das war der Knackpunkt, da hab ich lange für gesucht, dass man das so übergeben kann

str:= copy(str,1,pos('Dateiname',str)-1) + '.' + copy(str,pos('Dateiname',str)+9,length(str)) ; 
//das ist nur, damit ich den kompletten Dateinamem als Name habe, schreibe halt vorher an die Stelle vom '.' das Wort Dateiname (hoffe das ich nie ne datei habe, die dann so heißt, aber kann man ja noch ändern), und hier ersetzt er dann wieder das Wort durch einen '.'

ShellExecute(Application.Handle, 'open', PChar(str),   NilNil, SW_NORMAL)
end;

Falls jemand dazu noch Ideen hat, oder Verbesserungsvorschläge, die es noch einfacher machen, nur raus damit.
Oder Kritik ist auch erwünscht (aber macht mich nicht ganz runter, bin erstmal froh, dass es funktioniert :) )

Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt


Yogu - Do 26.02.09 20:09

Hallo,

wenn es so funktioniert ist das ja schonmal gut. Allerdings ist das natürlich ziemlich umständlich gelöst und verbesserungsfähig. Also, gute Nachrichten: Du kannst wieder was lernen :)

Ich beschreib dir jetzt mal den ersten von mir genannten Punkt genauer, das kannst du ja mal ausprobieren.

Also, die Idee ist folgende: Jede Komponente hat eine Eigenschaft Tag mit dem Datentyp Integer - also eine Zahl. In dieser Zahl können wir aber auch speichern, wo denn der Dateiname zu finden ist. Das machen wir so:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var Dateiname: PChar; Adresse: Integer;

// Wir wandeln den Dateinamen str in einen PChar um, da dieser
// besser mit Pointern zu bedienen ist. Ein PChar ist ein Zeiger
// auf das erste Zeichen der Zeichenkette.
Dateiname := PChar(str);

// Wir wandeln die Adresse auf das erste Zeichen in einen Integer um,
// um sie dann der Eigenschaft "Tag" der Komponente zuweisen zu können
Adresse := Integer(Dateiname);
pics[i].Tag := Adresse;

Das war's. Drei Anweisungen zum Speichern des Namens.

Jetzt noch das lesen, also alles wieder rückgängig


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var Adresse: Integer; Dateiname: PChar;

// Adresse aus Tag auslesen, vorher noch den Sender in eine
// TComponent casten, damit wir auf die Eigenschaft Tag zugreifen
// können
Adresse := TComponent(Sender).Tag;

// Adresse in ein PChar umwandeln, um auf die Zeichen zugreifen zu können
Dateiname := PChar(Adresse);

// - jetzt steht der Dateiname in der gleichnamigen Variable -

So einfach geht das :idea:

Bei Fragen einfach - fragen ;)

Grüße,
Yogu

Edit:

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Beim zweiten Quelltext fehlt aber noch ein klitzekleiner Cast würde ich sagen. ;-)

:oops:
Verpessert.


jaenicke - Do 26.02.09 20:15

Beim zweiten Quelltext fehlt aber noch ein klitzekleiner Cast würde ich sagen. ;-)


galikor - Do 26.02.09 21:20

Klingt interessant, ich probier das morgen gleich mal aus, heute keine Nerven mehr.
Hab eben noch gemerkt, dass wenn ich diese Bilder anzeigen lasse und dann Neue suche, weil es eine Art Bildersuche ist, dann kommt wieder son lustiger Fehler.

Fehlermeldung: Method 'Click' hides virtual method of base type 'TControl'

Denke es hängt damit zusammen, dass ich bei erneutem Drücken auf Suche, ja irgendwie die alten gefunden Bilder in dem Array of TImage wieder löschen muss. Das muss ich mir erstmal wieder näher anschauen.

Ich meld mich morgen mal, nach weiterem "Lernen". ^^


jaenicke - Do 26.02.09 21:37

Nenn deine Methode mal nicht ausgerechnet Click, dann kommt die Fehlermeldung auch nicht. Click gibts nämlich schon, damit kannst du einen Klick auf in diesem Fall das Formular simulieren, und durch deine neue Methode Click wird die alte versteckt.

Was meinst du warum die automatisch erstellten Methoden so schöne Namen haben wie Button1Click oder so und nicht nur alle Click heißen? Dann könnte die keiner auseinander halten, schon gar nicht der Compiler. ;-)

Deshalb: Nimm aussagekräftige Namen, auch wenn es mal ein paar Zeichen mehr zu tippen sind.


galikor - Fr 27.02.09 01:17

Da meine Kreativität zu wünschen läßt, heißt es jetzt ClickKlack.

Junge bin ich ein Voll*****.
Wenn ich meine pics[i]:=TImage.create(Form1); gemacht habe, hab ich Trottel doch total vergessen das "i" hochzuzählen. *Kopf->Tischplatte*

Wenn ich jetzt was neu suche und das alte lösche, spricht was gegen:


Delphi-Quelltext
1:
2:
3:
4:
for i:=0 to overflow do
begin
pics[i].Destroy;
end;

Funktioniert jetzt soweit alles - wie es soll, aber ist Destroy so die elegante Wahl?

PS: Danke an Yogu und jaenicke, falls ich noch Probleme haben sollte, weiß ich ja wo ich sie bekomme.
Und bevor ich hier was frage, seit euch gewiss, dass ich schon vorher ne Stunde (oder mehr) im Netz/ DelphiHilfe gesucht habe. ;)

Moderiert von user profile iconmatze: Delphi-Tags hinzugefügt


jaenicke - Fr 27.02.09 01:24

user profile icongalikor hat folgendes geschrieben Zum zitierten Posting springen:
Wenn ich jetzt was neu suche und das alte lösche, spricht was gegen:


Delphi-Quelltext
1:
for i:=0 to overflow do                    
Ist overflow die Anzahl oder der höchste Index? Wenn es die Anzahl ist, dann fehlt da ein -1.

user profile icongalikor hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
2:
3:
begin
pics[i].Destroy;
end;


Funktioniert jetzt soweit alles - wie es soll, aber ist Destroy so die elegante Wahl?
Nein, der Konstruktor Destroy sollte niemals direkt aufgerufen werden, es sollte immer Free benutzt werden. Das prüft z.B. vorher, dass das Objekt überhaupt noch existiert.