Laboratorium wirtualne 1/Moduł 2 - ćwiczenie 2/część 2

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania

wersja beta


LABORATORIUM WIRTUALNE 1

Ćwiczenie 2 - Środowisko programistyczne LabWindows/CVI

Część 2

Temat ćwiczenia:

Mechanizm obsługi zdarzeń

Cel ćwiczenia:

Materiał zaprezentowany w czasie prezentacji ma za zadanie zaznajomić słuchacza z mechanizmem obsługi zdarzeń w środowisku LabWindows/CVI.

Słuchacz posiądzie niezbędne wiadomości z dziedziny obsługi zdarzeń oraz odbierania i wysyłania wartości do i z elementów interfejsu użytkownika.


Plan prezentacji.

Budowanie szkieletu aplikacji

Budowę aplikacji zaczynamy od stworzenia nowego projektu. W tym celu z menu głównego wybieramy:
File > New > Project (*.prj)

Jest to nic innego jak stworzenie pustego obszaru roboczego oraz pliku zawierającego informacje o plikach składowych projektu.


Kolejnym etapem o którym była mowa we wcześniejszych prezentacjach jest zbudowanie interfejsu użytkownika. W przykładach kursu będziemy starali się stosować zasadę umieszczania jak najmniejszej ilości elementów na interfejsie użytkownika przed procesem generacji kodu aplikacji. Pozwala ona stopniowe dodawanie funkcjonalności a co za tym idzie na częste uruchamianie programu po wykonaniu drobnych zmian. Prawdopodobieństwo pomylenia zmiennych jest znacznie mniejsze niż w przypadku generacji kodu z całego interfejsu. Pozwala tez na szybkie wykrycie błędów i ich usunięcie – co ma szczególne znaczenie w przypadku niedoświadczonych użytkowników.

Aby utworzyć interfejs użytkownika wybieramy z menu głównego:

File > New > User Interface (*.uir)



Stosując się do poznanych zasad określamy następujące właściwości panelu interfejsu użytkownika:
  • w polu CONSTANT NAME wpisujemy PANEL (domyślnie środowisko powinno wpisać tą nazwę),
  • w polu Panel Title wpisujemy Program obsługi zdarzeń (w oknie podglądu powinien ukazać się zmieniony napis na pasku górnym interfejsu),
  • zaznaczamy pola Auto Center Vertically i Auto Center Horizontally powodujące wyśrodkowanie okna interfejsu na pulpicie w momencie startu aplikacji.

Resztę właściwości pozostawiamy bez zmian i naciskamy przycisk OK zatwierdzający wprowadzone zmiany.


Kolejnym etapem budowy interfejsu użytkownika będzie dodanie przycisku kończącego działanie aplikacji. Skoro mówione było wcześniej że umieszczamy na interfejsie jak najmniej elementów to dlaczego umieszczamy przycisk Wyjście? Wynika to z właściwości kreatora kodu który umożliwia automatyczne wygenerowanie kodu dla przycisku kończącego działanie aplikacji dodając w funkcji obsługi zdarzenia odpowiednią funkcję zamykającą interfejs (a tym samym kończącą działanie aplikacji).

W celu dodania do interfejsu przycisku Wyjście należy z menu głównego wybrać polecenie Create a następnie Command Button i wybrać Square Command Buton (oba sposoby dodawania zostały zaprezentowane na następnym slajdzie). Jest to typowy przycisk funkcyjny jaki można spotkać we wszystkich aplikacjach dla Windows. Po naciśnięciu go przez użytkownika zostaje wywołane zdarzenie obsługi, ale o tym w dalszej części kursu.


Następnie przechodzimy do właściwości elementu (poprzez dwukrotne klikniecie lewym przyciskiem myszy na elemencie). W oknie podglądu powinniśmy zobaczyć widok przycisku. Jeżeli go nie widać to znaczy że niechcący kliknęliśmy inny element np. Panel.

Zmieniamy następujące własciwości przycisku:

Constant Name – wpisujemy WYJSCIE

Określamy funkcję Controll Callback jaka ma być wywoływana po naciśnięciu przycisku Wyjście – wpisujemy Wyjscie.

Zmieniamy etykietę jak ma być wyświetlana na przycisku Label na __Wyjście.


Wprowadzone zmiany w formularzu właściwości zatwierdzamy przyciskiem OK. Widok panelu UI powinien wyglądać podobnie jak przedstawiony na slajdzie.

Generacja kodu C aplikacji.

Zani zostanie wygenerowany kod C aplikacji należy we właściwościach kreatora włączyć dodatkowe zdarzenia jakie mają być uwzględnione w czasie wstawiania kodu C. z menu należy wybrać:

Code > Preferences > Default Control Events


W formularzu zaznaczamy zdarzenia jakie chcemy aby kreator uwzględnił przy budowaniu kodu C aplikacji. Należy zaznaczyć następujące zdarzenia:
EVENT_COMMIT
EVENT_VAL_CHANGED
EVENT_RIGHT_CLICK
EVENT_RIGHT_DOULE_CLICK
EVENT_TIMER_TICK

Wybrane typy zdarzeń:
  • EVENT_COMMIT – domyślne zdarzenie wywoływane w momencie gdy użytkownik zakończy interakcję z elementem,
  • EVENT_VAL_CHANGED – wywoływane w momencie zmiany wartości elementu,
  • EVENT_RIGHT_CLICK – wywoływane w momencie kliknięcia prawego klawisza myszy na elemencie
  • EVENT_RIGHT_DOULE_CLICK - wywoływane w momencie dwukrotnego kliknięcia prawego klawisza myszy na elemencie
  • EVENT_TIMER_TICK – zdarzenie obsługi timera

Pozostałe zdarzenia zostaną poznane i omówione w dalszej części prezentacji.


Przystępujemy do generacji kodu C aplikacji. W tym celu w przestrzeni roboczej wybieramy okno zawierające interfejs użytkownika. W menu głównym będzie dostępna pozycja Code z której wybieramy:
Code > Generale > All Code

Spowoduje to otworzenie formularza określającego właściwości generowanego kodu aplikacji. Jeżeli do tej pory nie zapisaliśmy pliku interfejsu użytkownika to pojawi się monit o wykonanie tej czynności. Po naciśnięciu przycisku Yes pojawi się okno w którym możemy wybrać lokalizację katalogu gdzie ma zostać zapisany plik interfejsu. Zaleca się aby utworzyć katalog dla tworzonego projektu. Pozwala to na zachowanie porządku i łatwą identyfikacje plików należących do konkretnego projektu.


W naszym przypadku należy podać następujące dane:

Target file – wybieramy opcję: Create New Project.

Target Type – ponieważ ma to być aplikacja wybieramy Executable.

Project i Source Filename – pozostawiamy bez zmian.

Generale WinMain() instead of main() – zaznaczamy aby kreator wygenerował funkcję WinMain ().

Select Panels to load and display at startup – mamy jeden panel więc go zaznaczamy.

Panel Variable Name – pozostawiamy domyślną nazwę panelHandle.

Program Termination – zaznaczamy funkcję Wyjście aby generator wstawił funkcję kończąca działanie aplikacji.

Po wprowadzeniu zmian naciskamy przycisk OK co spowoduje przejście do kolejnego etapu..


Ostatnią czynnością jaką trzeba wykonać przed wygenerowaniem kodu jest ustawienie właściwości dla nowo tworzonego projektu (ponieważ taką opcje wybraliśmy w polu Target File). Zaznaczmy Create Project In New Workspace celem zdefiniowania nowej przestrzeni roboczej dla projektu. Z ustawień poprzedniego projektu przenosimy jedynie opcje Build Options.

Zatwierdzamy zmiany przyciskiem OK. W tym momencie powinien zostać wygenerowany kod C aplikacji.


W obszarze roboczym projektu pojawiło się nowe okno zawierające kod C aplikacji. Wygenerowany plik z kodem został automatycznie dodany do plików projektu.


W poprzednich krokach został zbudowany interfejs użytkownika oraz wygenerowany kod C aplikacji. Na tym etapie można już uruchomić aplikację. Na slajdzie przedstawione zostały dwa sposoby uruchamiana aplikacji w środowisku LabWindows/CVI.

Zbudowany został szkielet do budowy dowolnej aplikacji. Funkcjonalność jest obecnie ograniczona jedynie do przycisku Wyjście kończącego działanie programu


Działanie aplikacji zbudowanej w środowisku LabWindows/CVI jest oparte o procedurę obsługi zdarzeń. Procedura obsługi zdarzeń stosuje bardzo proste zasady dzięki którym jest w stanie poradzić sobie ze napływającymi zdarzeniami zarówno od użytkownika jak i urządzeń. Po uruchomieniu programu procedura obsługi zdarzeń przejmuje kontrolę nad wykonaniem aplikacji i oczekuje w pętli nieskończonej na nadejście zdarzenia lub do momentu wystąpienia instrukcji kończącej działanie programu. Schemat działania procedury obsługi zdarzeń został zaprezentowany na slajdzie.

