Maksymiuk Mateusz, gr. I. 3 Przykład realizacji aplikacji bazodanowej w środowisku C++ Builder



Pobieranie 101.34 Kb.
Data02.05.2016
Rozmiar101.34 Kb.

Maksymiuk Mateusz, gr. I.3

Przykład realizacji aplikacji bazodanowej w środowisku C++ Builder





Maksymiuk Mateusz, gr. I.3 1

Przykład realizacji aplikacji bazodanowej w środowisku C++ Builder 1

Zadanie 1

Realizacja zadania w środowisku C++ Builder 5.0 2

Stworzenie wersji instalacyjnej programu 29

Uruchomienie przykładu projektu aplikacji bazodanowej w środowisku C++Builder 39

Wymagania do sprzętu 40

Wymogi programu 40





Zadanie


Stworzyć aplikację, która będzie mogła się łączyć z dowolną bazą danych (aliasem) zainstalowaną w komputerze. Program musi realizować zapytania SQL podane przez użytkownika. Aplikacja ma także udostępniać dla użytkownika dane zawarte w tabelach wybranej bazy danych oraz informacje dotyczące pól poszczególnych tabel (nazwa pola, typ, rozmiar, precyzja oraz czy pole jest wymagane).

Realizacja zadania w środowisku C++ Builder 5.0


Po uruchomieniu programu C++ Builder, ukazuje się okno aplikacji wraz z nowym, „czystym” projektem, który zawiera jeden formularz oraz moduł (plik z kodem źródłowym) :

Każdy formularz jest zawsze powiązany z jednym modułem. Realizację programu rozpoczynamy od przygotowania interfejsu użytkownika. Na początek wstawiamy komponent Panel z palety Standard - po wybraniu palety Standard, klikamy na komponent Panel :



Następnie wstawiamy wybrany komponent do formularza – klikamy raz na formularz, po czym komponent pojawi się w danym miejscu :



Aby dostosować parametry komponentu Panel do naszych potrzeb musimy zmienić pewne jego właściwości w oknie Inspektora Obiektów (Object Inspector). Po wybraniu komponentu Panel na formularzu (kliknięcie lewym przyciskiem myszy) w oknie Inspektora Obiektów zmieniamy następujące właściwości :



  • Align na wartość alLeft,



  • Caption (tytuł) na łańcuch pusty,

  • BevelOuter (obramowanie zew.) na wartość bvNone (bez orbamowania),

  • Constraints.MinWidth na wartość 170 (minimalna szerokość).

Właściwości Constraints.MinWidth użyliśmy w celu zabezpieczenia komponentu Panel1 przed zbyt dużym zmniejszeniem jego rozmiaru przez użytkownika.


Po dokonaniu tych operacji, formularz programu wygląda następująco :

Teraz umieszczamy w komponencie Panel1, komponent GroupBox z palety Standard :



oraz zmieniamy jego następujące właściwości :



  • Align (rozmieszczenie) na wartość alTop (rozmieszczenie górne),

  • Caption na wartość „Alias bazy danych”,

Aktualny wygląd formularza :



Następnie umieszczamy w komponencie GroupBox1 komponenet ComboBox z palety Standard :



Komponent ten będzie nam służył do wyboru aliasu bazy danych.

Alias jest obiektem ściśle związanym z bazą danych. Zawiera on informacje o typie, parametrach oraz położeniu plików bazy danych. Poprzez alias możemy się łatwo odwoływać do bazy danych. Bez zdefiniowania aliasu, połączenie z bazą danych każdorazowo wymagałoby podania szczegółowych parametrów. Tworząc alias operacje tę wykonujemy tylko raz, a przy każdym połączeniu z bazą danych (poprzez alias) jej parametry są pobierane z wcześniej zdefiniowanego aliasu.

Nasz program do łączenia się z bazami danych używa engin’u BDE (Borland Database Engine) oraz ODBC (Open Database Connectivity). BDE jest motorem bazodanowym Borlanda obsługującym lokalne bazy danych typu Paradox czy dBase. Pozwala on także na łączenie się z serwerami baz danych RDBMS. Standardowe komponenty bazodanowe w Builderze korzystają właśnie z BDE. ODBC jest najlepiej dopracowaną technologią bazodanową Microsoftu. Architektura ODBC obejmuje bibliotekę API opartą o zapytaniach SQL, na bazie której opracowywane są sterowniki zapewniające dostęp do różnorodnych rodzajów baz danych. Mimo, iż nie jest to już technologia pierwszej młodości, ze względu na niezwykle szeroki zakres komercyjnych zastosowań sterowniki ODBC napotkać można niemalże w każdym współczesnym środowisku bazodanowym.


Poprzez przeciąganie komponentów (Drag & Drop) oraz rozciąganie kwadracików znajdujących się na brzegach wybranego komponentu możemy zmieniać jego położenie i rozmiar :

Teraz dodamy drugi komponent GroupBox z palety Standard do komponentu Panel1 oraz zmienimy jego właściwości :



  • Align na wartość alClient (rozmieszczenie na całym dostępnym obszarze),

  • Caption na wartość „Lista tabel”.

Do wyświetlania listy tabel oraz pól użyjemy komponentu TreeView z palety Win32. Komponent ten musimy umieścić w komponencie Panel1.



Modyfikujemy właściwość Align komp. TreeView na wartość alClient.



Następnie wstawiamy komponent Splitter z palety Additional



oraz zmieniamy jego właściwość Width (szerokość) na wartość 5.



Komponent Splitter służy do podziału obszaru okna (lub innego kontenera) na dwie części i umożliwia użytkownikowi zmianę rozmiaru tych części podczas pracy programu. Teraz umieszczamy na formularzu komponent PageControl z palety Win32. Komponent PageControl jest komponentem – kontenerem, używanym wtedy, kiedy na niedużym obszarze formularza musimy umieścić komponenty, które normalnie by się na nim nie zmieściły. Umożliwia on utworzenie wielu stron, które użytkownik może przełączać (zmieniać) podczas pracy programu. Przełączanie to odbywa się poprzez zakładki, dzięki którym użytkownik może wybrać żądaną stronę.



