[gelöst] Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
Helios
Lazarusforum e. V.
Beiträge: 93
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.0 Windows 10 64Bit / Lazarus 2.0.12 Debian 11 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

[gelöst] Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von Helios »

Hallo zusammen,

seit einigen Stunden versuche ich ein DBGrid mit einem Popup/Kontextmenu auszustatten der bei einem Maus-Rechtsklick erscheinen soll a la:

Code: Alles auswählen

procedure TForm1.DBGrid1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  col, row: integer;
begin
  if ssRight in Shift then
  begin
    DBGrid1.MouseToCell(X, Y, col, row);
    // Hier soll mal ein Kontext/Popup Menu rein
    // Lese den Primary Key Value aus der ersten Spalte der angeklickten Zeile und starte ein Update
    // Schreiben/Lesen eines BLOB via INSERT...
    ShowMessage('Rechtsklick: row: ' + IntToStr(row) + ', col:' + IntToStr(col));
  end;
end;
Aus der angeklickten Zeile möchte ich mir aus der ersten DBGrid Spalte den Primary Key Wert herauslesen und im Nachgang einen entsprechenden SQL INSERT abfeuern, mit dem ich eine Datei als BLOB in die entsprechende Zeile Lade.
Die row und col Werte sind leider nur die Zeilen/Spalten aus dem sichtbaren Bereich des DBGrid. Also nicht wirklich verwendbar, wenn die vorhanden Zeilen den Bildschirmbereich deutlich überschreiten (ist leider die Regel). Ich habe im Internet schon viel diesbzgl. recherchiert aber kann nicht glauben, dass die Lösung so kompliziert ist (u.A. ableiten eines CustomDB/StringGrid etc.). Ist das wirklich so eine "Rocketscience" den Wert einer bestimmten Zelle in einer angeklickten Zeile zu ermitteln?
Gibt es da beim DBGrid evtl. mittlerweile eine elegant(er)e Lösung?
Ich bin gespannt auf eure Vorschläge und bedanke mich bereits im Voraus für das Interesse an diesem Thema.
Gruß
Helios
Zuletzt geändert von Helios am Fr 7. Mai 2021, 23:09, insgesamt 1-mal geändert.

Soner
Beiträge: 513
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von Soner »

Das ist doch ganz leicht, du musst die Datasouurce-Komponente verwenden.
Wenn man in DBGrid auf einer Zeile klickt oder scrollt, dann zeigt die DB-Komponente immer die aktuelle Zeile. Du musst dann so etwas verwenden: DataSource1.Dataset.Fields[0] für 1. Spalte. Naturlich wenn die Spalten nicht so geordnet wie in Dataset sind, dann so: DataSource1.Dataset.FieldByName(DBGrid1.Columns[0].FieldName).

Ich würde die PopupMenu-Eigenschaft von DBGrid verwenden, dann können die Benutzer das Popup-Menü auch mit Taste aufrufen.

charlytango
Beiträge: 490
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz 2.0 fixes FPC 3.2 fixes
CPU-Target: Win 32Bit, 64bit
Wohnort: Wien

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von charlytango »

Helios hat geschrieben:
Di 4. Mai 2021, 21:57
Ist das wirklich so eine "Rocketscience" den Wert einer bestimmten Zelle in einer angeklickten Zeile zu ermitteln?
Gibt es da beim DBGrid evtl. mittlerweile eine elegant(er)e Lösung?
das ist wie bei vielem -- keine Rocketscience sondern "gewusst wie".
Einem DBGrid ist immer über eine Datasource irgend eine Datenquelle zugewiesen.
Und wann immer eine Zeile dieser Datenquelle im Grid angezeigt oder angeklickt wird, wird in der Datenquelle ein "Datensatzzeiger" auf die aktuelle Zeile gesetzt.

Wenn du also den Grid seine Arbeit tun lässt verhält er sich auch korrekt und du kannst direkt aus der Datenquelle deine Primary-ID abholen. (und den Griod links liegen lassen)

Code: Alles auswählen

iGesuchtePrimaryID := <Datenquelle>.FieldByName('PimaryID').AsInteger;
Nebenbemerkung: Falls du keinen besonderen Grund hast das anders zu machen (ZB aus Prinzip oder anderen Gründen) empfehle ich die Möglichkeiten von Lazarus zu nutzen.
Eine TActionList aufs Formular kleben
Eine Action anlegen und mit Doppelklick kannst du in den Eventhandler deinen Gewünschten Code schreiben.

Dann klebst du ein Rechtsklickmenü auf das Formular und erstellst einen Menüpunkt dem du die soeben angelegte Action zuweist (einfach auswählen).

Dem DBGrid weist du das Rechtsmenü zu und schon funktioniert alles wie gewünscht. Und kein Herumgefrickel mit MouseDown-Events.

