Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi StringGrid - Aktuelle Zeile löschen (https://www.delphipraxis.net/69072-stringgrid-aktuelle-zeile-loeschen.html)

Sturmrider 9. Mai 2006 21:04


StringGrid - Aktuelle Zeile löschen
 
Hallo Leute
Ich habe mir hier folgenden Source zusammengewurschtelt:
Delphi-Quellcode:
type
procedure BitBtnEintragLoeschenClick(Sender: TObject; const ARow : Integer);

//[...]

procedure TFSpielplan01.BitBtnEintragLoeschenClick(Sender: TObject; const ARow : Integer);
var
  i : integer;
begin
  for i := ARow to FSpielfeld.StringGrid1.RowCount - 2 do
  Begin
    FSpielfeld.StringGrid1.Rows[i].Clear;
    FSpielfeld.StringGrid1.Rows[i].AddStrings(StringGrid1.Rows[i+1]);
  end;
  FSpielfeld.StringGrid1.RowCount := FSpielfeld.StringGrid1.RowCount - 1;
end;
leider habe ich noch nicht so ganz verstanden, wie const ARow: Integer funktioniert bzw. wofür ARow genau steht... :oops:
Laut der Seite wo ich die Begriffe vorgeworfen bekommen habe müsste ich so die aktuell ausgewählte Zeile des StringGrids löschen können, wobei die Zeile darunter automatisch nachrückt...
Nur leider funktioniert das ganze auch gar nicht...
ich habe leider wirklich keine Ahnung, wie ich mein Ziel möglichst leicht erreichen kann :oops:
Wäre echt toll, wenn ihr mir helfen könntet! (vielleicht auch eine ganz andere Methode, die ich verstehe :oops: )

marabu 9. Mai 2006 21:38

Re: StringGrid - Aktuelle Zeile löschen
 
Hallo.

Hier ein Klassiker:

Delphi-Quellcode:
type
  TGridCracker = class(TCustomGrid);

procedure DeleteRow(sg: TStringGrid; index: Integer);
var
  iRow: Integer;
begin
  with TGridCracker(sg) do
  begin
    iRow := Row;
    DeleteRow(index);
    if iRow < RowCount
      then Row := iRow
      else Row := Pred(RowCount);
  end;
end;
Verwenden kannst du ihn so:

Delphi-Quellcode:
with FSpielfeld do
  DeleteRow(StringGrid1, StringGrid1.Row);
Grüße vom marabu

Sturmrider 9. Mai 2006 22:09

Re: StringGrid - Aktuelle Zeile löschen
 
Das mit dem
Delphi-Quellcode:
type
  TGridCracker = class(TCustomGrid);
funktioniert irgendwie nicht :( ich habe auch schon bereits
Delphi-Quellcode:
type
  TFSpielplan01 = class(TForm)
oben stehen. Wie mache ich, dass diese class auch funktioniert :oops: ? der zeit kommt nämlich ein Allert: ":" erwartet aber "=" gefunden. Und wenn ich einfach folgendes schreibe:
Delphi-Quellcode:
type
  TGridCracker : class(TCustomGrid);
kommt auch wieder ein Allert: "ein Bezeichner erwartet, aber "class" gefunden"

ansonsten, schoneinmal an dieser Stelle vielen Dank für deine Hilfe!

Hawkeye219 9. Mai 2006 23:21

Re: StringGrid - Aktuelle Zeile löschen
 
Hallo,

marabus Code sollte funktionieren. Zeige uns bitte, wie du ihn in deinen Quelltext eingebaut hast, vielleicht finden wir dann den Grund für die Fehlermeldungen.

Gruß Hawkeye

Sturmrider 10. Mai 2006 00:25

Re: StringGrid - Aktuelle Zeile löschen
 
Okey, hier der Code (ich weiß, dass das mit dem doppelten type nicht so gedacht war, aber anders funktioniert es überhaupt nicht...d.h. kann ich noch nichteinmal das Prog. starten):
Delphi-Quellcode:
unit mspielplan;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Grids, Buttons, ExtCtrls, Printers, Menus; {Printers}

type
  TFSpielplan01 = class(TForm)
{[...]}
    StringGrid1: TStringGrid;
{[...]}
    BitBtnEintragLoeschen: TBitBtn;
    BitBtnSpeichern: TBitBtn;
    BitBtnLaden: TBitBtn;
    BitBtnDrucken: TBitBtn;
{[...]}
    procedure BitBtnEintragLoeschenClick(Sender: TObject);
    procedure BitBtnNeuerEintragClick(Sender: TObject);
    procedure BitBtnSpeichernClick(Sender: TObject);
    procedure BitBtnLadenClick(Sender: TObject);
    procedure BitBtnDruckenClick(Sender: TObject);
{[...]}
   private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  FSpielplan01: TFSpielplan01; spalte, zeile, a, b, c: Integer;

implementation

uses mformular, mspielfeld;

{$R *.DFM}

type
  TGridCracker = class(TCustomGrid);

procedure DeleteRow(sg: TStringGrid; index: Integer);
var
  iRow: Integer;
begin
  with TStringGrid(sg) do
  begin
    iRow := Row;
    DeleteRow(index);
    if iRow < RowCount
      then Row := iRow
      else Row := Pred(RowCount);
  end;
end;

procedure TFSpielplan01.BitBtnEintragLoeschenClick(Sender: TObject);
begin
   with FSpielfeld do
  DeleteRow(StringGrid1, StringGrid1.Row);
end;

{#########das hier hatte ich ganz am Anfang...aber das löscht immer nur den untersten Beitrag und ist wohl viel zu Kompliziert gemacht ^^° #############
procedure TFSpielplan01.BitBtnEintragLoeschenClick(Sender: TObject);
var i: Integer; test: String;
begin
   x:= StringGrid1.RowCount;
   if StringGrid1.Cells[3,x-1] = 'H' then begin
      x2:= FSpielfeld.StringGrid1.RowCount;
      if x2>0 then begin
      x2:=x2-1;
      for i:=0 to 4 do begin
         FSpielfeld.StringGrid1.Cells[i,x2] := '';
      end;
      FSpielfeld.StringGrid1.RowCount:=x2;
      FSpielfeld.StringGrid1.Height := x2*25+25;
      end;
   end;
   test:= StringGrid1.Cells[3,x-1];
   if x>0 then begin
      x:=x-1;
      for i:=0 to 10 do begin
         StringGrid1.Cells[i,x] := '';
      end;
      StringGrid1.RowCount:=x;
      StringGrid1.Height := x*25+25;
   end;
end;        }
{[...]}
end.

marabu 10. Mai 2006 08:00

Re: StringGrid - Aktuelle Zeile löschen
 
Guten Morgen.

Die Typvereinbarung für die Klasse TGridCracker steht ja schon an einer brauchbaren Stelle. Im auskommentierten Click-Handler machst du aber mehr als nur eine Zeile in einem Grid löschen. Du prüfst, ob in der vorletzten Spalte der letzten Zeile im SpielplanGrid ein 'H' (Heimspiel?) eingetragen ist. Wenn ja, dann entfernst du die letzte Zeile aus dem SpielfeldGrid, bevor du dann die letzte Zeile aus dem SpielplanGrid auch entfernst. Beide Grids dimensionierst du neu, indem du die Gridabmessungen grob an den Zellbereich anpasst. Ich versuche mal behutsam ein paar Änderungen an deinem Click-Handler:

Delphi-Quellcode:
procedure TFSpielplan01.BitBtnEintragLoeschenClick(Sender: TObject);
var
  i, iSF, iSP: Integer;
  test: String;
begin
  iSP := Pred(StringGrid1.RowCount);
  if StringGrid1.Cells[3, iSP] = 'H' then
  begin
    iSF := Pred(FSpielfeld.StringGrid1.RowCount);
    DeleteRow(FSpielfeld.StringGrid1, iSF);
    ResizeGrid(FSpielfeld.StringGrid1);
  end;
  DeleteRow(StringGrid1, iSP);
  ResizeGrid(StringGrid1);
end;
Die Bedingungen unter denen eine Aktion ausgeführt werden darf, solltest du außerhalb des Aktionscodes prüfen. Ob x > 0 ist, prüfst du in deinem Code eh zu spät, der Zugriff auf die Zelle mit dem 'H' ist da schon ungeprüft gescheitert.

Hier noch die Routine ResizeGrid:

Delphi-Quellcode:
procedure ResizeGrid(sg: TStringGrid);
var
  iCol, iRow: Integer;
begin
  with sg do
  begin
    Width := ColCount * GridLineWidth + Ord(BorderStyle) * 3;
    for iCol := 0 to Pred(ColCount) do
      Width := Width + ColWidths[iCol];
    Height := RowCount * GridLineWidth + Ord(BorderStyle) * 3;
    for iRow := 0 to Pred(RowCount) do
      Height := Height + RowHeights[iRow];
  end;
end;
Noch ein paar allgemeine Ratschläge: Versuche deinen Variablen sprechende Namen zu geben - nicht StringGrid1 sondern SpielplanGrid. Und informiere dich mal über Actions.

Freundliche Grüße vom marabu

Hawkeye219 10. Mai 2006 08:12

Re: StringGrid - Aktuelle Zeile löschen
 
Die Typvereinbarung ist zwar vorhanden, sie wird aber nicht genutzt. :wink:

Delphi-Quellcode:
type
  TGridCracker = class(TCustomGrid);

procedure DeleteRow(sg: TStringGrid; index: Integer);
var
  iRow: Integer;
begin
  with TGridCracker(sg) do  // <--- so sollte es aussehen!
  begin
    iRow := Row;
    DeleteRow(index);
    if iRow < RowCount
      then Row := iRow
      else Row := Pred(RowCount);
  end;
end;
Gruß Hawkeye

Sturmrider 10. Mai 2006 14:13

Re: StringGrid - Aktuelle Zeile löschen
 
okey, das habe ich jetzt soweit verstanden (denke ich) :-D supi, DANKE!
Nur das mit dem "Die Typvereinbarung für die Klasse TGridCracker steht ja schon an einer brauchbaren Stelle." verstehe ich leider noch nicht so ganz :oops:
Delphi-Quellcode:
type
  TGridCracker = class(TCustomGrid);
mit dem Teil scheint das ganze nicht zu funktionieren...und ohne natürlich erst recht nicht :$
außerdem habe ich noch die Frage, sind Folgende Prozeduren nicht Subprozeduren und müssten auch unter privat eingetragen werden? :gruebel:
Delphi-Quellcode:
procedure DeleteRow(sg: TStringGrid; index: Integer);
procedure ResizeGrid(sg: TStringGrid);
(aber wenn, wie? :oops: 1zu1 nach oben kopieren?)

Gruß Sturmrider

[edit=SirThornberry]Delphi-Tags gesetzt. Mfg, SirThornberry[/edit]

marabu 10. Mai 2006 16:03

Re: StringGrid - Aktuelle Zeile löschen
 
Für deine Zwecke ist es in Ordnung, wenn du den Typ für die Hilfsklasse TGridCracker einfach am Beginn des Implementation Abschnittes deiner Form-Unit vereinbarst, so wie du es in deinem Beitrag schon gemacht hast. Wenn du dabei Syntaxfehler gemeldet bekommst, dann stelle deine Form (PAS und DFM) einfach mal als Anhang zur Verfügung und irgendwer korrigiert deinen Syntaxfehler. Die Hilfsklasse wird benötigt um auf die Methode TCustomGrid.DeleteRow() zugreifen zu können - die hat nämlich eine eingeschränkte Sichtbarkeit (private) und ist anders nicht ansprechbar.

Die Prozeduren DeleteRow() und ResizeGrid() habe ich so geschrieben, dass sie unabhängig von irgendeiner Form sind. So kannst du sie überall verwenden und musst ihren Code lediglich per $INCLUDE einbinden - oder du erstellst dir eine Unit GridUtils mit diesen Prozeduren. Auf jeden Fall solltest du keine Form-Methoden aus diesen Prozeduren machen. Es würde ihre allgemeine Verwendbarkeit verhindern.

marabu

Sturmrider 10. Mai 2006 18:44

Re: StringGrid - Aktuelle Zeile löschen
 
k, danke :-D
wäre super, wenn der jenige, der den Fehler findet und behebt ihn auskommentieren könnte! (so dass ich es auch nachvollziehen und daraus lernen kann :angel2: )

Gruß und vielen DANK!
Sturmrider

marabu 10. Mai 2006 20:49

Re: StringGrid - Aktuelle Zeile löschen
 
Sag einmal - warum hast du Formular und Unit voneinander entkoppelt? Geschieht bei dir überhaupt irgendetwas, wenn du auf die Schalter in deiner Werkzeugleiste klickst?

Ich vermute, dass du im Eifer des Gefechts die Zeile {$R *.DFM} aus dem Implementation-Abschnitt gelöscht hast. Füge die Zeile gleich als erste im Abschnitt wieder ein, speichere die Unit, entferne sie aus deinem Projekt und füge sie dann wieder hinzu. Syntaktisch ist alles in Ordnung und Testen kannst du dann auch.

marabu

Sturmrider 10. Mai 2006 21:41

Re: StringGrid - Aktuelle Zeile löschen
 
Liste der Anhänge anzeigen (Anzahl: 1)
ups, stimmmt :wall: dummer Fehler :oops:
Ich habe genau das gemacht, was du geschrieben hast ... jetzt kommen zwar keine Fehlermeldungen mehr, aber dafür funktioniert das mit dem löschen leider immer noch nicht :cry: (alle anderen Buttons funktionieren wieder wie immer ^^)
Könntest du vielleicht nocheinmal kurz drüber gucken? :oops: (da ist nämlich glaube ich noch irgendwo ein kleiner Fehler drin uu *ihn aber nicht findet*)

Gruß Sturmrider

marabu 10. Mai 2006 22:08

Re: StringGrid - Aktuelle Zeile löschen
 
Du musst mal genau beschreiben, was du von der Löschfunktion erwartest. Ein "Fehler" tritt eigentlich nicht auf. Wie soll ich testen?

Ich fürchte meine Batterie ist alle... Morgen geht es weiter.

Gute Nacht

marabu

Sturmrider 10. Mai 2006 22:15

Re: StringGrid - Aktuelle Zeile löschen
 
Ich erwarte, dass wenn man auf löschen (diesen roten X-Button) klickt, der aktuell ausgewählte Eintrag im StringGrid gelöscht wird und der der sich unter diesem Beitrag befindet (wenn dort einer ist) eins weiter nach oben rückt ^^
k, bis Morgen dann :) gute Nacht ^^

Achtung hier nach nur noch 1 Beitrag, dann nächste Seite

marabu 11. Mai 2006 07:37

Re: StringGrid - Aktuelle Zeile löschen
 
Guten Morgen.

Die aktuelle Zeile steht in der Eigenschaft Row:

Delphi-Quellcode:
procedure TFSpielplan01.BitBtnEintragLoeschenClick(Sender: TObject);
var
  iSF: Integer;
begin
{
  if StringGrid1.Cells[3, iSP] = 'H' then
  begin
    iSF := Pred(FSpielfeld.StringGrid1.RowCount);
    DeleteRow(FSpielfeld.StringGrid1, iSF);
    ResizeGrid(FSpielfeld.StringGrid1);
  end;
}
  DeleteRow(StringGrid1, StringGrid1.Row);
  ResizeGrid(StringGrid1);
end;
Allerdings musst du dir etwas einfallen lassen um die zugehörige Zeile aus dem SpielfeldGrid zu identifizieren. Momentan wird dort einfach die letzte Zeile im Grid gelöscht. Das ist bestimmt nicht richtig so. Dabei könnte dir diese Funktion helfen:

Delphi-Quellcode:
function LocateRow(sg: TStringGrid; index: Integer; value: String): Integer;
begin
  Result := sg.Cols[index].IndexOf(value);
end;
Du brauchst dann eine spezielle (unsichtbare) Spalte in beiden Grids. Im SpielfeldGrid enthält sie einen eindeutigen Schlüssel für die jeweilige Zeile, im SpielplanGrid enthält sie den Schlüssel der zugehörigen Zeile aus dem SpielfeldGrid.

marabu

Sturmrider 11. Mai 2006 13:38

Re: StringGrid - Aktuelle Zeile löschen
 
:oops: *nickt* soetwas habe ich mir schon gedacht (dass ich unsichtbar für jede Zeile eine ID mitlaufen lassen muss...)
aber genau das ist ja mein Problem, wie ich die aktuelle, markierte Zeile herausfinden kann (das mit dem löschen ist dann denke ich weniger das Problem)
Was macht diese funktion denn, die du mir da gepostet hast? :oops: *erlichgesagt keine Ahnung hat*
(Ich weiß, das gehört nicht zum Thema, aber kennst du vielleicht eine gute Delphi-Seite mit der/auf der man/ich noch ein bischen etwas dazu lernen kann? wir in der Schule sind leider an das Buch: "Ojektorientierte Programmierung mit Delphi - Ein Unterrichtswerk Bankd 1" gebunden...und das Buch ist leider voll mit Fehlern und geht auf wirklich wesentliche Dinge gar nicht ein <<")

Achso, übrigens das was ich bisher habe (auch upgeloadet habe) funktioniert leider überhaupt nicht (das mit dem löschen) auch nicht mit dem letzten Eintrag in die Tabelle :( ->auch nicht, wenn ich wie du im Post den Teil in dem loeschButtonClick lösche/kommentiere...

Gruß Sturmrider

PS: Tut mir leid, dass ich mich so doof anstelle :$

Sturmrider 15. Mai 2006 09:18

Re: StringGrid - Aktuelle Zeile löschen
 
k, hab das Problem gelöst ^-----^ danke für eure/deine Hilfe!!! :thumb:

Nogge 26. Jul 2007 18:54

Re: StringGrid - Aktuelle Zeile löschen
 
Ich habe mir mal selbst add- und delete-Methoden für TStringGrid geschrieben, die so, wie folgt, meiner Meinung nach objekt-orientiert implementiert sind:
Delphi-Quellcode:
{
  @author
          Nogge
  @description
          TStringGridEx extends TStringGrid with two methods, which based on
          methods and properties of TStringGrid. So TStringGridEx can easily be
          used as type-cast class without creating an instance of it.
            - addRow
                  Adds a new row to the end of the StringGrid and fills a
                  specific string in each column
            - deleteRow
                  Clears the content of each column of the row specified by an
                  index and, if applicable, deletes it from the StringGrid
}
unit StringGridEx;

interface

uses Grids, SysUtils;

type
  EListError = class(Exception);

  TStringGridEx = class(TStringGrid)
  public
    function addRow(const VCols: array of String): Integer;
    (* HINT for reintroduce:
        - overrides virtual method of TCustomGrid
        - changes access right from protected to public
    *)
    procedure deleteRow(ARow: Longint); reintroduce;
  end;

implementation

function TStringGridEx.addRow(const VCols: array of String): Integer;
var
  i: Integer;
begin
  // catch exception
  if (Length(VCols) > ColCount) then
    raise EListError.CreateFmt('Col index out of bounds (%d)', [High(VCols)])
  else
  begin
    // execute code
    if (Length(Cells[0, FixedRows]) = 0) then // wenn kein Zeichen enthalten ist
    begin
      for i := Low(VCols) to High(VCols) do
        Cells[i, FixedRows] := VCols[i];
    end
    else
    begin
      RowCount := RowCount +1;
      for i := Low(VCols) to High(VCols) do
        Cells[i, RowCount-1] := VCols[i];
    end;
    Result := RowCount -1;
  end;
end;

(*
    Clears all entries (Strings[] AND Objects[]) of the specific row
*)
procedure TStringGridEx.deleteRow(ARow: Longint);
begin
  // FixedRows should not be deleted
  if (ARow < FixedRows) or (ARow >= RowCount) then
  begin
    raise EListError.CreateFmt('Row index out of bounds (%d)', [ARow]);
  end
  else
  begin
    if (RowCount-1 > FixedRows) then
      inherited DeleteRow(ARow)
    else // FixedRows is always less than RowCount
      Rows[FixedRows].Clear;
  end;
end;
Verwendungsbeispiel:
Delphi-Quellcode:
uses: [...], StringGridEx;
[...]
// als einfacher Aufruf...
TStringGridEx(StringGrid1).deleteRow(2);
// ...oder als Methode
procedure DeleteRow(sg: TStringGrid; index: Integer);
begin
  TStringGridEx(sg).deleteRow(index);
end;
Hierdurch werden alle public-Methoden und Properties der Klasse TStringGrid sowie die beiden zusätzlichen public-Methoden von TStringGridEx zur Verfügung gestellt, ohne das private-Methoden und Attribute sichtbar werden.


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