Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Ermitteln, wie weit ein Formular gescrollt wurde

95 views
Skip to first unread message

Jörg Ostendorp

unread,
Mar 29, 2004, 3:08:24 PM3/29/04
to
Hallo NG,

einen wunderschönen Guten Abend!
Kann mir jemand einen Tipp geben, wie ich ermitteln kann,
wie weit ein Formular - oder genauer der Detailbereich -
gescrollt vorliegt, wenn keine Scrollbars vorhanden sind,
aus denen ich diese Info auslesen kann?
Ich meine zB die Situation, wenn das Formular relativ
stark verkleinert (wiederhergestellt) wurde, ein
weiter unten liegendes Steuerelement den Fokus hat und
somit der tatsächliche Ursprung des Detailbereichs
nicht mehr sichtbar ist.

Vielen Dank und viele Grüße
Jörg Ostendorp

Henry Habermacher [MVP Access]

unread,
Mar 30, 2004, 1:19:55 AM3/30/04
to
Hallo Jörg

Jörg Ostendorp wrote in news:%23fz4Cnc...@tk2msftngp13.phx.gbl:

> Kann mir jemand einen Tipp geben, wie ich ermitteln kann,
> wie weit ein Formular - oder genauer der Detailbereich -
> gescrollt vorliegt, wenn keine Scrollbars vorhanden sind,
> aus denen ich diese Info auslesen kann?
> Ich meine zB die Situation, wenn das Formular relativ
> stark verkleinert (wiederhergestellt) wurde, ein
> weiter unten liegendes Steuerelement den Fokus hat und
> somit der tatsächliche Ursprung des Detailbereichs
> nicht mehr sichtbar ist.

IMO gibt es keine Möglichkeit, herauszufinden, was auf dem sichtbaren
Bereich eines verkleinerten Formulars drauf ist. Wenn Du aber einem
Control den Focus gibt, sollte der sichtbare Bereich jedoch so
verschoben werden, dass dieses sichtbar wird.

Du kannst Dir dies zu Nutzen machen, indem Du nach dem Restore des Forms
folgenden Code ausführst:

On Error Resume Next
Forms("DeinFormular").Controls(Screen.ActiveControl.Name).SetFocus

Du kannst diesen Code auch beim Form_Activate Ereignis reinmachen. Das
Minimieren und anschliessende Restaurieren des Forms löst dieses
Ereignis jedoch nicht aus. Dieses wird nur ausgelöst, wenn das Formular
den Focus abgegeben hat.

Hoffe, dass das wenigstens ein bisschen weiterhilft, wenn ich schon die
eigentliche Frage negativ beantworten musste.

Gruss

Henry


--
Keine E-Mails auf Postings in NGs senden!
Don't send e-mails to postings in newsgroups!
KB: http://support.microsoft.com/default.aspx
FAQ: http://www.donkarl.com/FAQ/FAQStart.htm
OH: Online Hilfe von Microsoft Access (Taste F1)
Downloads: http://www.dbdev.org

Jörg Ostendorp

unread,
Mar 30, 2004, 8:46:27 AM3/30/04
to
Hallo Henry,

>> Kann mir jemand einen Tipp geben, wie ich ermitteln kann,
>> wie weit ein Formular - oder genauer der Detailbereich -
>> gescrollt vorliegt, wenn keine Scrollbars vorhanden sind,
>> aus denen ich diese Info auslesen kann?
>> Ich meine zB die Situation, wenn das Formular relativ
>> stark verkleinert (wiederhergestellt) wurde, ein
>> weiter unten liegendes Steuerelement den Fokus hat und
>> somit der tatsächliche Ursprung des Detailbereichs
>> nicht mehr sichtbar ist.

> IMO gibt es keine Möglichkeit, herauszufinden, was auf dem sichtbaren
> Bereich eines verkleinerten Formulars drauf ist. Wenn Du aber einem
> Control den Focus gibt, sollte der sichtbare Bereich jedoch so
> verschoben werden, dass dieses sichtbar wird.

Leider gehts bei meinem Problem wirklich nur darum, die
genaue Scrollposition festzustellen, nicht darum, auf ein Control zu
fokussieren.
Zur Erklärung: Ich möchte die relative Mausposition zum Detailbereich
ermitteln, unabhängig vom Mousemove der Steuerelemente oder des
Formulares. Das ist eigentlich ja auch kein Problem, wird aber einfach
unverhältnismäßig aufwendig, wenn das Formular bzw der Detailbereich
gescrollt vorliegt. Eine Möglichkeit, die aktuelle Scrollposition direkt
auszulesen wäre daher ziemlich ideal gewesen.
<Schneuz>.

Trotzdem vielen Dank!

Viele Grüße
Jörg Ostendorp

Henry Habermacher [MVP Access]

unread,
Mar 30, 2004, 9:34:47 AM3/30/04
to
Hallo Jörg

Jörg Ostendorp wrote in news:OffSS2lF...@TK2MSFTNGP12.phx.gbl:

> Zur Erklärung: Ich möchte die relative Mausposition zum Detailbereich
> ermitteln, unabhängig vom Mousemove der Steuerelemente oder des
> Formulares. Das ist eigentlich ja auch kein Problem, wird aber einfach
> unverhältnismäßig aufwendig, wenn das Formular bzw der Detailbereich
> gescrollt vorliegt. Eine Möglichkeit, die aktuelle Scrollposition
> direkt auszulesen wäre daher ziemlich ideal gewesen.
> <Schneuz>.

Mit Access Boardmitteln geht das nicht, vielleicht mit einem API
Gehangel, aber das entzieht sich für diesen Fall meiner Kenntnis. Sorry.
Vielleicht findest Du was wenn Du in der englischen FormsCoding NG
googelst?

Paul Rohorzka

unread,
Mar 31, 2004, 3:34:36 AM3/31/04
to
Hallo Jörg!

Schau bei Stephen Lebans www.lebans.com .
Der kann das.

HTH,
Paul

Henry Habermacher [MVP Access]

unread,
Mar 31, 2004, 4:18:50 AM3/31/04
to
Hallo Paul

Paul Rohorzka wrote in news:wovac.313844$Or1....@news.chello.at:

> Schau bei Stephen Lebans www.lebans.com .
> Der kann das.

Das ist aber für Endlosformulare und gibt nicht wieder, wie weit der
einzelne Detailbereich sichtbar ist oder nicht. Der Scrollbar gibt doch
die Recordnummer des obersten Records zurück, der in der
Endlosdarstellung angezeigt ist. Oder habe ich da was falsch verstanden?

Paul Rohorzka

unread,
Mar 31, 2004, 6:46:07 AM3/31/04
to
Hallo Henry!

>>Schau bei Stephen Lebans www.lebans.com .
>>Der kann das.
>
> Das ist aber für Endlosformulare und gibt nicht wieder, wie weit der
> einzelne Detailbereich sichtbar ist oder nicht. Der Scrollbar gibt doch
> die Recordnummer des obersten Records zurück, der in der
> Endlosdarstellung angezeigt ist. Oder habe ich da was falsch verstanden?

