Banner Access
Tekst informacyjny o polityce Cookies Close   

Uchwyt okna dialogowego "Ustawienia strony".
Odczytu i zmiany opcji wydruku raportu.

Szczegółowe omówienie metod pracy z oknami Windows zastosowanych w przykładzie <<Opcje wydruku raportu w pliku *.MDE. Ustawianie i odczyt.>>

Na stronie << Lista okien >> zapoznaliśmy się z podstawowymi funkcjami API umożliwiającymi nam uzyskanie potrzebnych danych o oknie "Ustawienia strony".
Aby wywołać interesujące nas okno i uzyskać jego uchwyt posłużymy się poniższą procedurą:

Private Sub btnSetupPage_Click()
Dim sRptName As String
sRptName ="Raport1"
DoCmd.OpenReport sRptName, acViewPreview
DoCmd.RunCommand acCmdPageSetup
' pobierz uchwyt aktywnego okna
lRet = GetActiveWindow
End Sub

Wstrzymanie wykonywania kodu przez okno dialogowe "Ustawienia strony". Odczyt uchwytu okna w procedurze Form_Timer formularza.

Niestety, po wywołaniu okna dialogowego wykonywanie dalszych instrukcji zostaje wstrzymane do czasu zamknięcia okna, a potem GetActiveWindow zwróci nam uchwyt zupełnie innego, bliżej nieokreślonego okna (prawdopodobnie Application.hWndAccessApp). Aby uzyskać uchwyt okna "Ustawienia strony" posłużymy się Timerem bieżącego formularza, w procedurze którego pobierzemy uchwyt otwartego okna dialogowego.

Private Sub btnSetupPage_Click()
Dim sRptName As String
sRptName ="Raport1"
DoCmd.OpenReport sRptName , acViewPreview
' Uruchamiamy Timer formularza
Me.TimerInterval = 50
' w celu wyeliminowania komunikatu błędu nr 2501
' - akcja.RunCommand została anulowana

On Error Resume Next
DoCmd.RunCommand acCmdPageSetup
' zamknij raport
DoCmd.Close acReport, sRptName
If Err.Number <> 0 Then Err.Clear
End Sub

a w Form_Timer() pobieramy potrzebny nam uchwyt okna i uruchamiamy procedurę odczytującą dane o strukturze okna "Ustawienia strony".

Private Sub Form_Timer()
Dim hWind As Long
Me.TimerInterval = 0
' zakładam, że uzyskaliśmy uchwyt okna "Ustawienia Strony"
hWind = GetActiveWindow
Call zbGetInfoWindPageSetup( hWind)
End Sub

Niestety, obserwujemy na ekranie chwilowe pojawienie się okna raportu. Czas widoczności okna raportu zależny jest od czasu ładowanie się raportu. Im raport bardziej skomplikowany tym dłuższy czas widoczności raportu.

Aby ograniczyć do minimum czas widoczności raportu nie możemy niestety ukryć raportu bezpośrednio po otwarciu przy pomocy:
Reports(sRptName).Visible = False
ponieważ nie zadziała instrukcja:
DoCmd.RunCommand acCmdPageSetup
Skorzystamy więc z funkcji ShowWindow (...) z parametrem SW_HIDE = 0
lRet = ShowWindow (Reports(sRptName).hwnd, SW_HIDE)
Niestety, nie na wiele nam się to zdało, gdyż w początkowej fazie pojawia się na ekranie okno raportu. Wykorzystamy w takim razie zdarzenie Report_Open(Cancel As Integer) i w nim przesuniemy nasz raport poza obszar widoczności.

Deklarujemy w formularze zmienną publiczną Public fMoveRpt As Boolean pozwalającą rozpoznać podczas otwierania raportu (w zdarzeniu Report_Open), czy chcemy przesuwać raport poza ekran, czy też użytkownik otwiera raport w normalny sposób.

Minimalizowanie efektu migotania ekranu podczas otwierania raportu i okna dialogowego "Ustawienia strony"

Metoda 1:

