# &kdevelop; programmeringshåndbogen

2002-12-05
2.0
Ralf Nolden

    Ralf.Nolden@post.rwth-aachen.de

Caleb Tennis

    caleb@aei-tech.com

1999 Ralf Nolden
2002 Caleb Tennis
&FDLNotice;

Brugerguide til C++ programudvikling for K-skrivebordsmiljøet (KDE) med det integrerede udviklingsmiljø &kdevelop;

KDE KDevelop IDE udvikling programmering

## Indledning

Mens Unix-systemer bliver mere og mere populære selv for nybegyndere som arbejder med computere, på grund af deres fordele i form af stabilitet og funktionalitet, bliver de fleste på en måde skuffede, fordi disse programmer ikke har konsistent udseende og hvert af dem opfører sig anderledes. Med KDE har udviklere en næsten perfekt måde at lave førsteklasses programmer for Unix-skrivebordssystemer, for at få en bredere brugergruppe kun på grund af kvaliteten som programmerne tilbyder. Derfor bliver KDE mere og mere populært som en basis for programkonstruktion, og udviklere vil drage fordel af mulighederne som systemet tilbyder.

### Hvad du allerede bør vide

For at bruge denne programmeringshåndbog på bedste måde, antager vi at du allerede kender til programmeringssproget C++. Hvis du ikke gør det, bør du gøre dig bekendt med det først. Information om C++ er tilgængelig via forskellige kilder, enten på skriftlig form i den lokale boghandel eller med vejledninger på internettet. Kendskab til konstruktion af grafiske brugergrænseflader kræves ikke, eftersom håndbogen forsøger at dække konstruktion af KDE-programmer, som også omfatter en introduktion til QT-værktøjskassen samt KDE-bibliotekerne og konstruktion af brugergrænseflader. Desuden bør du have gjort dig bekendt med &kdevelop;, ved at læse brugermanualen til &kdevelop;, som indeholder en beskrivende gennemgang af funktionerne som det integrerede udviklingsmiljø sørger for.

### Om denne håndbog

Denne håndbog er skrevet for at give udviklere en introduktion til udvikling af KDE-programmer ved at bruge det integrerede udviklingsmiljø KDevelop.

Følgende kapitler giver derfor en introduktion til hvordan projekter laves, forklarer kildekoden som allerede er lavet, og viser hvordan den givne kildekode kan udvides med forskellige funktioner som værktøjslinjer, menulinjer og visningsområder.

Derefter beskrives dialogeditoren i detalje, det forklares hvordan grafiske komponenter laves og hvordan indstillinger af komponentegenskaber udføres i detalje for alle komponenter som er til stede.

Endelig vil du lære om flere emner som udvider din kundskab om projektkonstruktion og hjælper dig med at løse yderligere problemer udover kodning, som at tilføje dokumentation om programgrænsefladen og udvide håndbøger.

#### I det næste kapitel

Vi vil kigge på QT- og KDE-bibliotekerne, vise grundlæggende begreber og hvorfor tingene ser ud som de gør. Desuden beskriver vi hvordan eksempelprogrammerne som kommer med med QT-værktøjskassen laves ved at bruge KDevelop, så nybegyndere allerede kan se de første resultater efter nogle få skridt, og derved lærer sig hvordan nogen af de bedste funktioner i &kdevelop; bruges.

#### I de følgende kapitler

Vil du lære hvordan:

- et program oprettes med programguiden

- Hvad projektskelettet allerede sørger for

- Hvad koden som allerede er lavet betyder

- Hvordan man laver egne visninger

- Hvordan programmets funktion kan udvides med dialoger, menulinjer og værktøjslinjer

- Hvordan programmet kan gøres brugervenligt ved at sørge for hjælpefunktioner

- Hvordan man skriver dokumentation til netbrug

### Yderligere information

Yderligere information om QT- og KDE-programmering er tilgængelig fra forskellige kilder:

- Programming with Qt af Matthias Kalle Dalheimer

- KDevelop's brugermanual, som kommer med udviklingsmiljøet KDevelop

- Online-referencen til QT-biblioteket

- KDE's netsted for udviklere

Desuden bør du søge hjælp ved at abonnere på de forskellige e-postlister, hvis adresser er tilgængelige på ovennævnte netsider, og på diskussionsgrupper i Usenet beregnet til brug for KDE og Unix-systemer samt programmeringssprogene C og C++.

For at få hjælp til det integrerede udviklingsmiljøet KDevelop, kan du sende spørgsmål til vores e-postliste på kdevelop@kdevelop.org. Husk at KDevelop-gruppen er interesseret i at tilbyde dig muligheder for at lave programmer, og derfor ikke er beregnet til at være en teknisk støttegruppe ifald de programmer du udvikler ikke virker på grund af implementeringsfejl eller forkert indstilling af operativsystemet. Med dette beder vi alle brugere at drage fordel af e-postlisten i de tilfælde hvor problemer med brug af selve det integrerede udviklingsmiljø opstår, samt for fejlrapporter og forbedringsforslag af funktionerne i udviklingsmiljøet.

## KDE- og QT-bibliotekerne

