Autor Beitrag
crowley
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 406

Win XP, Win Vista, Mandriva, Ubuntu
Delphi 4-8, Delphi 2006, Delphi 2007
BeitragVerfasst: Do 15.06.06 17:40 
Hallihallo ;)

Ich lasse mir die Daten eines TClientDataSets in einem TDBGrid anzeigen. Die Sortierung der Daten erfolgt über ein persistentes IndexDef- Objekt, dass - je nachdem welche(r) Spaltentitel angeklickt wurden - modifiziert wird.Das ganze funktioniert wirklich wunderprächtig und auch genauso wie es soll.
Jetzt habe ich aber folgendes Problem:
Ich habe eine Spalte mit Boolean-Werten, die ich in meinem TDBGrid mittels Checkboxen anzeigen lasse. Auch hier funktioniert diese Sortierung seeeeeehr gut. Leider eigentlich zu gut, denn wenn ich einen Wert ändere, wird der Datensatz einmal quer durch das ganze Grid verschoben. Wenn man ausreichend Datensätze im Grid drin stehen hat, wird einem förmlich schwindelig ;)
Mein erster Plan war, im OnBeforeEdit des ClientDataset zu prüfen, ob dieses Boolean-Feld mit im Index enthalten ist und wenn ja, dann den IndexName auf 'DEFAULT_ORDER' zu setzen, schlägt fehl. Denn der stellt die komplette Sortierung auf den Kopf (bzw. stellt die ursprüngliche Sortierung wieder her). In diesem Fall hilft mir nicht einmal ein GetBookmark und GotoBookmark ... denn mein zu editierender Datensatz liegt dann im Zweifelsfall ganz wo anders.
Was ich nun haben möchte, ist, dass wenn der Datensatz geändert wird, die bisherige Sortierung erhalten bleibt... aber keine weitere Sortierung (oder Neuordnung oder wie man das nun auch nennen mag) mehr stattfindet...
Ich möchte dann die Sortierung irgendwann neu anstossen, indem ich wieder auf den Spaltentitel klicke.

Hat da jemand eine Idee? Bin da doch gerade reichlich am verzweifeln... *seufz*

C.
crowley Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 406

Win XP, Win Vista, Mandriva, Ubuntu
Delphi 4-8, Delphi 2006, Delphi 2007
BeitragVerfasst: Fr 16.06.06 08:21 
ach jaaaa... ich will das ganze als Funktionalität in einer von TDBGrid abgeleiteten Klasse integrieren/anbieten.

Ein anderer Plan von mir war, eine Art Zeilennummer (RowNum/RecNo) mitzuführen, aber bei einer erneuten Sortierung/Indizierung des ClientDataset bleiben diese Nummern ja dennoch gleich... bzw. ich habe kein passendes Ereignis gefunden, diese zu updaten (OnCalcFields wird nicht ausgelöst dabei...).

Hat jemand eine Idee? Vielen Dank schon mal im Voraus

C.
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 16.06.06 08:44 
Hallo Crowley,
passiert die Umsortierung während der Datensatz im Edit-Modus ist oder nach dem Post?
crowley Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 406

Win XP, Win Vista, Mandriva, Ubuntu
Delphi 4-8, Delphi 2006, Delphi 2007
BeitragVerfasst: Fr 16.06.06 09:14 
also der herkömmliche weg ist, wenn ich meine sortierungsspalte auch die editierte spalte ist:

ausblenden Delphi-Quelltext
1:
2:
3:
dataset.edit;
dataset.fieldbyname('bool_feld').AsBoolean := Value;
dataset.post;


-> Datensatz wird aufgrund von Index durch's komplette Grid verschoben.

jetzt mache ich folgendes:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
beforeedit:
  wenn SortCol = ToBeEditedCol dann
    dataset.indexname = '' oder 'DEFAULT_ORDER' (oder hoffentlich bald was brauchbares :roll: )

dataset.edit;
dataset.fieldbyname('bool_feld').AsBoolean := Value;
dataset.post;


-> Leider wird nun durch das Setzen von IndexName sofort die Reihenfolge der Datensätze durcheinander geworfen (bzw. auf die ganz zu Anfang verwendete Sortierung zurückgesetzt). Das verwendete DBGrid bekommt diese Änderung allerdings nicht einmal mit und ändert stumpf den Wert in Beispiel-Row 8... ganz gleich ob das immer noch derselbe Datensatz ist oder nicht...

Moderiert von user profile iconjasocul: Quote-Tags durch Delphi-Tags ersetzt
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 16.06.06 09:26 
Schonmal folgendes probiert?
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
dataset.edit;
dataset.fieldbyname('bool_feld').AsBoolean := Value;
dataset.DisableControls;
dataset.post;
dataset.EnableControls;
crowley Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 406

Win XP, Win Vista, Mandriva, Ubuntu
Delphi 4-8, Delphi 2006, Delphi 2007
BeitragVerfasst: Fr 16.06.06 09:46 
ja... allerdings ohne erfolg... das DisableControls/EnableControls sperrt die angehängten Controls, die interne Indizierung/Sortierung wird davon aber nicht beeinflußt...
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 16.06.06 10:27 
Da wirst du wohl viel Arbeit reinstecken müssen.
Ein TDBGRid wird immer so reagieren. Eigentlich reagiert nicht das TDBGrid, sondern dein TClientDataSet. Ich habe mich jetzt nicht intensiv mit den Interna beschäftigt, aber IMHO ist es so, dass jedes Post die Daten an die Datenbank schickt und die Daten automatisch richtig einsortiert. Egal, was du mit deinem TIndexDef, IndexName, etc. machst, es wird immer so reagieren, wie du es beschrieben hast.
Du wirst dir dein DBGrid umschreiben müssen. Und zwar so, dass es nicht auf die Sortierung des ClientDataSet reagiert. Oder zumindest nur dann, wenn du es willst. Es kommt also auf das Zusammespiel des ClientDataSet und des DBGrid an. Entsprechend kannst du natürlich auch ein neues ClientDataSet schreiben, aber du wolltest ja ein neues TDBGrid machen.

Einen "einfachen Trick" kenne ich da nicht. Aber dein jetziger Weg führt IMHO nicht zur Lösung.
crowley Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 406

Win XP, Win Vista, Mandriva, Ubuntu
Delphi 4-8, Delphi 2006, Delphi 2007
BeitragVerfasst: Fr 16.06.06 10:52 
Na... um ehrlich zu sein, habe ich hier ja schon ein modifiziertes ClientDataSet und ebenso ein modifiziertes DBGrid... also die Kernfunktionalität ist schon grob da... um die komplette Funktionalität zu implementieren, finde ich jetzt nicht die rechte Zeit... aber ich habe mir einen - zumindest brauchbaren -Workaround überlegt... muss nur noch schauen, in wie weit der sich realisieren läßt...

Beim Deaktivieren der ständigen Sortierung setze ich
ClientDataSet.Indexname := 'DEFAULT_ORDER';

in dem Augenblick werden ja alle Datensätze neu angeordnet. Im Grid bleibt der aktive Datensatz auf der gleichen Zeile stehen, in der nun aber ein gänzlich anderer Datensatz "zu finden" ist. Meine Idee ist nun

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
procedure TMyDbGrid.DisableSort;
var
  loc_offset,
  loc_col    : integer;

  loc_names   : string;
  loc_fnames  : array of string;
  loc_fvalues : array of Variant;
begin
  if Assigned(DataSource) and Assigned(DataSource.DataSet) and
    (DataSource.Dataset is TClientDataset) then begin

    FSortDisabled := true;
    BeginUpdate;
    try
      SetLength(loc_fnames, TClientDataSet(DataSource.DataSet).FieldCount);
      SetLength(loc_fvalues, TClientDataSet(DataSource.DataSet).FieldCount);
      loc_names := '';

      for loc_col := 0 to Length(loc_fnames) - 1 do begin
        loc_fnames[loc_col] := TClientDataSet(DataSource.DataSet).Fields[loc_col].FieldName;
        loc_fvalues[loc_col] := TClientDataSet(DataSource.DataSet).FieldValues[loc_fnames[loc_col]];
        loc_names := loc_names + loc_fnames[loc_col] + ';';
      end;

      loc_names := copy(loc_names, 1, Length(loc_names) - 1);

      TClientDataSet(DataSource.DataSet).IndexName := 'DEFAULT_ORDER';
      TClientDataSet(DataSource.DataSet).First;

      if not TClientDataSet(DataSource.DataSet).Locate(loc_names, VarArrayOf(loc_fvalues), []) then
        ShowMessage('HEEELP');                                                                      


      { Bisherige Sortierung auch in der Visualisierung aufheben }
      if (dgIndicator in Options) then
        loc_offset := 1
      else
        loc_offset := 0;

      for loc_col := 0 to ColCount - 1 do
        if FArrow[loc_col + loc_offset] in [atUp, atDown] then
          FArrow[loc_col + loc_offset] := atNone;

      Invalidate;
    finally
      EndUpdate;
    end;
  end;
