Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - TButtons in TJvRichEdit
galagher - Mo 10.01.22 21:24
Titel: TButtons in TJvRichEdit
Hallo zusammen!
Ich möchte gerne einen (oder mehrere) TButtons in einem TJvRichEdit so "einfügen", dass er mitscrollt, dass er also seine Position im Text behält. Dabei soll der Button voll funktionsfähig bleiben, und es soll möglichst flüssig ablaufen. Gerne auch TSpeedButton oder TBitBtn!
Man kann ja Grafiken auf diese Weise einbinden, aber das kommt nicht in Frage, weil man nicht abfragen kann, welche Grafik gerade angeklickt wurde.
Ein TJvRichEdit als Parent einer Komponente geht - natürlich - ebenfalls nicht.
Kann man das mit Komponenten so überhaupt machen? Wenn ja, wie?
lg
Th69 - Di 11.01.22 12:29
Einen direkten (vom System vorgesehenen) Weg gibt es dafür nicht. Als einziger Weg bleibt wirklich nur den
Button dem
TJvRichEdit als "SubControl" hinzuzufügen und dann die Scroll-Messages (
WM_HSCROLL, WM_VSCROLL) abzufangen und die Position neu zu setzen (evtl. mußt du also das EditControl "subclass"en, also davon ableiten und die Messages dort behandeln).
Als Überblick kann ich dir nur den Petzold empfehlen:
Building a Better Scroll [
https://www-user.tu-chemnitz.de/~heha/petzold/ch04e.htm] (Code ist aber natürlich in C).
galagher - Mi 12.01.22 15:39
Th69 hat folgendes geschrieben : |
Einen direkten (vom System vorgesehenen) Weg gibt es dafür nicht. Als einziger Weg bleibt wirklich nur den Button dem TJvRichEdit als "SubControl" hinzuzufügen |
So wird das nichts, einen Button auf das JvRichEdit legen (in Wirklichkeit ja auf die TForm) und dann alles per Hand machen. Da verzichte ich lieber drauf!
Th69 - Mi 12.01.22 17:27
Auch wenn evtl. die Delphi-Komponenten das nicht direkt unterstützen, solltest du immer direkt per WinAPI-Funktion
SetParent [
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent] ein beliebiges Windows-Control als
Parent des Buttons zuweisen können (und dieser wird dann auch vom Windows-System nur innerhalb des sichtbaren Bereichs des
Parent-Controls angezeigt).
Und dann eben nur noch bei den Scroll-Messages (nachdem das eigentliche
TJvRichEdit diese verarbeitet hat), die Position des Buttons neu anpassen (so viel Code sollte das dann nicht sein).
In einem kleinen WinForms-Testprojekt (mit C#) habe ich das ansatzweise ausprobiert und es hat funktioniert. Einzig, wenn du sehr viele Buttons hast, kann natürlich die Performance ein bißchen darunter leiden.
galagher - Fr 14.01.22 12:34
Th69 hat folgendes geschrieben : |
Und dann eben nur noch bei den Scroll-Messages (nachdem das eigentliche TJvRichEdit diese verarbeitet hat), die Position des Buttons neu anpassen (so viel Code sollte das dann nicht sein). |
So aus dem Stand habe ich keine Vorstellung davon, wie ich das anpasse. Ich sehe mir das aber an, vielleicht komme ich ja weiter.
galagher - Fr 14.01.22 19:27
SetParent ist mir klar, nicht aber der Rest.
Es gibt ein Ereignis OnVerticalScroll, das gilt aber für beide vertikale Richtungen. Das ist es aber nicht, was du mit Scroll-Messages meinst.
Ich brauche einen Tipp... :nixweiss:
galagher - So 16.01.22 20:29
Ok:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.WndProc(var msg : TMessage); begin if msg.Msg = WM_VSCROLL then ;
inherited WndProc(msg); end; |
Die Prozedur wird ausgeführt, aber wie ermittle ich den Wert für
Button2.Top?
galagher - Mo 17.01.22 17:47
Th69 hat folgendes geschrieben : |
Indem du diese Position relativ zur aktuellen Scrollposition des TJvRichEdit berechnest |
Ich musste eine Klasse von TJvRichEdit ableiten, also muss ich das Programm noch ensprechend anpassen.
Soweit habe ich das erstmal. Button2 scrollt auf diese Weise aber in die falsche Richtung:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TJvRichEditX.WndProc(var msg : TMessage);
function GetVertScrollBarPosition: Integer; begin Result := GetScrollPos(Form1.aJvRichEditX.Handle, SB_VERT); end;
begin inherited WndProc(msg);
if msg.Msg = WM_VSCROLL then Form1.Button2.Top := GetVertScrollBarPosition; end; |
Th69 - Mo 17.01.22 19:10
Ich meinte ja auch:
Delphi-Quelltext
1:
| Button2.Top := InitialPosY + GetVertScrollBarPosition; |
(und
InitialPosY initialisierst du bei der ersten Zuweisung von
Button2.Top).
Alternativ berechnest du die Differenz der Scrollbewegung (also Werte
vor und
nach dem Scrollen vergleichen) und addierst diese zur Button-Position.
PS: Es sollte nur
Delphi-Quelltext
1:
| Result := GetScrollPos(Handle, SB_VERT); |
heißen...
galagher - Mo 17.01.22 20:31
Th69 hat folgendes geschrieben : |
Delphi-Quelltext 1:
| Button2.Top := InitialPosY + GetVertScrollBarPosition; | |
Perfekt! Nur statt + muss da ein - hin:
Delphi-Quelltext
1:
| Button2.Top := InitialPosY - GetVertScrollBarPosition; |
Das genügt mir völlig! Jetzt kann ich auf diese Art und Weise auch mehrere Buttons oder was auch immer einfügen, und es wirkt tatsächlich so, als wäre die Komponente im Text "engebettet" und scrollt perfekt mit! :dance2:
//Edit:
Nur eines noch: Wie lasse ich den Button sofort mitscrollen, wenn man am Balken der Bildlaufleiste zieht? Er wird da erst nachträglich an die neue Position gesetzt, wenn ich zusätzlich
Delphi-Quelltext
1: 2: 3:
| ... else Result := GetScrollPos(Handle, SB_THUMBPOSITION); |
angebe!
galagher - Di 18.01.22 16:50
Ja, es funktioniert auch ohne
SB_THUMBPOSITION, aber: Wenn man den Balken der Scrolleiste bewegt, wird der Button erst gesetzt, wenn man die linke Maustaste wieder loslässt.
Mit
GetScrollInfo habe ich noch Schierigkeiten, ich bin aber dran.
galagher - Mi 19.01.22 17:14
Das Ganze kann man aber auch einfach in der OnVerticalScroll-Prozedur unterbringen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.JvRichEdit1VerticalScroll(Sender: TObject); var iYPos: Integer; SInfo: TScrollInfo; begin SInfo.cbSize := SizeOf(SInfo); SInfo.fMask := SIF_ALL; GetScrollInfo(JvRichEdit1.Handle, SB_VERT, SInfo); iYPos := SInfo.nPos;
Button2.Top := InitialPosY - iYPos; end; |
Mit
SIF_TRACKPOS und
nTrackPos funktioniert es nicht,
SIF_ALL und
nPos scheinen korrekt zu sein, denn damit klappt es.
Bleibt immer noch der Effekt, dass beim Verschieben des Scrollbalkens die Position erst nach dem Loslassen der Maustaste gesetzt wird, und bei
OnMouseWheel passiert gar nichts. Ein Aufruf von
JvRichEdit1VerticalScroll im
OnMouseWheel setzt die Position nur ungefähr, aber nicht genau.
Aber das Prinzip funktioniert. Dank dir!
Th69 - Mi 19.01.22 17:29
galagher hat folgendes geschrieben : |
Bleibt immer noch der Effekt, dass beim Verschieben des Scrollbalkens die Position erst nach dem Loslassen der Maustaste gesetzt wird |
Und genau dafür ist doch
nTrackPos (im Unterschied zu
nPos).
galagher - Mi 19.01.22 19:53
Th69 hat folgendes geschrieben : |
Und genau dafür ist doch nTrackPos (im Unterschied zu nPos). |
SIF_ALL und
nPos: a) Pfeile der Bildlaufleiste und in die Bildlaufleiste klicken klappt, ziehen am Balken klappt nicht.
SIF_TRACKPOS und
nTrackPos: b) Ziehen am Balken klappt, Pfeile der Bildlaufleiste und in die Bildlaufleiste klicken klappt nicht.
SIF_TRACKPOS und
nPos: c) Beides klappt nicht.
SIF_ALL und
nTrackPos: Wie b).
Mal sehen, ob es da sonst noch etwas gibt.
galagher - Mi 19.01.22 20:17
Hier meine vorläufige Lösung, jetzt klappt alles:
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:
| procedure TForm1.JvRichEdit1VerticalScroll(Sender: TObject);
procedure VScroll(Sender: TControl); var iPos, iTrackPos: Integer; SInfo: TScrollInfo; begin SInfo.cbSize := SizeOf(SInfo); SInfo.fMask := SIF_ALL;
GetScrollInfo(JvRichEdit1.Handle, SB_VERT, SInfo); iPos := SInfo.nPos; iTrackPos := SInfo.nTrackPos;
if iTrackPos = 0 then TControl(Sender).Top := InitialY - iPos else TControl(Sender).Top := InitialY - iTrackPos; end;
begin VScroll(Button2); end; |
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 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!