Po umieszczeniu komponentu PageControl na formularzu i zmianie jego właściwości Align na wartość alClient musimy dodać strony, na których umiejscowimy komponenty. Aby to uczynić należy wcisnąć prawy przycisk myszy na komponencie PageControl i z menu kontekstowego wybrać polecenie „New Page” :



Operację tą wykonujemy dwukrotnie – otrzymamy dwie strony – domyślnie nazwane TabSheet1 i TabSheet2. Pojawi się teraz problem z wybieraniem komponentów PageControl oraz TabSheet1 i TabSheet2. Gdy klikniemy na środek komponentu PageControl zostanie wybrany jeden z komponentów TabSheet. Chcąc wybrać komponent PageControl musimy go kliknąć na wysokości jego zakładek lub po wybraniu jednej ze stron wcisnąć klawisz Escape (zostaje wtedy wybrany komponent rodzic). Aby przełączać widok stron wystarczy użyć zakładek. Zmieniamy teraz właściwości Caption komponentów : TabSheet1 na wartość „Dane”, a TabSheet2 na wartość „SQL”. Właściwość ActivePage (oznacza domyślną stronę początkową – tą która będzie aktywna po uruchomieniu programu) komponentu PageControl ustawiamy na stronę TabSheet1.



Ponieważ program będzie obsługiwać zapytania SQL oraz wyświetlać rekordy poszczególnych tabel potrzebujemy odpowiednich komponentów. Zapytania SQL są obsługiwane przez komponent Query z palety DataAccess, natomiast dostęp do tabel baz danych jest realizowany przez komponent Table także z palety DataAccess.





Tworzona przez nas aplikacja będzie wymagać jednego komponentu Query (obsługa zapytań) oraz dwóch komponentów Table : pierwszy będzie służył do odczytywania danych (rekordów) z tabel baz danych, natomiast drugi będzie potrzebny do uzyskania informacji na temat pól poszczególnych tabel (informacje o polach tabeli będą wyświetlane w komponencie TreeView oraz na osobnym formularzu). Umieszczamy teraz trzy powyższe komponenty na formularzu (ich pozycja na formularzu jest nieistotna gdyż są to komponenty niewizualne – tzn. takie których podczas pracy programu nie widać). Domyślnie otrzymują one nazwy Table1, Table2, Query1 :




Aby wyświetlić wyniki zapytania lub dane tabeli potrzebujemy odpowiedniego komponentu. W naszym programie użyjemy komponentu DBGrid z palety DataControls – który jest siatką (tabelką), w której są wyświetlane poszczególne rekordy tabeli lub zapytania.

Aby program wiedział, którą tabelę czy też zapytanie wyświetlić w danym komponencie DBGrid musimy ustalić odpowiednie połączenie. Nie jest jednak możliwe bezpośrednie połączenie komponentu Table (tabela) lub Query (zapytanie) z komponentem DBGrid. Musimy do tego celu użyć dodatkowo komponentu DataSource z palety DataAccess – będącego łącznikiem między komponentami Table, Query, a komponentem wyświetlającym dane – DBGrid.



Do formularza dodajemy dwa komponenty DataSource. Builder nada im automatycznie nazwy DataSource1 oraz DataSource2. Następnie ustawiamy właściwości tych komponentów :



  • właściwość DataSet komp. DataSource1 na wartość Query1,

  • właściwość DataSet komp. DataSource2 na wartość Table1.

Poprzez właściwość DataSet komponentu DataSource łączymy go z wybranym zapytaniem lub tabelą.

Umieścimy teraz na karcie z etykietą „Dane” komponent Panel z palety Standard oraz zmienimy jego właściwości:



  • Align na wartość alTop,

  • Caption na łańcuch pusty „”,

  • BevelOuter (obramowanie zew.) na wartość bvNone (brak obramowania).

Aktualny wygląd formularza :

Do wstawionego uprzednio Panelu dodajemy komponent DBNavigator z palety DataControls.



Ustawiamy jego właściwości w Inspektorze Obiektów :



  • właściwość Align na wartość alLeft (rozmieszczenie lewostronne),

  • właściwość DataSource na wartość DataSource2.

Komponent DBNavigator umożliwia łatwe przemieszczanie się do wybranych rekordów tabeli/zapytania, a także pozwala na dodawanie, edycję lub usuwanie rekordów. Poprzez jego właściwość DataSource łączymy ten komponent z odpowiednią tabelą/zapytaniem, na którym będzie on operować:

Następnie umieszczamy na stronie z etykietą „Dane” komponent DBGrid, który będzie wyświetlać rekordy wybranej tabeli bazy danych. Zmieniamy jego właściwości :



  • Align na wartość alClient,

  • DataSource na wartość DataSource2.

Poprzez właściwość DataSource, połączyliśmy komponent DBGrid z tabelą Table1 ( DBGrid1 > DataSource2 > Table1).

Widok formularza :


Przechodzimy teraz na kartę z etykietą „SQL”. Umieszczamy na niej komponent Panel z palety Standard oraz zmieniamy jego właściwości:



  • Align na wartość alTop (rozmieszczenie górne),

  • Caption na łańcuch pusty „”,

  • BevelOuter (obramowanie zew.) na wartość bvNone (brak obramowania).

Do uprzednio wstawionego komponentu Panel (o nazwie Panel3) dodajemy kolejny Panel i zmieniamy jego właściwości :



  • Align na wartość alRight (rozmieszczenie prawostronne),

  • Caption na łańcuch pusty „”,

  • BevelOuter (obramowanie zew.) na wartość bvNone (brak obramowania).

W komponencie Panel4 umieszczamy przycisk – komponent SpeedButton z palety Additional:



Przycisk ten będzie służył do uruchamiania zapytania SQL. Przyciski SpeedButton umożliwiają wyświetlanie, na swej powierzchni obrazka, który możemy wybrać za pomocą właściwości Glyph. Wraz z pakietem Builder jest dostarczana biblioteka obrazków, ikon, zdjęć itp., które możemy wykorzystać w naszym programie. Wszystkie one znajdują się w katalogu ...\Borland\Shared\Images lub w innym jeżeli zmieniliśmy domyślny katalog podczas instalacji. Dla naszego przycisku wybierzemy obrazek o nazwie „Query” (ścieżka : ...\Borland\Shared\Images\Buttons).



Do wpisywania tekstu zapytania SQL wykorzystamy komponent Memo z palety Standard.



