Discussion:
TControl: Scrollen (MouseMove) unterbinden, wenn Cursorr außerhalb ist
(zu alt für eine Antwort)
Stefan M. Huber
2016-06-03 10:11:36 UTC
Permalink
Grüß euch!

Kann man irgendwie unterbinden, dass ein Control weiterscrollt, wenn man
dessen Viewport verlässt?

Konkret:
1) TStringGrid auf einem Form, viele Zeilen vorhanden, sodass man
scrollen muss.
2) Mausklick und Taste halten mitten ins Grid.
3) Maus nach unten oder oben rausziehen (bei gedrückter Maustaste)

Resultat: Das Stringgrid scrollt weiter, sobald man außen herumwedelt.

Auch das MouseMove event wird hier weiter ausgeführt. Ein beherztes
if x<0 then EXIT;
hilft leider auch nicht, da offenbar die Implementierung selbst noch greift.


Stefan
Hans-Peter Diettrich
2016-06-03 13:12:20 UTC
Permalink
Post by Stefan M. Huber
Kann man irgendwie unterbinden, dass ein Control weiterscrollt, wenn man
dessen Viewport verlässt?
1) TStringGrid auf einem Form, viele Zeilen vorhanden, sodass man
scrollen muss.
2) Mausklick und Taste halten mitten ins Grid.
3) Maus nach unten oder oben rausziehen (bei gedrückter Maustaste)
Resultat: Das Stringgrid scrollt weiter, sobald man außen herumwedelt.
Ich tippe mal drauf, daß das Weiterscrollen ein Feature für
Touchscreen/pad sein soll.

Was sollte denn Deiner Meinung nach passieren, wenn der Benutzer die
Maus bei gedrückter Taste aus dem Control rauszieht, bzw. warum sollte
er sowas überhaupt machen? Mir fällt dazu nur Drag&Drop ein.

DoDi
Stefan M. Huber
2016-06-03 22:16:48 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Stefan M. Huber
Kann man irgendwie unterbinden, dass ein Control weiterscrollt, wenn
man dessen Viewport verlässt?
1) TStringGrid auf einem Form, viele Zeilen vorhanden, sodass man
scrollen muss.
2) Mausklick und Taste halten mitten ins Grid.
3) Maus nach unten oder oben rausziehen (bei gedrückter Maustaste)
Resultat: Das Stringgrid scrollt weiter, sobald man außen herumwedelt.
Ich tippe mal drauf, daß das Weiterscrollen ein Feature für
Touchscreen/pad sein soll.
Was sollte denn Deiner Meinung nach passieren, wenn der Benutzer die
Maus bei gedrückter Taste aus dem Control rauszieht, bzw. warum sollte
er sowas überhaupt machen? Mir fällt dazu nur Drag&Drop ein.
Drag&Drop müsste man ja extra erlauben.
M.E. sollte nichts passieren. Genauso wenig, wie wenn man aus einem
Button mit gedrückter Maustaste rausfährt und dann erst loslässt.

Im konkreten Fall haben wir das Problem, uns unsere TStringGrid-Controls
manchmal unkontrolliert zu scrollen beginnen. Es gibt keinen Code, der
sie automatisiert scrollt.
Aber mir ist aufgefallen, dass zB zu scrollen beginnen, wenn ich eine
Zelle anklicke, in der dann eine TComboBox eingeblendet wird und ich
danach das Programm wechsle (Alt+Tab). Ein MouseMove landet dann immer
noch im StringGrid. Höre ich auf, die Maus zu bewegen, stoppt das
scrollen. Bewege ich die Maus wieder, scrollt es weiter.

Ein 100%iges Reproduzieren gelingt mir aber nicht. Und ich habe dasselbe
Problem mit einem blöden kleinen Programm, in dem es nur 1 TForm mit 1
TStringGrid gibt, wo viele Zeilen befüllt sind auch schon nachvollziehen
können. 1x. Aber dennoch...

Klingt komisch, is aber so.

Stefan
Hans-Peter Diettrich
2016-06-04 12:15:03 UTC
Permalink
Post by Stefan M. Huber
Kann man irgendwie unterbinden, dass ein Control weiterscrollt, wenn
man dessen Viewport verlässt?
Zurück zum Problem. Man kann im Message-Dispatcher (WndProc...)
feststellen, ob sich die Maus im angesprochenen Control befindet, und
das Ereignis als erledigt markieren falls nicht (msg=0 setzen).

Man könnte auch versuchen, im OnExit Event ein WM_MOUSEUP o.ä. an das
StringGrid zu schicken, damit es das Scrollen abschaltet.

Möglicherweise werden auch Events verschlabbert, aber die Feststellung,
was da genau abläuft, ist ziemlich schwierig, da der Debugger dafür
nicht verwendbar ist. Sobald das Programm auf einen Breakpoint läuft,
kommen die GUI Messages durcheinander.

DoDi
Stefan M. Huber
2016-06-04 17:47:21 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Stefan M. Huber
Kann man irgendwie unterbinden, dass ein Control weiterscrollt, wenn
man dessen Viewport verlässt?
Zurück zum Problem. Man kann im Message-Dispatcher (WndProc...)
feststellen, ob sich die Maus im angesprochenen Control befindet, und
das Ereignis als erledigt markieren falls nicht (msg=0 setzen).
Man könnte auch versuchen, im OnExit Event ein WM_MOUSEUP o.ä. an das
StringGrid zu schicken, damit es das Scrollen abschaltet.
Möglicherweise werden auch Events verschlabbert, aber die Feststellung,
was da genau abläuft, ist ziemlich schwierig, da der Debugger dafür
nicht verwendbar ist. Sobald das Programm auf einen Breakpoint läuft,
kommen die GUI Messages durcheinander.
Ich weiß, ich arbeite schon mit Logfiles. Aber das ist extrem mühsam.
Ich glaub, ich werd's mal mit OnExit versuchen. Ich verstehe vor allem
nicht, warum die Messages noch durchkommen, wenn man das Programm
wechselt. Wir haben keine periodischen BringToFront oder ähnliches
eingebaut.

Naja
Stefan
Peter Below
2016-06-05 13:22:44 UTC
Permalink
Post by Stefan M. Huber
Grüß euch!
Kann man irgendwie unterbinden, dass ein Control weiterscrollt, wenn
man dessen Viewport verlässt?
1) TStringGrid auf einem Form, viele Zeilen vorhanden, sodass man
scrollen muss. 2) Mausklick und Taste halten mitten ins Grid.
3) Maus nach unten oder oben rausziehen (bei gedrückter Maustaste)
Resultat: Das Stringgrid scrollt weiter, sobald man außen herumwedelt.
Das ist Absicht. Wenn das nicht so funktionieren würde könnte man drag
& drop nur innerhalb der sichtbaren Zellen des Grids verwenden da man
keine Möglichkeit hätte, eine außerhalb liegenden Zielzelle während des
Ziehens in den sichtbaren Bereich zu scrollen.
Post by Stefan M. Huber
Auch das MouseMove event wird hier weiter ausgeführt. Ein beherztes
if x<0 then EXIT;
hilft leider auch nicht, da offenbar die Implementierung selbst noch greift.
stringgrid1.perform(WM_CANCELMODE, 0, 0);

könnte helfen.
--
Peter Below
TeamB
Stefan M. Huber
2016-06-06 07:09:29 UTC
Permalink
Servus!
Post by Peter Below
Post by Stefan M. Huber
Grüß euch!
Kann man irgendwie unterbinden, dass ein Control weiterscrollt, wenn
man dessen Viewport verlässt?
1) TStringGrid auf einem Form, viele Zeilen vorhanden, sodass man
scrollen muss. 2) Mausklick und Taste halten mitten ins Grid.
3) Maus nach unten oder oben rausziehen (bei gedrückter Maustaste)
Resultat: Das Stringgrid scrollt weiter, sobald man außen herumwedelt.
Das ist Absicht. Wenn das nicht so funktionieren würde könnte man drag
& drop nur innerhalb der sichtbaren Zellen des Grids verwenden da man
keine Möglichkeit hätte, eine außerhalb liegenden Zielzelle während des
Ziehens in den sichtbaren Bereich zu scrollen.
Post by Stefan M. Huber
Auch das MouseMove event wird hier weiter ausgeführt. Ein beherztes
if x<0 then EXIT;
hilft leider auch nicht, da offenbar die Implementierung selbst noch greift.
stringgrid1.perform(WM_CANCELMODE, 0, 0);
könnte helfen.
Nein, leider. Weder im OnExit, noch im OnMouseLeave. Beide Events werden
nicht gefeuert, wenn die Maustaste noch gedrückt ist.