Der Vorteil ist dass du die Actions in unterschiedlichsten Controls (Buttons Menüs Rechtsmenüs, Speedbars etc) verwenden kannst ohne irgend etwas zusätzlich zu programmieren. Und das auch mit Icon und anderen Gimmicks -- wenn du ZB die Action Disablest, wird das sofort auf alle Controls weitergegeben.

Im wesentlichen ist meine Antwort ähnlich wie die von Soner... nur etwas ausführlicher ;)

Helios
Lazarusforum e. V.
Beiträge: 93
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.0 Windows 10 64Bit / Lazarus 2.0.12 Debian 11 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von Helios »

Hallo Soner und charlytango, vielen Dank für eure Antworten!

Das bereits ein PopUp am DBGrid "klebt" hatte ich noch gar nicht gesehen (entschuldigt meine Tomaten auf den Augen).
Den Ansatz mit der TActionList muss ich mir noch genauer ansehen.

2 Fragen würde ich gerne noch in diesem Zusammenhang loswerden:
  • Wie erreiche ich es, dass mit dem Maus-Rechtsklick gleich auch die Zelle selektiert wird, wo der Rechtsklick stattgefunden hat?
    Das Selektieren geschieht ja immer erst bei einem Linksklick und der Rechtsklick ist dann ggf. außerhalb der selektierten Zelle/Zeile
    und dort erscheint dann i.d.R. das PopUp Menu am "falschen Platz".
  • Wie prüfe ich (richtig), dass die Zelle/Zeile eine "gültige" Zeile ist und nicht etwa ein leeres Grid, bei dem meine Abfrage

    Code: Alles auswählen

    iGesuchtePrimaryID := <Datenquelle>.FieldByName('PimaryID').AsInteger;
    ins Leere oder in einen Laufzeitfehler geht (ist mir wieder besseren Wissen natürlich prompt passiert :D )?
Könnt ihr mir da bitte nochmal helfen?

Vielen Dank und Gruß
Helios

wp_xyz
Beiträge: 4323
Registriert: Fr 8. Apr 2011, 09:01

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von wp_xyz »

Helios hat geschrieben:
Mi 5. Mai 2021, 18:23
Wie erreiche ich es, dass mit dem Maus-Rechtsklick gleich auch die Zelle selektiert wird, wo der Rechtsklick stattgefunden hat?
Das Selektieren geschieht ja immer erst bei einem Linksklick und der Rechtsklick ist dann ggf. außerhalb der selektierten Zelle/Zeile
und dort erscheint dann i.d.R. das PopUp Menu am "falschen Platz".
Dafür gibt es das Element "dgAnyButtonCanSelect" in den Options des DBGrid.
Helios hat geschrieben:
Mi 5. Mai 2021, 18:23
Wie prüfe ich (richtig), dass die Zelle/Zeile eine "gültige" Zeile ist und nicht etwa ein leeres Grid, bei dem meine Abfrage

Code: Alles auswählen

iGesuchtePrimaryID := <Datenquelle>.FieldByName('PimaryID').AsInteger;
ins Leere oder in einen Laufzeitfehler geht (ist mir wieder besseren Wissen natürlich prompt passiert :D )?
Du könntest im MouseDown die Funktion MouseToGridZone(X, Y) aufrufen - diese gibt außerhalb des Gitternetzes den Wert gzInvalid zurück, und in diesem Fall könntest du mit einer stillen Exception (Abort) die weitere Prozessierung des Klicks unterbinden. Ist nach meinem Gefühlt aber sehr "brutal" und könnte Nebeneffekte haben --> ausprobieren.

Code: Alles auswählen

uses Grids;
procedure TForm1.DBGrid1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if DBGrid1.MouseToGridZone(X,Y) = gzInvalid then
    Abort;
end;
Ansonsten musst du einfach die Zwischenschritte, die du bei der Auswertung des Mausklicks machen musst, um den Record und das Feld aus den X,Y-Koordinaten des Klicks zu ermitteln, überprüfen und darfst nur weitermachen, wenn die jeweiligen Zwischenergebnisse sinnvoll sind.

Helios
Lazarusforum e. V.
Beiträge: 93
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.0 Windows 10 64Bit / Lazarus 2.0.12 Debian 11 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von Helios »

Hallo wp_xyz,

Danke für den Tipp mit

Code: Alles auswählen

dgAnyButtonCanSelect
das war genau das was ich gesucht hatte.
Bzgl. "Wie prüfe ich (richtig), dass die Zelle/Zeile eine "gültige" Zeile ist " habe ich mich nicht an Deine Lösung (MouseToGridZone(X, Y)/Exception Handling) herangetraut.
Das habe ich jetzt durch folgenden Ansatz über das Pupup Menu gelöst:

Code: Alles auswählen

  //change for DBGrid Popup Menu
  if (dbfSource.Dataset.FindField('ID') <> nil) then
    grid.PopupMenu := PopupMenu1
  else
    grid.PopupMenu := nil;
