Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Listenindex überschreibt Maximum


WEBSTER - Do 03.04.08 19:05

Salute,

ich habe folgendes Problem.

Ich fülle mir so 4 Comboboxen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
////////////////////////////////////////////////////////////////////////////////
// Pointer mit interner Vermittlernummer wird in der Combobox hinterlegt

type
  PString = ^string;

procedure Tgeschaefte_bestaetigen_Form.add_vermittler_to_comboboxen(vname, vnr: string);
var
  ptrString1: PString;
  ptrString2: PString;
  ptrString3: PString;
  ptrString4: PString;
begin
  New(ptrString1);
  New(ptrString2);
  New(ptrString3);
  New(ptrString4);

  ptrString1^ := vnr;
  ptrString2^ := vnr;
  ptrString3^ := vnr;
  ptrString4^ := vnr;

  vermittler_nr_1_cxComboBox.Properties.items.AddObject(vname, TObject(ptrString1));
  vermittler_nr_2_cxComboBox.Properties.items.AddObject(vname, TObject(ptrString2));
  vermittler_nr_3_cxComboBox.Properties.items.AddObject(vname, TObject(ptrString3));
  vermittler_nr_4_cxComboBox.Properties.items.AddObject(vname, TObject(ptrString4));
end;


////////////////////////////////////////////////////////////////////////////////
// Vermittler werden in Combobox geladen

procedure Tgeschaefte_bestaetigen_Form.fill_vermittler_comboxbox;
begin
   /////////////////////////////////////////////////////////////////////////////
  // Alle Vermittler werden selektiert

  Str_SQL := 'select * from vermittler order by nname';

  //////////////////////////////////////////////////////////////////////////////
  // SQL wird aus geführt

  auftraege_verwalten_DataSource.DataSet := auftraege_verwalten_ADOQuery;

  auftraege_verwalten_ADOQuery.Close;
  auftraege_verwalten_ADOQuery.SQL.clear;
  auftraege_verwalten_ADOQuery.SQL.Add(str_sql);
  try
    auftraege_verwalten_ADOQuery.open;
  except
    ////////////////////////////////////////////////////////////////////////////
    // LogFile wird gefüllt

    global_data_tools.Fill_Log(TRUE, Str_SQL);

    //////////////////////////////////////////////////////////////////////////////
    // Cursor wird auf Default gesetzt

    Screen.Cursor := crDefault;

    ShowMessage('Fehler ! SQL Konnte nicht ausgeführt werden.' + chr(10) + chr(13) + Str_SQL);
  end;

  //////////////////////////////////////////////////////////////////////////////
  // Vermittler ComboxBoxen werden geleert

  vermittler_nr_1_cxComboBox.Properties.Items.Clear;
  vermittler_nr_2_cxComboBox.Properties.Items.Clear;
  vermittler_nr_3_cxComboBox.Properties.Items.Clear;
  vermittler_nr_4_cxComboBox.Properties.Items.Clear;

  //////////////////////////////////////////////////////////////////////////////
  // Vermittler ComboxBox wird gefüllt

  while not auftraege_verwalten_ADOQuery.Eof do
  begin

    ////////////////////////////////////////////////////////////////////////////////
    // Pointer mit interner Vermittlernummer wird in der Combobox hinterlegt

    add_vermittler_to_comboboxen(auftraege_verwalten_ADOQuery.FieldByName('vanrede').asString + ' ' + auftraege_verwalten_ADOQuery.FieldByName('vname').asString + ' ' + auftraege_verwalten_ADOQuery.FieldByName('nname').asString, auftraege_verwalten_ADOQuery.FieldByName('vnr').asString);

    auftraege_verwalten_ADOQuery.Next;
  end;
end;


Das funktioniert auch ganz gut.

Nun möchte ich, das der Itemindex auf das Item gesetzt wird, das den versteckten Wert beinhaltet:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
for I := 1 to auftraege_verwalten_ADOQuery.recordcount do
  begin
    vermittler_nr_cxComboBox := findcomponent('vermittler_nr_' + IntToStr(I) + '_cxComboBox');
    TcxComboBox(vermittler_nr_cxComboBox).properties.items.Objects[TcxComboBox(vermittler_nr_cxComboBox).ItemIndex] := Pointer(auftraege_verwalten_ADOQuery.FieldByName('vnr').asString);


    provision_cxTextEdit := findcomponent('provision_' + IntToStr(I) + '_cxTextEdit');
    TcxTextEdit(provision_cxTextEdit).Text := auftraege_verwalten_ADOQuery.FieldByName('anteil_prov_vnr').asString;

    auftraege_verwalten_ADOQuery.Next;
  end;

Hierbei erhalte ich immer die Meldung -> Der Index der Liste überschreitet das Maximum (-1)

Wenn ich mir hiermit den Wert der ersten Combobox auslese:

Delphi-Quelltext
1:
ShowMessage(IntToStr(LongInt(vermittler_nr_1_cxComboBox.properties.Items.Objects[vermittler_nr_1_cxComboBox.ItemIndex])));                    

dann erhalte ich den Wert 1250284.

so erhalte ich aber den richtigen Wert..

Delphi-Quelltext
1:
ShowMessage(pString(TcxComboBox(vermittler_nr_1_cxComboBox).properties.Items.Objects[TcxComboBox(vermittler_nr_1_cxComboBox).ItemIndex])^);                    


Wer kann mir helfen...

THX
WEBSTER

Moderiert von user profile iconjasocul: Code- durch Delphi-Tags ersetzt


oldmax - Fr 04.04.08 09:42

Hi
Es ist nicht grad leicht, deine Satzstruktur zu durchschauen, zumal die Zusammenhänge mir nicht ganz klar sind. Allerdings ist mir aufgefallen, das du das Ergebnis aus FindComponent nicht absicherst. Es kann durchaus sein, das du eine Niete ziehst und dann vermutlich mit dem Wert - 1 auf ein Combobox.Item zugreifst.
Vielleicht richtig, dennoch mal zu erwähnen ist, das die Datensätze bei 0 anfangen, deine Schleife aber 1 bis auftraege_verwalten_ADOQuery.recordcount läuft. Nicht unbedingt falsch, aber in Anbetracht der Tatsache, das der 1. Eintrag den Index 0 hat, habe ich mir angewöhnt, auch Schleifen entsprechend
von 0 nach auftraege_verwalten_ADOQuery.recordcount -1 laufen zu lassen.
Beim Durchlauf der Query kein Problem, allerdings darf sonst die Schleifenvariable nicht als Index für einen Eintrag in einer Listbox, Combobox, Grid oder Stringlist verwendet werden.
Vielleicht hilft es dir, den Fehler zu finden. Da ich hier kein Delphi installiert habe, kann ich auch nix nachvollziehen

Gruß oldmax


WEBSTER - Fr 04.04.08 09:58

Salute,

in der For Schleife des RecordCount werden nicht die Items behandelt, sondern meine 4 Comboboxen. Die Namen lauten vermittler_nr_1_cxComboBox .... vermittler_nr_4_cxComboBox, aus diesem Grund mache ich auch kein -1.

Vielleicht findet sich noch eine Lösung....



WEBSTER


WEBSTER - Fr 04.04.08 10:10

Salute,

das Porblem liegt hier:


Quelltext
1:
   TcxComboBox(vermittler_nr_cxComboBox).properties.items.Objects[TcxComboBox(vermittler_nr_cxComboBox).ItemIndex] := Pointer(auftraege_verwalten_ADOQuery.FieldByName('vnr').asString);                    


Nochmal zur Erläuterung:

Ich habe eine ComboBox mit folgendem Inhalt:

Herr Peter Muster | Unsichtbarerpointer Wert 23
Herr Peter Meier | Unsichtbarerpointer Wert 243
Frau Petra Meier | Unsichtbarerpointer Wert 241

Der unsichtbarer Pointer ist eine ID aus einer Tabelle.

Nun möchte ich den Itemindex auf 1 setzen, da ich eine Info habe, das Person mit der ID 243 aktiv ist. Wie bekomme ich das gelöst....?

früher habe ich es so gemacht:

ComboBox mit Inhalt:

Herr Peter Muster [23]
Herr Peter Meier [243]
Frau Petra Meier [241]

Habe mir mit POS die Stelle von [ und von ] ermittelt und dann mit copy die Zahl herausgeholt. Nun möchte ich das ganz halt per unsichtbaren Zeiger lösen...

Hoffe es haben alle verstanden.....


THX
WEBSTER


zuma - Fr 04.04.08 10:46

user profile iconWEBSTER hat folgendes geschrieben:


Quelltext
1:
   TcxComboBox(vermittler_nr_cxComboBox).properties.items.Objects[TcxComboBox(vermittler_nr_cxComboBox).ItemIndex] := Pointer(auftraege_verwalten_ADOQuery.FieldByName('vnr').asString);                    


THX
WEBSTER


Kann es sein, das du ein Object in die CoBo gesteckt hast, aber kein Object ansprichst ?
Also ein Cast ala

Quelltext
1:
TcxComboBox(vermittler_nr_cxComboBox).properties.items.Objects[TObject(TcxComboBox(vermittler_nr_cxComboBox).ItemIndex)] := Pointer(auftraege_verwalten_ADOQuery.FieldByName('vnr').asString);                    

evtl. dein Problem löst ?

Nur mal als denkhilfe, evtl. lieg ich auch voll daneben, aber ähnliche Fehler hab ich anfangs auch immer gern gemacht ;)


WEBSTER - Fr 04.04.08 10:57

Salute,

ich kann den Inhalt des Objektes aber mit

Quelltext
1:
ShowMessage(pString(TcxComboBox(vermittler_nr_1_cxComboBox).properties.Items.Objects[TcxComboBox(vermittler_nr_1_cxComboBox).ItemIndex])^);                    


auslesen, im showMessage steht dann die entsprechende ID drin.


WEBSTER


WEBSTER - Fr 04.04.08 11:10

Salute,

habe gerade mal deine Version ausprobiert:


Quelltext
1:
TcxComboBox(vermittler_nr_cxComboBox).properties.items.Objects[TObject(TcxComboBox(vermittler_nr_cxComboBox).ItemIndex)] := Pointer(auftraege_verwalten_ADOQuery.FieldByName('vnr').asString);                    


[Fehler] Inkompatible Typen: Integer und TObject.


WEBSTER


busybyte - Fr 04.04.08 11:15

Vermutung,wenn Du einen Pointer einträgst dann liest Deine Variante 1 auch nur den Pointer aber nicht den referenzierten Wert aus.
Deswegen ist Deine Variante 2 schon eher die Richtige und funktioniert ja auch.
Dein items.Objects[] ist ein Pointer auf ein Ado-Feld asString also string und nicht integer.


zuma - Fr 04.04.08 11:37

evtl. is auch mein Cast-bsp falsch, weiss ja nicht, was du als objekt darein gesteckt hast.
steckste ein integer rein, muste es natürlich auch als integer rausholen, usw.

mal grobes bsp:
rein

Delphi-Quelltext
1:
cobo_xy.add('String', TObject(123)); // << 123 zum Object gemacht                    


raus

Delphi-Quelltext
1:
Integer(cobo_xy....items.objects[0]); // << Object mit inhalt 123 als integer interpretieren                    


Moderiert von user profile iconChristian S.: Delphi-Tags hinzugefügt


WEBSTER - Fr 04.04.08 11:54

Salute,

die ComboxBoxen werden mit String gefüllt:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
procedure Tauftraege_erfassen_Form.add_vermittler_to_comboboxen(vname, vnr: string);
var
  ptrString1: PString;
  ptrString2: PString;
  ptrString3: PString;
  ptrString4: PString;
