![]() |
Problem: ComboBox über 2.Unit wird nicht korrekt dargestellt
Folgendes Problem:
Ich habe eine Hauptform (Form1) und möchte nun über eine ausgelagerte Unit eine modifizierte ComboBox TEnhComboBox bei Bedarf dynamisch auf die Form1 erstellen lassen. Zusätzlich wird dieser ComboBox ein DrawItem- Ereignis mitgeschickt, welches die Item-Inhalte "mehrspaltig" darstellt. Das erstellen und anzeigen der ComboBox- Inhalte funktioniert einwandfrei, hier aber nun mein Problem was mir zur Zeit den letzten Nerv raubt: Beim erstellen der dynamischen ComboBox und dem Vorfüllen der Item-Werte wird ein DropwDown-Ereignis ausgelöst, damit die ComboBox via dem OnDrawItem initialisiert wird. Danach soll zB. jeweils ein entsprechender Datensatz via ItemIndex als Standard ausgewählt werden. Hier tritt mein Problem auf: Sobald ein ItemIndex ausgewählt ist und dieser zur nächsten dynamische ComboBox geht, welche das ItemIndex-Ereignis auslöst, wird bei der vorherigen ComboBox der ItemIndex herausgenommen und der DropDown-Pfeil mit einem weißen Balken übelagert (wahrscheinlich wird der Textbereich über den DropDown-Pfeil als Overlay gezogen). Wird dann wieder auf eine "fehlerhaft" gezeichnete ComboBox geklickt, so wird diese wieder "richtig" gezeichnet, bis man wieder auf die nächste ComboBox klickt. Vielleicht hat einer eine Idee, die mir weiterhelfen könnte. UNIT1-FORM1:
Delphi-Quellcode:
UNIT2-DYNAMISCHES ERZEUGEN DER COMBOBOX AUF FORM1
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure ComboBoxDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); procedure Button1Click(Sender: TObject); procedure RunTimeEditClick(Sender:TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; Type TEnhComboBox = Class (TComboBox) Private fTagParam : Integer; fComboBoxDrawn : Boolean; Protected Published Property TagParam: Integer read fTagParam write fTagParam; Property ComboBoxDrawn: Boolean read fComboBoxDrawn write fComboBoxDrawn default false; End; const FeldTr : string[1] = '|'; RowTr : string[1] = ';'; CboWidth : integer = 400; var Form1: TForm1; RunTimeCombo : array[0..100] of array[0..20] of TEnhComboBox; Sender1:^TObject; //Übergabe des SenderObjects via Zeiger, anders geht es nicht !!! RunTimeEditX1,RunTimeEditX2 : integer; implementation uses unit2; {$R *.dfm} procedure TForm1.RunTimeEditClick(Sender:TObject); begin //der Sender wird via ZEIGER übergeben, da nur so der Sender in der Unit empfangen wird!!! Sender1:=@Sender; unit2.RunTimeEditClick; end; procedure TForm1.ComboBoxDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var x,pos1,AnzCol : integer; strVal, strAll: string; rc: TRect; arrWidth: array of Integer; begin with RunTimeCombo[RunTimeEditX2,RunTimeEditX1] do begin Canvas.Brush.Style := bsSolid; Canvas.FillRect(Rect); //Anzahl der Spalten suchen AnzCol := 1; for x:=0 to length(RunTimeCombo[RunTimeEditX2,RunTimeEditX1].Items[index]) do if copy(RunTimeCombo[RunTimeEditX2,RunTimeEditX1].Items[index],x,1)=FeldTr then inc(AnzCol); //Spaltenarray anlegen //wichtig: hier wird eine Zeile mehr angelegt, da diese benötigt wird //um die abschließende Breite zu setzen SetLength(arrWidth,AnzCol+1); //Spaltenarray aufteilen for x:=0 to AnzCol -1 do arrWidth[x] := 0+((CboWidth div AnzCol)*x); //Wichtig: abschließende Breite setzen arrWidth[AnzCol] := CboWidth; //aktuellen ArrayString des jeweiligen Index übergeben strAll := RunTimeCombo[RunTimeEditX2,RunTimeEditX1].Items[Index]; rc.Top := Rect.Top; rc.Bottom := Rect.Bottom; for x:=0 to AnzCol-1 do begin // Zeichenbereich für die einzelnen Spalten anlegen rc.Left := Rect.Left + arrWidth[x] + 2; rc.Right := Rect.Left + arrWidth[x+1] - 2; // Text für die jeweilige Spalte ausfiltern pos1 := Pos(FeldTr, strAll); if pos1 > 0 then strVal := Copy(strAll, 1, pos1 - 1) else strVal := strAll; strAll := Copy(strAll, pos1 + 1, Length(strAll) - pos1); // Text ausgeben Canvas.TextRect(rc, rc.Left, rc.Top, strVal); // Trennlinie zwischen Spalten zeichnen Canvas.MoveTo(rc.Right, rc.Top); Canvas.LineTo(rc.Right, rc.Bottom); end; end; end; procedure TForm1.Button1Click(Sender: TObject); begin unit2.ButtonsErstellen(Form1); end; end.
Delphi-Quellcode:
unit Unit2;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls; procedure ButtonsErstellen(Sender:TObject); procedure RunTimeEditClick; implementation uses unit1; procedure RunTimeEditClick; var Sender1:TObject; begin Sender1 := unit1.Sender1^; if sender1.ClassName = 'TEnhComboBox' then begin RunTimeEditX2 := (Sender1 as TEnhComboBox).TagParam; RunTimeEditX1 := (Sender1 as TEnhComboBox).Tag-1; end; end; procedure ButtonsErstellen(Sender:TObject); var xEdit,x,hoehe,edtLaenge : integer; begin x := 0; hoehe := 20; edtLaenge := 100; for xEdit := 0 to 2 do begin RunTimeCombo[xEdit,x] := TEnhComboBox.Create(Form1); with RunTimeCombo[xEdit,x] do begin Parent := Form1; Style := csOwnerDrawFixed; Top := (Hoehe+2) + (45*(x+1)); Tag := x+1; TagParam := xEdit; Width := edtLaenge; Left := 160 + ((edtLaenge+5)*(xEdit)); enabled:= true; visible := true; RunTimeCombo[xEdit,x].Items.Add('A|AAAA'+inttostr(xEdit)); RunTimeCombo[xEdit,x].Items.Add('B|BBBB'+inttostr(xEdit)); RunTimeCombo[xEdit,x].Items.Add('C|CCCC'+inttostr(xEdit)); OnDrawItem := Form1.ComboBoxDrawItem; OnDropDown := Form1.RunTimeEditClick; if unit1.RunTimeCombo[xEdit,x].Items.Count > 0 then begin unit1.RunTimeCombo[xEdit,x].Perform(CB_SETDROPPEDWIDTH,400,0); unit1.RunTimeCombo[xEdit,x].DroppedDown := true; unit1.RunTimeCombo[xEdit,x].DroppedDown := false; unit1.RunTimeCombo[xEdit,x].ItemIndex := 0; end; end; end; end; end. |
Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest
Du solltest das Design der Software nochmals überdenken.
Vor allem den Aufbau der Units. 1) Es ist nicht sinnvoll, von "aussen" (also von Unit2) ein Element auf Unit1 in Form1 zu erzeugen. 2) in Unit2 hast Du globale Prozeduren definiert. Diese gehören zu keinem Form. *Böse*. 3) Überleg Dir bessere Namen für die Units, Forms, Buttons, usw. Siehe Borland StyleGuide. |
Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest
Hallo RavenIV,
da ich leider nur einen nachgebauten Auszug aus dem Komplettprogramm hier als Diskussion eingebracht habe, habe ich nicht gerade auf die Korrektheit der globalen Variablen und Deklarationen geachtet *schäm*. Der Grund, warum ich eine ausgelagerte Unit2 benutze hat folgenden Grund: Ich habe mehrere Programme, die alle bei der Programmierung auf die Unit2 zugreifen sollen, damit ich diese gerade bei Fehlerkorrekturen nicht für jedes Programm einzeln anpassen muß. Hätte ich diese nicht, müßte ich alle Aufrufe in den einzelnen Programmen abbilden und das raubt einen schon mal Zeit und Nerven, zumal das hier wie gesagt nur ein nachgebauter Ausschnitt ist. Schleierhaft ist halt gesagt nur, warum gerade nach dem setzen des ItemIndex die ComboBox "fehlerhaft" gezeichnet wird. Ich habe daher auch schon versucht, direkt via einem Pointer auf den Sender zuzugreifen, was eigentlich auch gut funktioniert und mir von den einzelnen Komponenten auch korrekte Werte liefert, nur das ItemIndex- Problem bzw. das DrawEreignis scheint hierbei Probleme zu bereiten. |
Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest
Ich habe jetzt mal in den letzten Stunden noch ein wenig herumexperimentiert, dabei zwar nicht die Lösung des eigentlichen Problems für das ItemIndex-Phänomen gefunden, aber immerhin einen "Königsweg", der das Problem zumindestens löst (ACHTUNG: die folgenden Code-Beispiele sind nur aktualiserte oder NEU hinzugekommene Code-Schnipsel, die noch in das erste Script eingefügt/aktualisiert werden müßten):
1. In der Unit1 zusätzlich wurde ein Record erstellt, welches mir von allen dynamisch erzeugten Comboboxen die ItemIndex- Werte speichern soll, die angesprochen werden. Diese Werte werden dann via einem Timer, der sofort nach dem Create der Form1 gestartet und beendet wird via der Unit2 ausgeführt
Delphi-Quellcode:
2. In der UNIT2 wurden dann folgende Prozeduren eingefügt / aktualisiert
Type
TarrRunTimeComboDefault = record x1 : integer; x2 : integer; ItemIndex : integer; //DIESER WERT BEINHALTET DEN ANZUSPRECHENDEN ITEMINDEX !!! end; //.. var arrRunTimeComboDefault : array of TarrRunTimeComboDefault; //.. procedure TForm1.Timer1Timer(Sender: TObject); begin timer1.Enabled := false; unit2.ButtonsErstellen_ComboDefault; end;
Delphi-Quellcode:
Das ist wie gesagt noch nicht die Lösung des Problems bringt mich aber zu genau dem Ergebnis, was für mich gewünscht ist.procedure ButtonsErstellen(Sender:TObject); var xEdit,x,xArrCombo,hoehe,edtLaenge : integer; begin x := 0; hoehe := 20; edtLaenge := 100; //HILFSARRAY setzen und initialisieren (Standard 100 DS) xArrCombo :=-1; SetLength(unit1.arrRunTimeComboDefault,100); for xEdit := 0 to 2 do begin RunTimeCombo[xEdit,x] := TEnhComboBox.Create(Form1); with RunTimeCombo[xEdit,x] do begin Parent := Form1; Style := csOwnerDrawFixed; Top := (Hoehe+2) + (45*(x+1)); Tag := x+1; TagParam := xEdit; Width := edtLaenge; Left := 160 + ((edtLaenge+5)*(xEdit)); enabled:= true; visible := true; RunTimeCombo[xEdit,x].Items.Add('A|AAAA'+inttostr(xEdit)); RunTimeCombo[xEdit,x].Items.Add('B|BBBB'+inttostr(xEdit)); RunTimeCombo[xEdit,x].Items.Add('C|CCCC'+inttostr(xEdit)); OnDrawItem := Form1.ComboBoxDrawItem; OnDropDown := Form1.RunTimeEditClick; if unit1.RunTimeCombo[xEdit,x].Items.Count > 0 then begin unit1.RunTimeCombo[xEdit,x].Perform(CB_SETDROPPEDWIDTH,400,0); unit1.RunTimeCombo[xEdit,x].DroppedDown := true; unit1.RunTimeCombo[xEdit,x].DroppedDown := false; //HIER WERDEN DIE ERSTELLTEN COMBOBOXEN IN DAS HILFSARRAY DER UNIT1 GESCHRIEBEN inc(xArrCombo); unit1.arrRunTimeComboDefault[xArrCombo].x2 := xEdit; unit1.arrRunTimeComboDefault[xArrCombo].x1 := x; unit1.arrRunTimeComboDefault[xArrCombo].ItemIndex := 0; //oder andere Werte end; end; end; //wenn alles erstellt dann schneide arrCombo auf eigentliche Länge ab SetLength(unit1.arrRunTimeComboDefault,xArrCombo+1); end; procedure ButtonsErstellen_ComboDefault; var x : integer; begin for x:= 0 to high(unit1.arrRunTimeComboDefault) do begin RunTimeEditX2 := arrRunTimeComboDefault[x].x2; RunTimeEditX1 := arrRunTimeComboDefault[x].x1; RuntimeCombo[unit1.RunTimeEditX2 ,unit1.RunTimeEditX1].ItemIndex := arrRunTimeComboDefault[x].ItemIndex; end; end; |
Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest
Was ich noch anmerken wollte: Wozu definierst du dir einen Zeiger auf ein TObject um den Sender darin zu merken? Diese Variable Sender bzw. Sender1 sind intern schon Zeiger, da brauchst du nichts mehr hexen von wegen Adresse von und sowas. Also einfach das ^ und @ rausschmeissen und gut ist. Jetzt hast du sogar schon ein Problem, da du die Adresse des Übergabewertes, also von Sender ermittelst, nicht aber die von der Instanz selber, was du eigentlich wolltest. Somit ist die ganze Funktionalität nicht gegeben.
|
Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest
Zitat:
Ich habe auch ein Basisverzeichnis, auf welches sämtliche Projekte Zugriff haben und in dem ich einzelne Units mit Hilfsfunktionen habe, die ich immer wieder benötige. Es ist schließlich Delphi, und kein C#, wo alles in irgendwelchen Klassen gekapselt ist. |
Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:37 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