// Getestet mit D4 unter XP

// Manchmal möchte man in einer Spalte eines Stringgrids Zahlen untereinander-
// schreiben, um sie später zu addieren. Um beim Addieren aber keine Über-
// raschung zu erleben, wäre es gut, gleich bei der Eingabe
(hier beim Verlassen
//
einer Zelle) festzustellen, ob man wirklich eine Zahl eingetippt hat.
// Der folgende Code erlaubt darüber hinaus auch noch, Eingaben zusätzlich
// zu formatieren, z.B. in eine Währung mit zwei Dezimalstellen.
// Bei Datums- oder Zahlenspalten werden zunächst sogenannte Raw-Data gebildet,
// welche in einer Stringliste gespeichert werden. Hat eine Zelle den Fokus,
// werden diese Raw-Data in Label1 angezeigt und können mit der Zelle verglichen
// werden. Beispielsweise für eine Zahlen-Spalte:

Eingabe formatieren mitZeichen Zelle Label1 (Raw-Data)
+0 False False +0 0
0,0 False True (kein Einfluss) 0,0 0
-  0,019€ True True -0,02 € (Rundung!) -0,019
00000 True False 0,00 0
- 0,200 False False - 0,200 -0,2
0001,1000 True False 1,10 1,1
€ 35 - True True -35,00 € -35
20e+30 True True 2E31 € 2E31

// Oder für eine Datum-Spalte:

Eingabe formatieren Zelle Label1 (Raw-Data)
1.1.05 False 1.1.05 1.1.05
10122005 False 10122005 10.12.2005
3092005 True 03.09.2005 3.09.2005
21005 True 02.10.2005 2.10.05
05.07.05 True 05.07.2005 5.07.05

// Man setzt ein TStringGrid und zwei TLabel auf die Form und erzeugt
// alle Events mittels Doppelklick im Objektinspektor. Dann ergänzt man den Code
// wie hier unten gezeigt.
// Button1 wurde zusätzlich dazu genommen, um zu zeigen, wie mittels der
// Raw-Data eine genaue Addierung erfolgt.


// Variante 1
// Format pro Spalte, Formatierung ist vor Programmstart festgelegt.
// Raw-Data werden in einer Stringliste gehalten.

unit Unit1; 
 
interface 
 
uses 
  Windows, SysUtils, Classes, Forms, StdCtrls, Grids, Controls, Dialogs; 
 
type 
  TForm1 = class(TForm) 
    StringGrid1: TStringGrid; 
    Label1: TLabel; 
    Label2: TLabel;
    Button1: TButton; 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    procedure StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer; 
      const Value: string); 
    procedure StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; 
      var CanSelect: Boolean); 
    procedure Button1Click(Sender: TObject); 
    procedure StringGrid1KeyUp(Sender: TObject; var Key: Word; 
      Shift: TShiftState); 
    procedure StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; 
      Shift: TShiftState; X, Y: Integer); 
  private 
    { Private-Deklarationen } 
  public 
    procedure beiFehler; 
  end; 
 
var 
  Form1: TForm1; 
 
implementation 
 
 
{$R *.DFM} 
 
type 
  ColType = (Num, Dat, Txt); // Zahl,  Datum,  Text 
 
const 
  Spaltenzahl = 5; 
  aoct: array[0..Spaltenzahl - 1] of ColType = 
  (Txt, Txt, Txt, Dat, Num); // Grid hat 5 Spalten; 
 
  WZeichen = '€'; 
  dtm = 'dd.mm.yyyy'; 
  whrg: string = '#,##0.00'; 
 
  ueberwachen = true; 
  formatieren = true; 
  mitZeichen = true; 
 
  fehler: boolean = false; 
 
  merkCol: integer = -1; 
  merkRow: integer = -1; 
 