Po umieszczeniu go w Panelu3 ustawiamy jego właściwości :



  • Align na wartość alClient,

  • Lines na łańcuch pusty (usuwamy domyślny tekst „Memo1”),

  • Constraints.MinHeight na wartość 50 (minimalna dopuszczalna wysokość),

  • Constraints.MinWidth na wartość 50 (minimalna dopuszczalna szerokość).

Bieżący widok formularza:



Da Panelu3 dodamy teraz komponent Splitter z palety Additional:



oraz zmienimy jego właściwości :



  • Align na wartość alTop (rozmieszczenie górne),

  • Height (wysokość) na wartość 5.

Komponent Splitter posłuży nam do zmiany rozmiarów siatki DBGrid (wyświetlającej wyniki zapytania) oraz Panelu z komponentem Memo (tekst zapytania SQL) podczas pracy programu.

Potrzebny nam będzie także komponent do wyświetlania wyników zapytania SQL, czyli DBGrid z palety DataControls,

który umieścimy w komponencie Panel3. Ustawiamy właściwość DataSource komp. DBGrid na wartość DataSource1 (ponieważ komp. DataSource1 jest połączony z komponentem Query1 za pomocą właściwości DataSet to wstawiana przez nas siatka (DBGrid) będzie wyświetlać wyniki zapytania), a pozostałe właściwości:


  • Align na wartość alClient,

  • Constraints.MinHeight na wartość 50.

Aby uatrakcyjnić wygląd komponentu TreeView1, czyli drzewka, w którym wyświetlane będą tabele i ich pola, dodamy do niego obrazki. Będą to dwa obrazki symbolizujące tabelę i pole. Ponieważ nie możemy bezpośrednio dodać pojedynczych obrazków do komponentu TreeView, musimy użyć komponentu ImageList z palety Win32 :



Wygląd formularza :



ImageList jest obiektem, służącym do przechowywania obrazków. Aby dodawać/usuwać obrazki znajdujące się w ImageList należy użyć specjalnego edytora, który uruchamia się poprzez podwójne kliknięcie na komp. ImageList:



Za pomocą przycisku Add... dodamy do listy obrazek o nazwie Table znajdujący się w katalogu ...\Borland\Shared\Images\Buttons:



Po dodaniu obrazka wyświetli się okno informujące iż obrazek jest większy niż standardowy rozmiar i czy chcemy go podzielić na dwa oddzielne obrazki. Wybieramy opcję „Yes”.



Otrzymamy następujący rezultat :



Ponieważ nam potrzebny będzie tylko pierwszy (kolorowy) obrazek z indeksem 0, więc drugi (szary) obrazek możemy usunąć (wybieramy go i wciskamy „Delete”). Został tylko pierwszy obrazek.



Teraz dodajemy drugi obrazek o nazwie „Field”. Podobnie jak poprzednio potwierdzamy, iż chcemy go podzielić na dwa osobne, po czym ten drugi (szary) usuwamy. Teraz nasza lista zawiera dwa obrazki :



Aby połączyć komponent TreeView1 z komponentem ImageList1 należy ustawić właściwość Images pierwszego z nich na wartość ImageList1. Pozostaje jeszcze zmienić tytuł formularza z standardowego „Form1” na „Aplikacja bazodanowa”. Do tego celu wykorzystamy właściwość Caption formularza. Aby wybrać formularz kiedy jest on zakryty przez inne komponenty, należy wybrać dowolny komponent na tym formularzu i przyciskać klawisz Escape dopóki w Inspektorze Obiektów nie zostanie wyświetlona nazwa formularza „Form1”:



Ponadto ustawiamy właściwość Position formularza głównego na wartość poScreenCenter (formularz będzie się pojawiać na środku ekranu).

Aby zapisać efekty naszej pracy wybieramy polecenie menu File|Save All. Zostaniemy zapytani o katalog i nazwy plików, pod którymi chcemy zapisać projekt i moduł formularza. Wybieramy katalog, a nazwy plików zostawiamy domyślne.

Aby wyświetlić szczegółowe informacje dotyczące pól tabeli dodamy do projektu drugi formularz. Polecenie File|New Form. Do projektu zostanie dodany pusty formularz o nazwie Form2.



Zmieniamy jego następujące właściwości :



  • BorderStyle (rodzaj obramowania) na wartość bsDialog (okno bez możliwości zmiany rozmiaru),

  • Caption na wartość „Atrybuty pola”,

  • Width (szerokość) na wartość 230,

  • Height (wysokość) na wartość 195

Teraz dodajemy do formularza 10 komponentów Label (Label1 .. Label10) oraz właściwości Caption pierwszych pięciu ustawiamy odpowiednio na wartości :



  • Nazwa pola,

  • Typ pola,

  • Rozmiar,

  • Precyzja,

  • Wymagane.

Możemy także zwiększyć parametry czcionki (rozmiar=10, etykiety o numerach od 6 do 10 są pogrubione [Bold]) etykiet poprzez właściwość Font.

Dodamy teraz przycisk BitBtn z palety Additional:



oraz zmieniamy jego właściwości :



  • Kind (rodzaj) na wartość bkClose,

  • Caption na wartość „&Zamknij”.

Właściwość Kind przycisku BitBtn pozwala na szybkie określenie rodzaju przycisku. Może to być przycisk Ok, Anuluj, Zamknij itp. (do wyboru mamy kilkanaście standardowych rodzajów). Wraz z wyborem danej właściwości Kind przycisk automatycznie zmienia swoją etykietę i obrazek. Niestety etykieta jest w języku angielskim, więc należy ją zmienić na język polski. Charakterystyczny znak „&” przez literą „Z” w etykiecie przycisku informuje o klawiszu skrótu. W naszym programie będzie to kombinacja klawiszy Alt+Z (zawsze jest to Alt + wybrany znak). Zmieniamy jeszcze właściwość Position formularza Form2 na wartość poMainFormCenter (formularz będzie się pojawiać na środku formularza głównego).

Aby zapisać nowy formularz wraz z modułem wybieramy polecenie menu File|Save.
Teraz musimy napisać kod obsługujący polecenia użytkownika. Zaczniemy od formularza drugiego.

