Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - TextWidth ist falsch
NewMori - Mo 26.07.10 11:08
Titel: TextWidth ist falsch
Hi,
ich schreibe gerade ein Memo mit Syntax Highlighting. Und habe dort Tabs zugelassen, beim zeichnen arbeite ich mit Canvas.TextWidth um die Breite des Textes zu ermitteln. Leider funktioniert dies bei einem Tab nicht, sodass der Schreibmarker zwar richtig springt, aber der Tab nur wie ein Leerzeichen gezeichnet wird, was dann zur folge hat, das der Marker an der falschen Stelle ist. Hat jemand eine Lösung wie ich die richtige Breite eines Tabs herrausbekomme, oder ist es eine feste Breite etc. Ich wäre für Hilfe sehr dankbar.
Gerd Kayser - Di 27.07.10 01:29
Warum nimmst Du nicht ein RichEdit? Das beherrscht u. a. Tabulatoren und farbige Schrift.
jaenicke - Di 27.07.10 05:32
Gerd Kayser hat folgendes geschrieben : |
| Warum nimmst Du nicht ein RichEdit? Das beherrscht u. a. Tabulatoren und farbige Schrift. |
Hast du es mal versucht eine fertige Komponente für Syntaxhighlighting zu verwenden? Ich vermute nein...
Du kommst da nicht an alles heran, so dass das nicht gut funktioniert.
Die Breite eines Tabs ist ja z.B. kontextabhängig, je nach Implementierung. TextWidth kann ja nicht wissen wo in einer Zeile z.B. man sich befindet. Außerdem kann man die Breite eines Tabs in der Regel auch selbst definieren.
Das sinnvollste ist wohl einfach (wie Delphi selbst) für einen Tab eine feste Anzahl Leerzeichen zu verwenden, die man am besten auch einstellen kann.
NewMori - Di 27.07.10 09:04
jaenicke hat folgendes geschrieben : |
| Das sinnvollste ist wohl einfach (wie Delphi selbst) für einen Tab eine feste Anzahl Leerzeichen zu verwenden, die man am besten auch einstellen kann. |
Ich werde mir das RichEdit nochmal anschauen. Mein Problem besteht nicht darin, dass ich nicht in der Lage wäre ein Tab 5 Leerzeichen lang zu machen oder alle vollen 100 Pixel erst den nächsten Text zu zeichnen. Das Problem liegt in dem Marker, ich weis nicht wie ich ihn manipulieren kann, sodass er bei "meinen Tabs" richtig springt.
(Kann mir vielleicht auch jemand sagen wo ich die Zeichenfunktion für makierte Texte findet, in dieser Zeile greift mein WM_PAINT komischerweise nicht, oder soll ich dafür besser nen neues Thema aufmachen?)
Gerd Kayser - Di 27.07.10 17:53
jaenicke hat folgendes geschrieben : |
Hast du es mal versucht eine fertige Komponente für Syntaxhighlighting zu verwenden? Ich vermute nein...
Du kommst da nicht an alles heran, so dass das nicht gut funktioniert. |
Doch, ich habs heute Nachmittag probiert. :)
Kleines Beispiel:
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:
| procedure TForm1.Button1Click(Sender: TObject); begin RichEdit1.Clear; RichEdit1.Lines.Add('Satz: Ein kleiner Text.'); RichEdit1.Lines.Add('Ein weiterer Satz.'); RichEdit1.Lines.Add('Dieser Satz ist auch sehr kurz.') end;
procedure TForm1.Button2Click(Sender: TObject); var Stelle : integer; Suchwort : string; ChrFormat : TCharFormat2; Position : integer; Abbrechen : boolean; begin Suchwort := 'Satz';
FillChar(ChrFormat, SizeOf(TCharFormat2), 0); ChrFormat.cbSize := SizeOf(TCharFormat2); ChrFormat.dwMask := CFM_BackColor; ChrFormat.crBackColor := clYellow;
Abbrechen := false; Stelle := 1; while not Abbrechen do begin Position := PosEx(SuchWort, RichEdit1.Text, Stelle); if Position > 0 then begin RichEdit1.SelStart := Position - 1; RichEdit1.SelLength := Length(Suchwort); RichEdit1.SelAttributes.Style := [fsUnderline]; RichEdit1.SelAttributes.Color := clRed; SendMessage(RichEdit1.Handle, EM_SetCharFormat, SCF_Selection, LParam(@ChrFormat)); Stelle := Position + Length(Suchwort); end else Abbrechen := true; end; end; |
NewMori - Di 27.07.10 18:29
@Gerd Kayser: Danke für die Mühe, ich habe es mal ausprobiert. Es gibt ein Problem, wenn ich Strings habe soll alles dazwischen gefärbt werden, dort habe ich dann kein Suchwort. Auch müsste ich den kompletten Text mit allen Wörten nach jeder Änderung durchlaufen. Das kann man zwar lösen aber etwas umständlicher. Ich würde sowieso das WM_PAINT Ereigniss überschreiben und den Text dann neu formatieren. Das Problem ist jetzt, dass ich das eigendlich schon hinbekommen habe, mir fehlt wie gesagt nur eine Funktion etc. wie ich herrausbekomme wo ich nach einem Tab weiter zeichnen muss, bzw ob ich den Cursor an die Stelle rücken kann wo ich weiter zeichnen will.
Chromic - Di 27.07.10 18:35
Hallo!
Hmm. TMemo + Syntaxhighlighting, TRichEdit + Syntaxhighlighting... Da fällt mir so auf die schnelle ne nette Komponente ein, die es schon gibt und sich in vielen Projekten (zB Lazarus) hervorragend bewährt: SynEdit.
mfg Chromic
NewMori - Di 27.07.10 18:53
@Chromic: Das habe ich auch schon gefunden. Ich würde das allerdings gerne selber schreiben, bzw nicht noch eine externe Klasse brauchen, denn falls Fehler auftreten wird es schwierig Hilfe zu bekommen.
jaenicke - Di 27.07.10 19:08
Gerd Kayser hat folgendes geschrieben : |
| Doch, ich habs heute Nachmittag probiert. :) |
Soweit ist das auch kein Problem, aber es geht vor allem um sehr performante Anpassungen bei Änderungen im Quelltext usw., und da kommt man mit den Standardkomponenten nicht weit.
Es hat schon einen Grund weshalb diese Komponenten alle nicht auf TMemo oder TRichEdit basieren. Sowas wie SynEdit selbst zu schreiben ist aber illusorisch, da würde man Jahre dran sitzen.
Es geht ja hier um eine sehr einfach gestrickte Komponente, die nicht so viele Funktionen hat.
Und was das Problem angeht:
Wie gesagt: Ein Tab hat keine systemweit feste Breite. Es ist deine Definition in deiner Komponente wie breit der sein soll. ;-)
NewMori - Di 27.07.10 19:56
jaenicke hat folgendes geschrieben : |
Und was das Problem angeht:
Wie gesagt: Ein Tab hat keine systemweit feste Breite. Es ist deine Definition in deiner Komponente wie breit der sein soll. ;-) |
Der Text fängt nach einem Tab, aber immer nach einem festen Muster wieder an, zB. nach den nächsten vollen 100 Pixeln etc. leider weis ich nicht wie ich den Textanfang errechnen kann. Wenn ich das nicht herrausfinde wäre es vielleicht möglich den Textcursor umzusetzen, ich habe bis jetzt aber noch nicht das Event,die Funktion etc. gefunden um selber die Position des Cursors in Pixeln setzen zu können.
NewMori - Di 27.07.10 21:24
Ich habe jetzt eine Zwischenlösung gefunden, bei Schrift Courier New und Schriftgröße 10 kann man X so berechnen:
Delphi-Quelltext
1: 2:
| Tab:=65; X:=X-(X mod Tab)+Tab; |
Ich suche jetzt nochmal nach einer Lösung für alle Schriftarten Größen etc. Solange benutze ich diesen Code.
Gerd Kayser - Di 27.07.10 22:01
Versuchs mal damit:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.Button4Click(Sender: TObject); var Position : integer; PixelPosition : integer; Suchwort : string; begin Suchwort := 'Satz'; Position := Pos(Suchwort, Memo1.Text) - 1; PixelPosition := SendMessage(Memo1.Handle, EM_PosFromChar, Position, 0); ShowMessage('Zeichenposition: ' + IntToStr(Position) + #13#10 + 'Pixelposition-X: ' + IntToStr(LoWord(PixelPosition))+ #13#10 + 'PixelPosition-Y: ' + IntToStr(HiWord(PixelPosition))); end; |
jaenicke - Di 27.07.10 22:30
Das geht ja nur bei einem TMemo. :gruebel:
Gerd Kayser - Di 27.07.10 23:03
jaenicke hat folgendes geschrieben : |
| Das geht ja nur bei einem TMemo. :gruebel: |
RichEdit wollte er ja nicht. Des Menschen Wille ist nun einmal sein Himmelreich.
So geht es mit RichEdit:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.Button3Click(Sender: TObject); var Position : integer; PixelPosition : TPoint; Suchwort : string; begin Suchwort := 'Satz'; Position := Pos(Suchwort, RichEdit1.Text) - 1; SendMessage(RichEdit1.Handle, EM_PosFromChar, wParam(@PixelPosition), lParam(Position)); ShowMessage('Zeichenposition: ' + IntToStr(Position) + #13#10 + 'Pixelposition-X: ' + IntToStr(PixelPosition.X)+ #13#10 + 'PixelPosition-Y: ' + IntToStr(PixelPosition.Y)); end; |
Ich würde persönlich aber ein RichEdit bevorzugen. Mit ein wenig Nachdenken bekommt man auch bei größeren Texten eine performante Lösung hin. Der Rechner ist jedenfalls mit der Abarbeitung der Funktionen schneller, als ich jemals werde tippen können.
jaenicke - Mi 28.07.10 06:14
Also ich hatte das so verstanden, dass es eine eigene Komponente ohne TMemo ist. Das ist auch die sinnvollste Variante wie gesagt.
NewMori - Mi 28.07.10 09:30
jaenicke hat folgendes geschrieben : |
| Also ich hatte das so verstanden, dass es eine eigene Komponente ohne TMemo ist. Das ist auch die sinnvollste Variante wie gesagt. |
Ich benutze ein TMemo, nur das ich das WM_PAINT Ereigniss überschreibe.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!