Działanie procedury obsługi zdarzeń można opisać w kilku punktach. Jak już wspomniano wcześniej procedura obsługi zdarzeń (skrócie nazywana POZ) przejmuje kontrolę nad wykonaniem programu zaraz po uruchomieniu aplikacji. W momencie zaistnienia zdarzenia od użytkownika. POZ ustala źródło powstania zdarzenia czyli panel i element wywołujący zdarzenie. Następnie sprawdzane jest czy element posiada zdefiniowana funkcje obsługi zdarzenia. Jeśli nie to procedura przechodzi w stan oczekiwania na nadejście zdarzenia. W przypadku gdy funkcja obsługi zdarzenia (callback function) istnieje POZ sprawdza czy w funkcji obsługi zdarzenia został zaimplementowany kod obsługi wywołanego zdarzenia (instrukcja switch-case). Jeśli tak to zostaje wykonany kod obsługi zdarzenia. W przeciwnym wypadku funkcja obsługi zdarzenia zwraca sterowanie do POZ i następuje oczekiwanie na następne zdarzenie. Jeżeli w kodzie obsługi zdarzenia pojawi się funkcja QuitUserInterface to następuje zakończenie działania aplikacji.

Typy zdarzeń oraz ich działanie najlepiej zaobserwować na przykładzie. Szkielet programu jaki został utworzony wcześniej zostanie uzupełniony o elementy umożliwiające sterowanie zdarzeniami.


Zadaniem budowanej aplikacji jest sterowanie poziomem zbiornika za pożsrednictwem zadajnika.

W środowisku LabWindows/CVI możemy wyróżnić dwa zasadnicze typy elementów. Pierwsza grupę stanowią elementy pozwalające na zmianę stanu czy przekazanie informacji z interfejsu do kodu programu. SA to tak zwane zadajniki. Przykładowe zadajniki zostały przedstawione na slajdzie.

Drugą grupę elementów stanowią wskaźniki czyli elementy służące do wizualizacji danych.


Budowę aplikacji prezentującej obsługę zdarzeń zaczniemy od zmodyfikowania interfejsu użytkownika. Pierwszym elementem jaki trzeba dodać jest przełącznik binarny który ma posłużyć jako selektor zdarzenia.

Aby dostosować przełącznik do potrzeb aplikacji należy zmodyfikować pewne właściwości;

W polu Constant name wpisujemy ZDARZENIE. Należy pamiętać o sposobie nazewnictwa elementów omawianym w części pierwszej.

Funkcję control callback pozostawiamy pustą. Powstaje pytanie dlaczego, skoro chcemy zmieniać typ zdarzenia. Pozostawiamy ją pusta gdyż nie jesteśmy w stanie w prosty sposób wymusić typ zdarzenia jaki chcemy obsłużyć. Prościej będzie sprawdzić jakie jest zdarzenie i porównać z ustawioną wartością.

W polu initial state zmieniamy stan początkowy przełącznika na ON.

W polach ON Text oraz OFF Text wpisujemy odpowiednio EVENT_COMMIT oraz EVENT_VAL_CHANGED. W polach ON Value i OFF Value znajdują się wartości przypisane tym stanom – pozostawiamy je bez zmian.

Po wprowadzeniu zmian zatwierdzamy przyciskiem OK.


Kolejnym elementem jaki dodamy na interfejsie będzie suwak który będzie sterował poziomem w zbiorniku.

W formularzu właściwości suwaka definiujemy jego nazwę (constant name) na ZADAJNIK oraz podajemy nazwę funkcji control callback; Zadajnik. Proszę zwrócić uwagę na pole Data Type określające typ danych jakie będą używane do określenia położenia suwaka. Jest to typ double. Informacja ta będzie przydatna w czasie uruchamiania aplikacji. Po zmianie etykiety elementu można zatwierdzić zmiany przyciskiem OK.

Ostatnim elementem dodawanym na interfejsie użytkownika jest element typu Tank reprezentujący poziom w zbiorniku. Dane z suwaka będą przekazywane do tego elementu i będą określały bieżący poziom.

Wymagane zmiany we właściwościach zbiornika to:

Constant name: ZBIORNIK

Label: Zbiornik

Funkcję callback pozostawiamy pustą – nie będziemy obsługiwali użytkownika i zbiornika