var 
  ts: TStrings; 
 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  ts := TStringlist.create; 
  ts.add(#1); 
  Label1.Caption := ''; 
  Label2.Caption := ''; 
  with StringGrid1 do begin 
    FixedCols := 1; 
    ColCount := Spaltenzahl; 
    Options := Options + [goEditing]; 
  end; 
end; 
 
procedure TForm1.FormDestroy(Sender: TObject); 
var x, y: integer; 
begin 
  with StringGrid1 do 
    for x := 0 to ColCount - 1 do 
      for y := 0 to RowCount - 1 do 
        Objects[x, y] := nil; 
  ts.free; 
end; 
 
procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol, 
  ARow: Integer; const Value: string); 
var 
  i: integer; 
  n: double; 
  d: TDateTime; 
  V, s: string; 
  procedure anzeige; 
  begin 
    with StringGrid1 do 
      if (ACol = Col) and (ARow = Row) then 
        Label1.Caption := V; 
  end; 
begin 
  with StringGrid1 do begin 
    if not editormode and (ueberwachen or formatieren) then begin 
      V := Value; 
      Objects[ACol, ARow] := nil; 
      anzeige; 
      if (V = '') or not (aoct[ACol] in [Num, Dat]) then exit; 
      try 
        if aoct[ACol] = Num then begin 
          V := stringreplace(stringreplace(V, #32, '', [rfreplaceall]), 
            ThousandSeparator, '', [rfreplaceall]); 
          if mitZeichen then 
            V := stringreplace(V, WZeichen, '', []); 
          i := pos('+', V); 
          if (i = 1) or (i = length(V)) then delete(V, i, 1); 
          i := pos('-', V); 
          if (i = length(V)) then V := '-' + copy(V, 1, length(V) - 1); 
          if (V = DecimalSeparator) or (V = '-') or (V = '') then V := '0'; 
          n := strtofloat(V); 
          V := floattostr(n); 
          anzeige; 
          if formatieren then begin 
            s := formatfloat(whrg, n); 
            if mitZeichen then s := s + #32 + WZeichen; 
            Cells[ACol, ARow] := s; 
          end; 
        end else begin 
          if (pos(DateSeparator, V) = 0) and (pos(TimeSeparator, V) = 0) 
            then begin 
            case length(V) of 
              5, 7: begin 
                  insert(DateSeparator, V, 2); 
                  insert(DateSeparator, V, 5); 
                end; 
              6, 8: begin 
                  insert(DateSeparator, V, 3); 
                  insert(DateSeparator, V, 6); 
                end; 
            end; 
            anzeige; 
          end; 
          d := strtodate(V); 
          if formatieren then 
            Cells[ACol, ARow] := formatdatetime(dtm, d); 
        end; 
        i := ts.indexof(V); 
        if i < 0 then begin 
          ts.add(V); 
          i := ts.count - 1; 
        end; 
        Objects[ACol, ARow] := TObject(i); 
      except 
        beep; 
        Objects[ACol, ARow] := nil; 
        Cells[ACol, ARow] := ''; 
        Label1.Caption := ''; 
        Row := ARow; 
        Col := ACol; 
        fehler := true; 
        Label2.Caption := 'Falsche Eingabe in Zelle ' + 
          inttostr(ACol) + '/' + inttostr(ARow); 
      end; 
    end else begin 
      Label1.Caption := Value; 
      Label2.Caption := ''; 
      fehler := false; 
      merkCol := ACol; 
      merkRow := ARow; 
    end; 
  end; 
end; 
 
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, 
  ARow: Integer; var CanSelect: Boolean); 
var s: string; 
begin 
  with StringGrid1 do begin 
    if editormode then begin 
      editormode := false; 
      StringGrid1SetEditText(self, merkCol, merkRow, Cells[merkCol, merkRow]); 
    end; 
    s := ts[integer(Objects[ACol, ARow])]; 
    if s = #1 then Label1.Caption := Cells[ACol, ARow] 
    else Label1.Caption := s; 
  end; 
end; 
 
procedure TForm1.beiFehler; 
begin 
  with StringGrid1 do 
    if fehler then begin 
      Row := merkRow; 
      Col := merkCol; 
      fehler := false; 
    end; 
end; 
 
procedure TForm1.StringGrid1KeyUp(Sender: TObject; var Key: Word; 
  Shift: TShiftState); 
begin 
  beiFehler; 
