[gelöst]: TDBGrid - Löschen von Datensätzen im Multiselect

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
musicones
Beiträge: 35
Registriert: Di 8. Sep 2009, 09:13
OS, Lazarus, FPC: Win 10 (L 1.6.2 FPC 3.0.0)
CPU-Target: 64Bit

[gelöst]: TDBGrid - Löschen von Datensätzen im Multiselect

Beitrag von musicones »

Hallo,

ich möchte gerne aus einem TDBGrid X Datesätze auswählen und per Tastendruck "Entf" löschen.

Dazu mache ich aktuell folgendes:

Code: Alles auswählen

 
 
procedure TMainForm.FilesGrid_KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var i: integer;
begin
  case Key of
    VK_DELETE:
    begin
      if (0 < FilesGrid.SelectedRows.Count) then
      begin
        while (0 < FilesGrid.SelectedRows.Count) do
        begin
          with FilesGrid.DataSource.DataSet do
          begin
            // Jump to selected record
            GotoBookmark(Pointer(FilesGrid.SelectedRows.Items[0]));
 
            // Delete record
            Delete;
          end;
        end;
      end;
    end;
  end;
end;   
 


Dabei erhalte ich die Fehlermeldung, siehe Screenshot.


Da ich keinerlei Post hier und im englischen Forum dazu gefunden habe, gehe ich mal stark davon aus,
dass ich 'n Brett vorm Kopf habe und ihr das sicherlich eleganter löst ^_^.

Edit 1: Eines ist mir gerade noch aufgefallen. Am Ende bleibt immer eine leere Zeile im Grid über. Ich vermute jetzt mal, dass dies den Fehler auslöst, da es gar kein Bookmark
darauf gibt. Aber wie kommt diese leere Zeile zustande?


Gruß
Antonio
Dateianhänge
Fehlermeldung
Fehlermeldung
lazarus_2017-02-07_14-46-38.png (6.64 KiB) 1952 mal betrachtet
Zuletzt geändert von musicones am Mi 8. Feb 2017, 11:13, insgesamt 1-mal geändert.

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

Re: TDBGrid - Löschen von Datensätzen im Multiselect

Beitrag von wp_xyz »

Einfach mal so vor mich hingeraten: ich könnte mir vorstellen, dass durch das Löschen eines Datensatzes die Bookmarks ungültig werden. Daher würde ich, statt mit den SelectedRows zu arbeiten, eher den Wert des Key-Feldes der markierten Datensätze in einem Array speichern, dieses dann Element für Element durchlaufen, den Record mit dem betreffenden Key-Feld suchen und erst dann das Löschen ausführen.

Oder: SelectedRows des Grid kriegt nach dem Löschen in der Schleife nicht gleich mit, dass der 1.Datensatz nicht mehr vorhanden ist, und du versucht, diesen beim nächsten Durchlauf erneut zu löschen (du löschst ja immer SelectedRows.Items[0], was nur funktionert, wenn der nächste Datensatz an diese Position gerutscht ist). Schreibe doch nach dem Delete den Wert von FilesGrid.SelectedRows.Count in eine Dummy-Variable, die du mit Hilfe eines Breakpoints abfragen kannst.

musicones
Beiträge: 35
Registriert: Di 8. Sep 2009, 09:13
OS, Lazarus, FPC: Win 10 (L 1.6.2 FPC 3.0.0)
CPU-Target: 64Bit

Re: TDBGrid - Löschen von Datensätzen im Multiselect

Beitrag von musicones »

wp_xyz hat geschrieben: Schreibe doch nach dem Delete den Wert von FilesGrid.SelectedRows.Count in eine Dummy-Variable, die du mit Hilfe eines Breakpoints abfragen kannst.


Auf die Idee bin ich auch gekommen:

Code: Alles auswählen

 
procedure TMainForm.FilesGrid_KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var Counter: integer;
begin
  case Key of
    VK_DELETE:
    begin
      if (0 < FilesGrid.SelectedRows.Count) then
      begin
        Counter := FilesGrid.SelectedRows.Count;
 
        while (0 < Counter) do
        begin
          with FilesGrid.DataSource.DataSet do
          begin
            // Jump to selected record
            GotoBookmark( Pointer(FilesGrid.SelectedRows.Items[0]) );
 
            // Delete record
            Delete;
 
            // Decrease Counter
            Dec(Counter);
          end;
        end;
      end;
    end;
  end;
end
 


