Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi StringGrid nach Kriterien sortieren (https://www.delphipraxis.net/114635-stringgrid-nach-kriterien-sortieren.html)

Subsidenz 28. Mai 2008 15:17


StringGrid nach Kriterien sortieren
 
Einen wunderschönen guten Tag,

Ich habe mich in letzter Zeit etwas näher mit StringGrid beschäftigt und wollte gerne Zeilen sortieren, doch ich habe noch keine Ahnung wie das gehen soll.

Zu dem Problem:
Ich habe eine TComboBoxEx in der ich verschiedene Sortierkriterien auswählen kann.
In meiner StringGrid stehen nun Werte. Die fixierten Zellen haben zum Beispiel den Inhalt:'Titel' oder 'Interpret'.
Neben einem Titel-Wert (also in der gleichen Reihe) steht ein Wert unter 'Interpret'. Jetzt zum Knackpunkt der meine geistige Blockade ist: Wenn ich in meiner TComboBoxEx zum Beispiel auswähle, dass ich nach Titeln sortieren möchte, soll er die Spalte 1 also in der Spalte wo alle Titel stehen sortieren, ABER gleichzeitig die zugewiesenen Werte sich merken und zu dem jeweiligen Titel wieder rechts einfügen.

Zu dem Problem ein Screenshot:
http://www.bilder-space.de/show.php?...LFS0XonD4G.JPG

Ich hoffe ich habe mein Problem verständlich genug ausgedrückt, ansonsten fragt mich einfach.

Mit freundlichen Grüßen Subsidenz

Hansa 28. Mai 2008 15:24

Re: StringGrid nach Kriterien sortieren
 
Die Reklame verdeckt sofort das ganze Bild. Kann man keinem zumuten. :twisted: Deshalb : keine Antwort von mir.

mkinzler 28. Mai 2008 15:27

Re: StringGrid nach Kriterien sortieren
 
Häng den Screenshot doch als als Anhang an den Beitrag.

Subsidenz 28. Mai 2008 15:30

Re: StringGrid nach Kriterien sortieren
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von mkinzler
Häng den Screenshot doch als als Anhang an den Beitrag.

Wird gemacht 8)

QuickAndDirty 28. Mai 2008 15:42

Re: StringGrid nach Kriterien sortieren
 
Es gibt ein TStrings das Grid1.Columns[0] heist.
Das kannst du mit in eine Stringliste kopieren (Verwende tstrings.AddObject() )
bei TStringlist.objects[i] hinterlegst du einen eine Kopie der Zeile (@Record, Objekt, Pchar was auch immer )

Nach erzeugen der Stringlist müstest du sorted auf True stellen.
oder nach dem kopieren tStringlist.Sort aufrufen.

Jetzt kannst du aus der Stringlist heraus das Gitter neu aufbauen.

Die Stringlist benutzt ein auf Listen optimiertes Quicksort.

Subsidenz 28. Mai 2008 15:45

Re: StringGrid nach Kriterien sortieren
 
Zitat:

Zitat von QuickAndDirty
Es gibt ein TStrings das Grid1.Columns[0] heist.
Das kannst du mit in eine Stringliste kopieren (Verwende tstrings.AddObject() )
bei TStringlist.objects[i] hinterlegst du einen eine Kopie der Zeile (@Record, Objekt, Pchar was auch immer )

Nach erzeugen der Stringlist müstest du sorted auf True stellen.
oder nach dem kopieren tStringlist.Sort aufrufen.

Jetzt kannst du aus der Stringlist heraus das Gitter neu aufbauen.

Die Stringlist benutzt ein auf Listen optimiertes Quicksort.

Klingt schonmal gut, aber ich weiß nicht genau wie ich die Schleife mit record basteln sollte.
Hast du da einen Ansatz für mich? (Record Strukturen hab ich nicht so drauf :-D )

MFG Subsidenz

shmia 28. Mai 2008 17:06