end;


Ich lese mir quasi dynamisch alle Fieldnames und Values des aktiven Datensatzes ein, die Sortierung wird umgeschmissen und will den Datensatz wieder suchen... aber er findet ihn zum verrecken nicht mehr! Habe ich da etwas komplett übersehen oder mach ich da gänzlich etwas verkehrt?

C.

Danke dir schon mal für deine >aufmunternden< Worte... hab gleich schon viel mehr Hoffnung, dass ich es binnen der nächsten 3 Tage implementieren konnte *gg*
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 16.06.06 10:57 
Ich würde einen anderen Ansatz wählen und die Sortierung in Ruhe lassen. Der Anwender will doch immer ein einheitliches Bild.
Als Idee:
Die Sortierungsfelder und deren Inhalte (alte und neue) separat merken und die Grid-Sortierung damit durchführen. Oder ein Grid nehmen, dass nicht über ein DataSet verbunden ist und alles manuell machen.
crowley Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 406

Win XP, Win Vista, Mandriva, Ubuntu
Delphi 4-8, Delphi 2006, Delphi 2007
BeitragVerfasst: Fr 16.06.06 11:28 
huhu...

also... die anwenderschnittstelle ist und bleibt konsistent. das grid - so wie es hier vorlieg - wird schon seit 8 jahren in die anwendungen meiner firma integriert. also neue funktionalität ist eben die darstellung von boolean-werten mit einer "Art CheckBox" dazugekommen...

da dies die einzige Spalte ist, die in diesem Grid editierbar ist, ist sie eh was "besonderes".

Fakt ist, der Rechner ist über das Grid/ClientDataset an einen Server gebunden. Die Daten, die im Grid präsentiert werden, sind keine physikalisch in der Datenbank vorhandenen Werte... viel mehr nutze ich die Anbindung um mir am Client- Rechner alle Dateien in den LogVerzeichnissen unseres Servers anzeigen zu lassen. Da habe ich ebenfalls ein ClientDataset und einen Dataset- Provider. Im OnGetData lese ich die Verzeichnisse/Dateien ein. Auf der Client-Seite erzeuge ich weitere Felder/Spalten und ermittle im OnCalcFields zusätzliche Informationen anhand der vom Server übermittelten Daten.

Wie du siehst, es ist sinnfrei, die Daten im Grid zu ändern... denn Änderung von Dateinamen oder -größen sind implizit Unfug in diesem Kontext. Ich habe allerdings eine Boolean- Spalte hinzugefügt, in der die Dateien selektiert werden können... die ausgewählten Dateien übertrage ich später irgendwann auf den Client- Rechner, um sie dort weiter verarbeiten oder auswerten zu können. Dafür muss ich eben den Datensatz editieren können. Anhand mehrerer Filter kann der Anwender zwar einschränken, welche respektive wie viele und vor allem in welcher Reihenfolge er sich Datensätze (Logdateien) im Grid anzeigen lassen möchte. Eine Sortierung der "TransferFile"- Spalte ist auch sinnvoll und ich mag dem Anwender diese Möglichkeit nicht entziehen. Aber es ist nahezu anwenderunfreundlich, wenn man beim Verändern des Wertes in dieser Spalte sich plötzlich ganz woanders in der Datenmenge wiederfindet... stell dir vor, du magst ein paar aufeinanderfolgende Dateien de-/selektieren... und musst jedesmal, nachdem du einen Datensatz verändert hast, wieder ans andere Ende des Grids scrollen...

Daher will ich - in dem Fall, dass ich das Feld eines Datensatzes verändere, nachdem gerade sortiert wird - die automatische Sortierung deaktivieren...

hoffe, mein Anliegen/Ziel ist nachvollziehbar...

TStringGrid oder ein anderes Grid wäre zu langsam bzw. würde die übrigen Anforderungen an "unsere" Komponenten nicht erfüllen und müsste zuerst einmal komplett neu geschrieben/abgeleitet und mit Unmengen neuer Funktionalitäten ausgestattet werden.

C.
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 16.06.06 11:49 
Wie wäre es, wenn du die Multi-Select Eigenschaft nutzt?
Die CheckBox würde dann nur den Selected-Status das Datensatzes im Grid verändern. Es handelt sich dann aber um eine andere CheckBox, was der Anwender aber nicht zu sehen bekommt (z.B.: überlagert). Erst wenn eine Aktualisierung erfolgt, werden die Infos an die Tabelle übertragen.
Die Sortierung bliebe bestehen, wird aber bei Bedarf aktualisiert.
crowley Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 406