Zu blöd, dass ich das eigentliche Fehlverhalten mit dem Wechsel des
Programms nicht wirklich reproduzieren kann.

Stefan
Peter Below
2016-06-07 17:28:28 UTC
Permalink
Post by Stefan M. Huber
Post by Peter Below
stringgrid1.perform(WM_CANCELMODE, 0, 0);
könnte helfen.
Nein, leider. Weder im OnExit, noch im OnMouseLeave. Beide Events
werden nicht gefeuert, wenn die Maustaste noch gedrückt ist.
Du mußt da OnMouseMove verwenden, die aktuelle Position checken und
obiges ausführen, wenn sie außerhalb des Grid-Clientbereichs ist.
Dadurch sollte das Grid aus dem Drag-Modus gehen, auch wenn die
Maustaste gedrückt bleibt. Dadurch werden dann aber eventuell
Klick-Events für die Stelle generiert, über der der Mauszeiger gerade
ist.

Falls Du in deinem Programm irgendwelche längerdauerenden Operationen
in OnMouseMove oder OnDragOver machst, lass es. Das ist generell
problematisch bei Controls, die bei gedrückter Maustaste automatisch
weiter scrollen (auch via Scrollbars). Dazu verwenden sie nämlich einen
internen timer, und mitunter bekommt der nicht mit, dass die Maustaste
losgelassen wurde. Dann läuft der Timer munter weiter und produziert
scroll events solange die Maus in dem "aktiven" Bereich ist.
--
Peter Below
TeamB
Stefan M. Huber
2016-06-08 07:12:12 UTC
Permalink
Post by Peter Below
Post by Stefan M. Huber
Post by Peter Below
stringgrid1.perform(WM_CANCELMODE, 0, 0);
könnte helfen.
Nein, leider. Weder im OnExit, noch im OnMouseLeave. Beide Events
werden nicht gefeuert, wenn die Maustaste noch gedrückt ist.
Du mußt da OnMouseMove verwenden, die aktuelle Position checken und
obiges ausführen, wenn sie außerhalb des Grid-Clientbereichs ist.
OK, ich werd das mal probieren. Es passieren an sich keine langatmigen
Operationen bei den Events. Aber ich prüfe das ganze mal daraufhin, ob
es nicht doch wo - indirekt - Aktionen gibt, die zu lange dauern. Das
würde das sporadische Auftreten zumindest erklären.

Danke für den Hinweis

Ste"usenet rules!"fan
Stefan M. Huber
2016-06-08 07:37:43 UTC
Permalink
Post by Peter Below
Post by Stefan M. Huber
Post by Peter Below
stringgrid1.perform(WM_CANCELMODE, 0, 0);
könnte helfen.
Nein, leider. Weder im OnExit, noch im OnMouseLeave. Beide Events
werden nicht gefeuert, wenn die Maustaste noch gedrückt ist.
Du mußt da OnMouseMove verwenden, die aktuelle Position checken und
obiges ausführen, wenn sie außerhalb des Grid-Clientbereichs ist.
Damit funktioniert's. Bekomme ich eigentlich auch irgendwie raus, ob das
Control glaubt, dass die Maustaste nocht gedrückt ist, auch wenn sie
nicht gedrückt ist?

Es gibt nämlich tatsächlich Umstände, wo im Mousemove über mehrere Ecken
langatmigere Abläufe angestoßen werden.

Und ich will nicht einfach blind ein MOUSEUP ans Control schicken, wenn
die Maustaste nicht gedrückt ist.

Stefan
Stefan M. Huber
2016-06-08 08:42:11 UTC
Permalink
Post by Stefan M. Huber
Post by Peter Below
Post by Stefan M. Huber
Post by Peter Below
stringgrid1.perform(WM_CANCELMODE, 0, 0);
könnte helfen.
Nein, leider. Weder im OnExit, noch im OnMouseLeave. Beide Events
werden nicht gefeuert, wenn die Maustaste noch gedrückt ist.
Du mußt da OnMouseMove verwenden, die aktuelle Position checken und
obiges ausführen, wenn sie außerhalb des Grid-Clientbereichs ist.
Damit funktioniert's. Bekomme ich eigentlich auch irgendwie raus, ob das
Control glaubt, dass die Maustaste nocht gedrückt ist, auch wenn sie
nicht gedrückt ist?
Leider nicht so ganz. Wir haben eine Updateprüfroutine, die im
Mainthread läuft, aber in einem Non-VCL-Thread ein WindowsAPI-Fenster
anzeigt mit der Bitte um Geduld.

