![]() |
AW: Idee für Auswahlfunktion
Also ich finde VirtualStringTree/VirtualDrawTree auch die beste Wahl. Kann man auch schön mit einer Live-Suche (Beim Tippen schon Ergebnisse einblenden) kombinieren und unter dem Edit einblenden. Noch mehr vorgefertigt ist, denke ich, zu unflexibel. Es sein denn, man kann es nicht.
|
AW: Idee für Auswahlfunktion
Irgendwer hier im Forum hat mal eine SVG Komponente gemacht. Die würde ich erweitern!
Wegen TWebbrowser: Das Design lässt sich ja relativ einfach von Webseiten klauen und in eine Art Template umwandeln. bzw. man benutzt ein Template von ![]() und passt das an. |
AW: Idee für Auswahlfunktion
@Popov: Ehrlich gesagt habe ich mir das genauso vorgestellt :-D
Ich schätze mal, ich war mir der Vielfältigkeit von Combobox und Listbox nur nicht so bewusst. Trotzdem habe ich absolut keine Ahnung wie man so etwas mit diesen Komponenten erstellen soll :shock: |
AW: Idee für Auswahlfunktion
An für sich ist das nicht kompliziert, eher nur malen nach Zahlen, d. h. du hast deine Canvas auf der du zeichnest. Das ist fast genauso wie zeichnen auf dem Canvas des Formulars, einer Bitmap oder Image. Allerdings müssen hier vor allem drei Punkte beachtet werden.
Der erste ist, dass du schon auf der richtigen Canvas zeichnen mußt. Als Parameter bekommst du nur
Delphi-Quellcode:
und nicht
Control: TWinControl
Delphi-Quellcode:
. Du mußt
TListBox
Delphi-Quellcode:
also sagen, dass es eine TListbox ist. Das machst du mit
Control
Delphi-Quellcode:
with (Control as TListbox) do
Delphi-Quellcode:
Ob du nun mit With arbeitest (mußt du nicht, du kannst aber) oder anders, z. B. so
procedure TForm1.ListBox1DrawItem(Control: TWinControl;
Index: Integer; Rect: TRect; State: TOwnerDrawState); begin with (Control as TListbox) do begin ... end; end;
Delphi-Quellcode:
ist eigentlich egal. Beides geht.
procedure TForm1.ListBox1DrawItem(Control: TWinControl;
Index: Integer; Rect: TRect; State: TOwnerDrawState); var MyListBox: TListBox; begin MyListBox := (Control as TListbox); MyListBox.Canvas. ... Der zweite wichtige Punkt ist, dass du eigentlich auf der ganzen ListBox Canvas zeichnen kannst, aber das willst du ja nicht. Du willst nur auf dem kleinem Streifen des Items zeichnen. Dazu bekommst du den Parameter
Delphi-Quellcode:
. Jedes Item hat seinen eigenen Rect Bereich. Du mußt beim Zeichnen also in dem Bereich bleiben.
Rect: TRect
Die Prozedur
Delphi-Quellcode:
funktioniert so: sie wird so oft aufgerufen wie viele Items sichtbar sind. Sind fünf Items sichtbar, wird die Prozedur auch fünf mal aufgerufen. Nur bekommst du jedes Mal passend zu dem Item andere
OnDrawItem
Delphi-Quellcode:
Werte. Willst du also an Koordinate 1 und 1 einen Punkt setzten, dann nicht
Rect
Delphi-Quellcode:
, sondern
MyListBox.Canvas.Pixels[1, 1] := clBlack
Delphi-Quellcode:
. Du mußt also immer im Verhältnis zu Rect zeichnen. Läßt du es weg, zeichnest du alles oben in der ListBox.
MyListBox.Canvas.Pixels[Rect.Left + 1, Rect.Top + 1] := clBlack
Nur bedenke, man kann auch drüberzeichen in das darunterliegende Item. Die Begrenzung nach unten ist
Delphi-Quellcode:
, nach rechts
Rect.Bottom
Delphi-Quellcode:
. Also immer schön im im Bereich bleiben und es immer wieder überprüfen. Außerdem sollte man bedenken, dass es auch eine Funktion Rect gibt. Die Namenswahl des Parameters ist nicht sonderlich glücklich, aber auch keine Katastrophe. Man muß eben aufpassen. Wenn eine Fehlermeldung kommt, dann sollte men es nur wissen um was es geht.
Rect.Right
Der dritte wichtige Punkt ist, dass man die
Delphi-Quellcode:
Parameter betrachten sollte. Denn die sagen einem was für ein Item das aktuelle Item ist. Ist es ein normales Item oder eine der den Fokus besitz oder ist er gerade selektiert.
State: TOwnerDrawState
Delphi-Quellcode:
Das Beispiel fragt ab ob der Item gerade selektiert ist. In diesem Fall ändert sich die Schriftfarbe. Die Hintergrundfarbe ist schon automatisch in Brush.Color eingestellt. Eigentlich mußt du die Textfarbe und Hintergrundfarbe nicht einstellen, da sie schon voreingestellt sind. Das ist nur dann wichtig wenn du deine eigenen Farben wählen willst. Ansonsten bekommst du die Systemfarben voreingestellt.
with (Control as TListbox) do
begin if odSelected in State then Canvas.Font.Color := clInactiveCaptionText else Canvas.Font.Color := clWindowText; Wenn man sein eigenes Design wählen will, dann muß man die Hintergrundfarbe ändern, die Schriftfarbe, dann den Focus löschen und durch seinen eigenen ersetzte. Aber das erkläre ich evt. später, sonst verwirrt das alles nur. Zuletzt noch der Hinweis, dass
Delphi-Quellcode:
den Index beinhaltet der bei dem Durchlauf gerade gezeichnet wird.
Index: Integer
|
AW: Idee für Auswahlfunktion
Okay danke an Popov schon mal dafür und ich hab mich da auch gleich mal an die Arbeit gemacht. Bin allerdings nicht soo weit gekommen. Vielleicht wäre es hilfreich erst einmal den ganzen Quelltext zu posten und dann zu den einzelnen Schritten etwas zu sagen, weil ich mich leider noch nicht so gut mit Delphi auskenne.
|
AW: Idee für Auswahlfunktion
Liste der Anhänge anzeigen (Anzahl: 2)
So, sorry, habe dich übersehen. Hier nun der Sorcecode für das Beispiel vorne. Ich hab den Part mit den Daten heute noch etwas vereinfacht, da ich die Daten vorher in einem Record als Object am Item hatte, was die Sache zwar stark vereinfacht, aber für dich als Anfänger evtl. eine zusätzliche Hürde darstellt. Also habe ich ein anderes Konzept gewählt und alle Daten in einem String zusammengefasst. Das aber nur so nebenbei.
|
AW: Idee für Auswahlfunktion
Okay alles klar, danke dafür.
Ich habe es mir mal angeschaut und verstehe es auch weitestgehend, aber mir ist gerade schleierhaft wie ich jetzt die Daten einbinden kann :? Also es wird eben abgefragt
Delphi-Quellcode:
Path extrahiert einfach den Filepath (wird im FormCreate deklariert) und was ich mich jetzt frage ist wie ich die daten erfassen kann? Diese werden bislang in "Info(Username).txt" abgespeichert und ich habe diese bisher einfach mit einer Stringlist erfasst und dann ausgegeben. Aber in diesem Fall ist das ganze ein wenig schwieriger wenn ich mich nicht irre. Und kann ich das Bild auch einfach in die Imagelist laden. (Bild = Username.jpg)
if FileExists(path+Edit1.text+'.txt')then
begin Listbox1.Items.Add() |
AW: Idee für Auswahlfunktion
Wie du die mit deinen Daten umgehen kannst und welche du hast, das weißt doch du, nicht ich.
Ich hab dir das Beispiel umgeschrieben. Im Item selbst werden hier keine Daten mehr gespeichert. Stattdessen werden die Daten in einem Objekt an den Item gebunden. Die Daten können bei Bedarf gelesen werden, das Item selbst enthält nur noch einen leeren String. Bei dieser Methode kannst du deine Informationen viel besser verwalten. Du übergibst sie irgendwo an Info und dann greifst du sie bei Bedarf ab. Die Klasse Info vorher an deine Bedürfnissse anpassen. Sie ist simpel gehalten.
Delphi-Quellcode:
Das einzieg auf das du hier achten mußt ist, dass du Items nicht mehr direkt löschen darfst. Vorher mußt du das Objekt freigeben. Abgesehen am Ende. In FormDestroy werden die Objekte automatisch freigegeben.
type
TInfo = class Name: String; Ort: String; Freunde: Integer; ImageIndex: Integer; end; {Gibt den X-ten Teilstring eines mit Kommas getrennten Daten-Strings} function ExtractSubStr(Str: String; Index: Integer): String; var i: Integer; begin Result := ''; if Index < 1 then Exit; Str := Str + ','; for i := 1 to Index - 1 do Delete(Str, 1, Pos(',', Str)); Result := Trim(Copy(Str, 1, Pos(',', Str) - 1)); end; procedure TForm1.FormCreate(Sender: TObject); procedure SetInfo(s: String; var Info: TInfo); begin Info := TInfo.Create; Info.Name := ExtractSubStr(s, 1); Info.Ort := ExtractSubStr(s, 2); Info.Freunde := StrToIntDef(ExtractSubStr(s, 3), -1); Info.ImageIndex := StrToIntDef(ExtractSubStr(s, 4), -1); end; var Info: TInfo; begin ListBox1.Style := lbOwnerDrawFixed; {Beispieldaten. Letzter Wert Index ist für Bilder in ImageList} {SetInfo nur für Übergabe der Beispieldateien. Daten können auch anders an Info übergeben werden} SetInfo('Anna, Köln, 1, 0', Info); ListBox1.Items.AddObject('', Info); SetInfo('Kristina, München, 1 , 1', Info); ListBox1.Items.AddObject('', Info); SetInfo('Sonja, Berlin,,', Info); ListBox1.Items.AddObject('', Info); SetInfo('Petra, Frankfurt, 5 , 3', Info); ListBox1.Items.AddObject('', Info); SetInfo('Berbel, Lübeck,, 4', Info); ListBox1.Items.AddObject('', Info); ListBox1.Font.Name := 'Segoe UI'; ListBox1.Font.Size := 10; ListBox1.ItemHeight := 2 + ImageList1.Height + 2; end; procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var th, tl: Integer; i: Integer; bmp: TBitmap; Info: TInfo; begin with (Control as TListBox) do begin //Einstellungen für selektierten Item (A) if odSelected in State then Canvas.Brush.Color := $00EFD3C6; //Helles Blau für selektierte Items //Löscht den Item-Canvas Canvas.FillRect(Rect); //Einstellungen für selektierten Item (B) if odSelected in State then begin Canvas.Pen.Color := $00C66931; //Dunkleres Blau für Fokus-Rand Canvas.Brush.Style := bsClear; Canvas.Rectangle(Rect); end; Info := TInfo(Items.Objects[Index]); //-Bild 48x48 px aus ImageList zeichnen---------------------------------- bmp := TBitmap.Create; try i := Info.ImageIndex; if (i > -1) and (i <= Form1.ImageList1.Count - 1) then begin Form1.ImageList1.GetBitmap(i, bmp); Canvas.Draw(Rect.Left + 2, Rect.Top + 2, bmp); end; finally bmp.Free; end; //-Text-Zeile 1 ausgeben------------------------------------------------- //Seitenabstand für Text (rechts vom Bild) tl := ItemHeight + 4; //Oberkante für Textzeilen. Jeder neue Zeile addiert ihre Höhe dazu th := 2; Canvas.Font.Style := [fsBold]; //Font-Eigenschaften für aktuelle Zeile Canvas.Font.Color := $00C66931; //Blau und fett Canvas.TextOut(Rect.Left + tl, Rect.Top + th, Info.Name); th := Canvas.TextHeight(#32); //Unterkante alter Text = Oberkante neuer Text //-Text-Zeile 2 ausgeben------------------------------------------------- Canvas.Font.Style := Canvas.Font.Style - [fsBold]; //- Canvas.Font.Color := clWindowText; //Normal Canvas.TextOut(Rect.Left + tl, Rect.Top + th, Info.Ort); th := th + Canvas.TextHeight(#32); //s. o. //-Text-Zeile 3 ausgeben------------------------------------------------- Canvas.Font.Size := Canvas.Font.Size - 2; //- Canvas.Font.Color := clGray; //Grau und etwas kleiner if Info.Freunde > -1 then Canvas.TextOut(Rect.Left + tl, Rect.Top + th, Format('%d Gemeinsame Freunde', [Info.Freunde])) else Canvas.TextOut(Rect.Left + tl, Rect.Top + th, 'Keine gemeinsame Freunde'); //------------------------------------------------------------------------- //Überzeichnet alten Fokus if odFocused in State then Canvas.DrawFocusRect(Rect); end; end; procedure TForm1.FormDestroy(Sender: TObject); var i: Integer; begin with ListBox1 do //Objekte müssen separat freigegeben werden for i := 0 to Items.Count - 1 do TInfo(Items.Objects[i]).Free; //Freigeben end; Was deine Jpeg Daten angeht, so weiß ich nicht ob das mit ImageList geht. Alternativ beim laden in Bmp konvertieren und in Größe 48x48 konvertieren. |
AW: Idee für Auswahlfunktion
So also mithilfe dieses Quellcodes ist es mir gelungen, meine Daten zu laden:
Delphi-Quellcode:
das einzige Problem ist, ich weiß nicht wie ich das Bild lade (es ist eine jpg datei) und wenn man jetzt öfter nacheinander sucht, dann werden auf einmal immer wieder neue Items für die Listbox created, man hat also nach dem zweiten suchen zwei mal die selbe Person angezeigt.
type
TInfo=class Name:String; Ort:String; ImageIndex:Integer; end; var Form1: TForm1; Info: TInfo; Path:String; implementation {$R *.dfm} {Gibt den X-ten Teilstring eines mit Kommas getrennten Daten-Strings} function ExtractSubStr(Str: String; Index: Integer): String; var i: Integer; begin Result := ''; if Index < 1 then Exit; Str := Str + ','; for i := 1 to Index - 1 do Delete(Str, 1, Pos(',', Str)); Result := Trim(Copy(Str, 1, Pos(',', Str) - 1)); end; procedure TForm1.FormCreate(Sender: TObject); begin Doublebuffered:=True; Path:= ExtractFilepath(ParamStr(0)); Info := TInfo.Create; ListBox1.Style := lbOwnerDrawFixed; end; procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var th, tl: Integer; i: Integer; bmp: TBitmap; Info:TInfo; begin with (Control as TListBox) do begin //Einstellungen für selektierten Item (A) if odSelected in State then Canvas.Brush.Color := $00EFD3C6; //Helles Blau für selektierte Items //Löscht den Item-Canvas Canvas.FillRect(Rect); //Einstellungen für selektierten Item (B) if odSelected in State then begin Canvas.Pen.Color := $00C66931; //Dunkleres Blau für Fokus-Rand Canvas.Brush.Style := bsClear; Canvas.Rectangle(Rect); end; Info:=TInfo(Items.Objects[Index]); //-Bild 48x48 px aus ImageList zeichnen---------------------------------- bmp := TBitmap.Create; try i := Info.ImageIndex; if (i > -1) and (i <= Form1.ImageList1.Count - 1) then begin Form1.ImageList1.GetBitmap(i, bmp); Canvas.Draw(Rect.Left + 2, Rect.Top + 2, bmp); end; finally bmp.Free; end; //-Text-Zeile 1 ausgeben------------------------------------------------- //Seitenabstand für Text (rechts vom Bild) tl := ItemHeight + 4; //Oberkante für Textzeilen. Jeder neue Zeile addiert ihre Höhe dazu th := 2; Canvas.Font.Style := [fsBold]; //Font-Eigenschaften für aktuelle Zeile Canvas.Font.Color := $00C66931; //Blau und fett Canvas.TextOut(Rect.Left + tl, Rect.Top + th, Info.Name); th := Canvas.TextHeight(#32); //Unterkante alter Text = Oberkante neuer Text //-Text-Zeile 2 ausgeben------------------------------------------------- Canvas.Font.Style := Canvas.Font.Style - [fsBold]; //- Canvas.Font.Color := clWindowText; //Normal Canvas.TextOut(Rect.Left + tl, Rect.Top + th, Info.Ort); th := th + Canvas.TextHeight(#32); //s. o. //-Text-Zeile 3 ausgeben------------------------------------------------- Canvas.Font.Size := Canvas.Font.Size - 2; //- Canvas.Font.Color := clGray; //Grau und etwas kleiner //------------------------------------------------------------------------- //Überzeichnet alten Fokus if odFocused in State then Canvas.DrawFocusRect(Rect); end; end; procedure TForm1.FormDestroy(Sender: TObject); var i: Integer; begin with ListBox1 do //Objekte müssen separat freigegeben werden for i := 0 to Items.Count - 1 do TInfo(Items.Objects[i]).Free; //Freigeben end; procedure TForm1.Timer1Timer(Sender: TObject); var hallo:TStrings; begin if FileExists(path+ Edit1.Text+'.txt') then begin hallo:=TStringlist.Create; hallo.LoadFromFile(path+'Info'+Edit1.Text+'.txt'); Info.Name := hallo.Strings[0]+' '+hallo.Strings[1]; Info.Ort := hallo.Strings[3]; ListBox1.Items.AddObject('', Info); ListBox1.Font.Name := 'Segoe UI'; ListBox1.Font.Size := 10; ListBox1.ItemHeight := 2 + ImageList1.Height + 2; Edit1.Text:=''; hallo.free; end; Mögliche Lösung:
Delphi-Quellcode:
Jetzt sieht es aber nicht nur verbugt aus, sondern es können nicht mal zwei leute in der liste angezeigt werden, da ja direkt der zweite wieder gelöscht wird
if Listbox1.Items.Count>1 then
ListBox1.Items.Delete(1) else if FileExists(path+ Edit1.Text+'.txt') then begin .... Hilfe bitte :?: |
AW: Idee für Auswahlfunktion
Du hast zum Teil den Code verstanden, ein Teil wohl nicht.
Zum Beispiel bringt es nichts die Zeile zu wiederholen. Sie gilt für alle Items gleich:
Delphi-Quellcode:
. Das Gleiche gilt für ListBox1.Font.Name und ListBox1.Font.Size. Es ist eine Einmalige Einstellung.
ListBox1.ItemHeight := 2 + ImageList1.Height + 2;
Die Funktion ExtractSubStr hebe ich nur gebraucht um Beispieldaten zu füllen. Wenn man es nicht braucht, dann weg damit. Kein Fehler, aber bring etwas Struktur in deinen Code. Unübersichtlichkeit ist der erste Schritt zu Fehlern.
Delphi-Quellcode:
Kein Fehler, aber schütze deine Objekte mit
begin
if FileExists(path+ Edit1.Text+'.txt') then begin hallo:=TStringlist.Create;
Delphi-Quellcode:
Zuerst programmieren lernen und dann lernen es richtig zu machen (das hat mal einer so gepostet als ich ihm try finally vorschlug) ist nicht der richtige Weg.
try finally end;
Ohne
Delphi-Quellcode:
erzeugt den Programm im Fehlerfall Speicherlecks. Und wie ich mir die Prozedur angucke, ist sie geradezu prädestiniert dazu Fehler zu produzieren. Da reicht nur eine Datei die deine StringList hallo nicht mit ausreichend Daten füllt und schon bricht die Prozedur zusammen. Mit einem Speicherleck. Hier zuerst schützen, dann entweder vorher abfragen ob hallo Count genug Items liefert, oder besser bei jedem Item explizit fragen. So kann man wenigstens auf die Zeilen zugreifen die die Textdatei liefert.
try finalle end;
Zu deinem Problem mit Jpg, da gibt es zwei Möglichkeiten: die erste ist alle Daten auf der Festplatte vorher in Bmp und 48x48 zu konvertieren oder als Jpg zu laden, zu Bmp konvertieren und dann die Größe anpassen. Die Funktion die du suchst heißt JpgToBmp oder Jpg2Bmp oder statt Jpg auch JpegToBmp usw. Am besten wäre es du postest eine Beispieldatei, dann weiß man was du laden willst. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:12 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz