2005.02_KDevelop–narzędzie do tworzenia aplikacji z interfejsem graficznym_[Programowanie].pdf

(545 KB) Pobierz
439110678 UNPDF
narzędzia deweloperskie
KDevelop
– narzędzie do tworzenia
aplikacji z interfejsem
graicznym
Marek Sawerwain
narzędzie i sprawdzić, czy
będzie ono przydatne w pra-
cy, dobrze jest wykorzystać
je do realizacji jakiegoś zadania. Załóż-
my, że chcemy napisać niewielką apli-
kację, która będzie stanowił graficzną
nakładkę na program Wget . KDE oferuje
nam bardzo dobry program dla progra-
mistów o nazwie KDevelop . W tym arty-
kule pokażemy, jak z jego pomocą osią-
gnąć zdefiniowany powyżej cel, a tym
samym udowodnimy, że jest on aplikacją
godną polecenia.
jest poznanie adresu pliku – zakładamy,
że zostanie on podany przez użytkow-
nika. Następnie, gdy dysponujemy już
adresem, jesteśmy gotowi do wywoła-
nia programu Wget . KDE oferuje gotową
klasę o nazwie KProcess , która wspoma-
ga to zadanie. Jej najważniejszą właści-
wością jest fakt, iż pozwala w łatwy
Instalacja programu
KDevelop
Ponieważ już sporo czasu upłynęło od
wydania wersji 3.0 programu, to więk-
szość dystrybucji Linuksa oferuje ten
program – wystarczy tylko zainstalować
pakiet zawierający KDevelopa.
Po instalacji może okazać się, iż nie
możemy wywołać opcji Uruchom auto-
make . Okazuje się, że KDevelop wymaga
do poprawnej pracy wersji Automake
wyższej niż 1.6, a Autoconf wyższej niż
2.5. Problem ten pojawia się np. w wersji
Mandrakelinux 10.1, ale rozwiązanie jest
bardzo proste – wystarczy doinstalować
odpowiednie pakiety.
Z użytkowaniem KDevelopa wiąże
się też inny problem, gdyż po utworzeniu
projektu i wykonaniu z nim jakichś prac,
może okazać się, że KDevelop nie chce
ponownie wczytać naszej pracy, generu-
jąc sygnał 11. Rozwiązaniem jest skaso-
wanie w katalogu projektu dwóch plików:
pierwszy posiada rozszerzenie kdevses ,
a drugi pcs .
Podczas instalacji KDevelopa warto
upewnić się, czy zainstalowana zostanie
dokumentacja, gdyż omawiane narzę-
dzie ma bardzo dobry moduł do doku-
mentacji, który bardzo przydaje się pod-
czas pisania jakiejkolwiek aplikacji, nawet
tak prostej jak nasz projekt.
Na płycie CD/DVD
Na płycie CD/DVD znajduje się
kod źródłowy programu oraz
wszystkie listingi z artykułu.
Kilka założeń na początek
Interfejs naszego programu będzie pre-
zentował się bardzo skromnie. Wystarczą
nam dwa przyciski: jeden do zamknięcia
okna oraz drugi, którym rozpoczniemy
proces ściągania pliku. Będziemy rów-
nież potrzebowali komponentu o typie
QLineEdit , którego nazwiemy Address-
Text . Umieścimy w nim adres pliku,
który chcemy ściągnąć. Ponieważ pobie-
ranie pliku zrealizujemy za pomocą innej
aplikacji (co więcej, będzie ona działała
w trybie konsoli), to będziemy musieli
przechwytywać standardowe wyjście, na
które Wget wysyła wszelkie komunikaty
podczas swojej pracy. Wykorzystamy do
tego celu komponent o typie QtextEdit ,
którego nazwiemy MessageBoxText .
Jak zawsze, warto przygotować nie-
wielki schemat, w którym przedstawi-
my najważniejsze zdarzenia, które będą
zachodzić w naszym programie. Został
on przedstawiony na Rysunku 1. Jak
widać, proces ściągania pliku składa się
z kilku pomniejszych zadań. Pierwszym
O autorze
Autor zajmuje się tworzeniem
oprogramowania dla WIN32
i Linuksa. Zainteresowania: teoria
języków programowania oraz
dobra literatura.
Kontakt z autorem:
autorzy@lpmagazine.org
22 luty 2005
G dy chcemy poznać jakieś
439110678.038.png 439110678.039.png 439110678.040.png 439110678.041.png 439110678.001.png 439110678.002.png
kdevelop
narzędzia deweloperskie
Rysunek 2. Tworzenie nowego projektu
Rysunek 1. Główne zdarzenia pojawiające się w programie
Projektujemy formularz
Po utworzeniu projektu przygotujemy
w pierwszej kolejności okno formula-
rza. W górnym oknie Menadżera auto-
make (z prawej strony głównego okna
z kodem) wybieramy gałąź z naszym pro-
jektem, czyli wget_gui , a następnie kata-
log src . Gdy w dolnym oknie Menadże-
ra automake klikniemy prawym przyci-
skiem myszy na dowolnym pliku, pokaże
się nam małe menu z kilkoma opcjami.
Wybieramy opcję Utwórz nowy plik... .
Zobaczymy takie okno, jak na Rysunku 3.
Do pola Nazwa pliku wpisujemy np.
wget_gui_widget.ui , a następnie wybiera-
my typ pliku – Widget . Tworzymy widget,
który zostanie podłączony do głównego
okna naszej aplikacji. Okno tworzenia
tego pliku można także uzyskać wybie-
rając z menu Plik opcję Nowy .
Po wykonaniu tej operacji jeste-
śmy gotowi do utworzenia interfejsu za
pomocą QtDesignera . Niestety, jeśli uży-
wamy nowej wersji KDevelopa, to po
dwukrotnym kliknięciu na pliku wget_
gui_widget.ui , uruchomi się tylko prze-
glądarka KUIViewer , a nam jest potrzeb-
ny QtDesigner. W tym celu wystarczy
prawym przyciskiem myszy wybrać pod-
menu Otwórz w i z opcji, które się nam
wyświetlą, wybrać Projektanta Qt .
Ułożenie dwóch przycisków ( Push-
Button z sekcji Buttons okna Toolbox )
oraz dwóch komponentów ( LineEdit
i TextEdit z sekcji Input ) nie powinno
nikomu sprawić trudności, ale trzeba
odpowiednio zadeklarować sygnały.
sposób przechwycić dane kierowane
na standardowe wyjście (ang. stdout )
oraz na standardowe wyjście o błędach
(ang. stderr ), co czasem również może
się przydać.
jeszcze raz przycisk Następny . Zobaczy-
my okno, w którym znajduje się tekst
licencji. Będzie on dołączany do każde-
go pliku nagłówkowego. Jeśli chcemy,
aby do każdego takiego pliku były dołą-
czane inne informacje, w tym miejscu
możemy to zmienić. Gdy naciśniemy raz
jeszcze przycisk Następny , to tym razem
przycisk zmieni etykietę na Koniec i po
jego naciśnięciu zostanie wygenerowa-
ny podstawowy szkielet projektu.
Zanim zaczniemy go kompilować,
należy jeszcze wykonać dwie czynności.
Z okna Buduj wybieramy opcję Uruchom
Automake . Po kilku chwilach, gdy pro-
gram utworzy wszystkie skrypty, z tego
samego menu Buduj wybieramy opcję
Uruchom Configure . Wszystkie komuni-
katy będą wyświetlane w okienku na
dole programu. Dopiero po zakończe-
niu działania skryptu configure możemy
dokonać kompilacji projektu naciska-
jąc klawisz [ F8 ] lub wybierając z menu
Buduj opcję Buduj projekt . Utworzony
program uruchomiamy wciskając klawi-
sze [ Shift ]+[ F9 ] – z menu Buduj opcja
Wykonaj program .
Tworzymy projekt
Pierwszym krokiem jest utworzenie
nowego projektu w KDevelop. Nasz
program piszemy dla środowiska KDE,
więc po uruchomieniu programu prze-
chodzimy do menu Projekt . Wybie-
ramy z niego Nowy projekt... . Pokaże
się okno podobne do tego z Rysun-
ku 2. Na liście odszukujemy gałąź C++ ,
a następnie KDE, gdzie znajduje-
my pozycję Simple KDE Application .
We Właściwościach musimy podać
Nazwę Aplikacji . Załóżmy, że projekt
będzie nazywał się wget_gui . Pozosta-
łe pola mają dla nas mniejsze znaczenie.
Wybieramy teraz przycisk Następny , aby
przejść do następnego okna, w którym
będziemy mogli wybrać system kon-
troli wersji. Nam nie jest on potrzebny,
gdyż tworzona przez nas aplikacja nie
wymaga pracy grupowej. Wybieramy
Rysunek 3. Tworzenie pliku formularza
www.lpmagazine.org
23
439110678.003.png 439110678.004.png 439110678.005.png 439110678.006.png 439110678.007.png 439110678.008.png 439110678.009.png 439110678.010.png 439110678.011.png 439110678.012.png 439110678.013.png 439110678.014.png
narzędzia deweloperskie
Listing 1. Implementacja konstruktora wget_gui, w którym tworzymy formularz programu
# include "wget_gui.h"
#include <qlabel.h>
#include <kmainwindow.h>
#include <klocale.h>
# include "wgetguiwidget.h"
Rysunek 5. Tworzenie pliku podklasy
wget_gui :: wget_gui () : KMainWindow ( 0 , "wget_gui" ) {
// set the shell's ui resource file
setXMLFile ( "wget_guiui.rc" );
wystarczy wpisać dość podobne wyraże-
nie tworzące nasz formularz:
// new QLabel( "Hello World", this, "hello label" );
new wgetGuiWidget ( this , "wget gui" , 0 );
}
new wgetGuiWidget(this, "wget gui", 0);
wget_gui :: ~ wget_gui ()
{ }
W ten sposób, po kompilacji programu,
zamiast etykiety zobaczymy zaprojek-
towany przez nas formularz. Jak widać,
zmiany mają charakter tylko kosmetycz-
ny. Zaletą takiego podejścia jest fakt, że
nie musimy wprowadzać żadnych zmian
w funkcji main . Kod, który został tam
wygenerowany, możemy pozostawić bez
zmian.
# include "wget_gui.moc"
Z menu Edit wybieramy pozycję Slots...
i deklarujemy dwie funkcje: Download-
BTN_Slot() oraz CloseAppBTN_Slot() .
Następnie wciskamy klawisz [ F3 ] i kli-
kamy myszką na formularzu. Wywo-
łujemy okno View and Edit Connec-
tions , w którym, tak jak to widać na
Rysunku 4, podłączamy sygnały clicked
to dwóch funkcji odpowiadających
za przyciski ściągania oraz zakończe-
nia pracy aplikacji (nadawcą jest odpo-
wiedni przycisk, a odbiorcą – formularz,
czyli okno).
Po utworzeniu pliku w formacie ui
przystępujemy do generowania tzw.
pliku podklasy. Ta czynność także zosta-
ła w pełni zautomatyzowana. Wybiera-
my plik ui z okna Menadżera automa-
ke i prawym przyciskiem myszy wywo-
łujemy menu, z którego wybieramy opcję
Element podklas... . Pokaże się takie okno,
jak na Rysunku 5.
Jedyne, co musimy zrobić, to wpisać
nazwę klasy: wgetGuiWidget , bowiem
nazwa pliku uzupełni się samodzielnie.
Zwróćmy też uwagę na listę z metodami
– są tam nasze funkcje (sloty), które zde-
finiowaliśmy w programie QtDesigner.
Jeśli na liście nie zostały wymienione
powyższe sloty, to niestety trzeba prze-
rwać generowanie podklasy i powrócić
do QtDesignera, aby naprawić ten błąd.
Przycisk kończący pracę
programu
W tym momencie możemy zająć się
obsługą dwóch przycisków, które znaj-
dują się w naszym programie. Ich imple-
mentacja jest zawarta w pliku wgetgu-
iwidget.cpp . Jest to ten sam plik podkla-
sy (ang. subclass), który wygenerowa-
liśmy na podstawie formularza z pliku
wget_gui_widget.ui .
Zaczniemy od przycisku, którego
zadaniem jest zamknięcie aplikacji. Jak
łatwo się domyśleć, jest to bardzo łatwe
do wykonania. Na początku pliku dołą-
czamy dodatkowe pliki nagłówkowe:
Pierwsze poprawki
Projekt, który utworzyliśmy, zawie-
ra tylko jeden widget, a jest nim ety-
kieta Hello World . Należy w jakiś
sposób podmienić ten widget na formu-
larz, który przygotowaliśmy wcześniej
w programie QtDesigner. W pierwszej
kolejności otwieramy plik o nazwie
wget_gui.cpp . Zobaczymy plik o treści
podobnej do Listingu 1. Na początku
dołączamy plik nagłówkowy formularza,
który został przez nas zaprojektowany:
#include <qapplication.h>
#include <kapplication.h>
Znajdują się w nich klasy reprezentujące
całą aplikację.
W każdej aplikacji KDE mamy dostęp
do obiektu kapp , który reprezentuje
obiekt aplikacji. Wywołanie metody quit
spowoduje zamknięcie całego programu.
W naszej aplikacji funkcję do zamknięcia
programu nazwaliśmy CloseAppBTN_Slot .
Implementacja tej metody sprowadza
się do wywołania metody quit z obiek-
ty kapp :
#include "wgetguiwidget.h"
Następnie, w samym konstruktorze,
zamiast linii tworzącej etykietę:
Rysunek 4. Projektowanie interfejsu oraz
podłączanie sygnałów i funkcji
new QLabel( "Hello World", this, S
"hello label" );
24
luty 2005
439110678.015.png 439110678.016.png 439110678.017.png 439110678.018.png 439110678.019.png 439110678.020.png 439110678.021.png 439110678.022.png 439110678.023.png 439110678.024.png 439110678.025.png
 
