AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi Problem: ComboBox über 2.Unit wird nicht korrekt dargestellt
Thema durchsuchen
Ansicht
Themen-Optionen

Problem: ComboBox über 2.Unit wird nicht korrekt dargestellt

Offene Frage von "ruedigeruwe"
Ein Thema von ruedigeruwe · begonnen am 7. Apr 2008 · letzter Beitrag vom 8. Apr 2008
Antwort Antwort
ruedigeruwe

Registriert seit: 19. Okt 2006
7 Beiträge
 
Delphi 6 Enterprise
 
#1

Problem: ComboBox über 2.Unit wird nicht korrekt dargestellt

  Alt 7. Apr 2008, 12:18
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:
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.
UNIT2-DYNAMISCHES ERZEUGEN DER COMBOBOX AUF FORM1
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 = 'TEnhComboBoxthen
  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.
Uwe R.
  Mit Zitat antworten Zitat
Benutzerbild von RavenIV
RavenIV

Registriert seit: 12. Jan 2005
Ort: Waldshut-Tiengen
2.875 Beiträge
 
Delphi 2007 Enterprise
 
#2

Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest

  Alt 7. Apr 2008, 12:38
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.
Klaus E.
Linux - das längste Text-Adventure aller Zeiten...
Wer nie Linux mit dem vi konfiguriert hat, der hat am Leben vorbei geklickt.
  Mit Zitat antworten Zitat
ruedigeruwe

Registriert seit: 19. Okt 2006
7 Beiträge
 
Delphi 6 Enterprise
 
#3

Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest

  Alt 7. Apr 2008, 13:14
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.
Uwe R.
  Mit Zitat antworten Zitat
ruedigeruwe

Registriert seit: 19. Okt 2006
7 Beiträge
 
Delphi 6 Enterprise
 
#4

Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest

  Alt 7. Apr 2008, 14:50
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:
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;
2. In der UNIT2 wurden dann folgende Prozeduren eingefügt / aktualisiert
Delphi-Quellcode:


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;
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.
Uwe R.
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#5

Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest

  Alt 7. Apr 2008, 18:49
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.
  Mit Zitat antworten Zitat
s-off
(Gast)

n/a Beiträge
 
#6

Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest

  Alt 7. Apr 2008, 19:00
Zitat von RavenIV:
2) in Unit2 hast Du globale Prozeduren definiert. Diese gehören zu keinem Form. *Böse*.
Was ist daran böse?
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.
  Mit Zitat antworten Zitat
ruedigeruwe

Registriert seit: 19. Okt 2006
7 Beiträge
 
Delphi 6 Enterprise
 
#7

Re: Problem: ComboBox über 2.Unit wird nicht korrekt dargest

  Alt 8. Apr 2008, 07:27
Zitat von Muetze1:
... 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.
Ja da hast du recht, das kann wieder raus. Die Übergabe des Sender via Zeiger hatte bei mir eine andere Bewandnis, da ich teils große Probleme mit meiner Delphi-Version hatte, auf ein Sender-Object einer anderern Unit zuzugreifen (hier wurden nicht alle Eigenschaften via dem Sender-Object übergeben zB. die "Property TagParam") und der Zeiger war die einzige Möglichkeit, das alle Eigenschaften korrekt rüberkamen, ansonsten wurden mir immer Exceptions ausgelöst
Uwe R.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:35 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz