Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Label, Editfeld und DBlookupListbox (https://www.delphipraxis.net/2435-label-editfeld-und-dblookuplistbox.html)

Hansa 23. Jan 2003 11:54


Label, Editfeld und DBlookupListbox
 
Hi,

folgendes Problem (es geht um 2 Tables : Artikel und Warengruppen) : Ich habe hier ein Label, ein Editfeld, sowie eine Listbox. Folgendes soll gemacht werden : Nach Eingabe der Art.Nr. soll das Label mit der Warengruppe des Artikels beschriftet werden und die Nr. soll als Vorgabewert im Editfeld stehen. Sobald dieses betreten wird, soll die Box aufgehen.

Code:
  ArtDS.Active := false;
  ArtDs.SelectSQL.Text := 'SELECT * FROM ART8 WHERE NR = ' +   ArtNrEdit.Text;
  ArtDS.Active := true;
  WGDS.active := false;
  WGDS.SelectSQL.Text := 'SELECT * FROM WG8 WHERE ID = :ID_WG';
  WGDS.active := true;
  Label3.Caption := WGDS.FieldByName ('BEZ').value;
  Edit1.Text := WGDS.FieldByName ('NR').value;
Das da geht nicht : "Invalid Variant conversion". Das liegt an dem ID = :ID. Wie macht man das denn jetzt richtig? Aus Der Warengruppen-Table soll die Bez. der WG gesucht werden, deren ID gleich der ID_WG des Artikels ist.

Um überhaupt etwas zu sehen, habe ich das :ID_WG durch einen statischen Wert ersetzt. Dann läuft alles richtig. Dann noch etwas mit der Box. Wie gesagt, soll diese nur sichtbar sein, falls sich der Cursor in dem EditFeld befindet. Setze ich sie aber in dem Edit1Exit enabled und visible auf false, dann kann ich mit der Maus ja keinen Eintrag mehr auswählen, da ich zu diesem Zweck ja das Feld verlassen muß. :evil: Ich brauche also ein Unterscheidungsmerkmal, ob ich mich in dem Feld der WG-Nr. befinde, in der Listbox oder woanders (nur in diesem Fall dürfte dann visible und enabled auf false gesetzt werden). Wer weiß was dazu ?

Gruß
Hansa

harrybo 23. Jan 2003 12:33

Hi Hansa,
ich kann leider nicht ganz nachvollziehen, was genau passieren soll. Möglicherweise kommt es in Deinem Datenbestand vor, dass das ID Feld des aktuellen Datensatzes nicht besetzt, also NULL ist. Möglicherweise stimmt das Format auch nicht überein (string, longint). Außerdem, versuchs mal mit
Delphi-Quellcode:
Label3.Caption := WGDS.FieldByName('BEZ').AString;
  Edit1.Text := WGDS.FieldByName('NR').AsInteger;
Zu Deiner zweiten Sache: das scheint mir usibilitytechnisch ein Knieschuss zu sein. Klar bist Du nicht im Editierfeld, wenn Du die Liste anklickst. Wahrscheinlich hab ich auch noch nicht begriffen, was dahinter steckt, kannst Du das kurz genauer erläutern? Irgendein Trick wird uns dann schon einfallen (LastFocusedObject oder so).

gruß, harrybo

Hansa 23. Jan 2003 13:16

Hi harrybo,

zu 1 : Was hab ich denn da für einen Mist stehen ? :oops: Das ist mir ehrlich gesagt gar nicht aufgefallen, irgendwie hatte ich aber ein ungutes Gefühl :mrgreen: Das mit den Parametern bei SQL verstehe ich anscheinend nie. Weiß nie wo und wie die herkommen. Probier ich noch aus.

zu 2 : Die Box soll verschwinden, sobald klar ist, daß das Editfeld im Moment nicht gebraucht wird. sobald es betreten wird, soll die Box aufklappen, wobei natürlich die Möglichkeit der Auswahl gegeben sein muß. Ich müßte nur rausfinden ob der Focus in einem Feld <> WGedit UND <> Listbox ist. Nur wie? Oder geht es anders? Daaaaaa fällt mir gerade etwas ein :spin: ,es gibt doch bei jedem Feld ein Tag !!!! Keine Sau benutzt das, ich auch nicht. Aber für so einen Sonderfall ist das doch geradezu prädestiniert, oder nicht? Obwohl ich glaube, daß es auch anders / einfacher geht.

Gruß
Hansa

Sharky 23. Jan 2003 13:42

Zitat:

Zitat von Hansa
zu 2 : Die Box soll verschwinden, sobald klar ist, daß das Editfeld im Moment nicht gebraucht wird. sobald es betreten wird, soll die Box aufklappen, wobei natürlich die Möglichkeit der Auswahl gegeben sein muß. Ich müßte nur rausfinden ob der Focus in einem Feld <> WGedit UND <> Listbox ist. Nur wie? .....

Hai Hansa,

das ist relativ einfach zu lösen.

Ich habe es eben mal mit mehreren Edits und einer ComboBox auf dem Formluar getestet.

Im OnEnter vom Edit1 schreibst Du:

Delphi-Quellcode:
procedure TForm1.Edit1Enter(Sender: TObject);
begin
   ComboBox1.Visible := True;
end;
:lol: Das ist ja auch klar.

Jetzt kommt der grosse Zauber.

Im OnExit des Edits schreibst Du:

Delphi-Quellcode:
procedure TForm1.Edit1Exit(Sender: TObject);
begin
 If Not (ActiveControl = ComboBox1) then
  begin
   ComboBox1.Visible := False;
  end;
end;
ActiveControl wird nämlich gesetzt BEVOR das OnExit ausgelöst wird :P
Und so weisst Du zu welchem Control der Anweder gewechselt hat.

So, jetzt noch in das OnExit der ComboBox:

Delphi-Quellcode:
procedure TForm1.ComboBox1Exit(Sender: TObject);
begin
 If Not (ActiveControl = Edit1) then
  begin
   ComboBox1.Visible := False;
  end;
end;
Und fertig ist der Lack...

Hansa 23. Jan 2003 17:33

Hi,

Danke euch beiden, das geht jetzt alles einwandfrei :!:

@Harrybo :
Code:
 
  Label3.Caption := WGDS.FieldByName('BEZ').AsString;
  Edit1.Text := IntToStr (WGDS.FieldByName('NR').AsInteger);
//  Label3.Caption := WGDS.FieldByName ('BEZ').value;
//  Edit1.Text := WGDS.FieldByName ('NR').value;
Hab Dein Beispiel abgekupfert. IntToStr hat halt noch gefehlt und "AsString" schreibt man nicht "Astring" :mrgreen: *ichnichtschimpf* 2 Min., dann ging das. Auf die Idee mit dem value kam ich folgendermaßen : Fehler in der Code-Vervollständ. :!: FieldByName tauchte da nicht auf :!: Auswendig wußte ich die genaue Syntax nicht.

@Sharky : Das war genauso richtig. In 30 Min. war auch das fertig. Das war nur aufwendiger, weil ich die SQL-Statements etwas umbauen mußte. Vom Prinzip her war es kein Problem. Das geht ja runter wie Öl. Eine Frage, eine Antwort, nochmals gefragt : zweite Antwort. Und dann gehts. :dancer:

Aber ich weiß immer noch nicht, woher der weiß, daß das :ID ein Parameter ist, bzw. wo der Wert herkommt. Und was ich auch nicht genau weiß, wie kriege ich die ID der ausgewählten Warengruppe in den Artikel? Ich lese immer nur, das ginge automatisch, bei mir aber nicht einfach so.

Gruß
Hansa

harrybo 23. Jan 2003 17:52

Hi Hansa,
alles klar. Sorry mit AsString, war ein Tippfehler von mir. Ja, stimmt, FieldByName taucht in der Code-Vervollständigung nicht auf. Einfach schreiben, Klammer auf, Feldname, Klammer zu, Punkt, und es geht weiter mit der Code-Vervollständigung. Ok, IntToStr fehlte tatsächlich auch noch, war ja Gott sei Dank für Dich ein Klacks...

gruß, harrybo

Hansa 23. Jan 2003 18:07

Hi,

Zitat:

Zitat von harrybo
Ja, stimmt, FieldByName taucht in der Code-Vervollständigung nicht auf.

:spin2: :wall: Ich glaub ich werd noch bekloppt. Weil ich das nicht auf Anhieb gefunden habe, hab ich sogar die Vervollst. auf alphabetisch umgestellt, nix zu sehen. Jetzt habe ich noch einmal nachgeschaut und es wird aufgeführt :!: Was ist das denn ?

Gruß
Hansa

Hansa 24. Jan 2003 11:00

Hi,

so ganz fertig ist das ganze noch nicht, zumindest funktioniert es jetzt richtig. Aber gestern hatte ich nicht gemerkt daß hier :
Code:
ArtDs.SelectSQL.Text := 'SELECT * FROM ART8 WHERE NR = ' + ArtNrEdit.Text;
  ArtDS.Active := true;
  WGDS.active := false;
  WGDS.SelectSQL.Text := 'SELECT * FROM WG8 WHERE ID = :ID';
das :ID noch durch eine feste Zahl ersetzt war. 8) Natürlich lief es dann, weil das die passenden Zahlen waren.

Jetzt habe ich das zweite Select hierdurch ersetzt :
Code:
WGDS.SelectSQL.Text := 'SELECT * FROM WG8 WHERE ID = ' + IntToStr (ArtDS.FieldByName ('ID_WG').AsInteger);
Muß das tatsächlich so umständlich gemacht werden? Deshalb nochmals die Frage: Wie kriege ich die ID_WG aus dem ersten Select als Parameter an die zweite Übergeben ?

Gruß
Hansa

X-Dragon 24. Jan 2003 11:21

Kann man nicht die ID direkt als String auslesen? Also mit .AsString, dann müsste man sich das umwandeln doch sparen können. Aber eventuell dann noch das "=" durch LIKE ersetzen, falls dann eine Fehlermeldugn kommt "Type Mismatch ..." :).

harrybo 24. Jan 2003 11:26

Hi Hansa,
Du hast recht, es geht professioneller und auch schneller in der Ausführung wenn Du mit Parametern arbeitest. Vorteil: der SQL Text muss nicht geändert werden. Einen Parameter kannst Du im Design Modus über den Objekt Inspector anlegen (Params, hast Du wahrscheinlich schon) oder per Code für Deinen Fall mit
Delphi-Quellcode:
WGDS.Params.CreateParam(ftInteger, 'ID');
Deinen SQL Text kannst Du nun stehen lassen als
Delphi-Quellcode:
WGDS.SelectSQL.Text := 'SELECT * FROM WG8 WHERE ID = :ID';
Jetzt aktualisierst Du mit
Delphi-Quellcode:
with WGDS do try
  DisableControls;
  if Active then Close;
  ParamByName('ID').Value := ArtDS.FieldByName ('ID_WG').AsInteger;
  // Alternativ, wenn die Abfrage genau einen Parameter hat:
  // Params[0].Value := ArtDS.FieldByName ('ID_WG').AsInteger;
  Open;
finally
  EnableControls;
end;
Bingo! Umformen per IntToStr ist auch nicht nötig, da es sich ja um einen echten Integer Parameter handelt.
gruß, harrybo

Hansa 24. Jan 2003 11:39

Hi,

Zitat:

Zitat von X-Dragon
Kann man nicht die ID direkt als String auslesen?

Nein, kann man nicht ! Die ID ist in der DB als integer hinterlegt.

Etwas einfacher geht es aber schon (so wie ich es am Anfangang gemacht habe :
Zitat:

]Mit FieldValues können Sie auf die Werte der Felder in einer Datenmenge zugreifen. Geben Sie einfach das gewünschte Feld mit dem Parameter FieldName an.
Bei mir also so:

WGDS.FieldValues ['ID'];

Dann entfällt die Typumwandlung, bzw. wird sie intern gemacht !!

Zitat:

Zitat von X-Dragon
Aber eventuell dann noch das "=" durch LIKE ersetzen, falls dann eine Fehlermeldugn kommt "Type Mismatch ..." :).

Nee, nee. Fange nicht auch noch solchen Unfug an. :mrgreen: :spin: = wird benutzt bei genauen Vergleichen und LIKE mit % usw. bei ungenauen Vergleichen, Suchen usw. LIKE ohne % ist bei mir gleich =. :witch:

Gruß
Hansa

Hansa 24. Jan 2003 11:42

@harrybo : das da drucke ich mir aus, hol es mit und lese es zum Nachtisch. :lol: Auf den ersten Blick ist das das Gesuchte!

Gruß
Hansa

Sharky 24. Jan 2003 11:50

Zitat:

Zitat von Hansa
Hi,

Zitat:

Zitat von X-Dragon
Kann man nicht die ID direkt als String auslesen?

Nein, kann man nicht ! Die ID ist in der DB als integer hinterlegt.

Warum soll das nicht gehen?

Durch das .AsString Sagst Du deinem DataSet nämlich wie Du es haben möchtest.

Ich kann z.B. folgendes machen.
In der Tabelle ist das Feld NUMMER als Integer deklariert.

Code:
 var
  i_nummer  : Integer;
  s_nummer  : String;

begin
 i_nummer := Query1.FieldByName ('nummer').AsInteger;
 s_nummer := Query1.FieldByName ('nummer').AsString;
end;
Zumindest geht das so bei mir.

Hansa 24. Jan 2003 12:16

Hi Sharky,

das stimmt ja alles, aber guck Dir mal die Beiträge weiter oben an. FieldValues gibt es ja auch noch :!:

Gruß
Hansa

Hansa 24. Jan 2003 13:23

Hi,

Zitat:

Zitat von harrybo
WGDS.Params.CreateParam(ftInteger, 'ID');

Das da compiliert er bei mir nicht. Im OI finde ich das auch nicht. Wahrscheinlich liegt es daran, daß ich nicht IBX sondern FIBplus verwende. Weiß dazu jemand was ? Glaube nicht. Dann werde ich wohl oder übel mein englisch bemühen müssen, um einem Russen eine Frage zu stellen. :mrgreen:

Gruß
Hansa

X-Dragon 24. Jan 2003 13:47

Zitat:

Zitat von Hansa
...

Nee, nee. Fange nicht auch noch solchen Unfug an. :mrgreen: :spin: = wird benutzt bei genauen Vergleichen und LIKE mit % usw. bei ungenauen Vergleichen, Suchen usw. LIKE ohne % ist bei mir gleich =. :witch:

Gruß
Hansa

Hab ich auch gedacht, bis ich das Problem bei der DBase-DB hatte. Also immer trifft das nicht zu, kannst ja nochmal in meinen Thread schauen :).

harrybo 24. Jan 2003 14:19

Hi Hansa,
das liegt wahrscheinlich nicht am Unterschied zwischen FIBplus und IBX, ich wusste nur nicht, womit Du überhaupt arbeitest. Die Sache ist für Dich dann einfacher, die Queries haben automatische Parameter (siehe Object Inspector). Du brauchst den Parameter nicht zu definieren und kannst einfach zuweisen, z.B. mit
Delphi-Quellcode:
Query1.Params[0].Value := APar;
Gibt es keinen Parameter, wird er angelegt.

Hier mal eine allgemeine Funktion, die ein Dataset mit einem Parameter refreshed (IBX und Interbase). Übergeben wird das Dataset Object, der Wert des Parameters, der ID Wert auf den der Datensatzzeiger positioniert werden soll, Konstante, die sagt, was mit der laufenden Transaction passieren soll:
Delphi-Quellcode:
procedure TDM.RequeryDS1(ADataset: TIBDataset; APar: variant; AID: longint; AType: integer);
begin
  with ADataset do try
    DisableControls;
    if Active then if State in [dsEdit, dsInsert] then Post;
    Close;
    if Transaction.InTransaction then
      case AType of
        c_Commit       : Transaction.Commit;
        c_CommitRetain : Transaction.CommitRetaining;
        c_Rollback     : Transaction.Rollback;
      end;
    if not Transaction.InTransaction then Transaction.StartTransaction;
    Params[0].Value := APar;
    Active := true;
    if AID > 0 then Locate(Fields[0].FieldName, AID, []);
  finally
    EnableControls;
  end;
end;
gruß, harrybo

Hansa 24. Jan 2003 19:29

Hi harrybo,

wo kommt denn das RequeryDS1 hin ? Du scheinst da eine allgemeine Prozedur geschrieben zu haben. Im OI ist hierüber jedenfalls nichts zu finden.

Gruß
Hansa

harrybo 24. Jan 2003 21:30

Hi Hansa,
ja, es ist eine selfmade Procedure, die bei mir im Datamodul und dort im Public Abschnitt, damit man von draußen Zugrif drauf hat. Da ein Datamodul meist mehrere TDataset Objekte versammelt, kann man der Procedure noch mitteilen, welchen Dataset man aktualisieren will. Der Aufruf kann dann so aussehen:
Delphi-Quellcode:
DM.RequeryDS1(DM.dsTER, gActDate, gActRec.TER, c_Commit);
DM.dsTER ist hier ein TDataset, der Rest spricht für sich, hoffe ich (nach meinen Erfahrungen mit X-Dragon trau ich mich ja kaum noch, feste Werte irgendwo reinzuschreiben).

gruß, harrybo

P.S. sieht nach Master Detail aus, was Du vorhast. Da gibt es ja, zumindest bei IBX, die code-lose Variante mit zusätzlicher Datasource, die wunderbar läuft (ok, ein einziger BeforeInsert Trick).

Hansa 26. Jan 2003 11:54

Hi,

Zitat:

trau ich mich ja kaum noch, feste Werte irgendwo reinzuschreiben).
Kommt drauf an, wem Du das schreibst. :mrgreen: Bei mir kannst Du es ruhig reinschreiben. Komme mit den Parametern nämlich nicht so ganz klar. Kannst Du mir die mal kurz erklären ? Ich habe mir mal mein Programm neu angesehen und dabei gemerkt, daß ich so eine Prozedur gut gebrauchen könnte. Wahrscheinlich aber modifiziert.

Gruß
Hansa

harrybo 26. Jan 2003 23:31

Hi Hansa,
ich nehme mal folgendes Beispiel: ein Dataset soll Daten aus einer Tabelle Termine holen, und zwar für ein bestimmtes Datum (das ist der Parameter). Die Termine werden in einem Grid dargestellt. Was machen nun die Parameter?
  • ADataset: TIBDataset Hier gebe ich an, welcher Dataset neu geladen werden soll, bei mehr als einem Dataset macht das schon Sinn.
    APar: variant das ist in diesem Beispiel das Datum, kann in einem anderen Fall eine KundenID sein, daher variant. Man könnte hier zwar umformen, etwa in string, das widerspräche aber einer meiner Programmierregeln: einen Wert ausschließlich in seinem eigenen Format irgendwohin zu übergeben.
    AID: longint Die Id des Datensatzes, der zuletzt vom Benutzer angewählt war. Ist ID > 0 wird nach dem Refresh versucht, den Recordpointer an dieselbe Stelle zu positionieren (alle meine Tabellen haben einen Unique Key, immer an erster Stelle, also Fields[0]). Auf diese Weise kann man z.B. in Mehrbenutzersystemen refreshen, ohne dass der Benutzer es merkt, er "bleibt" praktisch auf seinem Datensatz.
    AType: integer Es muss geklärt werden, was mit der laufenden Transaktion passieren soll. Übergeben wird ein Integer 0 bis 4 als Konstante. Wird 0 übergeben (c_Idle), läuft die Transaction weiter, manchmal möchte man aber auch committen, dann müssen natürlich sämtliche Datenmengen, die an dieser Transaction hängen neu aktiviert werden.
Mehr ist es eigentlich nicht. Es wird noch gecheckt, ob der Dataset sich gerade im Editiermodus befindet, dann wird er zunächst noch gesichert. Ja und nun kann man jeden Dataset, der einen Parameter erwartet ganz bequem refreshen, ohne sich immer wieder um genannten Kram zu kümmern. Das Gleiche kann man dann auch für ein Query anlegen, also RequeryQU1(AQuery: TIBQuery, ...

gruß, harrybo

Hansa 28. Jan 2003 17:52

Hi,

der Sinn ist schon klar.

Zitat:

Zitat von harrybo
AID: longint Die Id des Datensatzes, der zuletzt vom Benutzer angewählt war. Ist ID > 0 wird nach dem Refresh versucht, den Recordpointer an dieselbe Stelle zu positionieren (alle meine Tabellen haben einen Unique Key, immer an erster Stelle, also Fields[0]). Auf diese Weise kann man z.B. in Mehrbenutzersystemen refreshen, ohne dass der Benutzer es merkt, er "bleibt" praktisch auf seinem Datensatz.

Du meinst wahrscheinlich den Primary Key. Kann durch einen anderen User der Record-Pointer der eigenen WS verschoben werden ?? Das da gilt hoffentlich nur, falls es sich um ein Grid o.ä. handelt. Wird die Abfrage gerade ausgeführt, dürfte es doch keinen Einfluß haben, oder doch ?

Zitat:

Zitat von harrybo
AType: integer Es muss geklärt werden, was mit der laufenden Transaktion passieren soll. Übergeben wird ein Integer 0 bis 4 als Konstante. Wird 0 übergeben (c_Idle), läuft die Transaction weiter, manchmal möchte man aber auch committen, dann müssen natürlich sämtliche Datenmengen, die an dieser Transaction hängen neu aktiviert werden.[/list]...

Hängt mit dem ersten zusammen : Was ist, wenn einer commited ? Ein anderer sieht doch davon nix, oder ? Weißt Du vielleicht noch etwas zu dem Back Difference Record zu sagen, darüber finde ich absolut nichts. Wie kommt man an den dran ?

Gruß
Hansa


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:16 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