Was mich wundert und stört ist der fakt, dass nach dem Löschen eine leere Zeile übrig bleibt, die auch als markiert erkannt wird. Wenn ich nun wieder auf ENTF drücke, wird versucht diese Zeile zu löschen, die gar kein Datensatz ist, das es beim Umsetzen des Bookmarks dann Probleme gibt, gibts nen Fehler.

Vermutlich ist das auslesen und Zwischenspeichern des Key-Feldes die Beste Variante.
Aber eigentlich müsste es für das Löschen von Datensätzen aus einem Grid heraus ein standardisiertes Verfahren geben.

Danke und Gruß
Antonio

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

Re: TDBGrid - Löschen von Datensätzen im Multiselect

Beitrag von wp_xyz »

Da hast du mich falsch verstanden. Du sollst nicht eine Zählvariable einführen, die nach dem Löschen runterzählt, sondern durch Setzen eines Breakpoints und mit Hilfe einer Dummy-Variablen feststellen, ob nach Delete wirklich die Anzahl der Zeilen in Grid.SelectedRows abgenommen hat. Eine Dummy-variable macht es einfacher, Grid.SelectedRows.Count abzufragen (einfach mit der Maus über die Dummy-Variable fahren, wenn das Programm angehalten hat).

Oder du setzt (ohne die Dummy-Variable einzubauen) einen Breakpoint auf GotoBookmark und gibst in einem Watch-Fenster folgendes ein: FilesGrid.FSelectedRows.FList.FCount - das ist eine für den Debugger verständliche Abfrage des Wertes von FilesGrid.SelectedRows.Count. Wenn das Programm das erste Mal hier anhält, ist noch nichts gelöscht, du solltest im Watchfenster die Anzahl der ursprünglich markierten Zeilen sehen. Drückst du F9, dann läuft das Programm weiter, löscht den ersten markierten Datensatz und hält wegen der Schleife wieder am GotoToBookmark an. Die Frage ist, ob nun die im Watchfenster angezeige Zeilenzahl um 1 abgenommen hat. Wenn nicht, liegt ein Fehler im DBGrid vor, weil es das Löschen des Datensatzes offenbar nicht mitgekriegt hat. Wenn ja, ist das Bookmark ungültig geworden, was du noch mit Dataset.Bookmarkvalue(FilesGrid.SelectedRows[0]) prüfen könntest.

Was mit der leeren Zeile ist, erscheint mir sekundär, solange nicht klar ist, was beim Löschen der Datensätze schief geht.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: TDBGrid - Löschen von Datensätzen im Multiselect

Beitrag von Michl »

musicones hat geschrieben:Was mich wundert und stört ist der fakt, dass nach dem Löschen eine leere Zeile übrig bleibt, die auch als markiert erkannt wird. Wenn ich nun wieder auf ENTF drücke, wird versucht diese Zeile zu löschen, die gar kein Datensatz ist, das es beim Umsetzen des Bookmarks dann Probleme gibt, gibts nen Fehler.
Das ist normal. Dort kann ein neuer Record eingefügt werden. Diesen nicht vorhandenen Eintrag kann man dann natürlich auch nicht löschen.

PS: Logik würde ich immer von Anzeigekomponenten entkoppeln, auch wenn die RAD einen dazu verleitet, sowas nicht zu tun.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

musicones
Beiträge: 35
Registriert: Di 8. Sep 2009, 09:13
OS, Lazarus, FPC: Win 10 (L 1.6.2 FPC 3.0.0)
CPU-Target: 64Bit

Re: TDBGrid - Löschen von Datensätzen im Multiselect

Beitrag von musicones »

Michl hat geschrieben:PS: Logik würde ich immer von Anzeigekomponenten entkoppeln, auch wenn die RAD einen dazu verleitet, sowas nicht zu tun.


Jaein? Ein Grid ist ja nicht "nur" eine Anzeigekomponente, sondern eine Komponente zur Interaktion mit den darstellenden Daten.
Insofern, muss sie die Interaktion auch sauber abwickeln können, bzw. die nötigen Methoden zur Verfügung stellen, es dem Entwickler zu ermöglichen,
dies zu tun.

wp_xyz hat geschrieben:Dataset.Bookmarkvalue(FilesGrid.SelectedRows[0]) prüfen könntest.


Du hasst dich vertippt, die Methode heisst BookmarkValid.
Damit kann ich den Bookmark vorher validieren und nur wenn true, wird der Datensatz versucht zu löschen.
Das klappt sehr gut!!