Ich hab's mir jetzt zwar nicht noch einmal angesehen,
aber soweit ich mich erinnern kann, hast du recht, dass
in einem Endlosformular die Datensatz-Nummer zurück-
gegeben wird. Wenn es sich tatsächlich um ein Einzel-
formular handelt, was ich dem Ursprungsposting aller-
dings nicht entnehmen kann, sind für die Bildlaufleiste
sicher andere Min/Max-Werte verwendet. Das ist aber
wohl nicht das Problem, sondern eher, wie man an die
aktuelle Position des Schiebers kommt. Das kann Jörg
aus Stephens Beispiel auf jeden Fall übernehmen.
Mit den Min/Max-Werten und der Position des Schiebers
sowie der Höhe der Formularbereiche und der InsideHeight
des Formulars sollte sich der sichtbare Ausschnitt mit
ein bissl kx+d et al berechnen lassen. Bei Interesse
an der horizontalen Bildlaufleiste entsprechend einfacher.

LG,
Paul

Jörg Ostendorp

unread,
Mar 31, 2004, 6:49:25 AM3/31/04
to

Hallo zusammen,

>>> [Scrollposition des Detailbereichs bei fehlenden Scrollbars ermitteln]

Paul Rohorzka schrieb:


> > Schau bei Stephen Lebans www.lebans.com .
> > Der kann das.

Henry Habermacher [MVP Access] schrieb,


> Das ist aber für Endlosformulare und gibt nicht wieder, wie weit der
> einzelne Detailbereich sichtbar ist oder nicht. Der Scrollbar gibt doch
> die Recordnummer des obersten Records zurück, der in der
> Endlosdarstellung angezeigt ist. Oder habe ich da was falsch verstanden?

Nein, Du irrst nicht, der Stephen kann das auch nicht (oder vorsichtshalber:
hat kein Bsp auf seiner Homepage, man weiß bei dem Kerl ja nie ..)

Ich habe mittlerweile fleißig weiter probiert und gesucht aber nüscht
gefunden, auch nicht in den anderen NGs (mp.vbwinapi & Co). Entweder muß es
eine so popelige Api-Funktion geben, daß niemand sie für wichtig genug hält,
um sie ins Netz zu Stellen, oder das posthum-Auslesen geht einfach wirklich nicht.
Daher gibts imho zwei Möglichkeiten:

1. Detailbereich hooken und Scroll-Message abfangen bzw auslesen
Das wäre sicherlich die korrekte Variante, hab ich aber noch nicht
ausprobiert

2. Bei nicht sichtbaren Scrollbars: wenn RECT < Width bzw Height
den Detailbereich einfach per SendMessage auf X=0/Y=0 zurückscrollen lassen bzw.
bei sichtbaren Scrollbars: Infos aus GetScrollInfo holen.

Das funktioniert soweit, ist aber ekelig, weil man dann erst wieder
prüfen muß wieviele ScrollBars angeschaltet sind (Me.ScrollBar), denn
dementsprechend ändert sich auch die Reihenfolge in der die ScrollBars
als ChildWindow ins Formular gesetzt werden bzw die Reihenfolge in der
die Handles vergeben werden (wenn ich das richtig getestet habe werden
zwar immer beide Scrollbars gezeichnet nur die sichtbare bekommt aber auch
ein Handle verpasst). Und da die ScrollBars SB_CTLs des Formulares
sind und keine SB-VERT/SB_HORZ des Detailbereichs, brauchts deren Handles
fürs GetScrollInfo. Sehr Unschön.

Viele Grüße
Jörg Ostendorp

Jörg Ostendorp

unread,
Mar 31, 2004, 7:09:01 AM3/31/04
to
Hallo Paul,

>> [...]
> [...]


> Wenn es sich tatsächlich um ein Einzel-
> formular handelt, was ich dem Ursprungsposting aller-
> dings nicht entnehmen kann, sind für die Bildlaufleiste
> sicher andere Min/Max-Werte verwendet.

Nochmal die Situation:
Es geht um ein Einzel-Formular. Dieses Formular
hat *keine* ScrollBars. Der sichtbare Ausschnitt des Detailbereichs ist
kleiner als der tatsächliche Detailbereich. Ein Steuerelement weit unten
hat den Fokus, so daß der eigentliche Ursprung 0/0 des Detailbereichs


nicht mehr sichtbar ist .

Es handelt sich hierbei also um eine "Ausnahmesituation", die
aber eben auch mal vorkommen kann und berücksichtigt werden soll
um korrekte Cursor-Koordinaten zu erhalten.

> Das ist aber wohl nicht das Problem, sondern eher, wie man an die
> aktuelle Position des Schiebers kommt. Das kann Jörg
> aus Stephens Beispiel auf jeden Fall übernehmen.

Naa, die Position des Schiebers zu ermitteln ist einfach. Voraussetzung
dafür ist aber, daß man überhaupt Bildlaufleisten hat

> Mit den Min/Max-Werten und der Position des Schiebers
> sowie der Höhe der Formularbereiche und der InsideHeight
> des Formulars sollte sich der sichtbare Ausschnitt mit
> ein bissl kx+d et al berechnen lassen.

Obacht, es geht um den Detailbereich, nicht ums Formular :-)
Das kann ja auch mal einen Formularkopf enthalten. InsideHeight & Co
geben letztlich nur den ClientRect des *Formulares* wieder...
Aber Du hast im Prinzip schon Recht: Wenn ScrollBars da sind
kann man aus ihnen alle benötigten Infos ziehen.

Viele Grüße
Jörg Ostendorp

Paul Rohorzka

unread,
Mar 31, 2004, 7:56:45 AM3/31/04
to
Hallo Jörg!

> Hallo Paul,
>
>
>>>[...]
>>
>>[...]
>>Wenn es sich tatsächlich um ein Einzel-
>>formular handelt, was ich dem Ursprungsposting aller-
>>dings nicht entnehmen kann, sind für die Bildlaufleiste
>>sicher andere Min/Max-Werte verwendet.
>
>
> Nochmal die Situation:
> Es geht um ein Einzel-Formular. Dieses Formular
> hat *keine* ScrollBars.

Sorry, das hatte ich überlesen. Damit erübrigen sich
meine Antworten natürlich. :-/

> Der sichtbare Ausschnitt des Detailbereichs ist
> kleiner als der tatsächliche Detailbereich. Ein Steuerelement weit unten
> hat den Fokus, so daß der eigentliche Ursprung 0/0 des Detailbereichs
> nicht mehr sichtbar ist .

> Es handelt sich hierbei also um eine "Ausnahmesituation", die
> aber eben auch mal vorkommen kann und berücksichtigt werden soll
> um korrekte Cursor-Koordinaten zu erhalten.

Hmmm. Ratlos.

>>Das ist aber wohl nicht das Problem, sondern eher, wie man an die
>>aktuelle Position des Schiebers kommt. Das kann Jörg
>>aus Stephens Beispiel auf jeden Fall übernehmen.
>
>
> Naa, die Position des Schiebers zu ermitteln ist einfach. Voraussetzung
> dafür ist aber, daß man überhaupt Bildlaufleisten hat

Klar. :-)

>>Mit den Min/Max-Werten und der Position des Schiebers
>>sowie der Höhe der Formularbereiche und der InsideHeight
>>des Formulars sollte sich der sichtbare Ausschnitt mit
>>ein bissl kx+d et al berechnen lassen.
>
> Obacht, es geht um den Detailbereich, nicht ums Formular :-)
> Das kann ja auch mal einen Formularkopf enthalten.