Mając aktywny widok formularza, klawiszem F12 zmieniamy widok na widok modułu (ponowne naciśnięcie F12 powraca do widoku formularza). Poprzez naciśnięcie prawego przycisku myszy na widoku moduły i wybraniu polecenia „Open Source/Header File” otworzy się strona z plikiem nagłówkowym modułu (ponowne jej wybranie spowoduje powrót do strony z plikiem źródłowym):



Każdy moduł w Builderze składa się z dwóch części :



  • części nagłówkowej – interfejsu klasy (znajduje się w nim definicja klasy)

  • części implementacyjnej (źródłowej) – będącej implementacją klasy.

Aby można było uzyskać łatwy dostęp do utworzonych uprzednio 5-ciu etykiet wyświetlających atrybuty pola wygodnie będzie stworzyć właściwości do ich obsługi. W pliku nagłówkowym (rozszerzenie .h) dodajemy w sekcji public następujące właściwości :

public: // User declarations

__fastcall TForm2(TComponent* Owner);

__property AnsiString Nazwa = {write = SetNazwa};

__property TFieldType Typ = {write = SetTyp};

__property int Rozmiar = {write = SetRozmiar};

__property int Precyzja = {write = SetPrecyzja};

__property bool Wymagane = {write = SetWymagane};

Poprzez te właściwości będzie można łatwo ustawiać treść odpowiednich etykiet służących do wyświetlania atrybutów pola.

Natomiast w sekcji private dodamy metody obsługujące te właściwości (wszystkie 5 właściwości jest wylko do zapisu) :

private:

void __fastcall SetNazwa(AnsiString value);

void __fastcall SetTyp(TFieldType value);

void __fastcall SetRozmiar(int value);

void __fastcall SetPrecyzja(int value);

void __fastcall SetWymagane(bool value);

Implementacja metod w pliku źródłowym (rozszerzenie .cpp):

void __fastcall TForm2::SetNazwa(AnsiString value)

{

Label6->Caption = value;



}
void __fastcall TForm2::SetTyp(TFieldType value)

{

//ustaw tresc etykiety "Typ pola"



Label7->Caption = ZamienTypPola(value);

// funkcja ZmienTyPola zamienia typ pola TFieldType na

// lancuch AnsiString

}
void __fastcall TForm2::SetRozmiar(int value)

{

// ustaw tresc etykiety rozmiar



Label8->Caption = IntToStr(value);

// funkcja IntToStr zamienia liczbę na lańcuch

}
void __fastcall TForm2::SetPrecyzja(int value)

{

// ustaw tresc etykiety precyzja



Label9->Caption = IntToStr(value);

}
void __fastcall TForm2::SetWymagane(bool value)

{

// ustaw tresc etykiety Wymagane



if (value) Label10->Caption = "Tak"; else

Label10->Caption = "Nie";

}
W metodzie SetTyp używana jest funkcja, której jeszcze nie zdefiniowaliśmy : ZamienTypPola. Funkcja ta służy do określenia nazwy typu pola będącej łańcuchem na podstawie typy TFieldType. Jej prototyp definiujemy w sekcji private pliku nagłówkowego :

AnsiString __fastcall ZamienTypPola(TFieldType typ);

Implementacje zamieszczamy w pliku źródłowym:

AnsiString __fastcall TForm2::ZamienTypPola(TFieldType typ)

{

switch (typ) {



case ftString : return "String";

case ftSmallint : return "SmallInt";

case ftInteger : return "Integer";

case ftWord : return "Word";

case ftBoolean : return "Boolean";

case ftFloat : return "Float";

case ftCurrency : return "Currency";

case ftBCD : return "BCD";

case ftDate : return "Date";

case ftTime : return "Time";

case ftDateTime : return "DateTime";

case ftAutoInc : "AutoIncrement";

case ftBytes, ftVarBytes, ftMemo, ftBlob, ftGraphic,

ftFmtMemo : return "Blob";

default : return "Inny";

}

}


Przejdziemy teraz do formularza głównego i zdefiniujemy w sekcji private, pliku nagłówkowego następujące metody :

private: // User declarations

void __fastcall UruchomZapytanie();

void __fastcall WypelnijDrzewo();

void __fastcall WypelnijListeAliasow();

void __fastcall DodajTabele();

void __fastcall DodajPola();

void __fastcall ZmienTabele();

void __fastcall OnChangeWlaczone(bool value);

void __fastcall PokazOpisPola();

W pliku źródłowym dodamy kolejno implementacje powyższych metod :
void __fastcall TForm1::UruchomZapytanie()

{

Query1->SQL = Memo1->Lines; //ustaw polecenie SQL



try //blok chroniony - obsluguje bledy

{

Query1->Open(); //otworz zapytanie



}

catch (Exception &E) //przechwyc bledy

{

if ( !dynamic_cast(&E) ) //w razie braku wyniku nie wyswietlaj bledu



throw; //w innym wypadku wyswietl blad

}

}



Powyższa metoda służy do wykonywania zapytania SQL wpisanego przez użytkownika do komponentu Memo1. Najpierw metoda przekazuje treść zapytania (Memo1->Lines) do właściwości komponentu Query1->SQL (właściwość ta służy do przechowywania komendy zapytania). Aby zapytanie uruchomić musimy wywołać metodę Open komponentu Query1. Wywołanie tej metody odbywa się w bloku chronionym, gdyż podczas otwierania zapytania mogą wystąpić błędy czasu wykonania (runtime errors). Problem polega na tym, że zapytania dzielimy na dwa typy :

  • zapytania wybierające (SELECT) – zwracające wynik,

  • zapytania wykonawcze (INSERT, DELETE, UPDATE) nie zwracające wyniku.

Jako, że metoda Open zawsze zwraca wynik, to podczas uruchomiania zapytania wykonawczego będzie wyświetlany błąd. Aby tego uniknąć w bloku catch sprawdzamy czy wykryty błąd jest rezultatem braku wyniku zapytania (wyjątek ENoResultSet). Jeżeli tak, to komunikat błędu nie zostanie wyświetlony, inaczej komunikat wyświetli się na ekranie.
void __fastcall TForm1::WypelnijDrzewo()