Re: StringGrid nach Kriterien sortieren
 
Entweder du nimmst eine Komponente, die dein StringGrid sortiert:
TSortAString Grid v.1.2.0 FWS 10 k 18 Mar 1998
By Johan Godfried. Sort a StringGrid (or any descendant) anyway you like, Horizontal / Vertical, Ascending / Descending, Character / Numeric / Date. Single column sort key only at this time. This is not grid, but for grid.
http://www.torry.net/vcl/grids/stringgrids/sasg.zip

oder du nimmst gleich ein erweitertes Stringgrid, dass die Sortierfunktionalität schon eingebaut hat:
z.B. TSortGrid v2.0
http://www.torry.net/pages.php?id=114

Ich verwende z.B. das XStringGrid und bin ganz zufrieden damit. (sortieren kann es auch)

Subsidenz 28. Mai 2008 19:13

Re: StringGrid nach Kriterien sortieren
 
Zitat:

Zitat von shmia
Entweder du nimmst eine Komponente, die dein StringGrid sortiert:
TSortAString Grid v.1.2.0 FWS 10 k 18 Mar 1998
By Johan Godfried. Sort a StringGrid (or any descendant) anyway you like, Horizontal / Vertical, Ascending / Descending, Character / Numeric / Date. Single column sort key only at this time. This is not grid, but for grid.
http://www.torry.net/vcl/grids/stringgrids/sasg.zip

oder du nimmst gleich ein erweitertes Stringgrid, dass die Sortierfunktionalität schon eingebaut hat:
z.B. TSortGrid v2.0
http://www.torry.net/pages.php?id=114

Ich verwende z.B. das XStringGrid und bin ganz zufrieden damit. (sortieren kann es auch)