Tworzymy pomocniczą procedurę w module raportu, w której za pomocą funkcji GetSystemMetrics (...) pobierzemy szerokość i wysokość ekranu, a funkcją MoveWindow (...) przesuniemy raport poza obszar ekranu (teoretycznie, ponieważ funkcja MoveWindow (...) przesuwa okna dzieci w/m okna rodzica, a nie współrzędnych ekranu.

Private Sub zbMoveRptOutScreen()
Dim lScreenX As Long
Dim lScreenY As Long
lScreenX = GetSystemMetrics(SM_CXSCREEN)
lScreenY = GetSystemMetrics(SM_CYSCREEN)
' Przesuń raport poza ekran (w lewo-dół o 100 pikseli)
MoveWindow Me.hwnd, lScreenX + 100, lScreenY + 100, 0, 0, False
End Sub
Metoda 2:

Pobierzemy współrzędne okna Accessa za pomocą funkcji GetWindowRect (...) i względem tych współrzędnych przesuniemy okno raportu. Właściwie powinniśmy pobrać współrzędne okna rodzica raportu (MDIClient), ale to niewiele zmienia ponieważ przenosimy raport o wartość 100 pikseli.

Private Sub zbMoveRptOutAcc()
Dim hAcc As Long
Dim rct As RECT
hAcc = Application.hWndAccessApp
GetWindowRect hAcc, rct
' Przesuń raport poza okno Accessa (w lewo-dół o 100 pikseli)
MoveWindow Me.hwnd, rct.Right + 100, rct.Bottom + 100, 0, 0, False
End Sub
w obu przypadkach w raporcie musimy obsłużyć zdarzenie Report_Open(...):
Private Sub Report_Open(Cancel As Integer)
Dim fNotUser As Boolean
' Sprawdź, czy otwarcie ma na celu odczyt/zapis opcji wydruku,
' czy też raport otwiera użytkownik

On Error Resume Next
    fNotUser = Forms("frmSetupPagel").fMoveRpt
If Err.Number <> 0 Then Err.Clear
If fNotUser Then
    ' Call zbMoveRptOutScreen
    Call zbMoveRptOutAcc
End If
End Sub

Wyeliminowaliśmy chwilowe pojawianie się otwartego raportu na ekranie, ale czas otwarcia raportu może nam w znaczny sposób wydłużyć czas odczytu lub zapisu opcji wydruku. Dodatkowo musimy oprogramować we wszystkich raportach, dla których chcemy zmieniać opcje wydruku, zdarzenie Report_Open.

Niestety, dla plików *.MDE jest to konieczne, jeżeli chcemy uniknąć nieprzyjemnego wizualnie efektu chwilowego pojawiania się okna raportu.

Metoda 3 - tylko w plikach bazy typu *.MDB

Poniżej przedstawiam sposób zmiany opcji wydruku bez konieczności zmian kodu raportów oraz ich otwierania, ale sposób ten działa tylko w plikach *.MDB ponieważ metody
    DoCmd.RunCommand acCmdPageSetup
nie można zastosować w plikach *.MDE dla raportów, które zostały zaznaczone w oknie bazy.

Za pomocą funkcji GetParentt (...) pobieramy uchwyt rodzica (MDIClient) okna bazy. Okno rodzic jest także rodzicem naszego formularza. Mając uchwyt rodzica i znając nazwę klasy okna bazy danych możemy znaleźć uchwyt okna bazy danych dzięki funkcji FindWindowEx (...) Następnie pobieramy współrzędne okna bazy i jego rodzica funkcją GetWindowRect (...)okno bazy danych przesuwamy poza obszar rodzica funkcją MoveWindow (...). W niewidocznym teraz dla nas oknie bazy danych zaznaczamy nasz raport. Po tej operacji okno bazy danych staje się widoczne, więc aby je ponownie ukryć użyjemy funkcji ShowWindow (...).
Żeby okno bazy danych po odsłonięciu pojawiło nam się dokładnie w starym miejscu (byśmy nie musieli go szukać poza ekranem) pobierzemy dodatkowo grubość obramowania okna dzięki GetSystemMetrics(...). Przeliczamy wcześniej pobrane współrzędne okna bazy danych i jego rodzica, odejmujemy szerokość i wysokość obramowania i ukryte okno bazy danych powróci na stare miejsce.

Private Sub zbMoveDbOutMDI()
Dim hParent As Long
Dim hWndDB As Long
Dim rctMDI As RECT
Dim rctDB As RECT
Dim lXBorder As Long
Dim lYBorder As Long
' pobierz uchwyt rodzica
hParent = GetParent(Me.hwnd)
' znajdź okno bazy danych
hWndDB = FindWindowEx(hParent, 0, "ODb", vbNullString)
' pobierz wymiary okna bazy danych
GetWindowRect hWndDB, rctDB
' pobierz wymiary okna MDIClient
GetWindowRect hParent, rctMDI
' przesuń okno bazy poza okno rodzica (w lewo-dół) o 100 pikseli
MoveWindow hWndDB, rctMDI.Right + 100, rctMDI.Bottom + 100, _
rctDB.Right - rctDB.Left, rctDB.Bottom - rctDB.Top, False
' zaznacz raport w oknie DB
DoCmd.SelectObject acReport, cRptName, True ' ukryj okno bazy danych
ShowWindow hWndDB, SW_HIDE
' pobierz szerokośc i wysokość obramowania okien
lXBorder = GetSystemMetrics(SM_CXEDGE) lYBorder = GetSystemMetrics(SM_CYEDGE)
' przekaż do okna bazy stare położenie
MoveWindow hWndDB, rctDB.Left - rctMDI.Left - lXBorder, _
rctDB.Top - rctMDI.Top - lYBorder, _
rctDB.Right - rctDB.Left, rctDB.Bottom - rctDB.Top, False
' uruchom Timer, który wywoła właściwą funkcję odczytu lub zapisu opcje wydruku
Me.TimerInterval = 50
On Error Resume Next
DoCmd.RunCommand acCmdPageSetup
If Err.Number <> 0 Then Err.Clear
' uaktywnij bieżący formularz
DoCmd.SelectObject acForm, Me.name, False
End Sub
Korzystając z wcześniej opisanych funkcji i procedur pozwalających odczytać niektóre właściwości okien możemy uzyskać bardziej szczegółowe dane o  oknie "Ustawienie strony":

Szczegółowe dane o oknie "Ustawienie strony" i jego potomkach (dzieciach).

Private Sub zbGetInfoWindPageSetup(hWndPage As Long)
Dim lRet As Long
Dim sBfClass As String
Dim hNext As Long
Dim i As Integer
Dim sMsg As String
Dim sClass As String * 20
Dim sWndText As String * 25
Dim sID As String * 5
hNext = GetWindow(hWndPage, GW_CHILD)
' Przygotuj nagłówki kolumn
sClass = Space(5) & "Klasa okna"
sWndText = Space(7) & "Tekst okna"
sID = " Id "
sMsg = sMsg & "|" & String(63, 61) & "|" & vbNewLine
sMsg = sMsg & "| Lp." & "| " & sClass & " | " & sWndText & " | " & sID & " |" & vbNewLine
sMsg = sMsg & "|" & String(63, 61) & "|" & vbNewLine
Do Until hNext = 0
sBfClass = zbGetClassWind(hNext)
i = i + 1    ' licznik okien
sClass = sBfClass
sWndText = zbGetTextWind(hNext)
sID = GetDlgCtrlID(hNext)
If i > 0 Then sMsg = sMsg & "| " & Format(i, "00") & ".| " & sClass & " | " & _
sWndText & " | " & sID & " |" & vbNewLine
hNext = GetWindow(hNext, GW_HWNDNEXT)
Loop
sMsg = sMsg & "|" & String(63, 61) & "|" & vbNewLine
Me.TxtIdPage = sMsg
End Sub
Tabela 1.   Struktura okna Ustawienia strony
Lp.Klasa oknaTekst oknaID
01.SysTabControl32-----1959
02.ButtonMarginesy (milimetry)1075
03.Static&Górny:1104
04.Edit30mm1156
05.StaticD&olny:1105
06.Edit35,011158
07.Static&Lewy:1102
08.Edit40mm1155
09.Static&Prawy:1103
10.Edit45,011157
11.ButtonPrzykład1957
12.Static-----1080
13.Static-----1081
14.Static-----1082
15.ButtonDrukuj &tylko dane1920
16.ButtonDrukuj nagłówki1964
17.Static-----1084
18.ButtonOrientacja1072
19.Static-----1962
20.Static-----1963
21.ButtonPio&nowa1056
22.ButtonPo&zioma1057
23.ButtonPapier1073
24.Static&Rozmiar:1089
25.ComboBoxA4 (210 x 297 mm)1137
26.StaticŹró&dło:1090
27.ComboBoxStandardy1138
28.ButtonDrukarka dla: Raport11074
29.ButtonDru&karka domyślna1960
30.Button&Użyj konkretnej drukarki1961
31.ButtonDruk&arka...1026
32.ButtonUstawienia siatki1958
33.StaticLiczba kol&umn:1944
34.Edit11925
35.StaticOdstęp wi&erszy:1950
36.Edit3cm1931
37.StaticO&dstęp kolumn:1945
38.Edit4cm1926
39.ButtonRozmiar kolumn1933
40.Static&Szerokość:1947
41.Edit5cm1928
42.StaticWyso&kość:1946
43.Edit3cm1927
44.Button&Jak pasma szczegółów1921
45.ButtonUkład kolumn1952
46.Button&W dół i w poprzek1954
47.ButtonW popr&zek i w dół1953
48.Static-----1083
49.ButtonOK1
50.ButtonAnuluj2

Pozostaje nam jeszcze zamknięcie okna dialogowego. W tym celu posłużymy się wcześniej zadeklarowaną funkcją SendMessage (...) z parametrem:
Private Const WM_CLOSE = &H10

lRet = SendMessage (hWndPage, WM_CLOSE, ByVal 0, ByVal 0)

lub identyfikatorem przycisku "Anuluj" z powyżej tabeli, oraz funkcją GetDlgItem(...), która zwróci nam uchwyt okna dziecka o podanym Identyfikatorze:
Private Const BM_CLICK = &HF5
Private Const cIdBtnOK As Long = 1
Private Const cIdBtnCancel As Long = 2

Call zbClickButton(hWndPage, cIdBtnCancel)

Private Sub zbClickButton(hWnd As Long, lIDWnd As Long)
Dim lRet As Long
    ' kliknij przycisk o ID = lIDWnd
    lRet = SendMessage(GetDlgItem(hWndPage, cIdBtnCancel ), BM_CLICK, ByVal 0, ByVal 0)
End Sub
ewentualnie w bardziej pokrętny sposób, gdy znamy dokładnie strukturę okna:
Private Sub zbClickCancel(hPageSetup As Long)
Dim hNext As Long
Dim lRet As Long
' pobierz uchwyt pierwszego dziecka okna rodzica
hNext = GetWindow(hPageSetup , GW_CHILD)
' ostatnie dziecko okna rodzica (przycisk Anuluj)
hNext = GetWindow(hNext, GW_HWNDLAST)
' kliknij Anuluj
lRet = SendMessage(hNext, BM_CLICK, ByVal 0, ByVal 0)
' dla przycisku OK musielibyśmy się cofnąć o jeszcze jedno okno
' hNext = GetWindow(hNext, GW_HWNDPREV)
End Sub

Jak widać w Tabeli 1.Struktura okna "Ustawienia strony" znajomość wszystkich okien nie jest nam potrzebna. Ograniczymy się jedynie do okien zawierających istotne dla nas informacje.
W tym celu deklarujemy zmienną wariantową
Dim arrID As Variant i przypisujemy do niej najistotniejsze dane z Tabeli 1
        arrID = Array("Nazwa opisowa okna", ID, Tekst)

Tabela 2.   Elementy tablicy arrID()
L.p.Nazwa opisowa oknaIDTekst
01."Margines góra:"1156True
02."Margines dół:"1158True
03."Margines lewy:"1155True
04."Margines prawy:"1157True
05."Drukuj Dane: "1920False
06."Orientacja pionowo:"1056False
07."Orientacja poziomo:"1057False
08."Rozmiar papieru:"1137True
09."Źródło:"1138True
10."Drukarka domyślna:"1960False
11."Konkretna drukarka:"1961False
12."Ilość kolumn:"1925True
13."Odstęp wierszy:"1931True
14."Odstęp kolumn:"1926True
15."Szerokość kolumn:"1928True
16."Wysokość kolumn:"1927True
17."Jak pasmo szczegółów:"1921False
18."Układ kolumn 1-w dół i poprzek:"1954False
19."Układ kolumn 2-w poprzek i w dół:"1953False

Dane z okien dla których Tekst = True odczytamy za pomocą wcześniej opisanej zbGetTextWind(hWind (...). Dane z pozostałych okien uzyskamy dzięki znanej już funkcji SendMessage (...) wywoływanej z parametrem:
Private Const BM_GETCHECK = &HF0

    lRet = SendMessage(hWnd, BM_GETCHECK, ByVal 0, ByVal 0)

Private Sub zbGetPageSetupByID(hWndPage As Long)
Dim arrID As Variant
Dim hNext As Long
Dim sMsg As String
Dim lRet As Long
Dim i As Integer
Dim sCol_1 As String * 35
Dim sCol_2 As String * 20

sCol_1 = Space(5) & "Ustawienia"
sCol_2 = Space(7) & "Wartość"
sMsg = sMsg & "|" & String(65, 61) & "|" & vbNewLine
sMsg = sMsg & "| Lp." & "| " & sCol_1 & " | " & sCol_2 & " | " & vbNewLine
sMsg = sMsg & "|" & String(65, 61) & "|" & vbNewLine

' Struktura tablicy:
' "Nazwa opisowa okna", Id okna, Odczyt - tekst = True; stan = False

arrID = Array( _
"Margines góra: ", 1156, True, _
"Margines dół: ", 1158, True, _
"Margines lewy: ", 1155, True, _
"Margines prawy: ", 1157, True, _
"Drukuj Dane: ", 1920, False, _
"Orientacja pionowo: ", 1056, False, _
"Orientacja poziomo: ", 1057, False, _
"Rozmiar papieru: ", 1137, True, _
"Źródło: ", 1138, True, _
"Drukarka domyślna : ", 1960, False, _
"Konkretna drukarka : ", 1961, False, _
"Ilość kolumn: ", 1925, True, _
"Odstęp wierszy: ", 1931, True, _
"Odstęp kolumn: ", 1926, True, _
"Szerokość kolumn: ", 1928, True, _
"Wysokość kolumn: ", 1927, True, _
"Jak pasmo szczegółów : ", 1921, False, _
"Układ kolumn 1-w dół i poprzek: ", 1954, False, _
"Układ kolumn 2-w poprzek i w dół: ", 1953, False)

For i = 0 To UBound(arrID) Step 3
hNext = GetDlgItem(hWndPage, arrID(i + 1))
If arrID(i + 2) = True Then
' odczytaj tekst okna
sCol_1 = arrID(i)
sCol_2 = zbGetTextWind(hNext)
sMsg = sMsg & "| " & Format(i, "00") & ".| " & _
sCol_1 & " | " & sCol_2 & " | " & vbNewLine
Else
' odczytaj stan okna klasy "Button"
lRet = SendMessage(hNext, BM_GETCHECK, ByVal 0, ByVal 0)
sCol_1 = arrID(i)
sCol_2 = lRet
sMsg = sMsg & "| " & Format(i, "00") & ".| " &
sCol_1 & " | " & sCol_2 & " | " & vbNewLine
End If
Next

Call zbClickButton(hWndPage, cIdBtnCancel)
sMsg = sMsg & "|" & String(65, 61) & "|"
Me.TxtIdPage = sMsg
End Sub

Odczyt dostępnych rozmiarów papieru.

Pozostało nam jeszcze tylko odczytanie dostępnych rozmiarów papieru oraz danych dotyczących podajnika papieru. Aby odczytać wszystkie pozycje listy w oknach klasy CboBox posłużymy się identyfikatorem ID okna oraz funkcją SendMessage (...) wywoływaną z odpowiednimi parametrami:

Private Sub zbGetItemList(hWnd As Long, ctl As ComboBox, ctlId As Long)
Dim sText As String
Dim lLenTxt As String
Dim sSourceCbo As String
Dim lCount As Long
Dim lIndex As Long
Dim lRet As Long
Dim hCbo As Long

' uchwyt okna klasy CboBox
hCbo = GetDlgItem(hWnd, ctlId)
' ilość pozycji na liście zwróci nam funkcja SendMessage (...) wywołana z parametrem:
Const CB_GETCOUNT= &H146
lCount = SendMessage(hCbo, CB_GETCOUNT, ByVal 0, ByVal 0)
' długość tekstu pozycji listy uzyskamy dzięki parametrowi:
Const CB_GETLBTEXTLEN = &H149
lLenTxt = SendMessage(hCbo, CB_GETLBTEXTLEN, ByVal lIndex, ByVal 0)
' po przygotowaniu buforu na tekst pozycji listy:
sText = String(lLenTxt, vbNullChar)
' i zadeklarowaniu nastepnej stałej:
Const CB_GETLBTEXT = &H148
' odczytujemy tekst pozycji listy :
lRet = SendMessage(hCbo, CB_GETLBTEXT, ByVal lIndex, ByVal sText)
sText = Left(sText, lLenTxt)

' Wszystkie pozycje listy odczytujemy w pętli For i tworzymy string będący źródłem listy
' pola Combo naszego formularza:
For lIndex = 0 To lCount - 1
lLenTxt = SendMessage(hCbo, CB_GETLBTEXTLEN, ByVal lIndex, ByVal 0
sText = String(lLenTxt, vbNullChar)
lRet = SendMessage(hCbo, CB_GETLBTEXT, ByVal lIndex, ByVal sText)
sText = Left(sText, lLenTxt)
sSourceCbo = sSourceCbo & sText & ";"
Next

ctl.RowSourceType = "Value List"
ctl.RowSource = sSourceCbo
' i wpisujemy do naszego pola Combo aktualną wartość okna klasy CboBox:
ctl.Value = zbGetTextWind(hCbo)

End Sub

Na <<następnej stronie>> zajmiemy się zmianą tekstu w oknach klasy Edit, odczytem poszczególnych pozycji listy w oknach klasy  CboBox oraz odczytem i zmianą opcji w oknach klasy RadioButton i CheckBox.