{

Screen->Cursor = crHourGlass; // pokaż klepsydre



try // blok chroniony - na wypadek bledu przywroci z powrotem zwykly kursor myszy

{

OnChangeWlaczone(false); // wylącz zdarzenie OnChange komponentu TreeView



Table1->Close(); // Zamknij tabele

Query1->Close(); // oraz zapytanie

Query1->DatabaseName = ComboBox1->Text; // ustaw Bazę danych zapytania

Table1->DatabaseName = ComboBox1->Text; // oraz tabel

Table2->DatabaseName = ComboBox1->Text;

DodajTabele(); // wypelnij drzewo tabelami

DodajPola(); // oraz ich polami

}

__finally



{

Screen->Cursor = crDefault; // przywroc kursor myszy

OnChangeWlaczone(true); // wlacz zdarzenie OnChange komponentu TreeView

}

}



Metoda WypełnijDrzewo służy do wypełnienia drzewa TreeView listą tabel i pól. Pierwszą czynnością jest zamiana kursora myszy na klepsydrę. Następnie wyłączane jest zdarzenie OnChange komponentu TreeView (dokładnie zostanie to opisane dalej). Następuje zamknięcie tabeli i zapytania (jest to konieczne aby móc zmienić właściwość DatabaseName). Teraz można ustawić alias wybranej przez użytkownika bazy danych (DatabaseName). Trzeba także dodać do komponentu TreeView listę tabel i pól. Ostatecznie w bloku finally przywracany jest zwykły kursor myszy oraz ponownie włączane zdarzenie OnChange. Operację zmiany wskaźnika myszy warto jest przeprowadzać w bloku try..finally, gdyż w przypadku wystąpienia błędu oryginalny wskaźnik myszy nie zostałby przywrócony i pozostała by klepsydra.
void __fastcall TForm1::WypelnijListeAliasow()

{

Session->GetAliasNames(ComboBox1->Items); //pobierz aliasy dla ComboBox'a



}

Metoda ta służy do wypełnienia listy komponentu ComboBox1 nazwami aliasów dostępnych w systemie. Do tego celu wykorzystaliśmy metodę GetAliasNames komponentu Session (ten komponent jest tworzony automatycznie – nie musimy go umieszczać na formularzu) – jako parametr przekazujemy listę, którą chcemy wypełnić.


void __fastcall TForm1::DodajTabele() // dodaje tabele do komponentu TreeView

{

TStringList* lista; // lista, ktora będzie przechowywac listę tabel



lista = new TStringList(); // utworzenie listy

TTreeNode* temp; // pomocnicza zmienna przechowująca galąź komponentu TreeView

try // blok chroniony zabezpiecza przed utratą pamięci zaj

{

Session->GetTableNames(ComboBox1->Text, "*.*", true, false, lista); //wypelnij liste tabel



TreeView1->Items->Clear(); // usun bieżące elementy komponentu TreeView

for (int i=0; iCount; i++) // dodaje wszystkie tabele z listy

{

if (i==0) temp = TreeView1->Items->Add(NULL, lista->Strings[0]); else



temp = TreeView1->Items->Add(TreeView1->Items->Item[i-1], lista->Strings[i]);

temp->ImageIndex=0; // przypisz obrazek z indeksem 0 (tabela)

temp->SelectedIndex=0;

}

}



__finally

{

delete lista; // ostatecznie usun obiekt listy



}

}

Metoda DodajTabele umieszcza listę dostępnych tabel w komponencie TreeView. Na wstępie tworzona jest pusta lista łańcuchów (lista). Lista ta jest wypełniana nazwami tabel poprzez metodę GetTableName (dokładny opis w Help’ie) komponentu Session. Metoda Clear czyści komponent TreeView (usuwa jego zawartość – stare nazwy tabel). Podczas iteracji przez nazwy tabel z listy są one dodawane do komponentu TreeView. Dodatkowo są ustawiane obrazki dla dodawanych gałęzi. Blok chroniony try..finally zabezpiecza przed utratą pamięci zajmowanej przez obiekt listy łańcuchów.


void __fastcall TForm1::DodajPola()

{

TTreeNode* temp; // pomocnicza zmienna przechowująca galąź komponentu TreeView



for (int i=0; iItems->Count; i++) // przebiega przez wszyskie

// tabele w TreeView

{

if (TreeView1->Items->Item[i]->Level>0) continue; //jeżeli level=0 to galąź jest tabela



// jeżeli level>0 to jest galąź pola

Table2->TableName = TreeView1->Items->Item[i]->Text; // ustawia Table2 na

// odpowiednią tabelę

Table2->FieldDefs->Update(); // aktualizuje listę pol

for (int j=0; j < Table2->FieldDefs->Count ; j++) // dodaje pola do TreeView

{

temp = TreeView1->Items->AddChild(TreeView1->Items->Item[i],



Table2->FieldDefs->Items[j]->Name); // dodaj pole

temp->ImageIndex=1; // ustaw obrazek na indeks 1 (obrazek pola)

temp->SelectedIndex=1;

}

}



}

Procedura wypełnia komponent TreeView nazwami pól poszczególnych tabel. Nazwy są pobierane z komponentu Table2, dokładnie z jego właściwości FieldDefs (zawiera atrybuty pól tabeli). Za pomocą właściwości Lavel (określa poziom zagnieżdżenia gałęzi) możemy określić czy dana gałąź jest tabelą czy polem - tabele są gałęziami głównymi (Level=0), a pola to podgałęzie (Level=1). Podczas iteracji pola są dodawane do komponentu TreeView, a jednocześnie są ustawiane obrazki, jakie będą wyświetlane w drzewie.


void __fastcall TForm1::ZmienTabele()

{

if (TreeView1->Selected->Level==0) // jeżeli użytkownik wybral tabele (level=0)



{

Table1->Close(); // zamknij tabele

Table1->TableName = TreeView1->Selected->Text; //ustaw tabele na nowo wybraną

Table1->Open(); // otworz tabele ponownie

}

}

Jest to prosta metoda, która zmienia tabelę wyświetlaną w komponencie DBGrid, gdy użytkownik wybierze element w komp. TreeView. Na początku dokonywane jest sprawdzenie czy mamy do czynienia z tabelą. Jeśli tak to tabela jest zamykana, ustawiana na wybraną i ponownie otwierana.


void __fastcall TMainF::OnChangeWlaczone(bool value) // wlącza/wylącza zdarzenie

// OnChange w TreeView

{

if (value)



TreeView1->OnChange = TreeView1Change; else

TreeView1->OnChange = NULL;

}