Ponieważ kod aplikacji został wcześniej wygenerowany więc nie znajduje się tam funkcja obsługi zdarzenia elementu zadajnik. Aby wygenerować funkcję obsługi zdarzenia należy nacisnąć prawy klawisz myszy i wybrać z menu podręcznego pozycję Generate Control Callback.

Jeżeli element nie będzie posiadał we właściwościach zdefiniowanej funkcji obsługi zdarzenia to opcja Generate Control Callback nie będzie dostępna. Na poprzednim slajdzie poza funkcją Generate Control Callback dostępna jest też opcja View Control Callback po naciśnięciu której użytkownik zostanie przeniesiony do kodu c w miejsce gdzie znajduje się funkcja obsługi zdarzenia ego elementu.

Po wybraniu funkcji Generate Control Callback została wygenerowana funkcja obsługi zdarzenia.

Została ona dodana na końcu pliku z kodem C. zawiera ona prawie wszystkie zdarzenia które zostały zaznaczone w trakcie generacji kodu. Nie zostało dodane jedynie zdarzenie obsługi Timera.

Jeżeli w trakcie budowy aplikacji okaże się ze potrzebne jest dodatkowe zdarzenie którego nie zaznaczyliśmy w fazie budowy szkieletu aplikacji to można z poziomu menu głównego:

Code > Preferences > Default Control Events

włączyć potrzebne zdarzenie. Od tej pory kreator funkcji obsługi zdarzeń będzie uwzględniał dodane zdarzenie.


Posiadając funkcję obsługi zdarzenia można przystąpić do oprogramowania niezbędnych funkcji programu. Na początku zbierzemy dane z zadajnika i z przełącznika typu zdarzenia jakie chcemy obsłużyć.

W miejscu oznaczonym strzałką wstawiona zostanie funkcja Get Control Value pobierająca położenie z przełącznika binarnego o nazwie ZDARZENIE (element o etykiecie Typ zdarzenia).

Organizacja biblioteki funkcji ma postać drzewa o różnych głębokościach. Funkcje zostały umieszczone w odpowiednich grupach dotyczących elementu bądź czynności. Funkcja Get Control Value jest jedną z najczęściej używanych funkcji. Grupa User Interface zawiera funkcje służące do obsługi interfejsu użytkownika. Na slajdzie widoczne są też inne grupy funkcji:

Advanced Analysis – grupa funkcji służących do wykonywania szeroko pojętych obliczeń i operacji matematycznych. Zawierają się tu funkcje generujące przebiegi, obliczające widmo sygnału, operacje macierzowe itp.

Formating and I/O – grupa funkcji sterujących wejściem/wyjściem, formatowaniem danych wejściowych, operacje na łańcuchach znakowych itp.

Utility – grupa funkcji zawierająca między innymi funkcje sterowania wątkami, procesami, portami itp.

ANSI C – funkcje standardowe z bibliotek języka ANSI C.

W środowisku LabWindows/CVI funkcje są pogrupowane intuicyjnie.


Ścieżka dostępu do funkcji Get Control Value.

Ścieżka dostępu do funkcji Get Control Value.

Ścieżka dostępu do funkcji Get Control Value.

Library > User Interface > Controls/Graphs/Strip Charts > General Functions

Jak widać na przykładzie dostęp do funkcji jest intuicyjny. W czasie wyszukiwania interesującej nas funkcji należy kierować się zasadami:

Czego dotyczy funkcja? Interfejs użytkownika, obliczenia, wejście/wyjście, komunikacja sieciowa itp.

Jaka jest podstawowa grupa funkcji? Element interfejsu, panel, okno dialogowe, operacje macierzowe, FFT, generacja sygnału, DataSocket itp.

Jaka podgrupa funkcji? Funkcje podstawowe, rysowanie wykresów, tabelki, operacje na macierzach jednowymiarowych, domena częstotliwościowa, nawiązywanie połączenia itp.

Głębokość drzewa może zawierać jeszcze parę poziomów w zależności jak można pogrupować funkcje.


Formularz funkcji Get Control Value. Opis poszczególnych agumentów funkcji znajduje się na kolejnych slajdach.

Pole PanelHandle jest uchwytem (wskaźnikiem) do Panelu na którym znajduje się element z którego zamierzamy odczytać dane. Uchwyt do panelu został zdefiniowany na etapie generacji kodu. W projekcie może być zdefiniowanych wiele Paneli. Środowisko ułatwia użytkownikowi zarządzanie zmiennymi oraz ich wybór za pomocą formularzy dostępnych po naciśnięciu przycisku select variable lub skrótu klawiaturowego Ctrl + A