Aus diesem Grund hatte ich ja "Formularbereichen" geschrieben.

> InsideHeight & Co
> geben letztlich nur den ClientRect des *Formulares* wieder...
> Aber Du hast im Prinzip schon Recht: Wenn ScrollBars da sind
> kann man aus ihnen alle benötigten Infos ziehen.

Würde mich interessieren, wenn du weiter gekommen bist.

LG,
Paul

Sven Arkasmussen

unread,
Mar 31, 2004, 9:36:06 AM3/31/04
to
Jörg Ostendorp schrieb:

> Es geht um ein Einzel-Formular. Dieses Formular hat *keine*
> ScrollBars. Der sichtbare Ausschnitt des Detailbereichs ist
> kleiner als der tatsächliche Detailbereich. Ein Steuerelement
> weit unten hat den Fokus, so daß der eigentliche Ursprung 0/0
> des Detailbereichs nicht mehr sichtbar ist .
> Es handelt sich hierbei also um eine "Ausnahmesituation", die
> aber eben auch mal vorkommen kann und berücksichtigt werden soll
> um korrekte Cursor-Koordinaten zu erhalten.

Mit der Höhe des Kopfbereichs, der Höhe des Fußbereichs, der Höhe des
Fensters das das Formular enthält (InsideHeight) und Oben und Höhe
des Steuerelements das den Fokus (Application.Screen.ActiveControl)
hat, mit dem allem zusammengenommen, müsstest du eigentlich so
ungefähr hinkommen, oder? Aufs Twip genau würde ich mich nicht
darauf verlassen wollen, aber auf Plus/Minus 5 Twips genau könnte
es schon das sein was du möchtest.

Salü,

Sven

--

Im Übrigen bin ich der Meinung, dass die Groß-/Kleinschreibung
abzuschaffen ist.

Jörg Ostendorp

unread,
Mar 31, 2004, 9:38:52 AM3/31/04
to

Hallo Paul,

>>[...]


> > Es handelt sich hierbei also um eine "Ausnahmesituation", die
> > aber eben auch mal vorkommen kann und berücksichtigt werden soll
> > um korrekte Cursor-Koordinaten zu erhalten.
>
> Hmmm. Ratlos.

Das beruhigt mich :-)

>> [..]


> > Naa, die Position des Schiebers zu ermitteln ist einfach. Voraussetzung
> > dafür ist aber, daß man überhaupt Bildlaufleisten hat
>
> Klar. :-)

Hab ich didaktisch gut erklärt, nicht?

> > Obacht, es geht um den Detailbereich, nicht ums Formular :-)
> > Das kann ja auch mal einen Formularkopf enthalten.
>
> Aus diesem Grund hatte ich ja "Formularbereichen" geschrieben.

Immer dieses Kleingedruckte..

> > Aber Du hast im Prinzip schon Recht: Wenn ScrollBars da sind
> > kann man aus ihnen alle benötigten Infos ziehen.
>
> Würde mich interessieren, wenn du weiter gekommen bist.

Ich bastle gerade noch am hooken, irgendwie kriege ich die ScrollMessage
aber nicht rein. Lösung kommt (hoffentlich) heute Abend. Muß mir jetzt
erstmal Schokolade kaufen gehen....

Viele Grüße
Jörg Ostendorp


Jörg Ostendorp

unread,
Apr 1, 2004, 6:48:53 AM4/1/04
to
Hallo Sven,

>> Es geht um ein Einzel-Formular. Dieses Formular hat *keine*
>> ScrollBars. Der sichtbare Ausschnitt des Detailbereichs ist
>> kleiner als der tatsächliche Detailbereich. Ein Steuerelement
>> weit unten hat den Fokus, so daß der eigentliche Ursprung 0/0
>> des Detailbereichs nicht mehr sichtbar ist .
>> Es handelt sich hierbei also um eine "Ausnahmesituation", die
>> aber eben auch mal vorkommen kann und berücksichtigt werden soll
>> um korrekte Cursor-Koordinaten zu erhalten.

> Mit der Höhe des Kopfbereichs, der Höhe des Fußbereichs, der Höhe des
> Fensters das das Formular enthält (InsideHeight) und Oben und Höhe
> des Steuerelements das den Fokus (Application.Screen.ActiveControl)
> hat, mit dem allem zusammengenommen, müsstest du eigentlich so
> ungefähr hinkommen, oder? Aufs Twip genau würde ich mich nicht
> darauf verlassen wollen, aber auf Plus/Minus 5 Twips genau könnte
> es schon das sein was du möchtest.

Ich glaube, so wie Du Dir das vorstellst klappt das eher auch nicht, oder
wie meinst Du das genau? Kopf- und Fußbereich sind imho ebenso unwichtig
wie das InsideHeight des Formulares ;-)
Bei "Oben" des Steuerelementes wird es aber schon interessanter.
Wenn man das WindowRect der Steuerelemente ermitteln könnte wär es
eigentlich ganz einfach: (Einheiten mal vernachlässigt)

Detailbereich-Ursprung-X = Abstand Steuerelement linker
Bildschirmrand - Steuerelement.Left
Detailbereich-Ursprung-Y = Abstand Steuerelement oberer
Bildschirmrand - Steuerelement.Top

Und auf diesen Punkt X/Y müßte sich dann halt der relative Cursor
beziehen.