end; 
 
procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; 
  Shift: TShiftState; X, Y: Integer); 
begin 
  beiFehler; 
end; 
 
 
 
// genaues Addieren einer Spalte 

procedure TForm1.Button1Click(Sender: TObject); 
var 
  s: string; 
  x: integer; 
  y: extended; 
  spalte: byte; 
begin 
  y := 0; 
  spalte := 4; 
  if (spalte <= high(aoct)) and (aoct[spalte] = Num) then begin 
    with StringGrid1 do begin 
      for x := FixedRows to RowCount - 1 do begin 
        s := ts[integer(Objects[spalte, x])]; 
        if s <> #1 then y := y + strtofloat(s); 
      end; 
    end; 
    Showmessage(Floattostr(y)); 
  end else Showmessage('Keine Zahlenspalte'); 
end; 
 
end. 

// -------------------------------------------------------

// Variante 2
// Format pro Zelle, Formatierung während der Laufzeit.
// Raw-Data werden in einem dynamischen Array gehalten. Diese muss bei
// Änderung des Grids (z.B. Zeilen oder Spalten hizufügen) ebenfalls
// geändert werden!!!
// Die Variable
reagierenBeiFehler legt fest, ob Eingaben, welche dem
// Zellenformat widersprechen, gelöscht oder kommentarlos beibehalten werden.

unit Unit1; 
 
interface 
 
uses 
  Windows, SysUtils, Classes, Forms, StdCtrls, Grids, Controls, Dialogs; 
 
type 
  TForm1 = class(TForm) 
    StringGrid1: TStringGrid; 
    Label1: TLabel; 
    Label2: TLabel; 
    Button1: TButton; 
    Button2: TButton; 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    procedure StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer; 
      const Value: string); 
    procedure StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; 
      var CanSelect: Boolean); 
    procedure StringGrid1KeyUp(Sender: TObject; var Key: Word; 
      Shift: TShiftState); 
    procedure StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; 
      Shift: TShiftState; X, Y: Integer); 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
  private 
    { Private-Deklarationen } 
  public 
    function Zahl(var V: string; ACol, ARow: integer; itg: boolean): boolean; 
    function Datum(var V: string; ACol, ARow: integer): boolean; 
    procedure Gross(var V: string; ACol, ARow: integer); 
    procedure beiFehler; 
    procedure BereichAnpassen(BegCol, EndCol, BegRow, EndRow: integer); 
  end; 
 
var 
  Form1: TForm1; 
 
implementation 
 
 
{$R *.DFM} 
 
type 
  CellType = (Txt, Upcs, Num, Intg, Dat); 
  //  Unformatiert, Großbuchstaben, Gleitkommazahl, Ganzzahl, Datum 
 
  fRecord = record 
    Typ: CellType; 
    Text, Frmt: string; 
    WZeichen: Char; 
  end; 
 
const 
  Spaltenzahl = 5; 
 
  merkCol: integer = -1; 
  merkRow: integer = -1; 
 
  falsch: boolean = false; 
  reagierenBeiFehler: boolean = true; 
 
var 
  aofr: array of array of fRecord; 
 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  Label1.Caption := ''; 
  Label2.Caption := ''; 
  with StringGrid1 do begin 
    FixedCols := 1; 
    ColCount := Spaltenzahl; 
    Options := Options + [goEditing]; 
    setlength(aofr, ColCount, RowCount); 
  end; 
end; 
 
procedure TForm1.FormDestroy(Sender: TObject); 
begin 
  aofr := nil; 
end; 
 
procedure TForm1.Gross(var V: string; ACol, ARow: integer); 
begin 
  with stringgrid1 do begin 
    aofr[ACol, ARow].Text := V; 
    Cells[ACol, ARow] := AnsiUppercase(V); 
  end; 
end; 
 
function TForm1.Zahl(var V: string; ACol, ARow: integer; itg: boolean): boolean; 
var 
  i, z: integer; 
  n: extended; 
  s: string; 