kdevelop
narzędzia deweloperskie
Listing 2. Implementacji metody DownloadBTN_Slot , odpowiedzialnej za ściągnięcie pliku
zgodnie z tym, co podałem powyżej, jest
następujący:
void wgetGuiWidget :: DownloadBTN_Slot () {
KProcess * task ;
Reader reader ;
*task << "wget –progress=dot";
*task << AddressText->text();
MessageBoxText -> append ( ">>> process begin <<<" );
Adres pliku jest odczytywany z wid-
getu AddressText . Warto jeszcze usta-
lić, jaki typ powłoki zostanie użyty
do wywołania polecenia wget . Doko-
nujemy tego metodą setUseShell . Kod,
który wykonuje tę czynność, jest nastę-
pujący:
task = new KProcess ;
* task << "wget –progress=dot" ;
* task << AddressText -> text ();
task -> setUseShell ( true , "/bin/sh" );
reader . edt = MessageBoxText ;
QApplication :: connect ( task ,
SIGNAL ( receivedStdout ( KProcess * , char * , int )) ,
& reader ,
SLOT ( read_stdout ( KProcess * , char * , int )));
task->setUseShell(true, "/bin/sh");
W tym momencie moglibyśmy uru-
chomić nasz proces metodą start , ale
wszystkie komunikaty z programu wget
są skierowane na konsolę, z której uru-
chomiamy program. Jeśli robimy to
z poziomu środowiska graficznego, to
nie zobaczymy żadnych komunikatów.
Z tego powodu należy przechwycić
wszystkie dane kierowane na strumie-
nie stdout oraz stderr . Wykorzystujemy
w tym celu obiekt reader . Aby mógł on
poprawnie wykonywać swoje działanie,
należy do pola edt skopiować wskaźnik
na komponent QTextEdit o nazwie Mes-
sageBoxText :
QApplication :: connect ( task ,
SIGNAL ( receivedStderr ( KProcess * , char * , int )) ,
& reader ,
SLOT ( read_stderr ( KProcess * , char * , int )));
if ( task -> start ( KProcess :: Block , Kprocess :: AllOutput ))
{
MessageBoxText -> append ( ">>> process end <<<" );
}
else
{
MessageBoxText -> append ( ">>> process failed <<<" );
}
}
void wgetGuiWidget::CloseAppBTN_Slot(){
kapp->quit();
}
który musimy utworzyć, aby wykonać
polecenie wget . Bardzo istotna jest rów-
nież druga zmienna – reader . Jest to zde-
finiowana przez nas klasa, która jest nam
potrzebna, aby przechwytywać dane ze
standardowego wyjścia.
W następnej linii umieszczamy komu-
nikat tekstowy o tym, że proces wywoła-
nia wget właśnie się rozpoczyna.
Teraz możemy przystąpić do właści-
wego zadania. Tworzymy obiekt task :
reader.edt=MessageBoxText;
Ściąganie pliku
Oprogramowanie drugiego przycisku to
nasze główne zadanie. Będziemy odwo-
ływać się do innych komponentów, więc
konieczne jest dołączenie odpowiednich
plików nagłówkowych. Ponieważ stosu-
jemy pola edycji o typie QLineEdit oraz
QTextEdit , to dołączamy następujące pliki
nagłówkowe:
Następnym zadaniem do wykonania jest
podłączenie sygnału przeznaczonego do
odbioru danych skierowanych na stan-
dardowe strumienie przez obiekt typu
KProcess . Wykonujemy je metodą con-
nect z klasy QApplication . Kod z Listin-
gu 2, wykorzystując obiekt reader , prze-
chwytuje dane ze standardowego wyj-
ścia oraz ze standardowego wyjścia
o błędach.
Podłączenie sygnału dla pierwsze-
go przypadku wygląda w następujący
sposób:
task=new KProcess;
#include <qlineedit.h>
#include <qtextedit.h>
Po jego utworzeniu możemy usta-
lić postać wywołania polecenia wget .
Zakładamy, że będzie ono wywoływane
w następujący sposób:
Jak już wcześniej wspomniałem, wy-
korzystujemy również klasę KProcess ,
więc będzie nam potrzebny plik
nagłówkowy kprocess.h . Po tych
wstępnych czynnościach przystępuje-
my do implementacji funkcji Downlo-
adBTN_Slot . Listing 2 zawiera jej pełny
kod źródłowy.
Pierwszym krokiem jest zadeklarowa-
nie dwóch zmiennych. Pierwsza z nich,
task , reprezentuje proces zewnętrzny,
QApplication::connect(task,
SIGNAL(receivedStdout
(KProcess *, char *, int)),
&reader,
SLOT(read_stdout(KProcess *, char *, S
int )));
wget --progress=dot S
http://www.adres.com.pl/katalog/plik.zip
Wielką zaletą klasy KProcess jest moż-
liwość składania polecenia z fragmen-
tów za pomocą przeciążonego operato-
ra << . Pierwszy fragment, co jest oczywi-
ste, musi zawierać nazwę polecenia. Kod,
w którym budujemy postać polecenia,
Polecenie dla strumienia stderr jest
bardzo podobne.
Używając QApplication::connect
sięgamy do wewnętrznych mechani-
www.lpmagazine.org
25
439110678.026.png 439110678.027.png 439110678.028.png 439110678.029.png
 