Ta metoda włącza lub wyłącza działanie zdarzenia OnChange komponentu TreeView. Zdarzenie OnChange odpowiada na każdą zmianę komponentu dokonaną czy to przez użytkownika, czy przez sam program. Ponieważ nam chodzi wyłącznie o reakcję na działanie użytkownika, to podczas zmiany właściwości komponentu TreeView z poziomu programu powinniśmy wyłączyć obsługę tego zdarzenia (np. podczas dodawania/usuwania listy tabel i pól z komponentu TreeView). W tym celu wystarczy pojedyncze wywołanie tej metody z odpowiednim parametrem.


void __fastcall TMainF::PokazOpisPola() // wyswietla formularz z opisem pola

{

int index; //zmienna pomocnicza przechowująca indeks pola w definicji pol tabeli



TFieldDef* fieldDef;//zmienna pomocnicza przechowująca pole tabeli

Table2->TableName = TreeView1->Selected->Parent->Text; // wybierz odpowiednią tabelę

Table2->FieldDefs->Update(); // aktualizuj listę pol

index = Table2->FieldDefs->IndexOf( TreeView1->Selected->Text ); // pobierz indeks

// wybranego pola

fieldDef = Table2->FieldDefs->Items[index]; // pobierz pole tabeli

Form2->Nazwa = fieldDef->Name; // ustaw odpowiednie atrybuty pola

Form2->Typ = fieldDef->DataType; // w formularzu Form2

Form2->Rozmiar = fieldDef->Size;

Form2->Precyzja = fieldDef->Precision;

Form2->Wymagane = fieldDef->Required;

Form2->Show(); // pokaż formularz Form2

}

Ostatnia metoda pokazuje okno dialogowe z atrybutami wybranego pola. Za pomocą właściwości Parrent odwołujemy się do gałęzi rodzica danego pola, czyli do gałęzi z nazwą tabeli. Korzystając z właściwości Table2->FieldDefs, którą najpierw aktualizujemy, otrzymujemy informacje dot. atrybutów wybranego pola. Po przekazaniu tych danych do formularza Form2 (poprzez jego właściwości, które wcześniej zdefiniowaliśmy) wyświetlamy go na ekranie.


Po utworzeniu wszystkich metod „roboczych” napiszemy procedury obsługi zdarzeń reagujące na konkretne działania użytkownika.
Zaraz po uruchomieniu programu musimy wypełnić listę aliasów w ComboBox’ie. Do tego celu posłuży nam zdarzenie OnCreate formularza głównego (jest ono wywoływane od razu po uruchomieniu programu). Aby utworzyć procedurę obsługi zdarzenia należy :

  • wybrać interesujący nas obiekt (Form1),

  • przejść do okna inspektora obiektów (F11),

  • wybrać kartę „Events” (zdarzenia),

  • dwukrotnie kliknąć na białe puste pole obok etykiety żądanego zdarzenia (OnCreate)

Wykonanie tej operacji spowoduje automatyczne dodanie pustej procedury obsługi zdarzenia:

void __fastcall TForm1::FormCreate(TObject *Sender)

{
}


Wpisujemy do tej metody wywołanie naszej procedury, która wypełnia listę aliasów :

void __fastcall TForm1::FormCreate(TObject *Sender) //wywolywana na początku

//pracy programu

{

WypelnijListeAliasow(); // po utworzeniu formularza wypelnij listę aliasow



}
Kolejnym zdarzeniem, jakie musimy obsłużyć jest zmiana aliasu w komponencie ComboBox1. Zdarzeniem które nas interesuje jest OnChange komponentu ComboBox1 :

void __fastcall TForm1::ComboBox1Change(TObject *Sender)//wywolywana przy zmianie aliasu

{

WypelnijDrzewo(); // poz zmianie aliasu aktualizuj listę tabel i pol



}
Dalej zostają zdarzenia :

Obsługa przycisku uruchamiającego zapytanie.

void __fastcall TForm1::SpeedButton1Click(TObject *Sender)//przy nacisnięciu przycisku

{

UruchomZapytanie(); // wykonaj zapytanie



}

Obsługa zmiany aktywnego elementu w komponencie TreeView (zmiana aktywnej tabeli).

void __fastcall TForm1::TreeView1Change(TObject *Sender, TTreeNode *Node)

// procedura wywolywana gdy nastąpi zmiana w TreeView (np. zmiana tabeli)

{

ZmienTabele(); // przy zmianie pozycji w TreeView zmien tabele



}
Na końcu pozostaje rozwiązanie problemu związanego z pokazywaniem atrybutów pola tabeli. Informacje będą wyświetlane po naciśnięciu prawego przycisku myszy na wybranym polu w komponencie TreeView.

void __fastcall TForm1::TreeView1MouseDown(TObject *Sender,

TMouseButton Button, TShiftState Shift, int X, int Y)

{ // odpowiada na nacisniecie przycisku myszy na komp. TreeView

if (Button==mbRight) // czy jest to prawy przycisk myszy

{

TTreeNode* node = TreeView1->GetNodeAt(X, Y); // pobierz wybraną galaz



if ((node!=NULL)&&(node->Level==1)) //jezeli galąź zawiera pole to

{

TreeView1->Selected = node; // wybierz tą galąź



PokazOpisPola(); // pokaz opis pola

}

}



}

Najpierw procedura sprawdza czy został naciśnięty prawy przycisk myszy. Jeżeli tak to uzyskuje informacje o gałęzi na której znajdował się wskaźnik myszy. Ponieważ wskaźnik mógł się nie znajdować nad żadną z gałęzi, to dokonywana jest weryfikacja przez porównanie z wartością NULL. Jeżeli jednak wskaźnik znalazł się nad pewną gałęzią drzewa to program sprawdza czy gałąź ta jest gałęzią z nazwą pola (Level==1). Gdy weryfikacja daje pozytywny wynik to omawiana gałąź stanie się gałęzią bieżącą (wybraną) oraz zostanie wyświetlony opis zaznaczonego pola.


Ponieważ formularz główny (Form1) odwołuje się do formularza drugorzędnego (Form2) to należy poinformować o tym kompilator – inaczej podczas kompilacji zostaną wyświetlone błędy. Mając aktywny formularz główny (Form1), wybieramy polecenie menu File|Include Unit Hdr... lub używamy kombinacji klawiszy Alt+F11.