W oknie wyświetlona zostanie lista zmiennych pasujących (typem) do pola. Jeżeli pozostawiliśmy domyślna nazwę uchwytu do panelu w czasie konfigurowania właściwości generowanego kodu to zmienna będzie nazywać się panelHandle (nazwa zgodna ze sposobem nazywania elementów – część 1 prezentacji). Należy ją wybrać i nacisnąć OK.

Jeżeli użyte zostaną biblioteki zewnętrzne zawierające deklarację dużej ilości zmiennych korzystanie z formularza może być uciążliwe. Z pomocą przychodzi pole Show Project Variable pozwalające na wyświetlenie zmiennych zadeklarowanych jedynie w kodzie budowanej aplikacji.


Jeżeli nie wyświetlają się zmienne bądź w śród nich nie ma zmiennej którą chcemy użyć należy przekompilować projekt za pomocą przycisku Build The Project. Sytuacja taka ma miejsce gdy nie korzystamy z kreatorów do deklaracji zmiennych.

Po wybraniu nazwy w formularzu i w podglądzie funkcji pojawi się wybrana wartość.

Następnym polem jest Control ID. Jest to nic innego jak informacja (uchwyt) o elemencie z którego chcemy pobrać wartość (w naszym przypadku będzie to położenie przełącznika). Aby wybrać uchwyt należy w polu Control ID ustawić kursor i nacisnąć enter lub z menu głównego wybrać Select Atribute/UIR Constant…

Z listy elementów wybieramy nazwę elementu z którego chcemy odczytać wartość. Wybieramy PANEL_ZDARZENIE i naciskamy przycisk OK. Nazwa elementu zostanie wstawiona do pola Control ID formularza.

Ostatnim polem formularza jakie trzeba wypełnić jest pole Value. Jest to nazwa zmiennej, do której funkcja zwróci wartość z elementu (w naszym przypadku położenie przełącznika). Jeżeli mamy taką zmienną zadeklarowaną to możemy ją wybrać tak jak w przypadku zmiennej panelHandle.

W naszym przypadku nie posiadamy takiej zmiennej więc będzie trzeba ja zadeklarować. Sposoby są dwa: ręczne zadeklarowanie zmiennej lub użycie kreatora do deklaracji zmiennej


Aby zadeklarować zmienną należy ustawić kursor w odpowiednim polu formularza (jeżeli tego nie zrobimy kreator nie będzie wstanie przechwycić typu zmiennej) i nacisnąć przycisk Declare Variable.

Typ zmiennej (Variable type) został automatycznie ustawiony na typ oczekiwany przez formularz funkcji. Klikając w strzałki obok typu zmiennej (int) lub w białe pole można zmienić typ zmiennej. W pole Variable Name wpisujemy nazwę zmiennej – w naszym przypadku będzie to „zdarzenie”.

Kreator umożliwia deklarację zmiennych lokalnych i zmiennych globalnych. Zmienne lokalne umieszczane są wewnątrz bloku kodu i mają zasięg jedynie w jego obrębie. Zmienne globalne są dostępne w całym programie. Kreator umieszcza je na początku kodu C.

Wypełniamy odpowiednie pola i naciskamy OK.


W formularzu w polu Value została wstawiona zmienna którą zadeklarowaliśmy. Należy zwrócić uwagę że przed nazwą zmiennej został automatycznie dodany znaczek & (symbol adresu) powodujący przekazanie adresu zmiennej a nie kopii zmiennej. W języku C podczas wywołania funkcji argumenty wejściowe odkładane są na stos. Zatem funkcja wykonuje swoje zadanie dysponując kopiami pobranych zmiennych. Funkcja GetCtrlVal a także i inne rozpoczynające przedrostkiem Get... zwracają wynik w jednym z argumentów wejściowych dlatego wymagają dostępu do oryginału zmiennej a nie do jej kopii. Zapewnione jest to przez podanie adresu zmiennej. Powyższa informacja (pojawianie się symbolu &) dotyczy jedynie wielkości skalarnych (pojedynczych zmiennych). W przypadku wektorów i tablic sama nazwa jest adresem tego typu zmiennych. Zatem po zdefiniowaniu i wstawieniu tego typu zmiennych symbol & nie występuje.

Pole Status pozostawiamy puste – nie będziemy w tej funkcji używać statusu wykonania operacji. Status używa się najczęściej w funkcjach z dostępem do sprzętu gdzie potrzebujemy informację o statucie wykonania operacji.