narzędzia deweloperskie
Listing 3. Plik nagłówkowy klasy Reader
AllOutput . Pierwsza wartość oznacza,
że nasza aplikacja zostanie zatrzymana
na czas wykonania się polecenia wget .
Druga wartość oznacza, że będzie-
my przechwytywać wszelkie informa-
cje kierowane do standardowych stru-
mieni wyjściowych. Gdyby istniała
potrzeba zarządzania standardowym
wejściem, to podajemy wartość KPro-
cess::Stdin . Gdyby istniała potrzeba
kontrolowania wszystkich trzech
standardowych strumieni, to należy
w metodzie start podać stałą KPro-
cess::All .
Jak widać na Listingu 2, wywoła-
nie jest objęte instrukcją warunkową.
Jeśli metoda zwróci logiczną prawdę,
to oznacza to, że proces zewnętrzny
zakończył się prawidłowo i plik został
poprawnie ściągnięty. Wbrew pozo-
rom, w ten sposób uzyskaliśmy gotowy
program, który jest nieskomplikowa-
ną nakładką na polecenie wget . Do
implementacji pozostała jeszcze klasa
Reader .
#include <kapplication.h>
#include <kprocess.h>
#include <qtextedit.h>
#include <qobject.h>
class Reader : public QObject {
Q_OBJECT
public :
Reader ( QObject * parent = 0 , const char * name = 0 );
~ Reader ();
QTextEdit * edt ;
public slots :
void read_stdout ( KProcess * p , char * b , int l );
void read_stderr ( KProcess * p , char * b , int l );
} ;
zmów, więc ważne są parametry, które
podajemy w przypadku tej metody.
Pierwszym jest obiekt, który będzie
generował sygnał – nasz obiekt task .
W drugim określamy rodzaj sygna-
łu. Zwróćmy uwagę na nazwę funk-
cji: receivedStdout . W przypadku stru-
mienia stderr nazwa funkcji w defini-
cji sygnału jest następująca: received
Stderr . W obu przypadkach funkcja
odpowiadająca na sygnał przyjmuje te
same parametry.
W trzecim argumencie metody con-
nect wskazujemy obiekt, który będzie
odbierał sygnał – reader .
W ostatnim parametrze musimy wska-
zać metodę, która zostanie wywołana
z obiektu reader w odpowiedzi na sygnał.
W nomenklaturze Qt/KDE metoda odpo-
wiadająca na sygnał nazywa się slotem,
więc w ostatnim parametrze stosujemy
makro SLOT .
Po podłączeniu obu sygnałów
możemy uruchomić program wget ,
wywołując metodę start z obiektu
task . Do przechwycenia danych wysy-
łanych do stdout i stderr w metodzie
start trzeba podać dodatkowe parame-
try: KProcess::Block oraz KProcess::
Klasa Reader
Listing 3 prezentuje plik nagłówkowy
klasy Reader . Jest to, jak widać, klasa dzie-
dzicząca z klasy QObject , co jest koniecz-
ne, aby poprawnie funkcjonował mecha-
nizm sygnałów i slotów. Nie należy doda-
wać jej samodzielnie do projektu, gdyż
Listing 4. Implementacja klasy Reader
# include "reader.h"
#include <kprocess.h>
Reader :: Reader ( QObject * parent , const char * name )
: QObject ( parent , name )
{ }
void Reader :: read_stdout ( KProcess * p , char * b , int l )
{
edt -> append ( QString :: fromLatin1 ( b , l ));
}
void Reader :: read_stderr ( KProcess * p , char * b , int l )
{
edt -> append ( QString :: fromLatin1 ( b , l ));
}
Reader :: ~ Reader ()
{ }
Rysunek 6. Tworzenie klasy Reader
# include "reader.moc"
26
luty 2005
439110678.030.png 439110678.031.png 439110678.032.png 439110678.033.png 439110678.034.png 439110678.035.png 439110678.036.png 439110678.037.png
 
Zgłoś jeśli naruszono regulamin