...
procedure TForm1.MenuItem1Click(Sender: TObject);
begin
  if (not(dbfSource.Dataset.FieldByName('ID').IsNull)) then
    ShowMessage('Here you can delete Id ' + dbfSource.Dataset.FieldByName('ID').AsString + '.');
end; 
Funktioniert eigentlich so wie ich es brauche und bin bisher noch in keine Probleme getappt, aber vielleicht hatte ich nur Glück :D .
Anbei ein kleines Testprojekt basierend auf
http://forum.lazarus.freepascal.org/ind ... msg199356
(da ich eine kleine Datenbank (TDBF) brauchte damit es mit dem Datenbankkomponenten auch testbar ist)
published2.zip
(3.94 KiB) 60-mal heruntergeladen
für die interessierte Gemeinde. Verbesserungen/Korrekturen sind mehr als willkommen.

Danke nochmal und Gruß
Helios

wp_xyz
Beiträge: 4323
Registriert: Fr 8. Apr 2011, 09:01

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von wp_xyz »

Du könntest noch die Einträge des Contextmenü disablen, wenn sie nicht zugänglich sind. Ein geeignetes Event dafür wäre das OnPopup:

Code: Alles auswählen

procedure TForm1.PopupMenu1Popup(Sender: TObject);
begin
  MenuItem1.Enabled := not dbfSource.Dataset.fieldByName('ID').IsNull;
  MenuItem2.Enabled := MenuItem1.Enabled;
end; 

Helios
Lazarusforum e. V.
Beiträge: 93
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.0 Windows 10 64Bit / Lazarus 2.0.12 Debian 11 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von Helios »

Hallo wp_xyz,

cool, so ist es noch besser bzw. nutzerfreundlicher.
Gefällt mir sehr gut. Danke!
Nun habe ich nur noch ein Problem (eigentlich ein anderes Thema). Bein Vergrößern des Applikationsfensters, bekomme ich es einfach nicht hin, dass sich das DBGrid an den NavigatorBar "anhängt". Nicht das Grid sondern die Navibar verändert seine Höhe. Ich habe wirklich schon alle Ankereditorkombinationen durch. Ist das ein Bug?

Gruß
Helios
published3.zip
(3.98 KiB) 54-mal heruntergeladen

wp_xyz
Beiträge: 4323
Registriert: Fr 8. Apr 2011, 09:01

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von wp_xyz »

Die einfachste Lösung ist, ein Panel einzufügen, in dem die Buttons aufgenommen werden. Dieses Panel bekommt Align = alBottom. Der Navigator bekomme auch Align = alBotton - falls er unter das Panel rutschen sollte, einfach im Form-Designer nach oben ziehen, bis Panel und Navigator ihre Plätze vertauschen. Das DBGrid bekommt dann Align = alClient.

Ohne dieses Zusatzpanel geht es auch, aber nur mit dem Anker-Editor. Das hast du anscheinend schon probiert, aber du hast vergessen, das Align des Navigators und des DBGrid auf alNone zurückzusetzen (falls eine Align-Einstellung existiert, würde sie den Anker-Editor übertrumpfen).

Helios
Lazarusforum e. V.
Beiträge: 93
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.0 Windows 10 64Bit / Lazarus 2.0.12 Debian 11 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von Helios »

Hallo wp_xyz,

erneut vielen Dank! Das kleine Projekt funktioniert nun wunderbar und sieht Dank Deiner Hilfe jetzt auch noch gut aus und ist bereit für den Einbau in das eigentliche "Großprojekt".
Nebenbei wieder einen Haufen nützlicher Dinge gelernt und wieder mehr überzeugt von Pascal und Lazarus.
Schönes Wochenende wp_xyz!
Gruß
Helios
published4.zip
(3.98 KiB) 59-mal heruntergeladen

Helios
Lazarusforum e. V.
Beiträge: 93
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.0 Windows 10 64Bit / Lazarus 2.0.12 Debian 11 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: [gelöst] Zugriff auf die Zellen Daten einer angeklickten Zeile eines DBGrid

Beitrag von Helios »

Sorry,
hatte gerade erst gesehen, dass ich hinter dem "end." der Beispielprogramme einiges an "Schrott" übersehen hatte.
Da schlägt der Compiler natürlich nicht an.
Um nicht allgemein zu verunsichern hier eine bessere Fassung incl. Erweiterung um das Einlesen und Auslesen
von (komprimierten!) (T)DFB Blobs über das besagte Popup Menu. Es fehlen sicher einige Try/Except Blöcke aber
vielleicht ist das trotzdem von Interesse.
Die Blob-Felder sind initial leer, daher muss erstmal eine Datei (Test *.txt ist dabei) hochgeladen werden.

Schönes (Rest) Wochenende
Helios
published5.zip
(6.52 KiB) 63-mal heruntergeladen

Antworten