Der Haken: Einige Steuerelemente, darunter auch Commandbuttons, scheinen
gar keine hwnd spendiert zu bekommen, mit der man die Bildschirmposition
ermitteln könnte, auch nicht wenn ich den Fokus nochmal extra draufsetze.
Beim Versuch das hwnd über Api GetFocus zu ermitteln
( http://www.mvps.org/access/api/api0027.htm ) kriege
ich jedenfalls nur das Formular zurück nicht die CommandButtons
(bei ActiveX-Zeugs klappts hingegen).


Viele Grüße
Jörg Ostendorp

Jörg Ostendorp

unread,
Apr 1, 2004, 6:47:20 AM4/1/04
to
Hallo Paul,

> Ich bastle gerade noch am hooken, irgendwie kriege ich die ScrollMessage
> aber nicht rein.

Ich gebs auf, das mit dem hooken will einfach nicht. :-(
Ich dachte, es würde in jedem Fall eine WM_VSCROLL/WM_HSCROLL
verschickt werden, wenn der sichtbare Teil des Detailbereichs
verschoben wird. Pustekuchen, 'ne ScrollMessages gibts nur
wenn auch ScrollBars vorhanden sind.
Und aus den anderen Msgs werde ich einfach nicht schlau:
Ich habe mal ausprobiert was passiert, wenn ich zwei
Commandbuttons an weit entfernte Stellen in
den Detailbereich setze und mich dann per Pfeiltasten
oder Tabulator von einem zum anderen bewege, so daß das
Formular gescrollt wird (wie gesagt Scrollbars sind nicht
vorhanden). Dabei werden folgende Msgs gefeuert (teilweise
mehrfach):

Für das Formular:
WM_KEYDOWN
Parameter: wparam/lparam für die gedrückte Taste
WM_KILLFOCUS
hwnd receiving focus
WM_SETFOCUS
hwnd losing focus
WM_PAINT
wparam 0x00000000 lparam 0x00000000
WM_ERASEBKGND
hdc-nummer
WM_KILLFOCUS
WM_SETFOCUS
WM_USER + 511 (0x000005ff)
wparam lparam (unterschiedlich)
WM_KEYUP
wieder param Taste
[..]

Für den Detailbereich (Parameter wie oben):
WM_SETFOCUS
WM_KILLFOCUS
WM_PAINT (auch 0)
WM_ERASEBKGGND
WM_SETFOCUS
WM_KILLFOCUS

Applikationsfenster:
gar nichts

Datenbankfenster:
WM_GETACTIVE
und diverse WM_USER


Wie Access sich daraus die Scroll-Position
bzw den neu zu zeichnenden Bereich ableitet
ist mir schleierhaft.

Bleibt wohl nur Variante 2:
wenn Scrollbars vorhanden sind notwendige Infos
per GetScrollInfo holen und wenn keine (oder nur eine)
vorhanden sind eben per SendMessage auf 0/0 bzw 0/Y
oder x/0 zurückscrollen.


Viele Grüße
Jörg Ostendorp

Paul Rohorzka

unread,
Apr 1, 2004, 10:27:02 AM4/1/04
to
Hallo Jörg!

Nun ja, ich schätze einmal, dass hier die interessierende
Information versteckt ist. Hast du schon einmal versucht,
diese Daten zu interpretieren? Vielleicht den Detailbereich
einmal gerade so groß machen, dass er ein Pixelchen zu
groß ist und schauen, was die beiden Parameter sagen. Dann
könntest du versuchen, mehr Pixel zu nehmen, um zu sehen,
was sich ändert. Hast du dann eine Vorstellung, wie die
Daten zu interpretieren sind, dann kannst du versuchen,
die User-Messages selbst zu schicken um zu sehen, ob der
Detailbereich reagiert.
Aaaaber: ich beneide dich nicht um diese Tüftlerei. :-/

> WM_KEYUP
> wieder param Taste
> [..]
>
> Für den Detailbereich (Parameter wie oben):
> WM_SETFOCUS
> WM_KILLFOCUS
> WM_PAINT (auch 0)
> WM_ERASEBKGGND
> WM_SETFOCUS
> WM_KILLFOCUS
>
> Applikationsfenster:
> gar nichts
>
> Datenbankfenster:
> WM_GETACTIVE
> und diverse WM_USER
>
>
> Wie Access sich daraus die Scroll-Position
> bzw den neu zu zeichnenden Bereich ableitet
> ist mir schleierhaft.
>
> Bleibt wohl nur Variante 2:
> wenn Scrollbars vorhanden sind notwendige Infos
> per GetScrollInfo holen und wenn keine (oder nur eine)
> vorhanden sind eben per SendMessage auf 0/0 bzw 0/Y
> oder x/0 zurückscrollen.

Hm? Wie? Das habe ich nicht verstanden?

Auf jeden Fall danke für die Infos, Jörg!
Falls du noch Nerven hast, hier weiterzuforschen,
wäre ich immer noch an den Erkenntnissen interessiert.

LG,
Paul

Paul Rohorzka

unread,
Apr 1, 2004, 10:35:59 AM4/1/04
to
Hallo Jörg,

noch ein kleiner Gedanke zum Problem.

Wenn ich mir vorstelle, dass Access bekanntlich seine
Steuerelemente selbst zeichnet und keine Windows dafür
verwendet, könnte man doch daraus schließen, dass
Access für jedes Window, das einen Formularbereich
aufnimmt, in einer internen Datenstruktur den
jeweiligen virtuellen Ursprung speichert und daraus
beim WM_PAINT die Positionen der Steuerelemente ab-
leitet.
Die ganze Scrollerei ohne Scrollbalken wird wahr-
scheinlich nur intern von Access selbst gehandelt,
und daher nicht zugänglich sein, da dafür eher
keine Windows-Messages verwendet werden.
Vielleicht liege ich aber falsch und die Parameter
der WM_USER-Messages des Detailbereichs-Windows
können Auskunft geben.

LG,
Paul

Sven Arkasmussen

unread,
Apr 1, 2004, 12:24:48 PM4/1/04
to
Jörg Ostendorp schrieb:

> Detailbereich-Ursprung-X = Abstand Steuerelement linker
> Bildschirmrand - Steuerelement.Left
> Detailbereich-Ursprung-Y = Abstand Steuerelement oberer
> Bildschirmrand - Steuerelement.Top
>
> Und auf diesen Punkt X/Y müßte sich dann halt der relative Cursor
> beziehen.

Nun, es gilt ja:

Höhe_sichtbarer_Ausschnitt = InsideHeight - Höhe_Kopfbereich
- Höhe_Fußbereich

Wenn nun zu einem Steuerelement außerhalb des momentan sichtbaren
Ausschnitts des Detailbereichs gesprungen wird, dann wird
gescrollt.

Das könnte man ja prüfen, ob aufgrund von Detailbereich_Ursprung_Y,
Höhe_sichtbarer_Ausschnitt, Oben_Steuerelement und Höhe_Steuerelement
das gerade zum aktiven Steuerelement gewordene Steuerelement ein
Scrollen hätte bewirken müssen oder nicht. Wenn ja, dann muss
Detailbereich_Ursprung_Y zu

Detailbereich_Ursprung_Y = Höhe_Detailbereich - (Oben_Steuerelement
+ Höhe_Steuerelement)
- Höhe_sichtbarer_Ausschnitt

neu ermittelt werden, wenn nicht dann darf das nicht gemacht werden.

Das gleiche gilt analog für Detailbereich_Ursprung_X. Dabei dann
viel Vergnügen.

Ka Prucha

unread,
Apr 1, 2004, 12:36:05 PM4/1/04
to
"Paul Rohorzka" schrieb

> Die ganze Scrollerei ohne Scrollbalken wird wahr-
> scheinlich nur intern von Access selbst gehandelt,
> und daher nicht zugänglich sein, da dafür eher
> keine Windows-Messages verwendet werden.

Servus

Sicher hat Access solche Routinen. Wahrscheinlich ist deshalb
auch die Anzahl der Elemente je Formular limitiert.
Soweit ich mich erinnern kann mußte zumindest früher jede
Anwendung auf das Repaint Ereignis selbst reagieren.
Das GUI stellt dabei nur die Koordinaten des Innenteils des
eigenen Fensters zur Verfügung. Ob es Bereiche aus einem
'privatem' Cache einblendet, verschiebt oder neu zeichnet, muß
die Anwendung (in diesem Fall Access/Jet) selbst entscheiden
und ausführen.

mfg Ka Prucha

Jörg Ostendorp

unread,
Apr 2, 2004, 12:49:07 AM4/2/04
to
Hallo Paul,

>> [..]


> > Wie Access sich daraus die Scroll-Position
> > bzw den neu zu zeichnenden Bereich ableitet
> > ist mir schleierhaft.
> >
> > Bleibt wohl nur Variante 2:
> > wenn Scrollbars vorhanden sind notwendige Infos
> > per GetScrollInfo holen und wenn keine (oder nur eine)
> > vorhanden sind eben per SendMessage auf 0/0 bzw 0/Y
> > oder x/0 zurückscrollen.
>
> Hm? Wie? Das habe ich nicht verstanden?

Na dann nochmal für die ganz langsamen zum mitschreiben ;-)
Was ich meine ist folgendes (mal +- unkommentiert und ohne
Fehlerbehandlung):

-(Ich hoffe, die Formatierung haut so einigermaßen hin)
-(den unschönen Timer, sollte man noch durch ein Public
-Event ersetzen, irgendwas wie ScreenMouseMove o.ä.)
-(Bei Bugs bitte melden)

' ****************************** <CODE> *********************************
' (Code ins Formular)

Option Compare Database
Option Explicit

'Typen
Private Type POINTAPI
X As Long
Y As Long
End Type

Private Type RECT
left As Long
top As Long
right As Long
bottom As Long
End Type

Private Type SCROLLINFO
cbSize As Long
fMask As Long
nMin As Long
nMax As Long
nPage As Long
nPos As Long
nTrackPos As Long
End Type

'Konstanten
'GetWindow
Private Const GW_CHILD = 5
Private Const GW_HWNDNEXT = 2
'WindowMessage
Private Const WM_HSCROLL As Long = &H114
Private Const WM_VSCROLL As Long = &H115
'ScrollBar
Private Const SB_PAGELEFT As Long = 2
Private Const SB_PAGEUP As Long = 2
Private Const SB_CTL As Long = 2
'ScrollInfo
Private Const SIF_RANGE = &H1
Private Const SIF_PAGE = &H2
Private Const SIF_POS = &H4
Private Const SIF_DISABLENOSCROLL = &H8
Private Const SIF_ALL = SIF_RANGE Or SIF_PAGE Or SIF_POS

'Eigene Variablen
Private P As POINTAPI
Private R As RECT
Private ScrI As SCROLLINFO

'APIS
Private Declare Function GetWindowRect Lib "user32.dll" _
(ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function GetWindow Lib "user32" _
(ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function GetClassName Lib "user32" _
Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, _
ByVal nMaxCount As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" ( _
ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function GetScrollInfo Lib "user32.dll" (ByVal hwnd As Long, _
ByVal n As Long, lpScrollInfo As SCROLLINFO) As Long


'Prozeduren

Private Sub Detailbereich_MouseMove(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Me!lblDetailCursorX.Caption = X
Me!lblDetailCursorY.Caption = Y
End Sub

Private Sub Form_Timer()

'(Besser Timer durch Public Event ScreenMouseMove ersetzen o.ä.)

'Mach was mit der *GetDetailCursorPosition*, zB:
'
GetCursorPos P
Me!lblScrollBars.Caption = Switch(Me.ScrollBars = 0, "Keine", Me.ScrollBars = 1, _
"Horizontal", Me.ScrollBars = 2, "Vertikal", Me.ScrollBars =
3, _
"Beide")
Me!lblAbsScreenCursorX.Caption = P.X
Me!lblAbsScreenCursorY.Caption = P.Y
Me!lblRelScreenCursorX.Caption = GetDetailCursorPosition.X
Me!lblRelScreenCursorY.Caption = GetDetailCursorPosition.Y
Me!lblHScrollPos.Caption = GetHScrollposition.nPos * 15
Me!lblVScrollPos.Caption = GetVScrollposition.nPos * 15
End Sub


Private Function FindDetailWindow(ByVal frmhwnd As Long) As Long
'Funktion von Stephen Lebans(?)
'Ermittel das Handle des Detailereichs
Dim Dhwnd As Long
Dim hwnd As Long
Dim ctr As Long
Dim counter As Long
counter = 2 ' Der Detailbereich ist IMMER das zweite "OFormSub"-ChildWindow
'des Formulares
ctr = 0
hwnd = frmhwnd
Dhwnd = GetWindow(hwnd, GW_CHILD)
Do
If fGetClassName(Dhwnd) = "OFormSub" Then
ctr = ctr + 1
If ctr = counter Then
FindDetailWindow = Dhwnd
Exit Function
End If
End If
Dhwnd = GetWindow(Dhwnd, GW_HWNDNEXT)
Loop While Dhwnd <> 0
FindDetailWindow = 0
End Function

Private Function FindHScrollbar(ByVal frmhwnd As Long) As Long
'Ermittelt das Handle der horizontalen ScrollBar
Dim Dhwnd As Long
Dim hwnd As Long
Dim ctr As Long
Dim counter As Long ' Reihenfolge der Scrollbar
'ist unterschiedlich je nachdem welche Scrollbars "an" sind
'Die Horizontale ist aber immer an erster Stelle, also
counter = 1
ctr = 0
hwnd = frmhwnd
Dhwnd = GetWindow(hwnd, GW_CHILD)
Do
If fGetClassName(Dhwnd) = "ScrollBar" Then
ctr = ctr + 1
If ctr = counter Then
FindHScrollbar = Dhwnd
Exit Function
End If
End If
Dhwnd = GetWindow(Dhwnd, GW_HWNDNEXT)
Loop While Dhwnd <> 0
FindHScrollbar = 0
End Function
Private Function FindVScrollbar(ByVal frmhwnd As Long) As Long
'Ermittelt das Handle der vertikalen ScrollBar
Dim Dhwnd As Long
Dim hwnd As Long
Dim ctr As Long
Dim counter As Long ' Reihenfolge der Scrollbar
'ist unterschiedlich je nachdem welche Scrollbars "an" sind
'Die vertikale kann an Stelle 1 oder 2 stehen, alse

Select Case Me.ScrollBars
Case 2
counter = 1
Case 3
counter = 2
Case Else
FindVScrollbar = 0 ' keine veretikale Scrollbar
Exit Function
End Select

ctr = 0
hwnd = frmhwnd
Dhwnd = GetWindow(hwnd, GW_CHILD)
Do
If fGetClassName(Dhwnd) = "ScrollBar" Then
ctr = ctr + 1
If ctr = counter Then
FindVScrollbar = Dhwnd
Exit Function
End If
End If
Dhwnd = GetWindow(Dhwnd, GW_HWNDNEXT)
Loop While Dhwnd <> 0
FindVScrollbar = 0
End Function

Private Function fGetClassName(hwnd As Long)
'Übersetzt die Klasse in eine verständliche Sprache :-)
Dim strBuffer As String
Dim lngLen As Long
Const MAX_LEN = 255
strBuffer = Space$(MAX_LEN)
lngLen = GetClassName(hwnd, strBuffer, MAX_LEN)
If lngLen > 0 Then fGetClassName = left$(strBuffer, lngLen)
End Function


Private Function GetHScrollposition() As SCROLLINFO
'Ermittelt alle Infos zur horizontalen
'Scrollbar. Ok, ein GetScrollPos-Api hätte es auch getan,
'aber dafür heißt diese Funkion jetzt so
Dim Dhwnd As Long
Dhwnd = FindHScrollbar(Me.hwnd)
With ScrI
.cbSize = LenB(ScrI)
.fMask = SIF_ALL
End With
GetScrollInfo Dhwnd, SB_CTL, ScrI
GetHScrollposition = ScrI
End Function

Private Function GetVScrollposition() As SCROLLINFO
'Ermittelt entsprechend die Infos zur vertikalen Scrollbar
Dim Dhwnd As Long
Dhwnd = FindVScrollbar(Me.hwnd)
With ScrI
.cbSize = LenB(ScrI)
.fMask = SIF_ALL
End With
GetScrollInfo Dhwnd, SB_CTL, ScrI
GetVScrollposition = ScrI
End Function

Private Function GetDetailCursorPosition() As POINTAPI ' in Twips
'Ermittelt nun endlich den relativen Cursor, je nachdem
'welche Scrollbar aktiviert ist
GetCursorPos P
GetWindowRect FindDetailWindow(Me.hwnd), R
'Anmerkung: *15 Umrechung in Twips (geht auch eleganter..), +15 weil
'der Detailbereich hier offenbar 1 Pixel-Offset hat)
Select Case Me.ScrollBars
Case 0
ScrollHome ' wenn keine Scrollbar zurückscrollen
GetDetailCursorPosition.X = (P.X - R.left) * 15 + 15
GetDetailCursorPosition.Y = (P.Y - R.top) * 15 + 15
Case 1
ScrollYHome 'wenn keine vertikale SB vertikal zurücksrollen
GetDetailCursorPosition.X = (P.X - R.left + GetHScrollposition.nPos) * 15 + 15
GetDetailCursorPosition.Y = (P.Y - R.top) * 15 + 15
Case 2
ScrollXHome 'wenn keine horizontale SB horizontal zurückscrollen
GetDetailCursorPosition.X = (P.X - R.left) * 15 + 15
GetDetailCursorPosition.Y = (P.Y - R.top + GetVScrollposition.nPos) * 15 + 15
Case 3
GetDetailCursorPosition.X = (P.X - R.left + GetHScrollposition.nPos) * 15 + 15
GetDetailCursorPosition.Y = (P.Y - R.top + GetVScrollposition.nPos) * 15 + 15
End Select
End Function

'Rückscroll-Funktionen
'For..next, weils 10fach einfach besser hält
'kann bei stark verkleinertem Fenster sonst schon mal
'Probleme machen
Private Function ScrollXHome()
Dim i As Integer
For i = 1 To 10
SendMessage Me.hwnd, WM_HSCROLL, SB_PAGELEFT, 0&
Next i
End Function

Private Function ScrollYHome()
Dim i As Integer
For i = 1 To 10
SendMessage Me.hwnd, WM_VSCROLL, SB_PAGEUP, 0&
Next i
End Function

Private Function ScrollHome()
Dim i As Integer
For i = 1 To 10
SendMessage Me.hwnd, WM_VSCROLL, SB_PAGEUP, 0&
SendMessage Me.hwnd, WM_HSCROLL, SB_PAGELEFT, 0&
Next i
End Function

'*********************************</Code>********************************


Bei mir funktioniert das so. Allerdings finde ich die
Lösung mit dem Zurücksrollen suboptimal. Daher ja
meine ursprüngliche Frage, ob es nicht eine Möglichkeit gibt
Scrollinfos auszulesen, wenn es keine ScrollBars gibt....


Viele Grüße
Jörg Ostendorp


Jörg Ostendorp

unread,
Apr 2, 2004, 1:00:12 AM4/2/04
to

Hallo Sven

> [..]


> Das gleiche gilt analog für Detailbereich_Ursprung_X. Dabei dann
> viel Vergnügen.

Danke ;-)
Ja, aber wenn ich das Access-Fenster verschiebe, wär alles für die Katz...
Ums nochmal deutlich zu machen: Mein ursprüngliches Problem war es
ja nicht einen relativen Cursor zu ermitteln, sondern eine einfachere bzw
elegantere Möglichkeit zu finden, als die die ich jetzt habe (schau mal ins Postign von
mir an Paul). Das wäre imho (nur) dann gegangen, wenn es eine Api-Funktion
gegeben hätte, mit der ich gleichzeitig die Rects des sichtbaren Teils
eines Fensters und des vollständigen Fenster hätte auslesen können.

Viele Grüße
Jörg Ostendorp


Jörg Ostendorp

unread,
Apr 2, 2004, 1:11:24 AM4/2/04
to

Hallo nochmal,

sorry, da hab ich wohl vergessen vor die

Me!lbl....Caption... noch nen Fliegendreck hinzusetzen

Aber ich hoffe, das ist selbsterklärend .. :-()

Viele Grüße
Jörg Ostendorp

Paul Rohorzka

unread,
Apr 2, 2004, 2:58:48 AM4/2/04
to
Hi Jörg!

> Hallo nochmal,
>
> sorry, da hab ich wohl vergessen vor die
>
> Me!lbl....Caption... noch nen Fliegendreck hinzusetzen
>
> Aber ich hoffe, das ist selbsterklärend .. :-()

Danke für den Code. Da wir dieses WoE (beginnend mit
heute) unsere Wohnung neu ausmalen, komme ich aber
wohl erst in ein paar Tagen dazu, mir das genauer
anzusehen. Danke aber vorerst. :-)

LG,
Paul

Paul Rohorzka

unread,
Apr 2, 2004, 3:14:37 AM4/2/04
to
Hallo Ka!

>>Die ganze Scrollerei ohne Scrollbalken wird wahr-
>>scheinlich nur intern von Access selbst gehandelt,
>>und daher nicht zugänglich sein, da dafür eher
>>keine Windows-Messages verwendet werden.
>
>
> Servus
>
> Sicher hat Access solche Routinen. Wahrscheinlich ist deshalb
> auch die Anzahl der Elemente je Formular limitiert.
> Soweit ich mich erinnern kann mußte zumindest früher jede
> Anwendung auf das Repaint Ereignis selbst reagieren.

Das ist auch heute noch so, dass jedes Fenster auf
WM_PAINT reagieren muss. Da gibt es IMHO eine Ausnahme:
Man kann beim Registrieren der Fensterklasse einen
Stil angeben, damit Windows das Bitmap des Client-Bereichs
selbstständig puffert und ggflls. wiederherstellt. Ist
aber aus Gründen der Systemressourcen nicht wirklich
besonders sinnvoll. Eher brute-force, quick'n'dirty.

> Das GUI stellt dabei nur die Koordinaten des Innenteils des
> eigenen Fensters zur Verfügung. Ob es Bereiche aus einem
> 'privatem' Cache einblendet, verschiebt oder neu zeichnet, muß
> die Anwendung (in diesem Fall Access/Jet) selbst entscheiden
> und ausführen.

Meine Worte. :-)


LG,
Paul

Jörg Ostendorp

unread,
Apr 3, 2004, 1:07:46 PM4/3/04
to
Hallo Paul,

nur noch mal fürs Protokoll :-)