Eine letzte Frage dazu: Ist es möglich diese leere Zeile für einen neuen Record abzuschalten (Property)?

Ansonten vielen Dank Euch.
Ich markiere den ersten Post als gelöst, da mein eigentliches Problem mit dank Eurer Hilfe gelöst ist.

Gruß
Antonio

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

Re: TDBGrid - Löschen von Datensätzen im Multiselect

Beitrag von wp_xyz »

musicones hat geschrieben:Damit kann ich den Bookmark vorher validieren und nur wenn true, wird der Datensatz versucht zu löschen.
Das klappt sehr gut!!

Und wenn das Bookmark mit Index 0 nicht valid ist, steckst du in einer Endlosschleife, weil nichts mehr gelöscht wird. Wie machst du's jetzt konkret?

musicones hat geschrieben:Eine letzte Frage dazu: Ist es möglich diese leere Zeile für einen neuen Record abzuschalten (Property)?

Vielleicht indem du das Editing-Flag in den Options ausschaltest, oder ReadOnly auf false setzt? Aber ob das in deinem Sinne ist? Mit Sicherheit kannst du nun nicht mehr im Grid direkt editieren (was ich aber ohnehin nie machen würde). Kannst du dann auch noch die markierten Datensätze löschen? (Wahrscheinlich, weil das Löschen nicht vom Grid ausgeht, sondern von deinem Code).

musicones
Beiträge: 35
Registriert: Di 8. Sep 2009, 09:13
OS, Lazarus, FPC: Win 10 (L 1.6.2 FPC 3.0.0)
CPU-Target: 64Bit

Re: [gelöst]: TDBGrid - Löschen von Datensätzen im Multisele

Beitrag von musicones »

Hier mal wie ich es jetzt umgesetzt habe:

Code: Alles auswählen

 
procedure TMainForm.FilesGrid_KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
 
  function GetSelectedRecords: TStrings;
  var
    List: TStrings;
    i: integer;
  begin
    result := nil;
 
    if (0 < FilesGrid.SelectedRows.Count) then
    begin
      List := TStringList.Create;
 
      for i := 0 to FilesGrid.SelectedRows.Count - 1 do
      begin
        with FilesGrid.DataSource.DataSet do
        begin
          FilesGrid.SelectedRows.Items[i];
 
          if BookmarkValid( Pointer(FilesGrid.SelectedRows.Items[i]) ) then
          begin
            // Jump to selected record
            GotoBookmark( Pointer(FilesGrid.SelectedRows.Items[i]));
 
            // Get guid of record
            List.Add(Files.FieldByName('Files_Guid').AsString);
          end;
        end;
      end;
 
      result := List;
    end;
  end;
 
var
  GuidList: TStrings;
  i: integer;
begin
  case Key of
    VK_DELETE:
    begin
      GuidList := GetSelectedRecords;
      try
        if Assigned(GuidList) then
        begin
          for i := 0 to GuidList.Count - 1 do
          begin
            if Files.Locate('Files_Guid', GuidList[i], []) then
            begin
             Files.Delete;
 
             // Wird vermutlich nicht benötigt, hatte das nur für Delphi TBookmarkList gelesen, dass die Bookmarks beim löschen
             // nicht aktualisiert werden und deshalb das Grid refreshed werden sollte.
             FilesGrid.Refresh;
            end;
          end;
        end;
      finally
         GuidList.Free;
      end
    end;
  end;
end;
 


Ich werde das Grid vermutlich auf ReadOnly setzen. Es war noch mehr Funktionalität geplant, bin aber mit der jetzigen erstmal zufrieden, somit brauche ich keine editierbares Grid.
Einen Wert möchte ich gerne editierbar machen. Da es sich aber um einen Wert handelt, der üblicherweise für mehrere Zeilen gilt, mache ich das über ein Editeld, dass ich per Schaltfläche auf die markierten Zeilen im Dataset editiere.

Gruß
Antonio

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

Re: [gelöst]: TDBGrid - Löschen von Datensätzen im Multisele

Beitrag von wp_xyz »

Genau, so in etwa würde ich das auch machen.

Da du zum direkten Löschen die Bookmarks nicht mehr benötigst, würde ich das Grid.Refresh zumindest aus der Schleife herausnehmen, es müsste reichen, das nach dem Abschluss der Aktion auszuführen.

Antworten