Det norske foretagende TrollTech (http://www.trolltech.com) sørger for en såkaldt GUI-værktøjskasse, som kaldes QT. GUI betyder "grafisk brugergrænseflade", og derfor vises QT-baserede program med knapper, vinduer osv., hvilket muliggør brugerinput ved at synliggøre funktionerne som et program sørger for. En sådan værktøjskasse behøves for at udvikle grafiske programmer som bruger grænsefladen X-windows på Unix-systemer, eftersom X ikke selv indeholder et fordefineret brugergrænseflade. Selv om andre værktøjspakker også er tilgængelige til at oprette en brugergrænseflade, tilbyder QT nogle tekniske fordele som gør programkonstruktion meget enkel. Desuden er QT-værktøjskassen også tilgængelig på Microsoft Windows-systemer, hvilket gør det muligt for udviklerne at lave deres programmer på begge platformene.

KDE-gruppen (http://www.kde.org) dannedes med det formål at gøre det mere brugervenligt at bruge Unix-systemer, og bestemte at QT-værktøjskassen skulle bruges til udvikling af en vinduehåndtering for X-windows, samt en mængde værktøjer som indgår i KDE-pakken. K-skrivebordsmiljøet indeholder derfor hovedkomponenterne vinduehåndteringen kwm, filhåndteringen kfm og startpanelet kpanel samt en mængde førsteklasses værktøjer og programmer. Efter KDE blev udgivet, kiggede mange udviklere på det nye miljø og hvad det havde at tilbyde. KDE-bibliotekerne sørger for væsentlige metoder og klasser som gør at alle programmer som konstrueres med dem ligner hinanden og opfører sig ens, så brugeren har den store fordel kun at behøve at vænne sig til brugen af et bestemt program, ikke til håndtering af dialoger og knapper. Desuden integreres KDE-programmer med skrivebordet, kan virke sammen med filhåndteringen via træk og slip, tilbyder sessionshåndtering, og meget mere hvis alle funktioner som tilbydes af KDE-bibliotekerne bruges. Både QT-værktøjskassen og KDE-bibliotekerne er implementerede med programsproget C++. Derfor er de fleste programmer som benytter sig af bibliotekerne også skrevet i C++. I de følgende kapitel tager vi en kort tur gennem bibliotekerne for at se hvad der allerede sørges for, og hvordan QT- og KDE-programmer i almindelighed laves.

Både QT-værktøjskassen og KDE-bibliotekerne er implementerede med programsproget C++. Derfor skrives også programmerne som bruger disse biblioteker oftest i C++. I de følgende kapitel tager vi en hurtig tur gennem bibliotekerne for at se hvad der allerede sørges for, og hvordan QT- og KDE-program laves i almindelighed.

### QT-værktøjskassen for grafiske brugergrænseflader

Som sagt, er QT-biblioteket en værktøjskasse som tilbyder grafiske elementer som bruges til at lave programmer med grafiske grænseflader og behøves for programmering for X-windows. Desuden tilbyder værktøjskassen:

- Et komplet sæt af klasser og metoder klare til at bruge til og med for programmering som ikke berører grafik

- En god løsning på brugerkommunikationen med virtuelle metoder og mekanismen med signaler og slot

- Et sæt fordefinerede grafiske grænsefladeselementer, som kaldes "grafiske kontroller" som kan bruges til at oprette synlige elementer

- Desuden fuldstændige fordefinerede dialoger som ofte bruges i programmer såsom fremgang- og fildialoger

Derfor er det meget væsentligt at kende til QT-klasserne, også selvom du kun vil programmere KDE-programmer. For at få et indblik i grundbegreberne for at oprette og kompilere et program med grafisk grænseflade, tager vi først et kig på et eksempelprogram som kun bruger QT. Derefter udvider vi det til et KDE-program.

#### Det første QT-program

Som sædvanligt skal programmer i C++ indeholde funktionen `main()`, som er programkørslens startpunkt. Eftersom vi ønsker at programmet skal være synligt som grafik i vinduer og tilbyde kommunikation med brugeren, skal vi først vide hvordan de kan vises for brugeren. Som et eksempel, tager vi et kig på det første eksempel som indgår i QT's referencedokumentation, og forklarer de grundlæggende skridt i kørslen, inklusive hvorfor og hvordan programmets vindue vises:

    #include <qapplication.h>
    #include <qpushbutton.h>

    int main( int argc, char **argv )
    {
    QApplication a( argc, argv );

    QPushButton hello( "Hello world!" );
    hello.resize( 100, 30 );

    a.setMainWidget( &hello );
    hello.show();
    return a.exec();
    }

Dette program tegner blot et vindue som indeholder en knap med "Hello world" som tekst. Som for alle QT-baserede programmer, skal du først oprette en udgave af klassen QApplication, som repræsenteres af variablen a.

Derefter laver programmet en udgave af klassen QPushButton som hedder hello. Dette bliver til knappen. Konstruktoren af hello tager en streng som parameter, som er indholdet i komponenten som bliver synligt som knappens tekst.

Derefter kaldes metoden resize() for knappen hello. Den ændrer komponenternes normalstørrelse (som i dette tilfælde er QPushButton) som den havde da den oprettedes, til længden 100 billedpunkter og højden 80 billedpunkter. Tilsidst kaldes metoden setMainWidget() og metoden show() for hello. Endelig køres vores QApplication med a.exec(), går ind i hovedbegivenhedsløkken og venter til den skal returnere en heltalsværdi til det omgivende operativsystem for at signalere at programmet er afsluttet.

#### Referencedokumentation for Qt

Lad os nu tage et hurtigt kig på referencedokumentationen for QT-biblioteket. For at gøre dette, start &kdevelop; og vælg "Qt" i dokumentationsfanebladets træ. Dokumentationssøgeren åbnes og viser startsiden i QT-referencedokumentationen. Dette er det første sted hvor du kan hente information om QT, dens klasser og tilgængelige funktioner som de sørger for. Desuden er ovenstående program det første som er med i vejledningsafsnittet. For at komme til klasserne vil vi kigge på, QApplication og QPushButton, vælg "Alphabetical Class List" og led efter tilsvarende navne. Følg en af dem for at tage en kig på klassedokumentationen.

Alternativt kan du bruge net-dokumentationen fra TrollTechs QT-dokumentation.

Du vil se konstruktoren og alle andre metoder som klassen QApplication sørger for. Hvis du følger et link, får du mere information om brugen og betydningen af metoderne, hvilket er meget nyttigt hvis du sommetider ikke kan indse den rigtige brug eller vil have et eksempel. Dette gælder også dokumentationen af KDE-bibliotekerne, som bruger en lignende slags dokumentation, derfor er dette næsten alt du behøver at vide om at bruge klassereferencer med dokumentationssøgeren.

##### Tolkning af eksemplet

Begyndende fra QApplication, finder du alle metoder som bruges i vort første eksempel:

- konstruktoren QApplication()

- metoden setMainWidget()

- metoden exec()

Tolkningen af hvorfor vi bruger disse metoder er meget enkel:

1. Opret en instans af klassen QApplication med konstruktoren, så vi kan bruge elementer for den grafiske grænsefladen som QT sørger for

2. Opret en grafisk komponent som bliver indholdet i vort programvindue

3. Sæt kontrollen som hovedkontrol for en

4. Kør en instans af QApplication

Det andet objekt i vort program er trykknappen, en instans af klassen QPushButton. Af de to konstruktorer der er til at oprette klassen, bruger vi den anden. Den tager en tekst, som er tekstindholdet i knappen. Her er det strengen "Hello world!". Derefter kalder vi metoden resize() for at ændre størrelse på knappen ifølge dens indhold. Knappen skal være større for at gøre strengen fuldstændigt synlig.

Men hvad gælder for metoden show()? Nu mærker du, at som de fleste andre grafiske komponenter, er QPushButton baseret på enkelt arv. Dokumentationen siger, Arver QButton. Følg linket til klassen QButton. Det viser mange andre kontroller som arves af QPushButton, som vi senere bruger til at forklare signal/slot-mekanismen. Under alle omstændigheder er metoden show() ikke på listen, og derfor skal den være en metode som også sørges for via arv. Klassen som QButton arver er QWidget. Følg kun linket igen, så ser du en hel mængde metoder som klassen QWidget sørger for, inklusive metoden show(). Nu forstår vi hvad der blev gjort i eksemplet med knappen:

1. Lav en instans af QPushButton, og brug den anden konstruktor til at angive knappens tekst

2. Ændr størrelsen på kontrollen til dens indhold

3. Sæt kontrollen som hovedkontrol instansen af QApplication

4. Fortæl den grafiske kontrol at den skal vises på skærmen ved at kalde show(), en metode som blev arvet fra QWidget

Efter at have kaldet metoden exec(), er programmet synligt for brugeren, og viser et vindue med knappen "Hello world!". Bemærk at programmer med grafiske grænseflader opfører sig noget anderledes sammenlignet med procedurebaserede program. Det vigtigste er at programmet går ind i en såkaldt "hovedbegivenhedsløkke". Det betyder at programmet skal vente på brugerens handlinger og derefter reagere på dem. Det betyder også, for et QT-program, at programmet skal være i hovedbegivenhedsløkken for at starte begivenhedshåndteringen. Næste afsnit beskriver kortfattet hvad det betyder for programmøren og hvad QT tilbyder for at håndtere begivenheder.

For brugere som allerede er avancerede: Knappen har ingen overliggende kontrol deklareret i konstruktoren. Derfor er den en topniveaukontrol og kører med en lokal begivenhedsløkke som ikke behøver at vente på hovedbegivenhedsløkken. Se dokumentationen for klassen QWidget og KDE's biblioteksreferenceguide.

#### Brugerkommandoer

Efter at have læst foregående afsnit, bør du allerede vide:

- Hvad QT-biblioteket sørger for for programmer med grafiske grænseflader,

- Hvordan et program som bruger QT laves, og

- Hvor og hvordan du finder information om klasser som du vil bruge med dokumentationssøgeren.

Nu fortsætter vi med at give programmet "liv" ved at behandle brugerbegivenheder. I almindelighed har brugeren to måder at kommunikere med et program: musen og tastaturet. En grafisk brugergrænseflade skal sørge for metoder for begge måder, som detekterer handlinger og gør noget som reaktion på handlingerne.

Vinduesystemet sender derfor alle kommunikationsbegivenheder til det tilsvarende program. QApplication sender dem derefter til det aktive vindue som en QEvent, og kontrollerne selv skal bestemme hvad som skal udføres med dem. En kontrol tager imod begivenheden og behandler QWidget::event(QEvent*), som afgør hvilken begivenhed der er sket og hvordan reaktionen skal være. Metoden event() udfører derfor håndteringen af hovedbegivenheden. Derefter sender metoden event() begivenheden til et såkaldt begivenhedfilter som afgør hvad der sker og hvad der skal udføres med begivenheden. Hvis intet filter signalerer at det er ansvarligt for begivenheden, kaldes speciel begivenhedshåndtering. På den måde kan vi skelne mellem:

- Tastaturbegivenheder: Tabulator og Shift+Tabulator:

  - virtual void focusInEvent(QFocusEvent *)

  - virtual void focusOutEvent(QFocusEvent *)

- Al øvrig tastaturindtastning:

  - virtual void keyPressEvent(QKeyEvent *)

  - virtual void keyReleaseEvent(QKeyEvent *)

- Museflytning:

  - virtual void mouseMoveEvent(QMouseEvent *)

  - virtual void enterEvent(QEvent *)

  - virtual void leaveEvent(QEvent *)

- Handlinger med museknapperne

  - virtual void mousePressEvent(QMouseEvent *)

  - virtual void mouseReleaseEvent(QMouseEvent *)

  - virtual void mouseDoubleClickEvent(QMouseEvent *)

- Vinduesbegivenheder som indeholder den grafiske kontrol

  - virtual void moveEvent(QMoveEvent *)

  - virtual void resizeEvent(QResizeEvent *)

  - virtual void closeEvent(QCloseEvent *)

Bemærk at alle begivenhedsfunktioner er virtuelle og protected. Derfor kan du implementere begivenhederne som du behøver i egne kontroller og angive hvordan din kontrol skal reagere. QWidget indeholder også nogle andre virtuelle metoder som kan være nyttige i dine programmer. Under alle omstændigheder er det nødvendigt at kende QWidget godt.

#### Interaktion mellem objekt med signaler og slots

Nu kommer vi til den mest åbenbare fordel ved QT-værktøjskassen: signal/slot-mekanismen. Den tilbyder en meget bekvem og nyttig løsning for kommunikation mellem objekter, som sædvanligvis løses med tilbagekaldsfunktioner i X-windows værktøjskasser. Eftersom kommunikationen kræver strikt programmering og ind imellem gør det meget svært at oprette brugergrænseflader (som beskrevet i QT-dokumentationen og forklaret i Programming with Qt af K. Dalheimer), opfandt TrollTech et nyt system hvor objekter kan sende signaler som kan forbindes til metoder som deklareres som slots. Som programmør af C++, behøver man kun at vide nogen ting om denne mekanisme:

- klassedeklarationen af en klasse som bruger signaler og slots skal indeholde makroen Q_OBJECT i begyndelsen (uden et semikolon), og skal afledes fra klassen QObject

- et signal kan sendes med nøgleordet emit, f.eks. emit signal(parametre);, inde i en hvilken som helst medlemsfunktion i en klasse som tillader brug af signaler og slots

- alle signaler som bruges af klasser som ikke arves skal tilføjes i klassedeklarationen i en signalsektion

- alle metoder som kan forbindes med et signal deklareres i sektioner med det yderligere nøgleord slot, f.eks. public slots: inde i klassedeklarationen

- metaobjektoversætteren moc skal køres over deklarationsfilen for at ekspandere makroer og oprette implementeringen (som man ikke behøver kende til). Uddatafilerne fra moc kompileres også af C++ oversætteren.

En anden måde at bruge signaler uden at aflede fra QObject er at bruge klassen QSignal. Se referencedokumentationen for mere information og eksempel på brug. Vi antager at du afleder fra QObject i det følgende.

På denne måde kan din klasse sende signaler hvor som helst og sørge for slots som signaler kan forbindes til. Ved at bruge et signal, behøver du ikke bryde dig om hvem der modtager det. Du behøver kun at sende signalet, og hvilken slot du end forbinder den til kan reagere når den sendes. Desuden kan en slot bruges som en almindelig metode i implementeringen.

For nu at forbinde et signal til en slot, skal du bruge metoderne connect() som varetages af QObject eller, hvis tilgængelige, specielle metoder som objekter sørger for for at angive forbindelsen for et vist signal.

##### Eksempel på brug

For at forklare hvordan objektinteraktion håndteres, tager vi vort første eksempel igen og udvider det med en enkel forbindelse:

    #include <qapplication.h>
    #include <qpushbutton.h>

    int main( int argc, char **argv )
    {
    QApplication a( argc, argv );

    QPushButton hello( "Hello world!" );
    hello.resize( 100, 30 );

    a.setMainWidget( &hello );

    connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));

    hello.show();
    return a.exec();
    }

Du mærker at alt du skal tilføje for at give knappen mere kommunikation er metoden connect(): connect (&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));. Hvad er betydningen nu? Klassedeklarationen af QObject siger følgende om metoden connect():

bool connect ( const QObject * afsender, const char * signal, const QObject * modtager, const char * medlem )

Dette betyder at du skal angive en QObject-instanspeger som er signalets afsender, hvilket betyder at den kan sende signalet, som første parameter. Derefter skal du angive signalet som du vil forbinde til. De to sidste parametre er modtagerobjektet som sørger for en slot, fulgt af medlemsfunktionen som er en virkelig slot som vil køres når signalet sendes.

Ved at bruge signaler og slots, kan programmets objekter nemt kommunikere med hinanden uden udtrykkeligt at afhænge af typen af modtagarobjektet. Du vil lære mere om hvordan denne mekanisme bruges produktivt senere i håndbogen. Mere information om signal/slot-mekanismen findes også i KDE's biblioteksreferenceguide og QT's reference på nettet.

### Hvad KDE sørger for

#### KDE 3.x bibliotekerne

KDE's hovedbibliotek som bruges til at lave KDE-programmer er:

- biblioteket kdecore, som indeholder alle klasser som er usynlige elementer til at sørge for programfunktioner

- biblioteket kdeui, som indeholder elementer i brugergrænsefladen såsom menulinjer, værktøjslinjer, osv.

- biblioteket kfile, som indeholder filvalgsdialoger

Desuden tilbyder KDE følgende biblioteker til specialløsninger:

- biblioteket kdefx, som indeholder pixmaps, billedeffekter og KStyle-udvidelsen af QStyle

- biblioteket khtml, som indeholder KDE's HTML-komponent

- biblioteket kjs, som indeholder KDE's understøttelse for Javascript

- biblioteket kio, som indeholder adgang til netværksfiler på lavt niveau

- biblioteket kparts, med understøttelse for programmer som kan genbruges, indlejres og udvides