begin 
  with stringgrid1 do begin 
    try 
      V := stringreplace(stringreplace(V, #32, '', [rfreplaceall]), 
        ThousandSeparator, '', [rfreplaceall]); 
      if aofr[ACol, ARow].WZeichen <> #0 then 
        V := stringreplace(V, aofr[ACol, ARow].WZeichen, '', []); 
      i := pos('+', V); 
      if (i = 1) or (i = length(V)) then delete(V, i, 1); 
      i := pos('-', V); 
      if (i = length(V)) then V := '-' + copy(V, 1, length(V) - 1); 
      if (V = DecimalSeparator) and not itg or (V = '-') or (V = '') 
        then V := '0'; 
      if itg then z := strtoint(V) else 
        n := strtofloat(V); 
      if itg then 
        V := inttostr(z) else 
        V := floattostr(n); 
      if aofr[ACol, ARow].Frmt <> '' then begin 
        if itg then n := z; 
        s := formatfloat(aofr[ACol, ARow].Frmt, n); 
        if aofr[ACol, ARow].WZeichen <> #0 then s := s + #32 + 
          aofr[ACol, ARow].WZeichen; 
        Cells[ACol, ARow] := s; 
      end; 
    except 
      result := false; 
      exit; 
    end; 
    result := true; 
  end; 
end; 
 
function TForm1.Datum(var V: string; ACol, ARow: integer): boolean; 
var 
  d: TDateTime; 
begin 
  with stringgrid1 do begin 
    try 
      if (pos(DateSeparator, V) = 0) and (pos(TimeSeparator, V) = 0) 
        then begin 
        case length(V) of 
          5, 7: begin 
              insert(DateSeparator, V, 2); 
              insert(DateSeparator, V, 5); 
            end; 
          6, 8: begin 
              insert(DateSeparator, V, 3); 
              insert(DateSeparator, V, 6); 
            end; 
        end; 
      end; 
      d := strtodate(V); 
      if aofr[ACol, ARow].Frmt <> '' then 
        Cells[ACol, ARow] := formatdatetime(aofr[ACol, ARow].Frmt, d); 
    except 
      result := false; 
      exit; 
    end; 
    result := true; 
  end; 
end; 
 
procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol, 
  ARow: Integer; const Value: string); 
var 
  V: string; 
  procedure anzeige; 
  begin 
    with stringgrid1 do 
      if (ACol = Col) and (ARow = Row) then 
        Label1.Caption := V; 
  end; 
  procedure fehler; 
  begin 
    with stringgrid1 do begin 
      beep; 
      Row := ARow; 
      Col := ACol; 
      aofr[ACol, ARow].Text := ''; 
      Cells[ACol, ARow] := ''; 
      Label1.Caption := ''; 
      falsch := true; 
      Label2.Caption := 'Falsche Eingabe in Zelle ' + inttostr(ACol) + 
        '/' + inttostr(ARow); ; 
    end; 
  end; 
begin 
  with StringGrid1 do begin 
    if not editormode then begin 
      V := Value; 
      anzeige; 
      if (Value = '') then begin 
        aofr[ACol, ARow].Text := ''; 
        exit; 
      end; 
      case aofr[ACol, ARow].Typ of 
        Intg: if not Zahl(V, ACol, ARow, true) then begin 
            if reagierenBeiFehler then begin 
              fehler; 
              exit; 
            end else aofr[ACol, ARow].Text := Value; 
          end else aofr[ACol, ARow].Text := V; 
        Num: if not Zahl(V, ACol, ARow, false) then begin 
            if reagierenBeiFehler then begin 
              fehler; 
              exit; 
            end else aofr[ACol, ARow].Text := Value; 
          end else aofr[ACol, ARow].Text := V; 
        Dat: if not Datum(V, ACol, ARow) then begin 
            if reagierenBeiFehler then begin 
              fehler; 
              exit; 
            end else aofr[ACol, ARow].Text := Value; 
          end else aofr[ACol, ARow].Text := V; 
        Upcs: Gross(V, ACol, ARow); 
      else aofr[ACol, ARow].Text := V; 
      end; 
      anzeige; 
    end else begin 
      Label1.Caption := Value; 
      Label2.Caption := ''; 
      falsch := false; 
      merkCol := ACol; 
      merkRow := ARow; 
    end; 
  end; 