Uzyskamy okno dialogowe, za pomocą którego dołączymy moduł formularza Form2 do formularza głównego:



Po dokonaniu tego zabiegu możemy uruchomić program poleceniem menu Run|Run lub wcisnąć klawisz F9. Warto też zmienić właściwość Text komponentu ComboBox1 na łańcuch pusty, tak aby po uruchomieniu programu nie był wyświetlany domyślny tekst „ComboBox1”.


Aby po ponownym uruchomieniu Buildera otworzyć nasz projekt wystarczy wybrać polecenie File|Open project i odszukać zapisany wcześniej projekt Project1.

Stworzenie wersji instalacyjnej programu


Po zaprojektowaniu programu możemy go uruchomić na własnym komputerze. Ponieważ nasz program korzysta z komponentów do obsługi baz danych, a komponenty te odwołują się do engin’u BDE (Borland Database Engine) to do prawidłowego działania programu, na innym niż nasz komputerze, niezbędny będzie motor BDE. Po skopiowaniu naszego programu na inny komputer, który nie posiada zainstalowanego BDE – program nie będzie działać. Aby móc rozpowszechniać aplikację na innych komputerach należy utworzyć wersję instalacyjną programu, która oprócz samego pliku wykonywalnego *.exe będzie zawierać niezbędne biblioteki. Do tego celu służy program narzędziowy (wchodzący w skład pakietu C++ Builder) InstallShield Express. Aby go zainstalować należy włożyć do stacji dysk CD z C++ Builderem i po wyświetleniu okna instalatora wybrać odpowiednie polecenie :

Po zainstalowaniu uruchamiamy InstallShield’a – pokazuje się następujące okno :



Wybieramy opcję utworzenia nowego projektu, po czym wyświetla się okno dialogowe :



W polu Project Name wpisujemy nazwę pliku projektu. Directory określa katalog w którym ma zostać utworzony projekt, natomiast opcjonalnie możemy go umieścić w określonym podkatalogu (New Subdirectory). Akceptujemy nasz wybór przyciskiem Create.

Mamy teraz do dyspozycji formularz, w którym skonfigurujemy parametry tworzonej przez nas wersji instalacyjnej programu :

Klikamy na pozycję Application Information.



Pole Application Name służy do podania nazwy naszej aplikacji (będzie ona wyświetlana w ikonie programu oraz w Menu Start w Windowsie). Application Executable określa plik *.exe naszej aplikacji (skompilowany program). Version służy do podania numeru wersji. Company to nazwa naszej firmy. Ostatanie pole edycyjne określa domyślny katalog instalacji naszego pogramu. Po uzupełnieniu pól przechodzimy na sąsiednią kartę o nazwie Main Window.



Na bieżącej karcie możemy ustawić oprawę graficzną jaka będzie towarzyszyć podczas instalacji naszego produktu. Tytuł naszej aplikacji możemy wpisać jako tekst (Text) lub wybrać bitmapę (Bitmap). Ponadto można wybrać logo naszej aplikacji (Logo Bitmap), jego położenie (Position) oraz kolor tła instalatora (Background Color).

Na ostatniej karcie – Features zaznaczamy opcję umożliwiającą poźniejsze odinstalowanie naszego programu. Wciskamy przycisk OK.

Przechodzimy do pozycji General Options :



Na karcie General wybieramy biblioteki, które chcemy dołączyć do naszego programu :



Ponieważ nasz program korzysta z komponentów bazodanowych, wybieramy pierwszą pozycję : BDE (Borland Database Engine). Po jej wybraniu ukazuje się okno umożliwiające konfigurację aliasów na komputerze na którym będziemy instalować program.



Ponieważ nie chcemy instalować żadnych aliasów – nasz program nie korzysta z własnych aliasów – klikamy Anuluj. Następnie zaznaczamy następujące pozycje :



  • BDE Control Panel File (program kontrolny do obsługi BDE),

  • Standard VCL Packages (biblioteki do obsługi standardowych komponentów – m.in. palety Standard, Additional i Win32),

  • Database Component Packages (biblioteki do obsługi baz danych),

  • BDE Database Component Packages (biblioteki do obsługi baz danych BDE)

Po wykonaniu tych operacji okno powinnow wyglądać tak :

Na karcie Advenced możemy sprawdzić jakie biblioteki (pliki) zostaną dołączone do naszego programu :



Wciskamy przycisk OK. Następnie wybieramy pozycję Groups and Files.



Na karcie Groups możemy dołączać do programu pliki i biblioteki wymagane do jego poprawnej pracy. Pozycja Program Files zawiera pliki programu. Następne dwa foldery zawierają biblioteki do obsługi BDE. Ostatni folder to biblioteki ogólnego przeznaczenia, z których korzysta nasz program (są one instalowane do katalogu System Windows’a). Ponieważ nasz program będzie wymagał kilku dodatkowych bibliotek więc musimy je dodać. Aby dodać bibliotekę do folderu System Files, klikamy na niego, wciskamy przycisk Insert Files... :



Po wybraniu w oknie dialogowym odpowiedniego pliku wciskamy Otwórz :



Dodajemy następujące biblioteki :



  • borlndmm.dll – wymagana do łączenia się z bibliotekami dll do obsługi serwerów baz danych (np. SYBASE),

  • cc3250.dll oraz cc3250mt.dll – wykorzystywane do obsługi graficznego interfejsu użytkownika (GUI).

Wszystkie te biblioteki znajdują się w katalogu BIN pakietu C++ Builder.

Karty Components oraz Setup Types służą do podziału wersji Instalacyjnej na mniejsze moduły co daje możliwość wyboru rodzaju instalacji (dla zaawansowanych projektów). Wciskamy przycisk OK.

Teraz wybieramy opcję Dialog Boxes.