Das sind sehr komplexe Codes, wobei ich ehrlich sein muss ... ich versteh nicht viel davon. :(
Ich möchte eigntlich nur, dass mein Programm, wenn ich den entsprechenden Eintrag in der ComboBoxEx ausgewählt habe, alle Einträge nach diesem Kriterium sortiert.

Kann mir da einer einen Code-Schnipsel geben? Oder zumindest entwickeln, den ich auf mein Programm anwenden kann?

MFG Subsidenz

Subsidenz 28. Mai 2008 19:27

Re: StringGrid nach Kriterien sortieren
 
Liste der Anhänge anzeigen (Anzahl: 2)
Vielleicht hilft es euch weiter wenn ich mal mein (fast) fertiges Programm uploade. Dann könnt ihr sehen wie das ungefähr funktionieren sollte. (Nur nach dem Prinzip)

Der Quellcode für das komplette Programm:

Delphi-Quellcode:
unit Seite1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, StdCtrls, jpeg, ExtCtrls, ComCtrls, TabNotBk,
  Buttons, iniFiles, Printers;

type
  TForm1 = class(TForm)
    Hintergrund: TImage;
    ueberschrift: TLabel;
    eigenschaften: TGroupBox;
    ltitel: TLabel;
    tinterpret: TLabel;
    tgroesse: TLabel;
    tlaenge: TLabel;
    titel: TEdit;
    interpret: TEdit;
    album: TEdit;
    groesse: TEdit;
    laenge: TEdit;
    grid: TStringGrid;
    operatoren: TGroupBox;
    ein: TButton;
    close: TBitBtn;
    spei: TButton;
    loeschen: TButton;
    laden: TButton;
    feld: TEdit;
    Label1: TLabel;
    talbum: TLabel;
    sort: TComboBoxEx;
    such: TEdit;
    Suchen: TButton;
    drucken: TButton;
    procedure sortChange(Sender: TObject);
    procedure druckenClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure einClick(Sender: TObject);
    procedure speiClick(Sender: TObject);
    procedure ladenClick(Sender: TObject);
    procedure gridClick(Sender: TObject);
    procedure feldChange(Sender: TObject);
    procedure loeschenClick(Sender: TObject);
    procedure SuchenClick(Sender: TObject);
    procedure suchClick(Sender: TObject);
    procedure GridCanSort(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1        : TForm1;
  ini         : TiniFile;
  a,b,n,i,j,l : Integer;
  t,z         : String;
  sl,f1        : TStringlist;
  ar          : array[0..1000] of string;

implementation


{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 grid.Cells[0,0]:='Titel';
 grid.Cells[1,0]:='Interpret';
 grid.Cells[2,0]:='Album';
 grid.Cells[3,0]:='Größe in mB';
 grid.Cells[4,0]:='Länge in min';
 sort.Items.Add('Titel');
 sort.Items.Add('Interpret');
 sort.Items.Add('Album');
 sort.Items.Add('Größe');
 sort.Items.Add('Länge');
end;


procedure TForm1.einClick(Sender: TObject);
begin
 if grid.Cells[0,grid.RowCount-1]>'' then
  begin
   grid.RowCount:=grid.RowCount+1;
   a:=grid.RowCount-1;
   grid.Cells[0,a]:=titel.Text;
   grid.Cells[1,a]:=interpret.Text;
   grid.Cells[2,a]:=album.Text;
   grid.Cells[3,a]:=groesse.Text;
   grid.Cells[4,a]:=laenge.Text;
   titel.SetFocus;
  end
 else
  begin
   a:=grid.RowCount-1;
   grid.Cells[0,a]:=titel.Text;
   grid.Cells[1,a]:=interpret.Text;
   grid.Cells[2,a]:=album.Text;
   grid.Cells[3,a]:=groesse.Text;
   grid.Cells[4,a]:=laenge.Text;
   grid.RowCount:=a+1;
   titel.SetFocus;
  end
end;

procedure TForm1.speiClick(Sender: TObject);
begin
a:=1;
n:=0;
b:=grid.RowCount-2;
t:='t';
for n:=0 to 4 do
 ini.EraseSection(t+IntToStr(n));
for a:=1 to b+1 do
 for n:=0 to 4 do
   ini.WriteString(t+IntToStr(n), IntToStr(a), grid.Cells[n,a]);
ShowMessage('Speichervorgang war erfolgreich!');
end;

procedure TForm1.ladenClick(Sender: TObject);
begin
a:=1;
n:=0;
t:='t';
 begin
  sl := TStringList.Create;
  try
    Ini.ReadSectionValues(t+IntToStr(0),sl);
    b := sl.Count;
    finally
    FreeAndNil(sl);
  end;
grid.RowCount:=b+1;
 for a:=1 to b do
  for n:=0 to 4 do
   grid.Cells[n,a]:=ini.ReadString(t+IntToStr(n), IntToStr(a), '');
end;
ShowMessage('Ladevorgang war erfolgreich!');
end;

procedure TForm1.GridCanSort(Sender: TObject);
var aCol: Integer;
  dosort: Boolean;
begin
  DoSort := ACol > 0;
end;

procedure TForm1.gridClick(Sender: TObject);
begin
feld.Text:=Grid.Cells[Grid.col, Grid.Row];
if (grid.Col=0) or (grid.Col=1) or (grid.Col=2)
 or (grid.Col=3) or (grid.Col=4) then
  GridCanSort;

end;

procedure TForm1.feldChange(Sender: TObject);
begin
 grid.EditorMode:=true;
 Grid.Cells[Grid.col, Grid.Row]:=feld.Text;
end;

procedure TForm1.loeschenClick(Sender: TObject);
begin
a:=0;
b:=0;
if grid.RowCount>2 then
 begin
  for b:=0 to grid.RowCount-2 do
   for a:=0 to 4 do
    grid.Cells[Grid.Col+a, Grid.Row+b]:=grid.Cells[Grid.Col+a, Grid.Row+1+b];
    grid.RowCount:=grid.RowCount-1;
 end
else
 for a:=0 to 4 do
  grid.Cells[0+a,1]:='';
end;

procedure TForm1.SuchenClick(Sender: TObject);
begin
i:=0;
j:=0;
for i:=0 to 5 do
 for j:=0 to grid.RowCount-1 do
  if grid.Cells[i,j]=such.Text then
   begin
    grid.Col:=i;
    grid.Row:=j;
    grid.SetFocus;
   end;
if feld.Text=such.Text then
  such.Text:='Gefunden!' else
  such.Text:='kein Eintrag';
such.SetFocus;
end;

procedure TForm1.suchClick(Sender: TObject);
begin
such.SelectAll;
end;


(*  Druckalgorithmus von capo (Benutzer von Delphi-PRAXiS Forum)
Web-Link: [url]http://www.delphipraxis.net/topic113547.html[/url] *)

procedure PrintStringGrid(Grid: TStringGrid; Title: string;
  Orientation: TPrinterOrientation);
var
  P, I, J, YPos, XPos, HorzSize, VertSize: Integer;
  AnzSeiten, Seite, Zeilen, HeaderSize, FooterSize, ZeilenSize, FontHeight: Integer;
  mmx, mmy: Extended;
  Footer: string;
begin
  //Kopfzeile, Fußzeile, Zeilenabstand, Schriftgröße festlegen
  HeaderSize := 100;
  FooterSize := 200;
  ZeilenSize := 50;
  FontHeight := 31;
  //Printer initializieren
  Printer.Orientation := Orientation;
  Printer.Title := Title;
  Printer.BeginDoc;
  //Druck auf mm einstellen
  mmx := GetDeviceCaps(Printer.Canvas.Handle, PHYSICALWIDTH) /
    GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSX) * 25.4;
  mmy := GetDeviceCaps(Printer.Canvas.Handle, PHYSICALHEIGHT) /
    GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY) * 25.4;

  VertSize := Trunc(mmy) * 10;
  HorzSize := Trunc(mmx) * 10;
  SetMapMode(Printer.Canvas.Handle, MM_LOMETRIC);

  //Zeilenanzahl festlegen
  Zeilen := (VertSize - HeaderSize - FooterSize) div ZeilenSize;
  //Seitenanzahl ermitteln
  if Grid.RowCount mod Zeilen <> 0 then
    AnzSeiten := Grid.RowCount div Zeilen + 1
  else
    AnzSeiten := Grid.RowCount div Zeilen;

  Seite := 1;
  //Grid Drucken
  for P := 1 to AnzSeiten do
  begin
    //Kopfzeile
    Printer.Canvas.Font.Height := 50;
    Printer.Canvas.TextOut((HorzSize div 2 - (Printer.Canvas.TextWidth(Title) div 2)),
      - 20,Title);
    Printer.Canvas.Pen.Width := 3;
    Printer.Canvas.MoveTo(0, - HeaderSize);
    Printer.Canvas.LineTo(HorzSize, - HeaderSize);
    //Fußzeile
    Printer.Canvas.Pen.Width := 0;
     Printer.Canvas.Pen.Style := psclear;
    Printer.Canvas.MoveTo(0, - VertSize + FooterSize);
    Printer.Canvas.LineTo(HorzSize, - VertSize + FooterSize);
    Printer.Canvas.Font.Height := 36;
    Footer := 'Seite: ' + IntToStr(Seite) + ' von ' + IntToStr(AnzSeiten);
    Printer.Canvas.TextOut((HorzSize div 2 - (Printer.Canvas.TextWidth(Footer) div 2)),
      - VertSize + 150,Footer);
    //Zeilen drucken
    Printer.Canvas.Font.Height := FontHeight;
    YPos := HeaderSize + 50;
    for I := 1 to Zeilen do
    begin
      if Grid.RowCount >= I + (Seite - 1) * Zeilen then
      begin
        XPos := 280;
        for J := 0 to Grid.ColCount - 1 do
        begin
          Printer.Canvas.TextOut(XPos, - YPos,
            Grid.Cells[J, I + (Seite - 1) * Zeilen - 1]);
          XPos := XPos + Grid.ColWidths[J] * 3;
        end;
        YPos := YPos + ZeilenSize;
      end;
    end;
    //Seite hinzufügen
    Inc(Seite);
    if Seite <= AnzSeiten then Printer.NewPage;
  end;
  Printer.EndDoc;
end;
// <-- Print Procedure


procedure TForm1.druckenClick(Sender: TObject);
var i:integer ;
begin
i:=0;
if i>0 then
begin
grid.RowCount:=grid.rowcount+1;
end;
i:=i+1;
PrintStringGrid(grid, 'Musik-Datenbank', poPortrait);
end;

procedure TForm1.sortChange(Sender: TObject);
begin
if sort.ItemIndex=1 then
end;

initialization
 ini := TIniFile.Create(ExtractFilePath( ParamStr(0))+'data.ini');
finalization
  ini.Free;
end.


MFG Subsidenz

PS: Wäre nett wenn einer sich mit meinem Problem befassen könnte. Ich habe da nicht so mein Talent.
Unbedingt das Programm und die Auslagerungsdatei in einen Ordner packen.

Hansa 28. Mai 2008 19:32

Re: StringGrid nach Kriterien sortieren
 
Warum der Umweg über die Combobox ? Ich würde über Klick auf Titelleiste sortieren lassen. Wie das bei einzeiligen Stringgrids geht hat Quickanddirty angedeutet. Mit einzeilig meine ich pro zusammenhängender Wert. Manchmal braucht man mehr Zeilen, um was gut darzustellen.

Subsidenz 28. Mai 2008 20:39

Re: StringGrid nach Kriterien sortieren
 
Zitat:

Zitat von Hansa
Warum der Umweg über die Combobox ? Ich würde über Klick auf Titelleiste sortieren lassen. Wie das bei einzeiligen Stringgrids geht hat Quickanddirty angedeutet. Mit einzeilig meine ich pro zusammenhängender Wert. Manchmal braucht man mehr Zeilen, um was gut darzustellen.

Ja das ginge auch aber mein Programmierverständnis geht soweit, dass ich was mit Code-Schnipseln in vereinfachter Form anfangen kann. Ich bräuchte einen Anfang. :wink:

Hansa 28. Mai 2008 21:07

Re: StringGrid nach Kriterien sortieren
 
Die Spalten des Stringgrids sind TStrings. Das ist nicht weit von der TStringlist weg und die hat die Methode Sort. Genau das ist der Ansatz. Pseudocode :
Delphi-Quellcode:
MyStringList.Items := MyStringGrid.Cols [x];
MyStringList.Sort
..und wieder zurück ins Stringgrid
Jetzt ist wohl das Hauptproblem, dass die Zeilen ja wohl zusammenbleiben müssen und dann nützt die sortierte Spalte alleine auch nichts ? Tja, dann wirds schon nicht mehr trivial. Viele kennen nicht mal die Objects-Eigenschaft. Mir fällt tatsächlich dafür aber nur die Objects-Eigenschaft ein. Du packst die Zellen jeder ZEILE mit AddObject in ein TObject (ähnlich wie record zu behandeln). Dieses muss an der Stringliste (AddObject von TStringList -> F1) dranpappen. Jetzt wird diese sortiert und das zu jedem Stringlist-Item gehörende Objekt (quasi die vorherige Zeile) ist mitsortiert !! Das Objekt muss dann nur wieder in das Stringgrid hinein. Du kapito ? :shock: Mann ist das einfach. :mrgreen: Ich muss gerade ein Stringgrid sortieren, bei dem das, was zusammengehört auf 1-5 Zeilen verteilt ist (in EINEM Stringgrid !). Da mache ich das ähnlich wegen der variablen Zeilen ist allerdings sogar TObjectList nötig. Bin schon 2 Wochen dran und immer noch nicht fertig damit. :shock:

Subsidenz 28. Mai 2008 21:52

Re: StringGrid nach Kriterien sortieren
 
Zitat:

Zitat von Hansa
Die Spalten des Stringgrids sind TStrings. Das ist nicht weit von der TStringlist weg und die hat die Methode Sort. Genau das ist der Ansatz. Pseudocode :
Delphi-Quellcode:
MyStringList.Items := MyStringGrid.Cols [x];
MyStringList.Sort
..und wieder zurück ins Stringgrid
Jetzt ist wohl das Hauptproblem, dass die Zeilen ja wohl zusammenbleiben müssen und dann nützt die sortierte Spalte alleine auch nichts ? Tja, dann wirds schon nicht mehr trivial. Viele kennen nicht mal die Objects-Eigenschaft. Mir fällt tatsächlich dafür aber nur die Objects-Eigenschaft ein. Du packst die Zellen jeder ZEILE mit AddObject in ein TObject (ähnlich wie record zu behandeln). Dieses muss an der Stringliste (AddObject von TStringList -> F1) dranpappen. Jetzt wird diese sortiert und das zu jedem Stringlist-Item gehörende Objekt (quasi die vorherige Zeile) ist mitsortiert !! Das Objekt muss dann nur wieder in das Stringgrid hinein. Du kapito ? :shock: Mann ist das einfach. :mrgreen: Ich muss gerade ein Stringgrid sortieren, bei dem das, was zusammengehört auf 1-5 Zeilen verteilt ist (in EINEM Stringgrid !). Da mache ich das ähnlich wegen der variablen Zeilen ist allerdings sogar TObjectList nötig. Bin schon 2 Wochen dran und immer noch nicht fertig damit. :shock:

Ja ich glaube das Licht in meinem Hirn wird schon heller :mrgreen: . So langsam komm ich glaub ich dahinter. Ich versuchs einfach mal nach deiner Idee. Danke erstmal bis dahin. Wenn ich die Lösung hab post ich die mal.

MFG Subsidenz

grenzgaenger 28. Mai 2008 21:54

Re: StringGrid nach Kriterien sortieren
 
guckste hier: Hier im Forum suchenstringgrid sortieren

Subsidenz 15. Jun 2008 13:50

Re: StringGrid nach Kriterien sortieren
 
So nach langem Rumprobieren und Suchen hab ich es endlich geschafft.

Delphi-Quellcode:
procedure SortStringGrid(var GenStrGrid: TStringGrid; ThatCol: Integer);
const
  TheSeparator = '@';
var
  CountItem, I, J, K, ThePosition: integer;
  MyList: TStringList;
  MyString, TempString: string;
begin
  CountItem := GenStrGrid.RowCount;
  MyList       := TStringList.Create;
  MyList.Sorted := False;
  try
    begin
      for I := 1 to (CountItem - 1) do
        MyList.Add(GenStrGrid.Rows[I].Strings[ThatCol] + TheSeparator +
        GenStrGrid.Rows[I].Text);
        Mylist.Sort;
      for K := 1 to Mylist.Count do
       begin
        MyString := MyList.Strings[(K - 1)];
        ThePosition := Pos(TheSeparator, MyString);
        TempString := '';
        TempString := Copy(MyString, (ThePosition + 1), Length(MyString));
        MyList.Strings[(K - 1)] := '';
        MyList.Strings[(K - 1)] := TempString;
       end;
      for J := 1 to (CountItem - 1) do
        GenStrGrid.Rows[J].Text := MyList.Strings[(J - 1)];
      end;
  finally
    MyList.Free;
  end;
end;

procedure TForm1.exChange(Sender: TObject);
begin
SortStringGrid(grid, ex.ItemIndex)
end;
Die Lösung ist eigentlich ganz einfach, nur muss man erst mal darauf kommen. :P

MFG Subsidenz


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