Wstawiamy funkcję Get Control Value do kodu. Na slajdzie uwidoczniona została wstawiona funkcja oraz deklaracja zmiennej.

W podobny sposób jak poprzednio wstawiamy funkcję Get Control Value pobierającą dane z elementu Zadajnik. Proszę zwrócić uwagę na typ zmiennej jaka ustawił kreator. Na slajdzie dotyczącym właściwości elementu Zadajnik ustawiliśmy typ zmiennej double. Kreator popełnił błąd, jednakże proszę go nie poprawiać. Na jego podstawie zostanie zaprezentowana sygnalizacja Bledu wykonania programu.

Własciwości elementu Zadajnik.

Wstawiwnie funkcji do programu.

W kolejnym kroku wstawimy niezbędny kod do sprawdzenia położenia przełącznika „Typ Zdarzenia” oraz wysłania wartości do elementu Zbiornik. W pierwszej kolejności uzupełnimy kod zdarzenia EVENT_COMMIT. W miejscu oznaczonym strzałką należy wstawić instrukcję warunkową if(…).

Dla osób znających programowanie w języku C może wydać się to stratą czasu aby do tak prostej funkcji używać kreatora. Należy jednak pamiętać że środowisko zostało stworzone z myślą o osobach nie będących programistami a jedynie posiadających wiadomości z dziedziny budowy i działania wirtualnych przyrządów pomiarowych. W związku z tym szereg podpowiedzi i kreatorów zostało dodanych do programu.

Należy pamiętać ze w języku C porównacie dwóch wartości odbywa się poprzez podwójny znak równości. Pojedynczy znak równości oznacza podstawienie. Jest to częsty błąd, niestety środowisko na etapie kompilacji nie sygnalizuje wystąpienia niejasności w kodzie.

Instrukacja warunkowa if(...)

Wstawienie funkcji Set Control Value pozwalającej na ustawienie poziomu w zbiorniku. Funkcje z grupy Set wysyłają dane do elementów. Różnica pomiędzy funkcją Get a Set Control Value jest widoczna w argumencie Value. Przekazujemy tutaj kopię zmiennej a nie adres (bez operatora adresu &).

Kod obsługi zdarzenia EVENT_COMMIT.

Kod obsługi zdarzenia EVENT_VAL_CHANGED.

Wszystkie niezbędne modyfikacje kodu C i interfejsu zostały wprowadzone. Można skompilować i uruchomić aplikację. Aplikacja uruchamia się poprawnie, jednakże przy próbie ruszenia suwakiem aplikacja zgłasza błąd. Oznacza on że aplikacja w linii 45 dostała wskaźnik do zmiennej typu int a powinien być wskaźnik do zmiennej typu double. Takie błędy będą się zdarzały przy korzystaniu z kreatorów. Należy nacisnąć przycisk Break. Następnie aby zatrzymać definitywnie program należy z menu górnego nacisnąć przycisk STOP w przeciwnym razie nie będzie można edytować kodu aplikacji.

Na slajdzie przedstawiona została informacja o wystąpieniu błędu. Czasami może się zdarzyć że środowisko będzie zgłaszało błąd dopiero w następnej linii. Sytuacja będzie miała miejsce np. gdy nie wstawimy średnika na końcu linii.

Zgodnie z sugestią środowiska aby usunąć błąd należy zmienić typ zmiennej wartosc z int na typ double. Jak zwykle można to zrobić na wiele sposobów: zmienić ręcznie deklarację lub użyć kreatora. Jeżeli decydujemy się na użycie kreatora należy ustawić kursor na nazwie funkcji GetCtrlVal w linii w której wystąpił błąd i nacisnąć klawisz Ctrl+P aby przywołać formularz funkcji. Następnie w polu Value należy ustawić kursor i nacisnąć przycisk deklaracji zmiennej (Declare Variable…).

Przywołany zostanie formularz deklaracji zmiennych. W polu Variable Type należy zmienić typ int na double a następnie nacisnąć przycisk OK. Można zamknąć formularz bez ponownego wstawiania funkcji (w argumentach funkcji nic nie uległo zmianie). Kreator deklaracji zmiennych dostawił wpis double wartosc. Niestety pozostał stary wpis deklaracji int wartosc który należy ręcznie usunąć z kodu.

Po tej operacji aplikacja będzie działa poprawnie.


Poprawny kod obsługi zdarzenia.

Prezentacja działania zdarzeń.