Za pomocą tego okna dialogowego możemy skonfigurować przebieg procesu instalacji programu oraz jego wygląd. Zaznaczenia poszczególnych pól wyboru włączają:



  • Welcome bitmap – obrazek powitalny,

  • Welcome message – wiadomość powitalną,

  • Software License Agreement – wyświetlanie okna z treścią licencji programu,

  • Readme Information – wyświetlanie okna z informacą opisującą działanie/instalację programu,

  • User Information – wyświetlanie formularza do wprowadzenia danych o użytkowniku i jego firmie,

  • Choose Destination Location – wyświetlanie formularza pozwalającego wybrać katalog instalacji,

  • Choose Database Location – wyświetlanie formularza pozwalającego wybrać katalog instalacji plików bazy danych,

  • Setup type – wyświetlanie formularza służącego do wyboru rodzaju instalacji (pełna/niestandardowa itp.),

  • Custom Setup – pokazywanie formularza służącego do konfiguracji składników które mają być zainstalowane,

  • Select Program Folder – wyświetlanie okna służącego do wyboru folderu w Menu Start, do którego ma być zainstalowany program,

  • Start Copying Files – wyświetlanie okna z informacjami o instalacji programu przed rozpoczęciem kopiowania plików na dysk,

  • Progress Indicator – wyświetlanie paska postępu podczas instalacji,

  • Billboards – wyświetlanie bilbordów podczas instalacji programu,

  • Setup Complete – wyświetlanie okna informującego o zakończeniu instalacji programu.

Większość powyższych opcji ma charakter czysto kosmetyczny. Najistotniejsze pozycje to wybór katalogu instalacji programu i plików bazy danych. W naszym przypadku zaznaczamy wybór katalogu programu (bez wyboru katalogu plików bazy danych – gdyż nasza aplikacja nie posiada żadnych własnych plików bazy danych), reszta opcji nie ma większego znaczenia i możemy ją zostawić jako domyślną. Po wybraniu odpowiednich opcji wciskamy przycisk OK.

Kolejną pozycję na liście stanowi etykieta Registry Changes – za jej pomocą możemy dokonywać zmian w rejestrze podczas instalacji naszego programu. Opcję tę pozostawiamy pustą, gdyż nasz program nie korzysta z rejestru Windows’a.

Przechodzimy do pozycji General Settings :

Na karcie General wybieramy polecenie dla skrótu uruchamiającego program oraz jego parametry. Możemy też ustawić wielkość okna programu. Jako polecenie skrótu widnieje łańcuch:

“[Program Files]\Project1.exe”

Wyrażenie [Program Files] oznacza katalog, do którego są kopiowane pliki programu (widnieje ono także na karcie Groups and Files – omawianej wcześniej). Project1 to nazwa pliku wykonywalnego programu. Na karcie Advenced możemy wybrać ikonę, katalog startowy oraz klawisz skrótu :



Wciskamy przycisk OK. Przechodzimy na kartę Disk Builder. Służy ona do zbudowania gotowej wersji instalacyjnej programu :



Wybieramy rodzaj nośnika i wciskamy przycisk Build.

Po zbudowaniu wersji instalacyjnej wybieramy polecenie Close i przechodzimy na pozycję TestRun, która służy do przetestowania wersji instalacyjnej. Podczas testu nie są kopiowane żadne pliki ani dokonywane zmiany w naszym systemie – cały proces instalacji jest jedynie symulowany. Po przetestowaniu instalatora możemy dokonać zmian w projekcie lub skopiować zbudowaną wersję instalacyjną na wybrany wcześniej nośnik za pomocą polecenie Copy To Floppy.

Uruchomienie przykładu projektu aplikacji bazodanowej w środowisku C++Builder


Przykład projektu aplikacji jest przechowany w katalogu „Builder” oraz zawiera następne pliki:

PROJECT1.res

PROJECT1.cpp

PROJECT1.bpr

PROJECT1.obj

PROJECT1.tds

PROJECT1.exe

PROJECT1.~bpr

PROJECT1.~cpp

PROJECT1.iwz

Unit1.cpp

Unit1.h


Unit1.dfm

Unit1.~cpp

Unit1.~h

Unit1.~dfm

Unit1.obj

Unit2.~h


Unit2.h

Unit2.cpp

Unit2.dfm

Unit2.~cpp

Unit2.~dfm

Unit2.obj


Pliki Project1.tds oraz Project1.exe to pliki zbudowane przez kompilator i można je usunąć, gdyż po otworzeniu projektu w C++ Builder’ze i skompilowaniu go zostaną one ponownie utworzone. Plik Project1.iwz to plik projektu wersji instalacyjnej programu (możemy go odczytać w InstallShield’zie). Pliki Unit1.* i Unit2.* to pliki formularzy i modułów. Po otworzeniu projektu wersji instalacyjnej (Project1.iwz) w InstallShield’zie mogą się pojawić problemy, ze względu na inne ścieżki plików załączanych do aplikacji. Należy wtedy wszystkie nieprawidłowe ścieżki poprawić (np. ścieżkę d:\Program Files\Builder\Cbuilder5\bin\borlndmm.dll na katalog c:\Builder\bin\borlndmm.dll)
Dla uruchomienia projektu trzeba:

  1. Skopiować wszystkie pliki w nowy katalog na dysku.

  2. Uruchomić C++Builder

  3. Otworzyć plik projektu : polecenie menu File|open, wybrać projekt o nazwie Project1.bpr

  4. Uruchomić program poleceniem menu Run|Run.


Wymagania do sprzętu


  1. Wymogi środowiska C++BUILDER:

  • Intel Pentium 90 lub szybszy (zalecany minimum P166),

  • Microsoft Windows 2000, Windows 98, Windows 95, lub Windows NT4.0 z pakietem Service Pack 3 lub nowszym,

  • 32MB RAM (zalecane 64MB),

  • Miejsce na dysku:

  • Wersja Enterprise:

  • 253 MB dla instalacji typu kompakt,

  • 388 MB dla pełnej instalacji,

  • Wersja Professional:

  • 240 MB dla instalacji typu kompakt,

  • 360 MB dla pełnej instalacji,

  • Wersja Standard:

  • 120 MB dla instalacji typu kompakt,

  • 185 MB dla pełnej instalacji,

  • napęd CDROM,

  • Monitor VGA lub o wyższej rozdzielczości,

  • Mysz lub inne urządzenie wskazujące.



Wymogi programu


Program powinien działać na komputerze spełniającym powyższe wymagania. Być może uda się go uruchomić także na komputerze z 16 MB RAM (Windows stworzy pamięć wirtualną).





©absta.pl 2016
wyślij wiadomość

    Strona główna