Derefter tager vi et kig på hvad der behøves for at forvandle vort første QT-program til et KDE-program.

#### Eksempel på et KDE-program

Du ser i det følgende, at det ikke er meget sværere at skrive et KDE-program end et QT-program. Du skal kun bruge nogle andre klasser for at komme til KDE's funktioner, så er du næsten klar. Vi diskuterer en ændret version af QT-koden ovenfor, som et eksempel:

    #include <kapplication.h>
    #include <qpushbutton.h>

    int main( int argc, char **argv )
    {
    KApplication a( argc, argv );

    QPushButton hello( "Hello world!" );
    hello.resize( 100, 30 );

    a.setTopWidget( &hello );

    connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));

    hello.show();
    return a.exec();
    }

Du ser at vi først har ændret fra QApplication til KApplication. Desuden var vi tvunget til at ændre den tidligere brugte metode setMainWidget() til setTopWidget som KApplication bruger til for at angive hovedkontrollen. Det er alt! Dit første KDE-program er klart. Du behøver kun at fortælle oversætteren hvilken deklarationssøgesti KDE har, og linkeren at den skal linke med kdecore-biblioteket med -lkdecore.

Eftersom du nu i det mindste ved hvad funktionen `main()` i almindelighed sørger for, og hvordan et program bliver synligt og tillader kommunikation mellem brugere og objekt, fortsætter vi med næste kapitel, hvor vort første program med &kdevelop; laves. Der kan du også prøve alt som tidligere blev nævnt, og se effekterne.

Hvad du yderligere bør have kigget på hidtil er QT-referencedokumentationen, især klasserne QApplication, QWidget og QObject og kdecore-biblioteksdokumentationen for klassen KApplication. KDE's biblioteksreferenceguide har også en fuldstændig beskrivelse af hvordan konstruktorerne i QApplication og KApplication kaldes, inklusive behandling af kommandolinjeflag.

## Lav nye programmer

### Programguiden

Programguiden i &kdevelop; er beregnet til at lade dig begynde at arbejde med et nyt projekt i &kdevelop;. Derfor laves alle projekter først af guiden, og derefter kan du begynde at bygge dem og udvide det som allerede varetages af kildekodeskelettet. Du kan vælge blandt flere projekttyper ifølge målet med dit projekt:

- KDE Application Framework: Indeholder kildekode for en fuldstændig rammestruktur til et almindeligt KDE-program

- QMake project: Laver et programskelet baseret på TrollTechs qmake konfigurationssystem

- Simple Hello world program: Opretter et C++ terminalbaseret program uden støtte for grafisk grænseflade

- En mængde andre programskeletter

I dette kapitel ser vi hvordan Programguiden kan startes, og hvad der skal udføres for at oprette et KDE-programmeringsprojekt. Dette er også det første skridt i opfølgningen hvor vi laver den oprindelige version af vort eksempelprojekt. Skridtene er oftest ens for alle andre projekttyper, men der er måske ikke så mange tilgængelige alternativer.

### Start af programguiden og oprettelse af projekt

#### Start af programguiden og første side

Åbn &kdevelop; for at begynde med dit KDE-program. Vælg Nyt projekt i projektmenuen. Programguiden starter, og du ser udvalgstræet på første side som indeholder tilgængelige projekttyper som kan laves. Vælg deltræet C++, derefter KDE, og Application framework.

Vi vil lave programmet KScribble som eksempelprojekt. Indtast det som programmets navn, og ændr eventuelt anden information som behøves længst nede på skærmen. Vælg derefter Næste.

Programguiden

#### Versionskontrolinformation

På denne skærm har du mulighed for at bestemme om projektet skal bruge et versionskontrollsystem som CVS. For vort eksempelprojekt bruger vi ikke versionskontrol, så sørg for at boksen siger Intet, og vælg Næste.

#### Deklarations- og kildekodeskabeloner

Følgende to sider viser eksempler på sidehoveder som havner øverst i deklarations- og kildekodefilerne som du laver med &kdevelop;. Lad dem blot være som de er for øjeblikket, og vælg Næste og derefter Afslut. Hvis knappen Afslut ikke er aktiveret, har du ikke indstillet alle valgmuligheder rigtigt. Brug knappen Tilbage for at gå tilbage til tidligere sider og ret eventuelle fejl.

#### Afslutning

Når den er færdig, skal Programguiden lukkes og meddelelsesvinduet skulle dukke op og vise information om aktiviteterne som &kdevelop; for øjeblikket udfører. I slutningen af alle aktiviteter skal du se **** Succes ****. Det betyder at det er lykkedes at lave programmets rammeomgivelser.

### Byg første gang

Efter at projektet har oprettet, tager vi først en tur gennem kildekoden for at få en almen forståelse for hvordan programmets rammeomgivelser ser ud. Det hjælper os ikke kun med at komme igang, men vi ved også hvor ændringer skal udføres i senere skridt.

I dette kapitel gøres antagelsen at du forstår den grundlæggende håndtering af &kdevelop;. Kig i KDevelops håndbog for at finde information hvis du behøver det.

Håndtering af automake viser projektfilerne som følger:

Filer i vores projekt

