Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Rund um die LCL und andere Komponenten
MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Lazarus 2.1.0 und TDBMemo -> [Gelöst]

Beitrag von MmVisual »

Das wird ja dann wieder extrem aufwändig :shock:
Ich habe in meinem Formular ca. 30 TDBMemo und TDBGrid drauf und wenn man dazu nun noch berechnete Felder anlegen muss ist das ebenfalls fehleranfällig. Man muss dann echt viel proggen und aufpassen wie ein Fuchs dass da alles gut geht. Dass das Grid auch immer den gleichen Inhalt zeigt wie das Memo. :|

Die ultimative Lösung ist wohl allen bösartigen Entwicklern die Schreibrechte auf die Lazarus Sourcen zu entziehen. :mrgreen:

Oder:

Die Abfrage OnGetText bekommt noch einen Parameter welche Komponente das wissen will, ähnlich dem Sender, dann könnte man da feststellen welche Komponente den Text denn wissen (TDBxxxxx) will und entsprechend einen konvertierten oder einen nackten Text übergeben.
EleLa - Elektronik Lagerverwaltung - www.elela.de

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Lazarus 2.1.0 und TDBMemo -> [Gelöst]

Beitrag von MmVisual »

@WP

Ich habe noch eine andere Idee:

Ist es möglich dass man dem TDBMemo ein neues Event "OnGetText" (TFieldGetTextEvent) spendiert?
(Und "OnSetText" (TFieldSetTextEvent))

Wird es benutzt, dann kann man da einen beliebigen Text zurück geben, genau gleich wie bei TField.OnGetText.
Wird es nicht benutzt dann wird TField.OnGetText genutzt, sofern es existiert, ansonsten TField.AsString, so wie es aktuell ist.

Damit erhält man die maximal mögliche Flexibilität und man ist nach wie vor Delphi Kompatibel.

Ein OnPaint Event oder zusätzliche berechnete Tabellenspalten zu benutzen ist nur eine Notlösung. In einer modernen Programmiersprache sollte man solche Krücken nicht vor finden müssen. Ich komme mir da vor wie ein Hacker der versucht irgend welche Lücken aus zu nutzen.
EleLa - Elektronik Lagerverwaltung - www.elela.de

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Lazarus 2.1.0 und TDBMemo -> [Gelöst]

Beitrag von MmVisual »

Ich habe das mal einprogrammiert wie ich mir das vorgestellt habe.

Kann das bitte jmd in die Lazarus Sourcen hoch laden?

TDBMemo_Fix.zip
(12.18 KiB) 115-mal heruntergeladen


Geänderte Dateien:
C:\fpcupdeluxe\lazarus\lcl\dbctrls.pp
C:\fpcupdeluxe\lazarus\lcl\include\dbmemo.inc

Es sind nur ein paar Codezeilen mehr und wenn man OnGetText / OnSetText nicht nutzt ist es kein Unterschied zum vorigen Stand.

Ich habe dazu einen neuen Bug-Tracker auf gemacht:
https://bugs.freepascal.org/view.php?id=35037
Damit könnt ihr LazDeveloper die Änderung auch in Lazarus dokumentieren :D
Ich hoffe damit, dass das ganze doch noch ein gutes Ende nimmt und für lange Zeit hält :oops:
Zuletzt geändert von MmVisual am Do 7. Feb 2019, 22:55, insgesamt 1-mal geändert.
EleLa - Elektronik Lagerverwaltung - www.elela.de

sstvmaster
Beiträge: 575
Registriert: Sa 22. Okt 2016, 23:12
OS, Lazarus, FPC: W10, L 2.2.6
CPU-Target: 32+64bit
Wohnort: Dresden

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von sstvmaster »

Da bin ich mal gespannt
LG Maik

Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von MmVisual »

So sieht die Ansicht aus wenn OnGetText nicht genutzt wird:
Bild1.png
Bild1.png (7.86 KiB) 2106 mal betrachtet


So wenn TField.OnGetText genutzt wird:
Bild2.png
Bild2.png (8.17 KiB) 2106 mal betrachtet


Und so wenn mein Fix vom TDBMemo genutzt wird:
Bild3.png
Bild3.png (8.73 KiB) 2106 mal betrachtet


Der Quellcode:

Code: Alles auswählen

procedure TForm1.ZQuery1ValMemoGetText(Sender: TField; var aText: string;
  DisplayText: Boolean);
var s: string;
begin
  s := StringReplace(Sender.AsString, LineEnding, '¶', [rfReplaceAll]);
  s := StringReplace(s, #13, '¶', [rfReplaceAll]);
  s := StringReplace(s, #10, '', [rfReplaceAll]);
  if Length(s) > 250 then
    aText := UTF8Copy(s, 1, 250) + '...'
  else  aText := s;
end;
 
procedure TForm1.DBMemo1GetText(Sender: TObject; Field: TField; var aText: string);
begin
  aText := Field.AsString;
end;


PS: Ich habe das ZIP nochmals geändert, nun wird als Sender auch das richtige übergeben und das Feld in einer extra Variable, dazu habe ich diesen Typ angelegt:

Code: Alles auswählen

  TDBCtrlsGetTextEvent = procedure(Sender: TObject; Field: TField; var aText: string) of object;
  TDBCtrlsSetTextEvent = procedure(Sender: TObject; Field: TField; const aText: string) of object;
 

Das geänderte ZIP ist in meinem vorigen Beitrag.
EleLa - Elektronik Lagerverwaltung - www.elela.de

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

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von Michl »

Ich denke nur mal laut, wenn ich nicht die Vorgschichte kennen würde und neu auf das Property treffe:

Da sehe ich nun das Property OnGetText im DBMemo und denke, klasse, da wandel ich meinen CP1252 Datenbank-String in einen UTF8-String um und stelle den dar. Soweit so gut, doch wie bekomme ich den dann zurück in meine Datenbank? Also müsste neben dem OnGetText auch ein OnSetText implementiert werden. Evtl. auch noch OnChange und OnValidate, wie im TField?

Wenn DBMemo ein OnGetText hat, warum ist das nicht auch beim DBEdit so?

Wenn ich händisch das DBMemo füllen will, warum nehme ich dann kein normales Memo und fülle es im OnAfterScroll?


Nur meine Gedanken, die mir da so in den Sinn kommen, wenn man diesen Thread und das Problem nicht kennt, wie es dazu gekommen ist. Weiß nicht, wie andere so einem Property gegenüber stehen.

Code: Alles auswählen

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

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

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von wp_xyz »

Genau dasselbe wollte ich eben auch schreiben.

Wo ist das Problem, den betreffenden Datasets ein weiteres berechnetes Feld zu geben, oder das Feld in der Query nochmals aufzuführen? In der Zeit, während der diese Diskussion läuft (und sie wird hiermit nicht enden), wäre das auch bei 30 Formularen schon erledigt.

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von MmVisual »

Das Problem ist dass ich nicht so einfach ein berechnetes Feld rein machen kann wie du es dir denkst. Es sind sehr viele Tabellen mit zig Spalten. Und bei jeder einzelnen Tabelle kann man sich die Spalten Ein-/Ausblenden wie man mag (auch die Größe und Position verändern) und das wird je User gemerkt so dass jeder seine Ansicht hat.
Mit Rechtsklick in die Titelleiste kommt immer ein automatisch generiertes Popup-Menü wo man sich die Spalten wählen kann. Und das neue berechnete Feld würde hier mit erscheinen, sowie das Original Feld.
Bild1.png

Jedoch braucht es nur das extra berechnete, damit man im Grid den Text sauber anschauen kann und das Memo bekommt das orignal Feld damit TDBMemo richtig geht. Damit würden alle Memo Felder der Tabelle gedoppelt werden.

Ja, bei TDBEdit sollte das auch mit rein und bei TDBGrid natürlich auch. Daher habe ich die Events "TDBCtrlsGetTextEvent " und "TDBCtrlsSetTextEvent " benannt, damit eben man diesen Event-Typ für die anderen Sachen auch verwenden kann.
In meinem Beispiel habe ich bereits das OnSetText schon einprogrammiert.
Ein OnChange hat das TDBMemo bereits, braucht es also nicht noch extra, ein OnValidate wüsste ich jetzt nicht für was man das brauchen würde, dafür hat man das OnSetText.

Das händische Füllen in ein TMemo ist auch wieder nur ein Notbehelf. Alles richtig abfragen, das TDataset in Edit versetzen bei Änderung, immer richtig speichern ist nicht so leicht erledigt.

Bei super kleinen Hobby Miniprogrämmchen mag das mit berechneten Feldern ja, gehen, da kann man sich das TDBGrid im Lazarus Designer sich das Design so zusammen schieben wie man mag, aber bei komplexen Amatuerprogrammen wie meiner geht das nicht.

Aktuell habe ich alle mit ein paar wenigen Routinen behandelt und geht gut, wenn ich jedoch entweder das TDBMemo in ein TMemo wandeln muss oder eine extra Spalte einbauen muss, dann ist jede Tabelle eine Sonderbehandlung. Sonderprogrammierung, Spaghetticode und genau damit habe ich ein Problem.
Mit nur diesen 2 kleinen Eingriffen in die Komponente, mit nur diesen paar Codezeilen kann man das vermeiden.
Zuletzt geändert von MmVisual am Fr 8. Feb 2019, 09:37, insgesamt 1-mal geändert.
EleLa - Elektronik Lagerverwaltung - www.elela.de

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von MmVisual »

Hier mal die DB Struktur, die ich im Hintergrund verwalte:
TutDBTabellenV4 - Kopie.png


(Ich musste das Bild verkleinern weil das Forum nur Bilder mit 1500Pixel mag)
EleLa - Elektronik Lagerverwaltung - www.elela.de

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

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von wp_xyz »

Hier ist noch eine andere Lösung, die du natürlich wieder als "bad crack/hack" bezeichnen wirst:

Schreibe eine neue Unit mit einem neuen DBGrid, z.B. TMyDBGrid und einer Funktion, die nur die DrawCellText-Methode überschreibt und dort für alle Memo-Spalten die von dir gewünschte String-Änderung vornimmt. Außerdem enthält sie eine Funktion, ein bestehendes DBGrid als TMyDBGrid zu clonen:

Code: Alles auswählen

type
  TMyDBGrid = class(DBGrids.TDBGrid)
  protected
    procedure DrawCellText(aCol,aRow: Integer; aRect: TRect;
      aState: TGridDrawState; aText: String); override;
  end
 
procedure TMyDBGrid.DrawCellText(aCol,aRow: Integer; aRect: TRect;
  aState: TGridDrawState; aText: String);
var
  f: TField;
begin
  f := GetFieldfromGridColumn(ACol);
  if Assigned(f) and (f.DataType = ftMemo) and (aRow >= FixedRows) then begin
    AText := ReplaceText(f.AsString, LineEnding, '¶');
    if Length(AText) > 20 then AText := Copy(AText, 1, 20) + '...';
  end;
  Canvas.TextRect(ARect, ARect.Left + varCellPadding, ARect.Top + varCellPadding, AText);
end;
 
function CloneDBGrid(ADBGrid: TDBGrid): TMyDBGrid;
var
  i: Integer;
  name: String;
begin
  name := ADBGrid.Name;
  Result := TMyDBGrid.Create(ADBGrid.Owner);
  Result.SetBounds(ADBGrid.Left, ADBGrid.Top, ADBGrid.Width, ADBGrid.Height);
  Result.Parent := ADBGrid.Parent;
  Result.DataSource := ADBGrid.DataSource;
  for i:=0 to ADBGrid.Columns.Count-1 do
    with Result.Columns.Add do begin
      Assign(ADBGrid.Columns[i]);
    end;
  // evtl. noch weitere Properties kopieren, da DBGrid offenbar kein Assign implementiert.
  ADBGrid.Free;
  Result.Name := name;
end;

Um ein bestehendes Formular anzupassen, musst du nun
- den OnGetText-Handler für die Memo-Felder entfernen (d.h., das Memo erhält den unmodifizierten Inhalt des DB-Feldes)
- die neue Unit in die Uses-Zeile aufnehmen
- in FormCreate CloneDBGrid aufrufen:

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
begin
  ...
  DBGrid1 := CloneDBGrid(DBGrid1);
end;

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von MmVisual »

Ich werde jetzt hoffentlich nicht von euch Lazarus Developern erschlagen ......

Ich war mal so frei und habe etwas Code in den Lazarus Sourcen geändert, TDBMemo, TDBEdit, TDBText und TDBGrid, das Ergebnis sieht dann so aus:
Bild1.png


Der Quellcode meienr EXE dazu:

Code: Alles auswählen

procedure TForm1.ZQuery1ValMemoGetText(Sender: TField; var aText: string;
  DisplayText: Boolean);
begin
  aText := '[Ähm ne]'; // << das wird gezeigt wenn meine Änderung nicht wirkt
end;
 
procedure TForm1.DBMemo1GetText(Sender: TObject; Field: TField;
  var aText: string);
begin
  aText := Field.AsString;
end;
 
procedure TForm1.DBText1GetText(Sender: TObject; Field: TField;
  var aText: string);
begin
  aText := 'Extra TDBText Text: ' + Field.AsString;
end;
 
procedure TForm1.DBEdit1GetText(Sender: TObject; Field: TField;
  var aText: string);
begin
  aText := 'Extra TDBEdit Text: ' + Field.AsString;
end;
 
procedure TForm1.DBGrid1GetCellText(Sender: TObject;  Field: TField; var aText: string);
begin
  If SameText(Field.FieldName, 'ValMemo') Then
    aText := StringReplace(Field.AsString, LineEnding, '¶', [rfReplaceAll]);
end;
Zuletzt geändert von MmVisual am Sa 9. Feb 2019, 16:24, insgesamt 2-mal geändert.
EleLa - Elektronik Lagerverwaltung - www.elela.de

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Beitrag von MmVisual »

Hier die Änderung der LCL Sourcen:
TDBMemo_Fix3.zip
(44.95 KiB) 110-mal heruntergeladen


In TDBGrid ist auch noch ein Bug in der Routine "procedure TCustomDBGrid.DoCopyToClipboard;", da wird bisher nicht "CheckDisplayMemo(F)" abgefragt.

Allgemein: Ich habe die SetText zwar programmiert, jedoch nicht getestet.
EleLa - Elektronik Lagerverwaltung - www.elela.de

Antworten