procent.zip
Autor: Krzysztof Naworyta
Baza w formacie MsAccess 97
31kB, 21-02-2003
Opis problemu:
Problem stary jak Access !
Ustawiliśmy w polu tabeli/formularza format procentowy, czy to przy pomocy ogólnej właściwości "procentowy" (Percent),
czy to w sposób bardziej zaawansowany: 0.00#%;-0.00#%[czerwony];0;-
Wszystko wyswietla się prawidłowo, czyli wartość 0.235
wyświetlana jest jako 23,5%
,
ale samo wprowadzanie danej jest trochę mało intuicyjne.
Mimo ustawionego formatu użytkownik musi wpisywać wartość w formacie ogólnym, czyli: 0.234
Rozwiązanie:
Jedno z pierwszych rozwiązań zaproponował LeS, polegające na triku z "sztucznym" formatem procentowym
LeS zauważył, że jeśli z poziomu procedury Load formularza ustawimy format jako "0.00% "
(spacja na końcu),
to Access potraktuje te dwa znaczki tak jak każdy inny stały znak w wyrażeniu formatującym,
a nie jako komendę do przemnożenia wartości przez 100.
Wada tej metody, to to, że wpisując 23.4 widzimy 23.4%, ale zapisana liczba jest liczbą 23.4,
nie zaś 0.234 jak byśmy chcieli przechowywać ją do dalszych obliczeń.
Swoje uwagi do tego rozwiązania sformułował Jacek Kubek
:
Oto jego słowa:
Bardziej naturalnym podejściem jest, aby wartość wyświetlana jako 20,14% przechowywana była jako 0,2014
(nie trzeba pamiętać o dzieleniu przez 100 w dalszych obliczeniach).
Dlatego Piotr Lipski zaproponował odwrotne podejście:
Pozostawiamy 'naturalny' mechanizm Access'a, a w polu przechowujemy wpisaną liczbę podzieloną przez 100:
Private Sub pole1_AfterUpdate() Me!pole1 = Me!pole1 / 100 End Sub(Propozycja Piotra była szersza, tj. dzieliła przez 100 tylko wartości > 1, lecz powodowało to efekt uboczny: niemożliwość wpisania np. 0,15%, lecz to tutaj nieistotne)
Private Sub pole1_AfterUpdate() If Right(Trim(Me!pole1.Text), 1) <> "%" Then Me!pole1 = Me!pole1 / 100 End If End SubI teraz jest pięknie ;-)
koniec cytatu
Co temu rozwiązaniu można by zarzucić ?
Może to, że jednak jakoś ingeruje w dokonane wpisy (dzielenie)
i zupełnie nie uwzględnia innych formatów, nie kończących się znakiem procentu.
Ale właśnie uwaga Jacka zwróciła moją uwagę, na coś co bez przerwy ignorowałem:
Podczas wpisywania wartości 23.4 wystarczy dołożyć ten nieszczęsny znak procentu,
a Access weźmie dzielenie na siebie !
Stąd już prosta droga do prób zautomatyzowania tego dodatkowego wpisu,
podobnie jak robione jest to w MS Excel, po ustawieniu w kolumnie formatu procentowego.
Z pomocą przyszła mi użyta już wcześniej w rozwiązaniu z formułami a'la Excel,
funkcja SetWindowText()
(user32.dll)
Poniżej przedstawiam szkicowe rozwiązanie w module formularza,
dla pola tekstowego o nazwie PoleProcent, zaprezentowane pierwotnie na grupie:
'***************************** code ***********************************Private Declare Function GetFocus Lib "user32" () As Long Private Declare Function SetWindowText Lib "user32" _ Alias "SetWindowTextA" _ ( _ ByVal Hwnd As Long, _ ByVal lpString As String _ ) As Long Private Sub PoleProcent_Change() Dim poz As Integer Dim strWpis As String Dim Hwnd As Long Dim lngResult As Long On Error GoTo err_exit' tylko kontrolka mająca focus jest oknem, które posiada uchwyt !Hwnd = GetFocus() poz = Me!PoleProcent.SelStart strWpis = Me!PoleProcent.Text' czy zapis kończy się znakiem procentu ?If Len(strWpis) > 0 And Right(strWpis, 1) <> "%" Then strWpis = CStr(strWpis) & "%"' jeśli nie, to go brutalnie tam wstawmy !lngResult = SetWindowText(Hwnd, strWpis) Me!PoleProcent.SelStart = poz End If err_exit: End Sub'**************************end code ***********************************
Ale czy musimy dla każdego pola z osobna pisać jego procedurę zdarzenia OnChange ?
Oczywiście Nie!
Od tego mamy różne sposoby, m.in. własne klasy.
Rozwiązanie taką klasę wykorzystujące zawarte jest w pliku procent.zip
Podałem tam trzy sposoby na jej wykorzystanie, starając się coraz bardziej uprościć konieczne czynności w formularzu.
Polecam Waszej uwadze, bo w naszym bazodanowym dziale jest stosunkowo niewiele okazji, aby z klasami się "zaprzyjaźnić" ;-)
Uwagi:
Wady rozwiązania, cóż ...
Jest jedna poważna, wynikająca z mechanizmów samego Access'a.
Dotyczy to tak samo prezentowanego przez Jacka Kubka rozwiązania z dzieleniem wpisu przez 100.
Otóż wszystko pięknie jak długo wpisujemy nasze procenty do pól pustych, ale co będzie
jeśli do wypełnionego pola cofniemy się klikając weń myszką, albo wchodząc kursorem i naciskając F2 ?
Otóż Access uprawia tu swoje hazardy !
Chyba najczęściej (tak wyszło w trakcie moich, pewnie tendencyjnych ;-), testów)
liczba 0.03457 sformatowana i widziana jako 3,46% po prostu ujawni swoją pełną postać, bez zaokrągleń: 3,457%
Jednak w pewnych wypadkach (trudnych jednoznacznie do określenia "kiedy")
format procentowy znika, na rzecz formatu ogólnego: 0.03457
Czy to źle ?
Jak długo nie wtrącamy się w mechanizmy Access'a, nie! Raz tak, raz śmak, po wyjściu z pola i tak zobaczymy format procentowy ...
Gorzej, jeśli w tym drugim przypadku dokonamy jakiejś korekty wpisu, przykładowo:
ops, końcowa cyfra nie 7, ale 8 !
Zmieniamy zapis 0.03457 na 0.03458 i w tym momencie wyzwalana jest nasza procedura OnChange,
która nie znajduje na końcu znaku procenta, dostawia go i otrzymujemy ... no właśnie:
0.03% !
buuuuuuuu !!!! Jak to teraz wytłumaczę klientowi ?
Czy znajdziemy na to jakieś obejście ? Nasuwa się jedno:
przy wejściu do pola sprawdzamy czy nie nastąpiła zmiana formatu z procentowego na ogólny.
Jeśli tak, to ustawiamy jakąś zmienną na True, która to wartość zablokuje wykonanie mojej procedury Change ...
Cóż, jestem w trakcie opracowywania takiego w miarę niezawodnego algorytmu ...
Inna wada:
Algorytm nie działa na związanych polach walutowym i decimal !
Wynika to z tego, że Access ignoruje wpis % w tych polach.
(2003/02/25) A oto obiecywane rozwiązanie: procent2.zip
W tym rozwiązaniu kontroluję zdarzenia OnKeyUp i OnMouseUp.
Procenty po wejściu do pola, nawet tego, który swą zawartość próbuje wyświetlić w formacie ogólnym, są odpowiednio korygowane.
Stwarza to jednak dodatkowe problemy ! Pole w takich wypadkach jest edytowane (a z nim cały rekord)
Jeśli ustawimy źródło wiersza na recordset nieedytowalny (np: Select Distinct ...), to uzyskamy nieciekawy efekt kasowania zawartości kontrolki.
Czy, podsumowując, słusznym będzie wniosek, że formatu procentowego najlepiej nie używać wcale ?
To juz zostawiam decyzji każdego z osobna.
Aby jednak zachęcić Kolegów do przyjrzenia się temu rozwiązaniu, dołączyłem dodatkową małą klasę, która odpowiada za poruszanie
się po formularzu ciągłym w taki sam sposób jak w arkuszu (strzałki Up i Down)
Klasa rozpoznaje czy przypadkiem nie "wpadliśmy" do rozwiniętego pola kombi, gdzie strzałki powinny zachowywać się neutralnie,
czyli chodzić po polu kombi, nie po rekordach.
Używać można to "jak małpka" ;-)
Wystarczy do docelowej bazy zaimportować klasę clsKeysUpDown
oraz moduł basComboState
(zapożyczony ze strony Ashisha)
oraz w kodzie formularza ciągłego zarejestrować instancję klasy:
'***************************** code ***********************************Dim KeysNavi As New clsKeysUpDown'zmienna na poziomie modułuPrivate Sub Form_Open(Cancel As Integer) (...)'procedura rejestrująca w instancji klasy instancję naszego formularzaKeysNavi.RegisterFormForKeyDownUp Me End Sub'************************* end code ***********************************