Wenn ihc während dieser Updateprüfung Mousedown, ruasbewegen aus dem
Grid und Mouseup mache, bekommt das Control das nicht mit. Warum das
Mousedown noch ankommt, weiß ich noch nicht.

Konsequent weitergefragt: Gibt es ein Event, das beim Weiterscrollen
ausgelöst wird, wenn man außerhalb des Controls ist?

Stefan
Peter Below
2016-06-08 17:17:51 UTC
Permalink
Post by Stefan M. Huber
Post by Stefan M. Huber
Post by Peter Below
Post by Peter Below
stringgrid1.perform(WM_CANCELMODE, 0, 0);
Du mußt da OnMouseMove verwenden, die aktuelle Position checken
und obiges ausführen, wenn sie außerhalb des Grid-Clientbereichs
ist.
Damit funktioniert's. Bekomme ich eigentlich auch irgendwie raus,
ob das Control glaubt, dass die Maustaste nocht gedrückt ist, auch
wenn sie nicht gedrückt ist?
Nein, wie ein Control das intern handled ist Sache des Controls, da
gibt es keinen Standard. Aber WM_CANCELMODE sollte das Control auf
jeden Fall aus diesem internen "Scroll" Status bringen, egal wie das
scrolling intern realisiert wird.
Post by Stefan M. Huber
Leider nicht so ganz. Wir haben eine Updateprüfroutine, die im
Mainthread läuft, aber in einem Non-VCL-Thread ein WindowsAPI-Fenster
anzeigt mit der Bitte um Geduld.
Wenn ihc während dieser Updateprüfung Mousedown, ruasbewegen aus dem
Grid und Mouseup mache, bekommt das Control das nicht mit. Warum das
Mousedown noch ankommt, weiß ich noch nicht.
Das hat vermutlich mit dem mouse capture zu tun. Normalerweise bekommt
ein Control nur Maus-Messages wenn es

a) enabled ist (bzw. das Fenster, zu dem es gehört)
b) die Maus innerhalb der Client area des Controls ist.

Wenn ein Control auch mouse messages bekommen will, wenn der Cursor die
client area verläßt, muss es sich bei Mouse down den mouse capture
holen. Den verliert es aber nur allzuleicht wieder wenn irgend ein
anderes Fenster sich den capture krallt. Das ist so eine
Highlander-Situation: es kann nur einen geben, und zwar *systemweit*.
Post by Stefan M. Huber
Konsequent weitergefragt: Gibt es ein Event, das beim Weiterscrollen
ausgelöst wird, wenn man außerhalb des Controls ist?
Nun, auch das hängt leider vom Control ab. Wenn es intelligent
geschrieben ist scrollt es indem es sich selbst WM_VSCROLL-Messages
schickt, als ob der Benutzer den Scrollbar benutzt. In einem
entsprechenden Handler kann man aber dann normalerweise nur schwer
entscheiden, was nun die Ursache der Message war.
--
Peter Below
TeamB
Hans-Peter Diettrich
2016-06-06 23:48:51 UTC
Permalink
Post by Peter Below
Post by Stefan M. Huber
1) TStringGrid auf einem Form, viele Zeilen vorhanden, sodass man
scrollen muss. 2) Mausklick und Taste halten mitten ins Grid.
3) Maus nach unten oder oben rausziehen (bei gedrückter Maustaste)
Resultat: Das Stringgrid scrollt weiter, sobald man außen herumwedelt.
Das ist Absicht. Wenn das nicht so funktionieren würde könnte man drag
& drop nur innerhalb der sichtbaren Zellen des Grids verwenden da man
keine Möglichkeit hätte, eine außerhalb liegenden Zielzelle während des
Ziehens in den sichtbaren Bereich zu scrollen.
Drag&Drop benutzt CaptureMouse, deshalb funktioniert das dort anders als
im normalen Betrieb.
Post by Peter Below
stringgrid1.perform(WM_CANCELMODE, 0, 0);
könnte helfen.
Stimmt, das sollte helfen.

DoDi
Loading...