end; 
 
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, 
  ARow: Integer; var CanSelect: Boolean); 
begin 
  with StringGrid1 do begin 
    if editormode then begin 
      editormode := false; 
      StringGrid1SetEditText(Form1, merkCol, merkRow, Cells[merkCol, merkRow]); 
    end; 
    Label1.Caption := aofr[ACol, ARow].Text; 
  end; 
end; 
 
procedure TForm1.BereichAnpassen(BegCol, EndCol, BegRow, EndRow: integer); 
var 
  x, y, z: integer; 
  s: string; 
begin 
  z := 0; 
  with StringGrid1 do begin 
    editormode := false; 
    for x := BegCol to EndCol do 
      for y := BegRow to EndRow do begin 
        s := aofr[x, y].Text; 
        if s <> '' then 
          case aofr[x, y].Typ of 
            Upcs: Gross(aofr[x, y].Text, x, y); 
            Num: if not Zahl(aofr[x, y].Text, x, y, false) then 
                if reagierenBeiFehler then begin 
                  aofr[x, y].Text := ''; 
                  Cells[x, y] := ''; 
                  inc(z); 
                end else aofr[x, y].Text := s; 
            Intg: if not Zahl(aofr[x, y].Text, x, y, true) then 
                if reagierenBeiFehler then begin 
                  aofr[x, y].Text := ''; 
                  Cells[x, y] := ''; 
                  inc(z); 
                end else aofr[x, y].Text := s; 
            Dat: if not Datum(aofr[x, y].Text, x, y) then 
                if reagierenBeiFehler then begin 
                  aofr[x, y].Text := ''; 
                  Cells[x, y] := ''; 
                  inc(z); 
                end else aofr[x, y].Text := s; 
          else Cells[x, y] := aofr[x, y].Text; 
          end; 
      end; 
    Label1.Caption := aofr[Col, Row].Text; 
    if z > 0 then begin 
      beep; 
      Label2.Caption := inttostr(z) + ' Zellen mussten eliminiert werden'; 
    end else 
      if not falsch then Label2.Caption := ''; 
  end; 
  falsch := false; 
end; 
 
procedure TForm1.beiFehler; 
begin 
  with StringGrid1 do 
    if falsch then begin 
      Row := merkRow; 
      Col := merkCol; 
      falsch := false; 
    end; 
end; 
 
procedure TForm1.StringGrid1KeyUp(Sender: TObject; var Key: Word; 
  Shift: TShiftState); 
begin 
  beiFehler; 
end; 
 
procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; 
  Shift: TShiftState; X, Y: Integer); 
begin 
  beiFehler; 
end; 
 
 
 
// Beispiel der Formatzuweisung für eine einzelne Zelle 
 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
  aofr[1, 2].Typ := Dat; 
  aofr[1, 2].Frmt := 'dd.mm.yyyy'; 
  if StringGrid1.Cells[1, 1] <> '' then BereichAnpassen(1, 1, 2, 2); 
end; 



// ein Beispiel, wie man ganzen Bereiche (z.B. Spalten) 
// Formatierungen zuweist 
 
procedure TForm1.Button2Click(Sender: TObject); 
var 
  x: integer; 
begin 
  with StringGrid1 do begin 
    for x := FixedRows to RowCount - 1 do begin 
      aofr[1, x].Typ := Num; 
      aofr[1, x].Frmt := '#,##0.00'; 
      aofr[1, x].WZeichen := '€'; 
 
      aofr[2, x].Typ := Intg; 
      aofr[2, x].Frmt := '0';
      aofr[2, x].WZeichen := #0;  
 
      aofr[3, x].Typ := Dat; 
      aofr[3, x].Frmt := 'd.m.yy'; 
 
      aofr[4, x].Typ := Upcs; 
    end; 
    BereichAnpassen(1, 4, FixedRows, RowCount - 1); 
  end; 
end;
 
end. 



Zugriffe seit 6.9.2001 auf Delphi-Ecke