Lazarus 2.1.0 und TDBMemo -> [noch Offen]
-
- Beiträge: 1468
- 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]
Das wird ja dann wieder extrem aufwändig
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.
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.
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.
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
-
- Beiträge: 1468
- 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]
@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.
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
-
- Beiträge: 1468
- 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]
Ich habe das mal einprogrammiert wie ich mir das vorgestellt habe.
Kann das bitte jmd in die Lazarus Sourcen hoch laden?
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
Ich hoffe damit, dass das ganze doch noch ein gutes Ende nimmt und für lange Zeit hält
Kann das bitte jmd in die Lazarus Sourcen hoch laden?
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
Ich hoffe damit, dass das ganze doch noch ein gutes Ende nimmt und für lange Zeit hält
Zuletzt geändert von MmVisual am Do 7. Feb 2019, 22:55, insgesamt 1-mal geändert.
EleLa - Elektronik Lagerverwaltung - www.elela.de
-
- Beiträge: 576
- 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]
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)
Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)
-
- Beiträge: 1468
- 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]
So sieht die Ansicht aus wenn OnGetText nicht genutzt wird:
So wenn TField.OnGetText genutzt wird:
Und so wenn mein Fix vom TDBMemo genutzt wird:
Der Quellcode:
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:
Das geänderte ZIP ist in meinem vorigen Beitrag.
So wenn TField.OnGetText genutzt wird:
Und so wenn mein Fix vom TDBMemo genutzt wird:
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
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.
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;
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.
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.
-
- Beiträge: 1468
- 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]
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.
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.
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.
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
-
- Beiträge: 1468
- 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]
Hier mal die DB Struktur, die ich im Hintergrund verwalte:
(Ich musste das Bild verkleinern weil das Forum nur Bilder mit 1500Pixel mag)
(Ich musste das Bild verkleinern weil das Forum nur Bilder mit 1500Pixel mag)
EleLa - Elektronik Lagerverwaltung - www.elela.de
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:
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:
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;
-
- Beiträge: 1468
- 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]
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:
Der Quellcode meienr EXE dazu:
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:
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
-
- Beiträge: 1468
- 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]
Hier die Änderung der LCL Sourcen:
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.
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