Inden vi dukker ned i kildekoden, skal vi lade &kdevelop; bygge og køre vort nye program. For at gøre det, vælges Byg projekt i menuen Byg, eller der trykkes på F8. Udskriftsvinduet åbnes og viser udskrevne meddelelser under kompileringsfasen.

    1 cd /home/caleb/kscribble && WANT_AUTOCONF_2_5=1 WANT_AUTOMAKE_1_6=1 gmake k
    2 gmake all-recursive
    3 gmake[1]: Entering directory `/home/caleb/kscribble'
    4 Making all in doc
    5 gmake[2]: Entering directory `/home/caleb/kscribble/doc'
    6 Making all in .
    7 gmake[3]: Entering directory `/home/caleb/kscribble/doc'
    8 gmake[3]: Nothing to be done for `all-am'.
    9 gmake[3]: Leaving directory `/home/caleb/kscribble/doc'
    10 Making all in en
    11 gmake[3]: Entering directory `/home/caleb/kscribble/doc/en'
    12 /usr/local/kde3/bin/meinproc --check --cache index.cache.bz2 /home/caleb/kscribble/doc/en/index.docbook
    13 gmake[3]: Leaving directory `/home/caleb/kscribble/doc/en'
    14 gmake[2]: Leaving directory `/home/caleb/kscribble/doc'
    15 Making all in po
    16 gmake[2]: Entering directory `/home/caleb/kscribble/po'
    17 gmake[2]: Nothing to be done for `all'.
    18 gmake[2]: Leaving directory `/home/caleb/kscribble/po'
    19 Making all in src
    20 gmake[2]: Entering directory `/home/caleb/kscribble/src'
    21 source='main.cpp' object='main.o' libtool=no \
    22 depfile='.deps/main.Po' tmpdepfile='.deps/main.TPo' \
    23 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
    24 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/kde3/include
       -I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
       -Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
       -ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
       -c -o main.o `test -f 'main.cpp' || echo '/home/caleb/kscribble/src/'`main.cpp
    25 /usr/lib/qt/bin/moc /home/caleb/kscribble/src/kscribble.h -o kscribble.moc
    26 source='kscribble.cpp' object='kscribble.o' libtool=no \
    27 depfile='.deps/kscribble.Po' tmpdepfile='.deps/kscribble.TPo' \
    28 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
    29 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/kde3/include
       -I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
       -Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
       -ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
       -c -o kscribble.o `test -f 'kscribble.cpp' || echo '/home/caleb/kscribble/src/'`kscribble.cpp
    30 kscribble.cpp: In member function `void KScribble::setupActions()'
    31 kscribble.cpp:107: warning: unused variable `KAction*custom'
    32 /usr/lib/qt/bin/moc /home/caleb/kscribble/src/kscribbleview.h -o kscribbleview.moc
    33 source='kscribbleview.cpp' object='kscribbleview.o' libtool=no \
    34 depfile='.deps/kscribbleview.Po' tmpdepfile='.deps/kscribbleview.TPo' \
    35 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
    36 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/kde3/include
       -I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
       -Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -ansi
       -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new -c
       -o kscribbleview.o `test -f 'kscribbleview.cpp' || echo '/home/caleb/kscribble/src/'`kscribbleview.cpp
    37 kscribbleview.cpp: In member function `void KScribbleView::print(QPainter*,
    38  int, int)':
    39 kscribbleview.cpp:79: warning: unused parameter `QPainter*p'
    40 kscribbleview.cpp:79: warning: unused parameter `int height'
    41 kscribbleview.cpp:79: warning: unused parameter `int width'
    42 /usr/lib/qt/bin/moc /home/caleb/kscribble/src/pref.h -o pref.moc
    43 source='pref.cpp' object='pref.o' libtool=no \
    44 depfile='.deps/pref.Po' tmpdepfile='.deps/pref.TPo' \
    45 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
    46 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/kde3/include
       -I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
       -Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
       -ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
       -c -o pref.o `test -f 'pref.cpp' || echo '/home/caleb/kscribble/src/'`pref.cpp
    47 /usr/local/kde3/bin/dcopidl /home/caleb/kscribble/src/kscribbleiface.h
    > kscribbleiface.kidl ||
       ( rm -f kscribbleiface.kidl ; /bin/false )
    48 /usr/local/kde3/bin/dcopidl2cpp --c++-suffix cpp --no-signals --no-stub kscribbleiface.kidl
    49 source='kscribbleiface_skel.cpp' object='kscribbleiface_skel.o' libtool=no \
    50 depfile='.deps/kscribbleiface_skel.Po' tmpdepfile='.deps/kscribbleiface_skel.TPo' \
    51 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
    52 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/kde3/include
       -I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
       -Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
       -ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
       -c -o kscribbleiface_skel.o `test -f 'kscribbleiface_skel.cpp' ||
       echo '/home/caleb/kscribble/src/'`kscribbleiface_skel.cpp
    53 /bin/sh ../libtool --silent --mode=link --tag=CXX g++ -Wnon-virtual-dtor -Wno-long-long -Wundef -Wall
       -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -ansi -D_XOPEN_SOURCE=500
       -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new -o kscribble -R
       /usr/local/kde3/lib -R /usr/lib/qt/lib -R /usr/X11R6/lib -L/usr/X11R6/lib -L/usr/lib/qt/lib
       -L/usr/local/kde3/lib main.o kscribble.o kscribbleview.o pref.o kscribbleiface_skel.o -lkio
    54 source='kscribble_client.cpp' object='kscribble_client.o' libtool=no \
    55 depfile='.deps/kscribble_client.Po' tmpdepfile='.deps/kscribble_client.TPo' \
    56 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
    57 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/kde3/include
       -I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
       -Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
       -ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
       -c -o kscribble_client.o `test -f 'kscribble_client.cpp' || echo
       '/home/caleb/kscribble/src/'`kscribble_client.cpp
    58 /bin/sh ../libtool --silent --mode=link --tag=CXX g++ -Wnon-virtual-dtor -Wno-long-long -Wundef
       -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -ansi -D_XOPEN_SOURCE=500
       -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new -o kscribble_client -R
       /usr/local/kde3/lib -R /usr/lib/qt/lib -R /usr/X11R6/lib -L/usr/X11R6/lib -L/usr/lib/qt/lib
       -L/usr/local/kde3/lib kscribble_client.o -lkdecore
    59 gmake[2]: Leaving directory `/home/caleb/kscribble/src'
    60 gmake[2]: Entering directory `/home/caleb/kscribble'
    61 gmake[2]: Nothing to be done for `all-am'.
    62 gmake[2]: Leaving directory `/home/caleb/kscribble'
    63 gmake[1]: Leaving directory `/home/caleb/kscribble'
    64 *** Succes ***

Som du kan se, har vi puttet linjenumre foran hver linje som ikke vises i udskriften, men som gør det nemmere at beskrive hvad der sker under bygningen. For det første virker byggeprogrammet rekursivt. Det betyder at det begynder i mappen hvor det startes, først går ned i undermapper, en af gangen, og derefter går tilbage til mappen hvor det startedes, behandler den, og derefter afslutter.

Den første interessante linje er 24. Bemærk at g++, som er vores C++ oversætter, kaldes af make på denne linje for at kompilere den første kildekodefilen i vores projekt - i dette tilfælde main.cpp. Mange yderligere kommandolinjeflag bruges også med g++ oversætteren. Visse er standard, mens andre kan indstilles via &kdevelop;.

Inden næste fil (kscribble.cpp, linje 29) kompileres, køres først moc (metaobjektoversætteren) for kscribble.h (linje 25). Det sker fordi KScribble-klasser bruger signaler og slots, så makroen Q_OBJECT skal ekspanderes, og moc gør det for os. Resultatfilen, kscribble.moc, bruges af kscribble.cpp via udsagnet #include i filen.

### Kildekodeskelettet

For at gøre det klart hvordan et KDE-program virker, skal vi først undersøge kildekodeskelettet, som allerede varetages af programguiden, meget nøjagtigt. Som vi allerede har set, har vi et sæt kildekode- og deklarationsfiler som opbygger den oprindelige programkode og gør den klar til at køre. Derfor er den nemmeste måde at forklare koden at følge implementeringen linje for linje som den behandles under kørsel af programmet til det går ind i hovedbegivenhedsløkken og er klart til at acceptere brugerindput. Derefter kigger vi på funktionerne som muliggør kommunikation med brugeren, og hvordan visse ting fungerer. Dette er formodentlig den bedste måde at forklare rammeomgivelserne, og eftersom det er ens for næsten alle KDE-programmer, gør det at du kan læse kildekode også fra andre projekter. Desuden lærer du dig hvor forskellige dele af koden skal ændres for at få dit program til at opføre sig som det er beregnet til at gøre.

#### Funktionen main()

Eftersom programmet begynder at køre ved at gå ind i funktionen `main()`, er det der vi begynder at kigge på koden. Funktionen `main()` i KScribble er implementeret i filen main.cpp, og kan også findes ved at bruge klassesøgeren og vælge mappen "Globale funktioner".

    1  int main(int argc, char **argv)
    2  {
    3      KAboutData about("kscribble", I18N_NOOP("KScribble"), version, description,
    4                       KAboutData::License_GPL, "(C) 2002 Dit Navn", 0, 0, "du@du.se");
    5      about.addAuthor( "Dit Navn", 0, "du@du.se" );
    6      KCmdLineArgs::init(argc, argv, &about);
    7      KCmdLineArgs::addCmdLineOptions(options);
    8      KApplication app;
    9
    10    // registrer os som en DCOP-klient
    11    app.dcopClient()->registerAs(app.name(), false);
    12
    13    // se om vi starter med sessionshåndtering
    14    if (app.isRestored())
    15        RESTORE(KScribble)
    16    else
    17    {
    18        // ingen session.. start kun som almindeligt
    19        KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    20        if (args->count() == 0)
    21        {
    22            KScribble *widget = new KScribble;
    23            widget->show();
    24        }
    25        else
    26        {
    27            int i = 0;
    28            for (; i < args->count(); i++)
    29            {
    30                KScribble *widget = new KScribble;
    31                widget->show();
    32                widget->load(args->url(i));
    33            }
    34        }
    35        args->clear();
    36    }
    37
    38    return app.exec();
    39 }

Det der først sker nu, er at objektet KApplication laves som almindeligt, men vi har tilføjet nogle KDE-metoder som angiver information om programmet og forfatteren af programmet.

#### Start af brugerprogrammet

... (endnu ikke skrevet)

#### Konstruktoren

Lad os kigge lidt på konstruktoren og se hvordan instansen kaldes

    1  KScribble::KScribble()
    2      : KMainWindow( 0, "KScribble" ),
    3        m_view(new KScribbleView(this)),
    4        m_printer(0)
    5  {
    6      // accepter træk og slip
    7      setAcceptDrops(true);
    8
    9      // fortæl KMainWindow at det virkelig er hovedkontrollen
    10     setCentralWidget(m_view);
    11
    12     // indstil derefter vore handlinger
    13     setupActions();
    14
    15     // og en statuslinje
    16     statusBar()->show();
    17
    18     // tillad visningen at ændre statuslinjen og overskriften
    19     connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
    20             this,   SLOT(changeStatusbar(const QString&)));
    21     connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
    22             this,   SLOT(changeCaption(const QString&)));
    23
    24  }

Bemærk at KScribble arver klassen KMainWindow, en ofte brugt basisklasse for KDE-programmer. Vi initierer en klasse som hedder KScribbleView som central grafikkomponent, laver en KStatusBar via metoden statusBar() (på linje 16), og forbinder nogle signaler og slots.

## Konstruktion af programvisning

### Indledning

Når et program med en grafisk grænseflade udvikles, sker hoveddelen af arbejdet ved at sørge for en såkaldt "visning" for programmet. En visning er i almindelighed en grafisk kontrol som viser data i et dokument og sørger for metoder til at manipulere dokumentets indhold. Dette kan udføres af brugeren via de begivenheder som laves via tastaturet og musen. Kompleksere handlinger behandles ofte af værktøjslinjer og menulinjer som kommunikerer med visningen og dokumentet. Statuslinjen sørger så for information om dokumentet, visningen eller programmets status. Som eksempel, kigger vi på hvordan en editor er konstrueret, og hvor hver del kan findes.

En editor antages i almindelighed at sørge for en grænseflade til at vise og/eller ændre indhold i et tekstdokument for brugeren. Hvis du starter Kate, ser du følgende i den visuelle grænseflade:

- Menulinjen: sørger for komplekse handlinger samt at åbne, gemme og lukke filer eller afslutte programmet.

- Værktøjslinjen: tilbyder ikoner som giver hurtigere adgang til de oftest brugte funktioner,

- Statuslinjen viser status for markørpositionen med nuværende linje og søjle,

- Visningen i vinduets midte, som viser et dokument og tilbyder en markør forbundet til tastaturet og musen for at håndtere data.

Nu er det enkelt at forstå at en visning er programmets mest enestående del, og at konstruktionen af visningen bestemmer hvor nyttigt og let at acceptere programmet er. Det betyder at et af de første skridt i udviklingen er at afgøre formålet med programmet og hvilken slags konstruktion af visningen som passer bedst til at lade en hvilken som helst bruger arbejde med programmet, med en minimal anstrengelse for at lære sig hvordan brugergrænsefladen skal håndteres.

Visninger varetages af QT- og KDE-bibliotekerne for visse formål, såsom tekstredigering og visning af HTML-filer. Vi beskriver visse aspekter af disse her højniveaukontroller i næste afsnit. Men for de fleste programmer skal nye komponenter konstrueres og implementeres. Det er dette som gør at programmøren også bliver en formgiver, og hvor kreativiteten sættes på prøve. Trods dette bør du først forsøge at opnå noget intuitivt. Husk at mange brugere accepterer ikke et program som ikke:

- har et godt grafisk udseende

- tilbyder mange funktioner

- er nemt at håndtere

- er hurtigt at lære at bruge

Det behøves ikke at siges at stabilitet er et af hovedmålene med konstruktionen. Ingen kan forhindre fejl, men et minimum kan i det mindste opnås med smarte konstruktionsmål og udbredt brug af objektorienterede konstruktioner. C++ gør det til en fornøjelse at programmere hvis du ved hvordan man udnytter dens muligheder - arv, at skjule information og genbrug af eksisterende kode.

Når et KDE- eller QT-projekt laves, skal du altid have en visning som arver en QWidget, enten med direkte arv eller fordi en bibliotekskontrol som du vil bruge arver QWidget. Derfor har Programguiden allerede oprettet en visning som er en instans af klassen programnavnView, som allerede arver QWidget.

Dette kapitel beskriver derfor hvordan bibliotekskontroller bruges til at oprette visninger for KDE- og QT-programmer som laves med &kdevelop;. Derefter kigger vi på bibliotekerne og hvilke slags visninger de allerede tilbyder.

### Brug af biblioteksvisninger

Når programmets konstruktion er sat op, bør du først lede efter eksisterende kode som kan gøre livet meget enklere. En del af dette er at lede efter en grafisk komponent som kan bruges til visningen, eller i det mindste for en del af den, enten direkte eller med arv. KDE- og QT-bibliotekerne indeholder allerede et sæt grafiske komponenter som kan bruges til endemålet. Der er to muligheder at bruge dem:

1. Fjern den nye visningsklasse og opret en instans af en bibliotekskontrol, og sæt den så som visningen,

2. Ændr arv for den visningsklasse der sørges for, til klassen for bibliotekskontrollen som skal bruges.

Under alle omstændigheder er det vigtigt at vide at hvis programskelet ikke linkes med biblioteket som indeholder den grafiske kontrol for øjeblikket, kommer linkningen til at mislykkes. Efter du har bestemt dig for at bruge en vis grafisk kontrol, så kig efter biblioteket som skal linkes ind. Åbn derefter "Projekt"->"Projektindstillinger" i menulinjen for &kdevelop;. Gå til siden "Link-indstillinger" og led efter afkrydsningsboksene som angiver de biblioteker som bruges for øjeblikket. Hvis biblioteket for din kontrol allerede er markeret, kan du lade projektindstillingerne være uforandrede og begynde at gøre de nødvendige ændringer baseret på dit valg. Hvis ikke, og linkindstillingerne tilbyder at tilføje biblioteket med en afkrydsningsboks, så markér den og tryk på "O.k." for at lukke dialogen igen. I alle andre tilfælde, tilføj biblioteket i redigeringslinjen nedenunder med flaget -l. For biblioteker som dit program skal søge efter inden byggefiler laves af configure-scriptet, tilføjes tilsvarende søgemakro i filen configure.in som findes i projektets rodmappe, og makroen tilføjes på redigeringslinjen. Tænk på at du skal køre "Byg"->"Autoconf og automake" og "Byg"->"Configure" inden byggefilerne indeholder den rigtige ekspansion af biblioteksmakroen.

Desuden, hvis deklarationsfilerne for biblioteket som skal tilføjes ikke er med i den nuværende deklarationssøgesti (som ses i flaget -I for "make" i udskriftsvinduet), skal du tilføje søgestien i dialogen Projektindstillinger på siden "Oversætterindstillinger" med flaget -I eller i den tilsvarende automake-makro på redigeringslinjen for "Yderligere indstillinger".

#### Visninger i Qt

Når du kigger på den første side af QT's net-dokumentation, finder du et link til "Widget Screenshots", hvor du kan kigge på hvordan de grafiske kontroller som QT indeholder ser ud. De er parate til at bruge, og kan kombineres til at give komplekse kontroller som kan oprette programvisninger eller dialoger. I det følgende beskriver vi nogle af disse, som er meget nyttigt til at oprette programvisninger, men husk at KDE-bibliotekerne sommetider indeholder andre kontroller med samme formål. Disse diskuteres i næste afsnit.

Her er nogle vink om hvilken Qt-komponent der kan bruges til hvilket slutmål:

1. Hvis visningsområdet ikke er stort nok til at vise alle data, skal brugeren kunne panorere i dokumentet med lister til venstre og længst nede i visningen. QT sørger for klassen QScrollView for dette, som tilbyder et underliggende område med panoreringsmulighed. Som tidligere forklaret, kan du lade dine egne grafiske kontroller arve QScrollView, eller bruge en instans for at håndtere dit dokuments visningskomponent.

2. For at oprette en egen ScrollView, lad komponenten View arve fra QWidget og tilføj lodrette og vandrette rullebjælker med QScrollBars. (Dette udføres af KDE's kontrol KHTMLView.)

3. Til tekstbehandling, bruges QTextEdit. Denne klasse sørger for en fuldstændig grafisk teksteditorkontrol, som allerede kan klippe, kopiere og indsætte tekst og håndteres af en visning med rullebjælker.

4. Brug QTable til at vise data som er arrangeret i en tabel. Eftersom QTable også håndteres af rullebjælker, tilbyder den en god løsning for programmer med tabelberegninger.

5. For at vise to forskellige grafiske kontroller eller to instanser af samme kontrol samtidigt, bruges QSplitter. Den tillader at visninger lægges side ved side med vandrette eller lodrette opdelere. Kmail er et godt eksempel på hvordan det ser ud. Hovedvinduet er opdelt lodret af en opdeler, og det højre vindue er igen opdelt vandret.

6. QListView viser information i en liste og et træ. Det er nyttigt til at oprette filtræer eller en hvilken som helst anden hierarkisk information som du vil håndtere.

Du mærker at kun QT tilbyder et helt sæt grafiske kontroller som er klare til brug, så du ikke behøver opfinde nye løsninger hvis de passer til dine behov. Sideeffekten når standardkontroller bruges er at brugere allerede ved hvordan de håndteres, og kun behøver koncentrere sig om de data som vises.

#### Visninger i KDE

KDE-bibliotekerne blev opfundet for at gøre det nemmere at designe programmer for K-skrivebordsmiljøet og gøre det muligt for dem at have flere funktioner end kun hvad QT tilbyder. Biblioteket kdeui tilbyder:

1. KListView: en mere kraftfuld version af QListView

2. KIconView: en grafisk viser af ikonfiler

Biblioteket khtml sørger på den anden side en fuldstændig HTML-tolkningskomponent, som er klar til brug. Den har allerede rullebjælker, så du behøver ikke engang at håndtere det. En mulig brug kan være at integrere den som en forhåndsvisningskontrol for en HTML-editor. Den bruges af programmer såsom Konqueror til at vise HTML-filer.

### Lav egne visninger

Ikke skrevet endnu

## Indstil menulinjer og værktøjslinjer

### Indledning

Menulinjer og værktøjslinjer er nogen af de vigtigste dele af et program til at sørge for metoder at arbejde med en dokumentstruktur. Du bør gøre alle funktioner tilgængelige via menulinjen, som en almen regel. Disse metoder som ikke er tilgængelige på et vist tidspunkt i brugen af programmet bør være deaktiverede.

Desuden kan et program kun indeholde en menulinje, men flere værktøjslinjer. Værktøjslinjer, på den anden side, bør kun indeholde de oftest brugte kommandoer med ikoner eller sørge for metoder til hurtig adgang som kombinationsbokse til at vælge værdier.

### Hvordan virker det?

Vort program arver klassen KMainWindow som automatisk håndterer at oprette en menulinje og værktøjslinjer for os. I metoden KScribble::setupActions() er der et kald til KMainWindow::createGUI(). Denne metode indlæser en ressourcefil, i dette tilfælde kscribbleui.rc, for at initiere menuerne ved start. Bemærk at kscribbleui.rc er på listen som en af projektfilerne i Håndtering af automake. Åbnes filen ses dette:

    1 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
    2 <kpartgui name="kscribble" version="1">
    3 <MenuBar>
    4   <Menu name="custom"
    ><text
    >C&ustom</text>
    5     <Action name="custom_action" />
    6   </Menu>
    7 </MenuBar>
    8 </kpartgui
    >

Forklaring ...

En anden måde at ændre indholdet i menuen og værktøjslinjerne er at manipulere dem direkte via metoderne som der sørges for i deres klasser. Metoden menuBar() returnerer for eksempel kontrollen KMenuBar som er menulinjen i vort program. Kigger du i dokumentationen for KMenuBar og klassen den arver QMenuBar, finder du et stort antal metoder der hedder insertItem(), som lader dig tilføje punkter til menulinjen.

KMainWindows metoder statusBar() og toolBar() giver dig også passende grafiske kontroller.

### Indstilling af genvejstaster

Noget meget professionelt som du altid bør tilføje i programmet er genvejstaster. De bruges oftest af erfarne brugere som vil arbejde hurtigt med deres programmer og er villige til at lære sig genveje. KDE-bibliotekerne tilbyder klassen KAction til dette, som sørger for genvejstaster og adgang til globalt indstillede standardgenveje.

Normalt bruger kun rammeprogrammer oprettet af &kdevelop; almindelige genvejstaster såsom F1 for at komme til nethjælp, Ctrl+N for Ny fil, osv.

Hvis programmet indeholder mange genvejstaster bør du gøre dem indstillelige via en indstillingsmenu. Enten kan det kombineres med anden programindstilling i en QWidget eller være alene. KDE-biblioteket sørger allerede for en KKeyChooser til at bruge i fanebladsdialoger, mens KKeyDialog sørger for en indstillingsdialog for genvejstaster som er parat til brug.

## Hjælpefunktioner

### Indledning

En meget vigtig del af udviklingsprocessen er at sørge for hjælpefunktioner for brugeren om muligt. De fleste udviklere tenderer at forsinke dette, men du bør huske at en normal bruger ikke nødvendigvis er en Unix-ekspert. Han kommer måske fra den mørke side af programmelbrug som tilbyder alle gode ting som en bruger kan behøve for at indarbejde sig i brugen af et program uden nogensinde at røre ved en håndbog. Derfor sørger KDE- og QT-bibliotekerne for alle muligheder som oftest anses at gøre et program professionelt i den almindelige brugers øjne, med hjælpefunktioner som er klare til brug. Inde i programmet er de:

- Værktøjsvink

- Hjælp i statuslinjen

- Hvad er dette...? knapper

Desuden bør programmet sørge for en mulighed for at komme til en HTML-baseret håndbog direkte med den almindelige hjælpetast F1. Dette sammenhængsafhængige hjælpesystem sørges der automatisk for via klassen KMainWindow, også selvom du som forfatter skal sørge for indholdet.

Eftersom &kdevelop; også tilbyder alle slags hjælp, ligesom KDE-rammeomgivelserne som laves af programguiden allerede indeholder støtte for dette, hjælper dette kapitel dig med at lære dig hvor og hvordan du kan tilføje hjælpefunktioner.

Under udviklingen af programmet bør du forsøge at være konsekvent i hvad du gør. Derfor bør du udføre nødvendige skridt direkte når du udvider koden. Det forhindrer at du behøver at dykke ned i koden igen for at finde ud af hvad programmet gør eller hvad du havde til hensigt med visse dele af koden.

### Værktøjsvink

En meget nem måde at sørge for hjælp er værktøjsvink. De er små hjælpemeddelelser som dukker op når brugeren flytter musen hen over en kontrol som sørger for et værktøjsvink, og forsvinder når musen flyttes. Den populæreste brug af værktøjsvink er i værktøjslinjer hvor værktøjsvinkene bør være så små som muligt, eftersom værktøjslinjer kan indstilles til at vise indholdet på forskellige måder: enten vises knappen, knappen med tekst til højre, knappen med tekst nedenfor, eller kun tekst. Denne indstilling bør kunne indstilles af brugeren, men det er ikke helt nødvendigt. Teksten vises alligevel som et værktøjstips, og en værktøjslinje består oftest af knapper og andre grafiske kontroller såsom redigeringsfelter og kombinationsbokse. For en fuldstændig beskrivelse, se klassereferencen for KToolBar, som findes i kdeui-biblioteket.

Som et eksempel kigger vi på knappen "Ny fil" i et generelt program:

Der sørger parten i18n("New File") for meddelelsen i værktøjsvinket. Det omgives af makroen i18n(), som som sørges for af kapp.h, for at oversætte værktøjsvinket til sproget som for øjeblikket er valgt.

Værktøjsvink kan også tilføjes i hvilken som helst egen grafisk kontrol ved at bruge QToolTip som QT sørger for. Et eksempel på det ville kunne være:

### Udvidelse af statuslinjen

Eftersom programmer som arver KMainWindow også indeholder en statuslinje, tilbyder den også et sæt færdige statuslinjemeddelelser for alle menu- og værktøjslinjesobjekter. En hjælpemeddelelse i statuslinjen er en kort meddelelse som udvider betydningen af et værktøjsvink, eller kan ses som en erstatning for et værktøjsvink for et punkt i menulinjen, og vises (som navnet angiver) i statuslinjen når brugeren aktiverer en menu og markerer et menupunkt.

### Knappen Hvad er dette?

Knappen Hvad er dette...? sørger for hjælpevinduer med formålet at give brugeren hjælp med en vis kontrol i visningen som bruges eller et objekt i en værktøjslinje. Den er i værktøjslinjen og aktiveres når brugeren trykker på knappen. Markøren ændres til en pilemarkør med et spørgsmålstegn, præcis som knappen selv ser ud. Derefter kan brugeren klikke på en synlig kontrol og får så et hjælpevindue. Som en øvelse kan du prøve opførslen med knappen Hvad er dette...? inde i &kdevelop;.

For at tilføje "Hvad er dette...?" hjælp til en af dine grafiske kontroller, bruges den statiske metode QWhatsThis::add(QWidget *widget, const QString &text)

## Dokumentation

### Indledning

På grund af at projekter ofte mangler et fuldstændigt sæt brugerdokumentation, indeholder alle projekter i &kdevelop; en håndbog oprettet i forvejen. På den måde opfyldes et andet af KDE's mål: At sørge for tilstrækkeligt med nethjælp for at støtte brugere som ikke er bekendte med programmet. Dette kapitel introducerer derfor hvordan dokumentationsskabelone der sørges for kan udvides, og hvad du skal gøre for at brugeren skal få adgang til den.

### Brugerdokumentation

Projektdokumentationen er i projektmappe/doc/en, eller måske en anden mappe hvis engelsk ikke er dit modersmål. Der er en fil, index.docbook, hvor dokumentationen opbevares. Formatet for at redigere filen forklares på KDE's netside for dokumentation.

### Programdokumentation

En anden vigtig del af dokumentationen er at inkludere en beskrivende hjælp for klassegrænsefladen. Det lader dig og andre programmører bruge dine klasser ved at læse klassedokumentationen i HTML, som kan laves med KDoc. &kdevelop; understøtter fuldstændigt brug af KDoc til at oprette KDE-biblioteksdokumentation en, rammeomgivelserne for dit program er også allerede dokumenteret. For at arbejde sig ind i koden som der sørges for, er det en god starte at læse netdokumentationen. Det følgende beskriver hvad som skal udføres for at få dokumentation af programmeringsgrænsefladen frem, hvordan &kdevelop; hjælper dig med at tilføje den, og hvilke særlige mærker som KDoc sørger for.

## Internationalisering

### Indledning

Internationalisering med i18n er et system som bruges for at tilbyde internationale versioner af et program eller projekt. Det svære ved at skrive programmer er at de kun understøtter sproget som de oprindelig blev lavet med. Dette synliggøres med tekster, menupunkter og lignende. Målet med internationaliseringen er at sørge for programmer og biblioteksfunktioner på brugerens sprog, og på den måde gøre det muligt for brugere som ikke har originalsproget som modersmål at bruge funktionerne som tilbydes og føle sig mere fornøjet og behagelig.

## Medvirkende

... (endnu ikke skrevet)

## Bibliografi

GNU Make Manual

Richard M. Stallman
Roland McGrath

GNU Automake

David MacKenzie
Tom Tromey

GNU Autoconf

David MacKenzie
Ben Elliston

Using the GNU Compiler Collection

Richard M. Stallman

GNU Libtool

Gordon Matzigkeit
Alexandre Oliva
Thomas Tanner
Gary V. Vaughan

GNU Autoconf, Automake, and Libtool

1st edition
October 2000
Gary V. Vaughan
Ben Elliston
Tom Tromey
Ian Lance Taylor
New Riders Publishing ISBN 1578701902

Advanced Programming in the UNIX(R) Environment

1st edition
June 1992
W. Richard Stevens
Addison-Wesley Pub Co ISBN 0201563177

Thinking in C++, Volume 1: Introduction to Standard C++

2nd Edition
April 15, 2000
Bruce Eckel
Prentice Hall ISBN 0139798099

Open Source Development with CVS

2nd Edition
October 12, 2001
Karl Fogel
Moshe Bar
The Coriolis Group ISBN 158880173X

Programming PHP

1st edition
March 2002
Rasmus Lerdorf
Kevin Tatroe
O'Reilly & Associates ISBN 1565926102

Programming Python

2nd Edition
March 2001
Mark Lutz
O'Reilly & Associates ISBN 0596000855

Gui Programming With Python : Using the Qt Toolkit

Bk&Cd-r edition
January 2002
Boudewijn Rempt
Opendocs Llc ISBN 0970033044

Programming Perl

Kamelbogen

3rd Edition
July 2000
Larry Wall
Tom Christiansen
Jon Orwant
O'Reilly & Associates ISBN 0596000278

Learning Perl

Lama-bogen

3rd Edition
July 15, 2001
Randal L. Schwartz
Tom Phoenix
O'Reilly & Associates ISBN 0596001320
&underFDL;