Ich hab mir das Ganze jetzt als Klassenmodul zusammengezimmert.
Darin gibts ein Event "DetailMouseMove", das dann vom Formular her aufgerufen
werden kann. Der Unterschied zum normalen Detailbereich_Mousemove
ist letztlich nur der, daß einerseits die Shift- und Button-Sachen fehlen
(war ich zu faul für) andererseits, daß die Cursorposition nun aber auch auch
über den Steuerlementen (auch Subform & Co) zurückgegeben wird und zwar ohne
das nervige Flackern eines Timers.

Änderungen gegenüber dem bisher geposteten Code:
- Ich habe ein bißchen aufgeräumt
- Umrechnung des Pixel und Twips korrekt übern DeviceCap
- Zusätzliche Prüfung auf IsWindowEnabled bei den
Scrollbars. (Gibt ansonsten ggf falsche Koordinaten,
wenn man ein gescrolltes Fenste vergrößert, so daß die Scrollbars
nicht mehr sichtbar sind. Dann wird nämlich die Position
immer noch gespeichert, obwohl der Detailbereich ab
0/0 neu gezeichnet wird. <Nerv>)

Ich denke mal, allgemeine Warnungen wegen des hookens könnte ich mir
ersparen ;-), aber falls jemand anderes das noch lesen sollte:
Das Ganze läuft wegen des "AdressOf" im Klassenmodul nur
ab A00 (glaube ich zumindest), ist ohne Fehlerbehandlung,
Netz und doppelten Boden und somit eine prima Gelegenheit,
seine Anwendung ins Nirwana zu schicken.


Der Code besteht also jetzt aus drei Teilen
1. Formular
2. Allg Modul "modPublicDetailEvents"
3. Klassenmodul "clsPublicDetailEvents"

*******************************************************************
1. Formular:

Option Compare Database
Option Explicit

Dim WithEvents cDetailMouseMove As clsPublicDetailEvents

Private Sub Form_Load()
Set cDetailMouseMove = New clsPublicDetailEvents
cDetailMouseMove.ini Me
End Sub

Private Sub cDetailMouseMove_DetailMouseMove(x As Long, y As Long)
'Mach was mit den Cursorkoordinaten
End Sub

Private Sub Form_Unload(Cancel As Integer)
Set cDetailMouseMove = Nothing
End Sub

*******************************************************************
2. Allgemeines Modul, dieses MUß "modPublicDetailEvents"
heißen (oder AdressOf im cls muß angepaßt.)
(Name, weil man hier ja btw auch noch andere Events einbauen könnte..)

Option Compare Database
Option Explicit

Public pPublicDetailEvents As clsPublicDetailEvents

Public Function fctDetailProc(ByVal hwnd As Long, ByVal msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long

fctDetailProc = pPublicDetailEvents.DetailProc(hwnd, msg, wParam, lParam)

End Function

*********************************************************************
3. Klassenmodul clsPublicDetailEvents (muß ebenfalls so heißen..)


Option Compare Database
Option Explicit

Private Type POINTAPI


X As Long
Y As Long
End Type


Private Type RECT
left As Long
top As Long
right As Long
bottom As Long
End Type

Private Type SCROLLINFO
cbSize As Long
fMask As Long
nMin As Long
nMax As Long
nPage As Long
nPos As Long
nTrackPos As Long
End Type


'Events ------------------------------------------------------
Public Event DetailMouseMove(X As Long, Y As Long)


'Konstanten --------------------------------------------------


'GetWindow
Private Const GW_CHILD = 5
Private Const GW_HWNDNEXT = 2

'GetWindowLong
Private Const GWL_WNDPROC As Long = (-4)


'WindowMessage
Private Const WM_HSCROLL As Long = &H114
Private Const WM_VSCROLL As Long = &H115

Private Const WM_NCHITTEST As Long = &H84
Private Const WM_SETCURSOR As Long = &H20


'ScrollBar
Private Const SB_PAGELEFT As Long = 2
Private Const SB_PAGEUP As Long = 2
Private Const SB_CTL As Long = 2

'SCROLLINFO


Private Const SIF_RANGE = &H1
Private Const SIF_PAGE = &H2
Private Const SIF_POS = &H4

Private Const SIF_ALL = SIF_RANGE Or SIF_PAGE Or SIF_POS

'Devicecap
Private Const DC_LOGPIXELSX As Long = 88
Private Const DC_LOGPIXELSY As Long = 90

'Eigene Konstanten
Private Const conOffset As Long = 1 'Pixel-Offset des Detailbereichs
Private Const tpi As Long = 1440 ' Twips per Inch


'Variablen -------------------------------------------------


Private P As POINTAPI
Private R As RECT
Private ScrI As SCROLLINFO

Private mform As Form
Private mDetailhwnd As Long
Private mDetailProc As Long
Dim zzz As Long


'APIS--------------------------------------------------------


Private Declare Function GetWindowRect Lib "user32.dll" _

(ByVal hwnd As Long, lpRECT As RECT) As Long


Private Declare Function GetWindow Lib "user32" _
(ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function GetClassName Lib "user32" _
Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, _
ByVal nMaxCount As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" ( _
ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function GetScrollInfo Lib "user32.dll" (ByVal hwnd As Long, _
ByVal n As Long, lpScrollInfo As SCROLLINFO) As Long

Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, _
ByVal hDC As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, _
ByVal iCapability As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long, ByVal wNewWord As Long) As Long
Private Declare Function IsWindowEnabled Lib "user32.dll" ( _
ByVal hwnd As Long) As Long


'Prozeduren ---------------------------------------------------
Public Sub ini(frm As Form)
Set mform = frm
mDetailhwnd = FindDetailWindow
Set modPublicDetailEvents.pPublicDetailEvents = Me
hook
End Sub

Private Function GetDetailCursorPosition() As POINTAPI ' in Twips

'Ermittelt relativen Cursor zum Detailbereich, je nachdem


'welche Scrollbar aktiviert ist
GetCursorPos P

GetWindowRect mDetailhwnd, R
Select Case mform.ScrollBars


Case 0
ScrollHome ' wenn keine Scrollbar zurückscrollen

P.X = P.X - R.left + conOffset
P.Y = P.Y - R.top + conOffset


Case 1
ScrollYHome 'wenn keine vertikale SB vertikal zurücksrollen

P.X = P.X - R.left + GetHScrollposition.nPos + conOffset
P.Y = P.Y - R.top + conOffset


Case 2
ScrollXHome 'wenn keine horizontale SB horizontal zurückscrollen

P.X = P.X - R.left + conOffset
P.Y = P.Y - R.top + GetVScrollposition.nPos + conOffset
Case 3
P.X = P.X - R.left + GetHScrollposition.nPos + conOffset
P.Y = P.Y - R.top + GetVScrollposition.nPos + conOffset
End Select
GetDetailCursorPosition = GetTwipsFromPixel(P)
End Function

Private Function FindDetailWindow() As Long
'Funktion stammt von Stephen Lebans(?)


'Ermittel das Handle des Detailereichs

Dim hwnd As Long 'Formular-Handle
Dim chwnd As Long 'Child-Handle
Dim counter1 As Long
Dim counter2 As Long
counter1 = 0
counter2 = 2 ' Der Detailbereich ist IMMER das zweite
'"OFormSub"-ChildWindow des Formulares
hwnd = mform.hwnd
chwnd = GetWindow(hwnd, GW_CHILD)
Do
If fGetClassName(chwnd) = "OFormSub" Then
counter1 = counter1 + 1
If counter1 = counter2 Then
FindDetailWindow = chwnd


Exit Function
End If
End If

chwnd = GetWindow(chwnd, GW_HWNDNEXT)
Loop While chwnd <> 0


FindDetailWindow = 0
End Function

Private Function FindHScrollbar() As Long


'Ermittelt das Handle der horizontalen ScrollBar

Dim hwnd As Long
Dim chwnd As Long
Dim counter1 As Long
Dim counter2 As Long ' Reihenfolge der Scrollbar


'ist unterschiedlich je nachdem welche Scrollbars "an" sind
'Die Horizontale ist aber immer an erster Stelle, also

counter1 = 0
counter2 = 1
hwnd = mform.hwnd
chwnd = GetWindow(hwnd, GW_CHILD)
Do
If fGetClassName(chwnd) = "ScrollBar" Then
counter1 = counter1 + 1
If counter1 = counter2 Then
FindHScrollbar = chwnd


Exit Function
End If
End If

chwnd = GetWindow(chwnd, GW_HWNDNEXT)
Loop While chwnd <> 0


FindHScrollbar = 0
End Function

Private Function FindVScrollbar() As Long


'Ermittelt das Handle der vertikalen ScrollBar

Dim hwnd As Long
Dim chwnd As Long
Dim counter1 As Long
Dim counter2 As Long ' Reihenfolge der Scrollbar


'ist unterschiedlich je nachdem welche Scrollbars "an" sind
'Die vertikale kann an Stelle 1 oder 2 stehen, alse

Select Case mform.ScrollBars
Case 2 'nur vertikale SB
counter2 = 1
Case 3 ' beide SBs
counter2 = 2
End Select

counter1 = 0
hwnd = mform.hwnd
chwnd = GetWindow(hwnd, GW_CHILD)
Do
If fGetClassName(chwnd) = "ScrollBar" Then
counter1 = counter1 + 1
If counter1 = counter2 Then
FindVScrollbar = chwnd


Exit Function
End If
End If

chwnd = GetWindow(chwnd, GW_HWNDNEXT)
Loop While chwnd <> 0


FindVScrollbar = 0
End Function

Private Function fGetClassName(hwnd As Long)
'Übersetzt die Klasse in eine verständliche Sprache :-)
Dim strBuffer As String
Dim lngLen As Long
Const MAX_LEN = 255
strBuffer = Space$(MAX_LEN)
lngLen = GetClassName(hwnd, strBuffer, MAX_LEN)
If lngLen > 0 Then fGetClassName = left$(strBuffer, lngLen)
End Function

Private Function GetHScrollposition() As SCROLLINFO
'Ermittelt alle Infos zur horizontalen
'Scrollbar.

Dim DhWnd As Long
DhWnd = FindHScrollbar


With ScrI
.cbSize = LenB(ScrI)
.fMask = SIF_ALL
End With

GetScrollInfo DhWnd, SB_CTL, ScrI
GetHScrollposition = ScrI
If IsWindowEnabled(DhWnd) = False Then
GetHScrollposition.nPos = 0
End If
End Function

Private Function GetVScrollposition() As SCROLLINFO
'Ermittelt entsprechend die Infos zur vertikalen Scrollbar

Dim DhWnd As Long
DhWnd = FindVScrollbar


With ScrI
.cbSize = LenB(ScrI)
.fMask = SIF_ALL
End With

GetScrollInfo DhWnd, SB_CTL, ScrI
GetVScrollposition = ScrI
If IsWindowEnabled(DhWnd) = False Then
GetVScrollposition.nPos = 0
End If
End Function

'Rückscroll-Funktionen (For..next, weils 10fach einfach besser hält)
Private Sub ScrollXHome()


Dim i As Integer
For i = 1 To 10

SendMessage mform.hwnd, WM_HSCROLL, SB_PAGELEFT, 0&
Next i
End Sub

Private Sub ScrollYHome()


Dim i As Integer
For i = 1 To 10

SendMessage mform.hwnd, WM_VSCROLL, SB_PAGEUP, 0&
Next i
End Sub

Public Sub ScrollHome()


Dim i As Integer
For i = 1 To 10

SendMessage mform.hwnd, WM_VSCROLL, SB_PAGEUP, 0&
SendMessage mform.hwnd, WM_HSCROLL, SB_PAGELEFT, 0&
Next i
End Sub

'Umrechnung Pixel in Twips
Private Function GetTwipsFromPixel(pixel As POINTAPI) As POINTAPI
Dim dc As Long
dc = GetDC(0)
GetTwipsFromPixel.X = (pixel.X / GetDeviceCaps(dc, DC_LOGPIXELSX)) * tpi
GetTwipsFromPixel.Y = (pixel.Y / GetDeviceCaps(dc, DC_LOGPIXELSY)) * tpi
ReleaseDC 0, dc
End Function

Public Function DetailProc(ByVal hwnd As Long, ByVal msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long

Select Case msg
Case WM_NCHITTEST, WM_SETCURSOR
RaiseEvent DetailMouseMove(GetDetailCursorPosition.X, _
GetDetailCursorPosition.Y)
'Werbung: Hier könnte auch Ihre Message stehen :-)
End Select
DetailProc = CallWindowProc(mDetailProc, hwnd, msg, wParam, lParam)
End Function

Private Sub hook()
mDetailProc = SetWindowLong(mDetailhwnd, GWL_WNDPROC, _
AddressOf modPublicDetailEvents.fctDetailProc)
End Sub

Private Sub unhook()
SetWindowLong mDetailhwnd, GWL_WNDPROC, mDetailProc
End Sub

Private Sub Class_Terminate()
unhook
End Sub

'**************************************************************************
</Code>

Noch ein schönes Wochenende!

Viele Grüße
Jörg Ostendorp


Klaus Oberdalhoff [MVP]

unread,
Apr 3, 2004, 3:09:27 PM4/3/04
to
Hi,

> Ich denke mal, allgemeine Warnungen wegen des hookens könnte ich mir
> ersparen ;-), aber falls jemand anderes das noch lesen sollte:
> Das Ganze läuft wegen des "AdressOf" im Klassenmodul nur
> ab A00 (glaube ich zumindest),

Nope, für Access 97 gibt es einen unsupporteten "Hack" für AddressOf

http://www.mvps.org/access/api/api0031.htm

bzw gleich bei

http://www.trigeminal.com/lang/1033/codes.asp?ItemID=19#19

mfg

Klaus Oberdalhoff

Jörg Ostendorp

unread,
Apr 3, 2004, 5:32:38 PM4/3/04
to
Hallo Klaus,

> > Das Ganze läuft wegen des "AdressOf" im Klassenmodul nur
> > ab A00 (glaube ich zumindest),

> Nope, für Access 97 gibt es einen unsupporteten "Hack" für AddressOf
>
> http://www.mvps.org/access/api/api0031.htm

> http://www.trigeminal.com/lang/1033/codes.asp?ItemID=19#19


Danke für den Hinweis, gut zu wissen..
Da steht sogar was in der KnowHow zu, unglaublich :-)


Viele Grüße
Jörg Ostendorp

Falls es jemanden interessiert, noch eine kleine Berichtigung:
Hatte beim Testen irgendwie Probleme wenn ich bei AddressOf
nur die Funktion ohne Modulanamen angegeben habe, lag aber
anscheinend doch an was anderem...
(3. ".. there are so many different ways to set up things wrong.")

Also reicht doch:


Public Sub ini(frm As Form)

'..
Set pPublicDetailEvents = Me
'.. ^^^^^^^^^^^^
End Sub

'und

Private Sub hook()
mDetailProc = SetWindowLong(mDetailhwnd, GWL_WNDPROC, _

AddressOf fctDetailProc)
' ^^^^^^^^
End Sub

und das mit der festen Modulbezeichnung ist dann Unsinn.


0 new messages