begin
  New(ptrString1);
  New(ptrString2);
  New(ptrString3);
  New(ptrString4);

  ptrString1^ := vnr;
  ptrString2^ := vnr;
  ptrString3^ := vnr;
  ptrString4^ := vnr;

  vermittler_nr_1_cxComboBox.Properties.items.AddObject(vname, TObject(ptrString1));
  vermittler_nr_2_cxComboBox.Properties.items.AddObject(vname, TObject(ptrString2));
  vermittler_nr_3_cxComboBox.Properties.items.AddObject(vname, TObject(ptrString3));
  vermittler_nr_4_cxComboBox.Properties.items.AddObject(vname, TObject(ptrString4));
end;


add_vermittler_to_comboboxen('Herr Peter Müller','121');



WEBSTER


busybyte - Fr 04.04.08 12:36

Dann kann es so nicht funktionieren

Delphi-Quelltext
1:
ShowMessage(IntToStr(LongInt(vermittler_nr_1_cxComboBox.properties.Items.Objects[vermittler_nr_1_cxComboBox.ItemIndex])));                    

keine Referenzierung und dazu noch integer bzw. Longint

Moderiert von user profile iconChristian S.: Delphi-Tags hinzugefügt


WEBSTER - Fr 04.04.08 12:50

Salute,

und wie mache ich es richtig...?

WEBSTER


busybyte - Fr 04.04.08 13:46

Die Lösung hast Du schon selbst geschrieben.
Beispiel;

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
type
  PString = ^string;
Var
PtrString:Array of PString;

procedure TForm1.Button1Click(Sender: TObject);
Var Vname:String;
cnt1:integer;
begin

Setlength(PTrString,2);
for cnt1:=0  to Length(PtrString) - 1 do

 begin
 New(PtrString[cnt1]);
   case cnt1 of 0:begin
                  Vname:='Herr Maier';
                  PtrString[cnt1]^:='Salute';
                  end;
                1:begin
                  Vname:='Herr Müller';
                  PtrString[1]^:='123';
                  end;
    end;
  combobox1.Items.AddObject(vname,TObject(PtrString[cnt1]));
 end;

end;

procedure TForm1.Button2Click(Sender: TObject);
Var
tmp:String;
index_:integer;
begin
Index_:=combobox1.Items.IndexOf('Herr Maier');
tmp:=pString(ComboBox1.Items.Objects[index_])^;
showmessage(tmp);

Index_:=combobox1.Items.IndexOf('Herr Müller');
tmp:=pString(ComboBox1.Items.Objects[index_])^;
showmessage(tmp);
end;


Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt


WEBSTER - Fr 04.04.08 13:55

Salute,

vielen Dank für deine Mühe.... echt super...

Werde es gleich mal versuchen umzusetzen....

WEBSTER


busybyte - Fr 04.04.08 14:02

Gerne,es müssen aber noch Sicherheitsabfragen eingebaut werden wenn z.B. ein Eintrag nicht gefunden wird und der Index grösser items.count-1 oder kleiner 0 ist usw. und zum Schluss sollten noch alle Pointer freigegeben werden.
Im Beispiel verwende ich die standard TCombobox.


WEBSTER - Fr 04.04.08 14:11

Salute,

wann und warum müssen die Pointer wieder freigegeben werden?
Die werden doch eh beim schließen der Form gelöscht... , oder ?

Meinst du die Freigabe mit Dispose ?

WEBSTER


busybyte - Fr 04.04.08 14:28

Das gehört zum sauberen Programmierstil,
es wäre unschön Speicherlecks und Pointer, die ins Nirvana zeigen, zu hinterlassen.
Die IDE säubert das zwar (soviel ich weiss), aber ausserhalb Delphi ist das nicht schön.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
Var cnt1:integer;
begin
for cnt1 := 0 to Length(PtrString)- 1 do
begin
dispose(PtrString[cnt1]);
PtrString[cnt1]:=nil;
end;
end;

Säubern normalerweise bei Programmende.

Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt