|  | 
| 
   
   
   |  |  |  |  |  |  • I.2. Access - Tabele i kwerendy [2] •
    2.1 Jak policzyć rekordy w tabeli ?2.2 Jak sprawdzić, czy istnieje tabela ?2.3 Jak sprawdzić, czy istnieje pole w tabeli ?2.4 Jak dodać pole do tabeli bazowej lub tabeli połączonej ?2.5 Jak zmienić nazwę pola w tabeli bazowej lub tabeli połączonej ?2.6 Jak wywołując funkcję DLookup przekazać kwerendzie parametr ?2.7 Dlaczego kwerenda wywołuje => Błąd wykonania '3061' Za mało parametrów. Oczekiwano np. 2 ?2.8 Czy można odzyskać usuniętą przez pomyłkę tabelę ?2.9 Jak obliczyć średnią liczb z 2 lub więcej pól tego samego rekordu ?2.10 Jak ukryć tabelę, by nie była widoczna w oknie bazy (nawet po ustawieniu w menu Narzędzia/Opcje/Widok/Pokaż obiekty ukryte(systemowe) = True ?2.11 Jak pobrać współrzędne kursora myszy nad oknem tabeli (kwerendy) poza obszarem danych ?2.12 Jak sprawdzić czy zdarzenie MouseUp kwerendy, zainicjowane zdarzeniem MouseDown nad nagłówkiem kolumny lub selektorem rekordów, zaszło nad obszarem danych ?2.13 Jak sprawdzić, czy tabela lub kwerenda otwarta jest w widoku Arkusz danych (DataSheet), a formularz lub raport nie jest w widoku Projekt (DesignView) ? |  |  |  |  |  |  |  |  |  |  |  |  |  | 2.12 Jak sprawdzić czy zdarzenie MouseUp kwerendy, zainicjowane zdarzeniem MouseDown nad nagłówkiem kolumny lub selektorem rekordów, zaszło nad obszarem danych ? Jest to próba odpowiedzi na problem poruszony w wątku: Przechwytywanie zdarzeń tabel/kwerend (czyżby ostatnia wersja ?) dotyczący przechwytu zdarzenia MouseUp.
 Otóż, jeżeli wciśniemy lewy przycisk myszy w oknie formularza w widoku Datasheet nad nagłówkiem kolumny, selektorem rekordów, nad kwadratem w lewym górnym rogu lub obszarem okna gdzie nie ma danych, to zachodzi zdarzenie Form_MouseUp.
I wydaje się oczywiste, że zdarzenie Form_MouseUp wystąpi zawsze, gdy puścimy lewy przycisk myszy (nawet poza obszarem formularza). Ale niestety, tak nie jest. Zdarzenie Form_MouseUp nie zachodzi nad obszarem danych. I w przykładzie chodzi o przechwycenie zdarzenia Form_MouseUp nad obszarem danych.
 Dodatkowo potrzebna jest informacja, czy zdarzenie Form_MouseUp zaszło w formularzu. Jeżeli zaszło zdarzenie, to w funkcji przechwytujacej nie robimy nic, jeżeli nie to coś tam musimy wykonać. "Dowiadujemy się" o tym uruchamiając po przechwyceniu komunikatu w formularzu kwerendy Timer, w którym następuje zmiana stanu publicznej zmiennej fHoook.
 Jak się okazało moje twierdzenie że : gdy puścimy lewy przycisk myszy poza obszarem formularza to zajdzie zdarzenie Form_MouseUp nie jest prawdziwe.
 
 Cytuję wypowiedź Krzysztof Pozorka:
 
 <cyt>
 
 
Troche jednak te komunikaty w tytule okna nie zawsze sa trafne. Np taki scenariusz:</cyt>Klikam naglowek kolumny -> MouseUp poza obszarem danych
 Klikam myszka poza oknem -> MouseUp nad obszarem danych
 Czyli w pierwszej czesci rozpoznal dobrze, ale pozniejsze klikniecie poza
 obszarem daje informacje, ze MouseUp wystapilo nad obszarem. Z punktu
 widzenia uzytkownika to nie jest prawda.
 
 A swoja droga to zwarta realizacja przechwytu zdarzen myszki. Mozna by
 powiedziec, ze bardzo dydaktyczna, gdyby... nie oszczednosc komentarzy;-)
 
 
 I okazuje się, że jeżeli kursor myszy po naciśnięciu przycisku myszy ma postać strzałki (domyślny kształt) to po przeciągnięciu kursora poza obszar okna i puszczeniu przycisku nie jest generowane zdarzenie Form_MouseUp.
 Aby wiedzieć, z jakim kursorem mamy do czynienia pobieram uchwyt kursora przed otwarciem kwerendy i sprawdzam w zdarzeniu Form_MouseDown, czy aktualny uchwyt kursora jest zgodny z wcześniej pobranym. Jeżeli jest taki sam, to sprawdzam czy Form_MouseDown było nad kwadratem w górnym lewym rogu (tym co zaznacza wszystkie rekordy). Jeżeli tak to kończymy, jeżeli nie, to uruchamiamy przechwyt komunikatów myszy.
 
 
  ΔΔΔ  |  |  |  |  |  |  |   |  |  |  |  |  |  | 2.13 Jak sprawdzić, czy tabela lub kwerenda otwarta jest w widoku Arkusz danych (DataSheet), a formularz lub raport nie jest w widoku Projekt (DesignView) ?Najpierw za pomocą funkcji SysCmd z argumentem acSysCmdGetObjectState sprawdzamy, czy dany obiekt jest otwarty:
 ObjectState = SysCmd(acSysCmdGetObjectState, typ_obiektu, nazwa_obiektu)
 
 gdzie:
 typ_obiektu: acTable, acQuery, acForm, acReport, acMacro, acModule
 Funkcja zwraca dowolną kombinację trzech poniższych stałych:
 acObjStateOpen	- otwarty
 acObjStateNew	- nowy
 acObjStateDirty	- zmodyfikowany, ale nie zapisany
 Jeżeli obiekt, do którego odwołuje się argument nazwa_obiektu nie jest otwarty lub nie istnieje, funkcja SysCmd zwraca wartość ZERO.
 
 Jeżeli ObjectState = 0 to wiemy, że obiekt nie jest otwarty, lub nie istnieje. W przeciwnym wypadku musimy sprawdzić, czy tabela lub kwerenda jest w widoku Arkusz Danych. Możemy to zrobić znajdując kolejno okna dzieci w oknie klasy "MDIClient" . Poszukiwane okna posiadają klasę "OTable" lub "OQry". Po znalezieniu okna sprawdzamy, czy tytuł tego okna zawiera nazwę naszego poszukiwanego obiektu.
 Jeżeli tak, to sprawdzamy, czy jest widoczne okno dziecko klasy "OSUI" (te nad dolną krawędzią okna, służące do nawigcji pomiędzy rekordami). Jeżeli jest widoczne to tabela lub kwerenda jest w widoku Arkusz Danych (DataSheet).
 
 
  Private Declare Function FindWindowEx Lib "user32" _
 Alias "FindWindowExA" _
 (ByVal hWnd1 As Long, _
 ByVal hWnd2 As Long, _
 ByVal lpsz1 As String, _
 ByVal lpsz2 As String) As Long
 Declare Function IsWindowVisible Lib "user32" _
 (ByVal hwnd As Long) As Long
 Private Declare Function GetParent Lib "user32" _
 (ByVal hwnd As Long) As Long
 Private Declare Function GetWindowText Lib "user32" _
 Alias "GetWindowTextA" _
 (ByVal hwnd As Long, _
 ByVal lpString As String, _
 ByVal cch As Long) As Long
 
 
  ' pobiera nazwę obiektu i jego typ,
 ' dla tabeli lub kwerendy zwraca TRUE jeżeli jest otwarta w widoku Arkusz danych,
 ' dla formularzu i raportu  zwraca TRUE nie jest otwarty w widoku "Projekt",
 ' dla makra i modułu  zwraca TRUE nie jest on otwarty.
 
  Public Function zbIsObjLoaded( _
 sObjName As String, _
 lObjType As Long) As Boolean
 Dim hObj As Long
 Dim sObjTitle As String
 Dim hWind As Long
 Dim lSepInObjName As Long
 Dim lSepInTitle As Long
 Dim sClassName As String
 Const MY_FORM_DESIGN_VIEW = 0
 Const MY_OBJECT_CLOSED = 0
 Const MY_SEP_NAME As String = " : "
 
 Select Case lObjType
 ' sprawdź, czy argument lObjType ma prawidłową wartość
 Case acTable, acQuery, acForm, acReport, acMacro, acModule
 If SysCmd(acSysCmdGetObjectState, _
 lObjType, sObjName) = MY_OBJECT_CLOSED Then
 Exit Function
 End If
 Case Else
 Err.Raise vbObjectError + 1, "Function zbIsObjLoaded ()", _
 "Nieprawidłowa wartość parametru 'lObjType'"
 End Select
 
 Select Case lObjType
 Case acTable, acQuery
 ' ustaw nazwę klasy poszukiwanego okna
 If lObjType = acTable Then
 sClassName = "OTable"
 Else
 sClassName = "OQry"
 End If
 ' szukaj okna rodzica dla wszystkich okien Tabel i Kwerend
 hWind = FindWindowEx(Application.hWndAccessApp, _
 ByVal 0&, "MDIClient", vbNullString)
 Do
 ' szukaj okna Tabeli (Kwerendy) klasy: sClassName
 hObj = FindWindowEx(hWind, ByVal hObj, _
 sClassName, vbNullString)
 If hObj > 0 Then
 ' pobierz tytuł okna tabeli, kwerendy
 sObjTitle = zbGetTextWind(hObj)
 ' szukaj od tyłu ciągu " : "
 lSepInObjName = InStrRev(sObjName, _
 MY_SEP_NAME, , vbBinaryCompare)
 lSepInTitle = InStrRev(sObjTitle, _
 MY_SEP_NAME, , vbBinaryCompare)
 'w nazwie nie ma " : "
 ' Access 2007 w oknie tabeli i kwerendy nie dopisuje
 ' po nazwie obiektu ciągu " : Tabela" lub " : Kwerenda"
 ' Przytnij nazwę do ostatniego wystąpienia " : " za nazwą sObjName
 If lSepInObjName = 0 Then
 If lSepInTitle > 0 Then
 sObjTitle = Left$(sObjTitle, lSepInTitle - 1)
 End If
 Else
 If lSepInTitle > lSepInObjName Then
 sObjTitle = Left$(sObjTitle, lSepInTitle - 1)
 End If
 End If
 ' porównaj tytuł okna z wzorcem: sObjName
 If StrComp(sObjTitle, sObjName, vbTextCompare) = 0 Then
 ' szukaj okna z przyciskami nawigacyjnymi
 hWind = FindWindowEx(hObj, ByVal 0&, "OSUI", vbNullString)
 zbIsObjLoaded = CBool(IsWindowVisible(hWind))
 Exit Function
 End If
 End If
 Loop Until hObj = 0
 Case acForm
 If Forms(sObjName).CurrentView <> MY_FORM_DESIGN_VIEW Then
 zbIsObjLoaded = True
 End If
 Case acReport
 ' spróbuj pobrać właściwość dostępną tylko w widoku acPreviw
 On Error Resume Next
 zbIsObjLoaded = CBool(Reports(sObjName).Page)
 On Error GoTo 0
 Case acMacro, acModule
 zbIsObjLoaded = True
 End Select
 
 End Function
 
 
  ' funkcja pomocnicza zwracająca tytuł okna o uchwycie hWind,
 Private Function zbGetTextWind(hWind As Long, _
 Optional lMaxSizeBuffer As Long = 256) As String
 Dim sBff As String
 Dim lRet As Long
 
 sBff = String(lMaxSizeBuffer, vbNullChar)
 lRet = GetWindowText(hWind, sBff, lMaxSizeBuffer)
 zbGetTextWind = Left$(sBff, lRet)
 End Function
  ΔΔΔ  |  |  |  |  |  |  |  |  |