Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Rund um die LCL und andere Komponenten

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

Beitragvon MmVisual » 7. Feb 2019, 12:36 Re: Lazarus 2.1.0 und TDBMemo -> [Gelöst]

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.
MmVisual
 
Beiträge: 1096
Registriert: 10. Okt 2008, 22:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3) | 
CPU-Target: 32/64Bit
Nach oben

Beitragvon MmVisual » 7. Feb 2019, 20:46 Re: Lazarus 2.1.0 und TDBMemo -> [Gelöst]

@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.
MmVisual
 
Beiträge: 1096
Registriert: 10. Okt 2008, 22:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3) | 
CPU-Target: 32/64Bit
Nach oben

Beitragvon MmVisual » 7. Feb 2019, 21:27 Re: Lazarus 2.1.0 und TDBMemo -> [Gelöst]

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) 7-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 7. Feb 2019, 22:55, insgesamt 1-mal geändert.
MmVisual
 
Beiträge: 1096
Registriert: 10. Okt 2008, 22:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3) | 
CPU-Target: 32/64Bit
Nach oben

Beitragvon sstvmaster » 7. Feb 2019, 21:57 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Da bin ich mal gespannt
LG Maik
sstvmaster
 
Beiträge: 236
Registriert: 22. Okt 2016, 22:12
Wohnort: Dresden
OS, Lazarus, FPC: Windows 7 32bit (L 2.0.4 FPC 3.0.4) | 
CPU-Target: 32Bit
Nach oben

Beitragvon MmVisual » 7. Feb 2019, 22:31 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

So sieht die Ansicht aus wenn OnGetText nicht genutzt wird:
Bild1.png
(7.86 KiB) Noch nie heruntergeladen


So wenn TField.OnGetText genutzt wird:
Bild2.png
(8.17 KiB) Noch nie heruntergeladen


Und so wenn mein Fix vom TDBMemo genutzt wird:
Bild3.png
(8.73 KiB) Noch nie heruntergeladen


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.
MmVisual
 
Beiträge: 1096
Registriert: 10. Okt 2008, 22:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3) | 
CPU-Target: 32/64Bit
Nach oben

Beitragvon Michl » 8. Feb 2019, 00:46 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

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; 
Michl
 
Beiträge: 2325
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon wp_xyz » 8. Feb 2019, 00:57 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

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.
wp_xyz
 
Beiträge: 2993
Registriert: 8. Apr 2011, 08:01

Beitragvon MmVisual » 8. Feb 2019, 08:13 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

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 8. Feb 2019, 09:37, insgesamt 1-mal geändert.
MmVisual
 
Beiträge: 1096
Registriert: 10. Okt 2008, 22:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3) | 
CPU-Target: 32/64Bit
Nach oben

Beitragvon MmVisual » 8. Feb 2019, 08:28 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

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)
MmVisual
 
Beiträge: 1096
Registriert: 10. Okt 2008, 22:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3) | 
CPU-Target: 32/64Bit
Nach oben

Beitragvon wp_xyz » 8. Feb 2019, 10:09 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

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;
wp_xyz
 
Beiträge: 2993
Registriert: 8. Apr 2011, 08:01

Beitragvon MmVisual » 8. Feb 2019, 21:24 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

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 9. Feb 2019, 16:24, insgesamt 2-mal geändert.
MmVisual
 
Beiträge: 1096
Registriert: 10. Okt 2008, 22:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3) | 
CPU-Target: 32/64Bit
Nach oben

Beitragvon MmVisual » 8. Feb 2019, 21:31 Re: Lazarus 2.1.0 und TDBMemo -> [noch Offen]

Hier die Änderung der LCL Sourcen:
TDBMemo_Fix3.zip
(44.95 KiB) 7-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.
MmVisual
 
Beiträge: 1096
Registriert: 10. Okt 2008, 22:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3) | 
CPU-Target: 32/64Bit
Nach oben

• Themenende •
Vorherige

Zurück zu Komponenten und Packages



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 7 Gäste

porpoises-institution
accuracy-worried