Ich benutze in Access 2007 in einem Endlos-Formular das Ereigniss MouseMove
eines Steuerelements im Detailbereich. Die Routine soll dabei auf jenen
Datensatz zugreifen, auf dessen Steuerelement mit der Maus gezeigt wurde.
Wie kann ich im Code vom MouseMove-Ereignis herausfinden, welcher Datensatz
sich unterm Mauszeiger befindet? Es ist ja nicht notwendigerweise der, der
aktuell den Focus hat.
Ich hoffe, ich habe das jetzt verständlich formuliert
(und ich hoffe, dass das überhaupt irgendwie möglich ist)
Herzlichen Dank im Voraus für alle Tipps und Hinweise!
Grüße
Günther Grund
Stephen Lebans hat einiges "irgendwie möglich" gemacht.
Hier findest du seine Beispiel-DB:
http://www.lebans.com/conformscurcontrol.htm
--
Servus
Karl
****************
Access-FAQ: http://www.donkarl.com
Das wäre prinzipiell genau das, was ich suche - allerdings hatte ich
gehofft, dass man nicht derart tief in die Trickkiste greifen muss.
Hauptproblem ist außerdem, dass es nicht zuverlässig funktioniert. Auf
meinem alten XP-Rechner werden zumindest am Anfang die richtigen Werte
angezeigt, nach einer Weil Rauf- und Runter-Scrollen dann aber nicht mehr.
Auf meinem Win7-PC werden von Anfang an falsche Werte angezeigt.
Werd' mich mal in den Code vergraben...
Danke nochmal
Grüße
Günther
Günther Grund schrieb:
> Danke Karl für den Link!
>
> Das wäre prinzipiell genau das, was ich suche - allerdings hatte ich
> gehofft, dass man nicht derart tief in die Trickkiste greifen muss.
Ich versucht eine Variante ohne API-Funktionen:
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Static lastRsPos As Long
Dim tempRsPos As Long
Dim rs As DAO.Recordset
tempRsPos = (Y - Me.CurrentSectionTop) \ Me.Section(0).Height _
+ (Me.CurrentSectionTop > Y)
If lastRsPos <> tempRsPos Then
lastRsPos = tempRsPos
Set rs = Me.RecordsetClone
rs.Bookmark = Me.Bookmark
rs.Move tempRsPos
'ControlTipText für die Steuerelemente einstellen
Me.Steuerelement1.ControlTipText = """" & rs.Fields("Feld1") & """"
Me.Steuerelement2.ControlTipText = """" & rs.Fields("Feld2") & """"
'...
End If
End Sub
> Hauptproblem ist außerdem, dass es nicht zuverlässig funktioniert.
Das Problem besteht auch noch in dem Code von mir, der nur
funktioniert, solange der markierte DS sichtbar ist.
... aber vielleicht kann man (=du ;-)) das noch beheben.
mfg
Josef
--
Code-Bibliothek für Access-Entwickler: http://access-codelib.net/
Access-FAQ von Karl Donaubauer: http://www.donkarl.com/
Günther Grund schrieb:
Nun sah ich mir auch den Code von Lebans an. :-)
=>
Damit es bei mir (Win7 und AC07) funktionierte, musste ich folgendes
ändern:
Klasse clsControlData:
Private Function fIsScrollBar(frm As Form) As Long
...
'If fGetClassName(hWnd_VSB) = "scrollBar" Then
'Austausch gegen:
If fGetClassName(hWnd_VSB) = "NUIScrollbar" Then
...
EDIT: hab gerade gesehen, dass Du Dich auch in den Lebans-Code vertieft
hast...
@Karl:
Ich habe mir den Code nun etwas genauer angeschaut:
Der Fehler beim Test mit Win7&Access2007 war leicht zu beheben:
ALT: If fGetClassName(hWnd_VSB) = "scrollBar" Then
NEU: If InStr(fGetClassName(hWnd_VSB), "scrollBar") > 0 Then
Der ClassName lautet aktuell „NUIScrollbar“ statt ehemals „scrollBar“.
Damit läuft der Code perfekt - auch unter WinXP&Access2007RunTime.
Da ich mit API-Funktionen bislang wenig zu tun hatte, hätte ich dazu noch
eine wichtige Frage:
Kann man davon ausgehen, dass die ganze Sache „in der freien Wildbahn“
zuverlässig funktioniert oder muss man damit rechnen, dass auf jedem zweiten
Windows-Rechner das irgendwie schiefläuft?
(Ich habe den Declare-Part des Codes unten angehängt.)
Beim Test unter WinXP&Access2003 traten zwei Fehler auf, die mit Access2007
nicht aufgetreten sind:
Fehler 1:
Wenn man, nachdem die letzte Zeile sichtbar geworden ist, noch weiter nach
unten scrollt, liefert folgender Aufruf nicht mehr die richtigen Werte:
lngRet = apiGetScrollInfo(hWndSB, SB_CTL, sinfo)
Sehe ich das richtig, dass das einfach bedeutet „Pech gehabt, geht einfach
nicht“?
Fehler 2:
Sobald man einmal auf die Pfeil-Schaltflächen der Bildlaufleiste klickt,
funktioniert der Code nicht mehr. (Wenn man per Mausrad, etc. scrollt, passt
alles). Die Ursache liegt darin, dass die Bestimmung, ob es sich um die
horizontale oder vertikale Bildlaufleiste handelt, nicht mehr funktioniert:
Private Const SBS_VERT = &H1&
Private Const GWL_STYLE = (-16)
If apiGetWindowLong(hWnd_VSB, GWL_STYLE) And SBS_VERT Then
Das Problem ließe sich wahrscheinlich dadurch lösen, dass man den
Scrollbar-handle gleich beim Laden des Formulars bestimmt (und nicht bei
jeder Mausbewegung neu), da er ohnehin gleich bleibt.
Da beide Fehler am selben Rechner aber mit Access2007Runtime nicht
auftreten, liegt der Schluss nahe, dass die API-Funktionen (bzw. deren
korrektes Funktionieren) nicht auf der Windows-Version, sondern auf der
verwendeten Office-Version beruhen. Liege ich da richtig? (Ich hoffe, dass
ist jetzt keine allzu blöde Frage…)
Herzlichen Dank für alle Rückmeldungen.
Grüße
Günther
-------------- Declare Part-------------
Private Declare Function apiGetScrollInfo _
Lib "user32" Alias "GetScrollInfo" (ByVal hWnd As Long, _
ByVal n As Long, lpScrollInfo As SCROLLINFO) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Const GWL_HINSTANCE = (-6)
Private Declare Function apiGetClassName Lib "user32" _
Alias "GetClassNameA" _
(ByVal hWnd As Long, _
ByVal lpClassname As String, _
ByVal nMaxCount As Long) _
As Long
Private Declare Function apiGetParent Lib "user32" _
Alias "GetParent" _
(ByVal hWnd As Long) _
As Long
Private Declare Function apiGetWindowLong Lib "user32" _
Alias "GetWindowLongA" _
(ByVal hWnd As Long, _
ByVal nIndex As Long) _
As Long
Private Declare Function apiGetWindow Lib "user32" _
Alias "GetWindow" _
(ByVal hWnd As Long, _
ByVal wCmd As Long) _
As Long
Private Declare Function GetCursorPos Lib "user32" _
(lpPoint As POINTAPI) As Long
Private Declare Function GetWindowRect Lib "user32" _
(ByVal hWnd As Long, lpRect As RECT) 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 nIndex As Long) As Long
Günther Grund schrieb:
> Eine API-Funktionen freie Lösung wäre mir in der Tat lieber, aber die
> Einschränkung, dass der Ausdruck „Me.CurrentSectionTop“ nur verfügbar ist
> (bzw. einen verwertbaren Wert liefert) wenn der aktuelle Datensatz sichtbar
> ist, wird mit einer „kleinen Anpassung“ nicht zu umgehen sein. Das wird nur
> mit einer neuen Idee gehen - und derzeit kam mir noch keine solche (falls
> Dir noch etwas einfällt, würde ich mich freuen - muss ja nicht gleich eine
> fertig ausprogrammierte Lösung sein, die Idee genügt…)
Vermutlich wirst du um das Auslesen der Position der Bildlaufleiste
per API-Funktion nicht herumkommen.
[...]
> Da ich mit API-Funktionen bislang wenig zu tun hatte, hätte ich dazu noch
> eine wichtige Frage:
> Kann man davon ausgehen, dass die ganze Sache „in der freien Wildbahn“
> zuverlässig funktioniert oder muss man damit rechnen, dass auf jedem zweiten
> Windows-Rechner das irgendwie schiefläuft?
Ich nutze häufig API-Funktionen und es fällt mir momentan keine von
mir verwendete Variante ein, die "instabil" läuft.
Ein mögliches Problem gibt es eventuell: ein Virenscanner (z. B. der
von Kaspersky) könnte so streng eingestellt sein, dass kein
API-Zugriff erlaubt ist.
Ich hätte noch eine Fage zur Funktion fIsScrollBar:
Gemäß den Kommentaren von Lebans sollte diese nur einen Handle auf eine
sichtbare (!) vertikale Bildlaufleiste zurückgeben. Gemäß meinen Versuchen
gibt sie aber auch einen Handle zurück, wenn die vertikale Blidlaufleiste
unsichtbar ist.
Meine Frage wäre daher: Wie kann man (wenn das überhaupt geht) die Funktion
so anpassen, dass (unter Access2007) tatsächlich nur eine sichtbare
Bildlaufleiste ausgelesen wird?
Dies wäre deshalb von Vorteil, weil der zurückgegebenen Positionswert einer
unsichtbaren Bildlaufleiste in bestimmten Fällen nicht 1, sondern ein
Fanatasiewert ist, welcher dazu führt, dass die ganze Sache nicht mehr
funktioniert.
Die einzige Situation, die ich entdeckt hätte, in der wirklich keine
vertikale Bildlaufleiste gefunden wird, ist folgende: Das Endlos-Formular ist
ein Unterformular und beim Laden wird zunächst keine Bildlaufleiste benötigt.
Hier kommt dann der Part mit "fGetScrollBarPos = False" zum Tragen, der
meines Erachtens nur dann zur aufrufenden Procedur passt, wenn man ihn auf
"fGetScrollBarPos = 1" korrigiert.
Zur Vollständigkeit unten die beiden Listings.
Grüße und Danke für alle bisherigen Rückmeldungen
Günther
Private Function fIsScrollBar(frm As Form) As Long
' Get ScrollBar's hWnd
Dim hWnd_VSB As Long
Dim hWnd As Long
hWnd = frm.hWnd
' Let's get first Child Window of the FORM
hWnd_VSB = apiGetWindow(hWnd, GW_CHILD)
' Let's walk through every sibling window of the Form
Do
' Thanks to Terry Kreft for explaining
' why the apiGetParent acll is not required.
' Terry is in a Class by himself! :-)
'If apiGetParent(hWnd_VSB) <> hWnd Then Exit Do
If InStr(fGetClassName(hWnd_VSB), "scrollBar") > 0 Then
If apiGetWindowLong(hWnd_VSB, GWL_STYLE) And SBS_VERT Then
Debug.Print "Scrollbar gefunden!", hWnd_VSB
fIsScrollBar = hWnd_VSB
Exit Function
End If
End If
' Let's get the NEXT SIBLING Window
hWnd_VSB = apiGetWindow(hWnd_VSB, GW_HWNDNEXT)
' Let's Start the process from the Top again
' Really just an error check
Loop While hWnd_VSB <> 0
' SORRY - NO Vertical ScrollBar control
' is currently visible for this Form
fIsScrollBar = -1
Debug.Print "Keine Scrollbar gefunden!"
End Function
Public Function fGetScrollBarPos(frm As Form) As Long
' Return ScrollBar Thumb position
' for the Vertical Scrollbar attached to the
' Form passed to this Function.
Dim hWndSB As Long
Dim lngRet As Long
Dim sinfo As SCROLLINFO
' Init SCROLLINFO structure
sinfo.fMask = SIF_ALL
sinfo.cbSize = Len(sinfo)
sinfo.nPos = 0
sinfo.nTrackPos = 0
' Call function to get handle to
' ScrollBar control if it is visible
hWndSB = fIsScrollBar(frm)
If hWndSB = -1 Then
fGetScrollBarPos = False
Exit Function
End If
' Get the window's ScrollBar position
lngRet = apiGetScrollInfo(hWndSB, SB_CTL, sinfo)
'Debug.Print "nPos:" & sInfo.nPos & " nPage:" & sInfo.nPage & " nMax:"
& sInfo.nMax
fGetScrollBarPos = sinfo.nPos + 1
End Function
Günther Grund schrieb:
> Ich hätte noch eine Fage zur Funktion fIsScrollBar:
>
> Gemäß den Kommentaren von Lebans sollte diese nur einen Handle auf eine
> sichtbare (!) vertikale Bildlaufleiste zurückgeben. Gemäß meinen Versuchen
> gibt sie aber auch einen Handle zurück, wenn die vertikale Blidlaufleiste
> unsichtbar ist.
Ich gestehe, dass ich gerade zu faul war den Code von Lebans genauer
anzusehen, aber würde eventuell bereits so etwas ausreichen:
Public Function GetVerticalScrollbarHandle(ByRef frm As Form) As Long
If (frm.ScrollBars And 2) = 0 Then 'keine vert. Bildlaufleiste
GetVerticalScrollbarHandle = 0
Exit Function
End If
'NUIScrollbar
GetVerticalScrollbarHandle = _
FindWindowEx(frm.hWnd, 0, "NUIScrollbar", vbNullString)
End Function
Anm.: FindWindowEx ist eine API-Funktion.