Win XP, Win Vista, Mandriva, Ubuntu
Delphi 4-8, Delphi 2006, Delphi 2007
BeitragVerfasst: Fr 16.06.06 12:07 
funktioniert leider auch nicht wirklich... das DBGrid liegt auf einem TabControl, das anhand des aktuellen Tabs weitere Filter vornimmt (die einzelnen Logverzeichnisse)... auf dem ersten Tab zeige ich alle Dateien an... bedeutet, wenn ich verschiedene Filter nacheinander aktiviert habe, habe ich natürlich auch unterschiedliche Datenmengen und dennoch muss ich mir bei jeder einzelnen Datei merken, ob sie aktiviert wurde oder nicht... bedeutet, wenn ich im dritten Tab fünf Dateien markiere und im zweiten Tab noch einmal vier Dateien, sollen auf der ersten Seite alle neun Dateien markiert sein...

es soll möglichst nur ein Kopiervorgang gestartet werden müssen...
*kopfkratz*

sehr vertrackt das ganze... *seufz*

aber sag mal... hast du eine ahnung, warum das hier scheitert?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
var
  loc_col    : integer;

  loc_names   : string;
  loc_fnames  : array of string;
  loc_fvalues : array of Variant;
begin
  ...
  try
    SetLength(loc_fnames, TClientDataSet(DataSource.DataSet).FieldCount);
    SetLength(loc_fvalues, Length(loc_fnames));
    loc_names := '';

    for loc_col := 0 to Length(loc_fnames) - 1 do begin
      loc_fnames[loc_col] := TClientDataSet(DataSource.DataSet).Fields[loc_col].FieldName;
      loc_fvalues[loc_col] := TClientDataSet(DataSource.DataSet).FieldValues[loc_fnames[loc_col]];
      loc_names := loc_names + loc_fnames[loc_col] + ';';
    end;

    loc_names := copy(loc_names, 1, Length(loc_names) - 1);

    TClientDataSet(DataSource.DataSet).IndexName := 'DEFAULT_ORDER';
    if not TClientDataSet(DataSource.DataSet).Locate(loc_names, VarArrayOf(loc_fvalues), []) then
       ShowMessage('HEEELP');
  ...
end;


Locate findet diesen Datensatz einfach zum verrecken nicht ... *haare rauf*... macht auch keinen Unterschied, ob der Datensatz gefiltert ist oder nicht... er findet ihn nicht... *seufz*
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 16.06.06 12:24 
Hast du dir die Werte im Fehlerfall mal anzeigen lassen?
Syntaktisch konnte ich im Moment nichts fehlerhaftes feststellen.
Notfalls zum Test mal manuell die Werte in das Locate eintragen.
crowley Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 406

Win XP, Win Vista, Mandriva, Ubuntu
Delphi 4-8, Delphi 2006, Delphi 2007
BeitragVerfasst: Fr 16.06.06 12:49 
himpf... der zeigt mir die Daten an, die ich ihm gegeben habe bzw. die er ausgelesen hat... manuell eingegebene Daten findet er ebenfalls nicht...

komische sache das mit dem Locate...

edited: der datensatz wird via locate nicht gefunden, aber wenn ich "manuell" danach scanne, finde ich ihn... das erfüllt nun zu 99% seinen Zweck:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
  ...

  if not TClientDataSet(DataSource.DataSet).Locate(loc_names, VarArrayOf(loc_fvalues), []) then begin
    TClientDataSet(DataSource.DataSet).First;

    loc_found := false;
    while not TClientDataSet(DataSource.DataSet).Eof and not loc_found do begin
      loc_found := true;
      loc_col   := 0;
      while (loc_col < Length(loc_fnames)) and loc_found do begin
        if loc_fvalues[loc_col] <> TClientDataSet(DataSource.DataSet).FieldValues[loc_fnames[loc_col]] then
          loc_found := false;
        inc(loc_col);
      end;

      if not loc_found then
        TClientDataSet(DataSource.DataSet).Next;
    end;
  end;

  ...


das einzige, was mich jetzt noch stört, ist, dass wenn ich den code ausführe, die sortierreihenfolge noch einmal umgekehrt wird :gruebel: und erst dann deaktiviert wird ...

na... aber ich mach nun aber gleich hier feierabend... wünsch schon mal ein hübsches wochenende

C.