A

Abstract class
Afgeleide klasse
Afronden van getallen
Array
Array declaratie
Array elementen benaderen
Array initialisatie
Array kopiëren
Array Pointers
Array Referentie
ArrayList
ArrayOfArrays

AWT

J


JAR
JavaDoc
JDK
JIT
JRE
JVM


S



Scanner

Split
Static function
Static variable
String
Swing
Switch statement (integer)
Switch statement (String)

B


Bibliotheek


Bool


K


Key bindings
Klasse
Klassendiagram



T


Tab-bladen
Tekenen

Timer
Try catch


C


Casten
Char
CheckBox
Cirkel tekenen
Class
Class diagram
Class voorbeeld 1
Class voorbeeld 2
ComboBox
Commentaar in Java
Compound Assignment Operators
Conditional operator (?:)
Confirmationbox
Console applicatie
Constant
Constructor VB1
Constructor VB2
Coordinate system

L




Lijn tekenen
ListBox


U


UML diagram





D


Declaratie van variabelen
Default constructor
Dialoogvenster
Do while loop
doClick
Documentatie
Double

drawArc( x, y, width, height, startAngle, arcAngle)
drawLine(x1, y1, x2, y2)
drawOval(x, y, width, height)
drawPolygon( int[] xPoints, int[] yPoints, nPoints)
drawPolygon(poly)
drawPolyline(int[] xPoints, int[] yPoints, nPoints)
drawRect(x, y, width, height)
drawString(String s, x, y)







M


main ( )
Messagebox
Methoden in Java
Minimum en maximum waarde van primitieve typen
MouseClicked event
MouseMoved event

V


Variabelen in Java





E


Erfenis


Event
Event listeners
Exceptionhandling
Extends

N



Netbeans IDE




W



While loop

Wrapper Class


F



File I/O
Float
For loop

O


Object
Object georiënteerd programmeren in Java

Opstartproces
Overladen (overloaden)


X








G



Globale variabelen
Graphics
Graphics-objects
GUI-toepassing met Netbeans


P


PaintComponent
Picture

Polyline tekenen
Printf en println


Y








H



Herhalingslussen
Herhalingslussen ontsnappen
HTML


Q








Z








I


If statement
Initialisatie van variabelen
Inputbox
Int
Integer
Interface
Is-A relatie

R


Radiobutton
Random getallen
Rechthoek tekenen











JAVA met Netbeans (Zie Deitel Hst 1 + 2)


Netbeans is een Integrated Development Environment (IDE) waarmee o.a. Java projecten kunnen worden opgezet (maar ook: JavaScript, PHP, Python, Groovy, C, C++, Scala, Clojure).

Er zijn verschillende versies van Java zoals:

JVM, JRE, JDK, bytecode en JIT

De kern van het Java platform wordt gevormd door het concept van de 'Java Virtual Machine' (JVM). Deze voert de Java bytecode uit.
De Java bytecode van een bepaald programma is altijd gelijk, onafhankelijk van de hardware of gebruikte besturingssysteem.
In de JVM zit een Just In Time compiler (JIT) die de Java bytecode vertaald naar machine afhankelijke code.
Dit zorgt er voor dat het opstarten van Java programma's iets trager verloopt, de code wordt eerst omgezet, maar als het programma eenmaal loopt, dan werkt het net zo snel als programma's die rechtstreeks naar machine code zijn omgezet.

Let wel: de Java programma's zijn platform onafhankelijk (write once, run anywhere), maar de Java Virtual Machines die deze programma's in feite uitvoeren (omzetten naar machinecode) zijn dat NIET. Elke ondersteunde platform heeft dus zijn eigen JVM.

Bij Java hoort een Java Virtual Machine (JVM) en een Java Runtime Environment (JRE).
Als men alleen Java programma's wilt draaien en niet zelf ontwikkelen dan kan men volstaan met het installeren van de JRE; als men echter ook zelf programma's wil schrijven dan is de JDK (Java Developter Kit) of Netbeans noodzakelijk.

Declaratie van variabelen in Java.

In Matlab was het niet nodig om variabelen te declareren, d.w.z. extra informatie te geven over het type en grootte van de variabelen. In de meeste programmeertalen en dus ook in Java is dat echter wel noodzakelijk.

Door het type van een variabele te declareren geeft de programmeur aan hoeveel geheugenruimte (RAM) gereserveerd moet worden voor die variabele.
In Java  kent men infeite oneindig veel typen variabelen, deze zijn in te delen in fundamentele (primitieve) en afgeleide typen.
Voorbeelden van fundamentele variabelen zijn:
 
  • byte,
  • signed,
  • unsigned
  • short,
  • int,
  • long
  • float,
  • double
  • char,
  • Strings
  • bool

Enkele Primitive Data Types
Keyword Description Size/Format
(integers)
byte Byte-length integer 8-bit two's complement
short Short integer 16-bit two's complement
int Integer 32-bit two's complement
long Long integer 64-bit two's complement
(real numbers)
float Single-precision floating point 32-bit IEEE 754
double Double-precision floating point 64-bit IEEE 754
(other types)
char A single character 16-bit Unicode character
bool A boolean value (true or false) true or false
String
Let op met hoofdletter S is een object van
aan elkaar 'geregen' karakters
"Dit is een String"

Als een variabele niet zal wijzigen in een programma (constant zal blijven) dan geeft men dit aan m.b.v. het keyword final.
Bijvoorbeeld:
final int HOURS_DAY = 24;
final double PI = 3.14;

Hierbij is afgesproken dat constanten met hoofdletters worden aangegeven zodat ze gemakkelijker te herkennen zijn.

Initialisatie van variabelen in Java.

Na declaratie volgt initialisatie.
Met declaratie geeft men aan hoeveel geheugenruimte gereserveerd moet worden voor een variabele, met initialisatie kent men een waarde toe aan een variabele.
Bijvoorbeeld:

Eerst deckaratie en daarna initialisatie
Declaratie én initialisatie samen
int intA;
intA = 4;
int intA = 4;

Gebruik van methoden (= functies = subroutines = procedures) in Java.

Net als in Matlab wordt ook in Java veelvuldig gebruik gemaakt van functies om de programma's overzichtelijk en efficiënt te houden ..... er zijn echter enkele verschillen:

Gebruik van commentaar in Java.

Net als in Matlab is het mogelijk (en NOODZAKELIJK) om in uw programma's ook commentaar te plaatsen.
In Java kan dat op twee manieren:

Afspraken over naamgeving van variabelen, methoden en klassen in Java.

De namen van variabelen
De namen van methoden
De namen van klassen


Een eerste Console-toepassing met Netbeans (zie Deitel § 2.5)

Console applicatie = dos window

In principe kan elk Java programma in een ASCII-editor zoals bijvoorbeeld 'kladblok' (notepad) worden geschreven. Nadeel is echter dat men totaal geen 'hulp' krijgt en alle commando's dus uit het hoofd moet kennen.
Om het leven wat eenvoudiger te maken zijn speciale IDE's ontwikkeld (Integrated Developers Environment). Bekende Java IDE's zijn Netbeans en Eclipse.

Java programma's zijn grof weg in twee categorieën in te delen:
Elk Java programma moet de methode main bevatten; dit is de eerste methode die aangeroepen wordt als de applicatie start.
als voorbeeld wordt nu een programma geschreven dat vraagt om de invoer van twee integers. Deze worden bijelkaar opgeteld en het resultaat wordt in de console afgedrukt.
Start een nieuw project


Kies de default 'Java Application'


Geef de applicatie een logische naam en zorg ervoor dat de optie 'Create Main Class ' aangevinkt is




De IDE heeft een stukje code voor u klaargemaakt!
Tevens is duidelijk waar u uw code moet aanbrengen.



Om data vanaf het toetsenbord in te lezen kan men gebruik maken van het commando 'scanner' ..... echter .... dit geeft een fout!


Hier komt de IDE ons te hulp: Linksklik met de muis op het rode uitroepteken en kies



Scanner is een commando dat niet tot de standaard 'uitrusting' van Java behoort. De bibliotheek waarin Scanner gedefinieerd is, moet afzonderlijk worden ingeladen via een 'import' commando.


Het complete programma komt er alsvolgt uit te zien:


public class Som1 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // create a Scanner to obtain input from the command window
        Scanner input = new Scanner( System.in );
        int number1;    // first number to add
        int number2;    // second number to add
        int sum;        // sum of number1 and number2
       
       
        System.out.print( "Enter first integer: " );    // prompt
        number1 = input.nextInt();                      // read first number from user

        System.out.print( "Enter second integer: " );   // prompt
        number2 = input.nextInt();                      // read second number from user

        sum = number1 + number2;                        // add numbers, then store total in sum

        System.out.printf( "Sum is %d\n", sum );        // display sum       
    }// end method main
}// end class Som1

Compileer dit programma ......
en draai hem


Men kan ook de shortcuts gebruiken:




Printf en println

Om uitvoer naar het scherm te schrijven maakt men vaak gebruik van de commando's printf en println.
Printf staat voor geformateerde uitvoer
Println staat voor afdrukken per regel (met return).

printf integer formatting

As a summary of printf integer formatting, here’s a little collection of integer formatting examples. Several different options are shown, including a minimum width specification, left-justified, zero-filled, and also a plus sign for positive numbers.

Description

Code

Result

At least five wide

printf("'%5d'", 10);

'   10'

At least five-wide, left-justified

printf("'%-5d'", 10);

'10   '

At least five-wide, zero-filled

printf("'%05d'", 10);

'00010'

At least five-wide, with a plus sign

printf("'%+5d'", 10);

'  +10'

Five-wide, plus sign, left-justified

printf("'%-+5d'", 10);

'+10  '

printf - floating point numbers

Here are several examples showing how to format floating-point numbers with printf:

Description

Code

Result

Print one position after the decimal

printf("'%.1f'", 10.3456);

'10.3'

Two positions after the decimal

printf("'%.2f'", 10.3456);

'10.35'

Eight-wide, two positions after the decimal

printf("'%8.2f'", 10.3456);

'   10.35'

Eight-wide, four positions after the decimal

printf("'%8.4f'", 10.3456);

' 10.3456'

Eight-wide, two positions after the decimal, zero-filled

printf("'%08.2f'", 10.3456);

'00010.35'

Eight-wide, two positions after the decimal, left-justified

printf("'%-8.2f'", 10.3456);

'10.35   '

Printing a much larger number with that same format

printf("'%-8.2f'", 101234567.3456);

'101234567.35'

printf string formatting

Here are several examples that show how to format string output with printf:

Description

Code

Result

A simple string

printf("'%s'", "Hello");

'Hello'

A string with a minimum length

printf("'%10s'", "Hello");

'     Hello'

Minimum length, left-justified

printf("'%-10s'", "Hello");

'Hello     '

Summary of special printf characters

The following character sequences have a special meaning when used as printf format specifiers:

\a

audible alert

\b

backspace

\f

form feed

\n

newline, or linefeed

\r

carriage return

\t

tab

\v

vertical tab

\\

backslash

As you can see from that last example, because the backslash character itself is treated specially, you have to print two backslash characters in a row to get one backslash character to appear in your output.

Here are a few examples of how to use these special characters:

Description

Code

Result

Insert a tab character in a string

printf("Hello\tworld");

Hello world

Insert a newline character in a string

printf("Hello\nworld");

Hello
world

Typical use of the newline character

printf("Hello world\n");

Hello world

A DOS/Windows path with backslash characters

printf("C:\\Windows\\System32\\");

C:\Windows\System32\






Voorbeeld van een programma dat de maximale waarden van de verschillende standaard datatypen afdrukt (primitieve variabeletypen).

    public static void main(String[] args)
    {
        // integers
        byte largestByte   = Byte.MAX_VALUE;
        short largestShort = Short.MAX_VALUE;
        int largestInteger = Integer.MAX_VALUE;
        long largestLong   = Long.MAX_VALUE;

        // real numbers
        float largestFloat   = Float.MAX_VALUE;
        double largestDouble = Double.MAX_VALUE;

        // other primitive types
        char aChar = 'S';
        boolean aBoolean = true;

        // display them all
        System.out.println("\nThe largest byte value is "    + largestByte);
        System.out.println("The largest short value is "   + largestShort);
        System.out.println("The largest integer value is " + largestInteger);
        System.out.println("The largest long value is "    + largestLong);

        System.out.println("The largest float value is "  + largestFloat);
        System.out.println("The largest double value is " + largestDouble);

        if (Character.isUpperCase(aChar))
        {
            System.out.println("The character " + aChar + " is upper case.");
        }
        else
        {
            System.out.println("The character " + aChar + " is lower case.");
        }
        System.out.println("The value of aBoolean is " + aBoolean);
    }





De parameters van main.

Zoals eerder vermeld moet elke Java programma de methode 'main ( )' bevatten.  Deze methode kan gebruikt worden om 'invoer' aan het programma te geven.
Bij het invoeren van een commando op de command prompt, kunnen parameters worden meegegeven. Deze parameters worden in een String array met de naam args opgeslagen.
Zie onderstaand voorbeeld.

public class ArgumentSom {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        int i, som;
        som = 0;
        // Controleer of het aantal parameters > 1 is
        if (args.length > 1)
        {
            for(i=0; i < args.length; i++ )
            {
                som = som + Integer.parseInt(args[i]);
            }
            System.out.println("\n\n");
            System.out.println("Er zijn " + args.length + " argumenten ingevoerd. \n");
            System.out.println("De Som van deze argumenten is: " + som);
        }
        else
        {
            System.out.println("\n\n");
            System.out.println("Start het programma met minstens 2 argumenten! ");        
        }
    }// end method main
}// end class ArgumentSom

 

Programma in een dos-window opstarten met het commando (zorg wel dat je in de juiste directory staat):

java -jar "ArgumentSom.jar"  a b c
 
Waarbij a b en c de getallen zijn die bij elkaar opgeteld moeten worden.





Opgaven

Schrijf een console applicatie die de maximum én minimum waarden van de verschillende datatypen (zoals byte, short, integer, double..... etc)afdrukt




Een eerste GUI-toepassing

AWT en SWING

Java bevat twee verschillende klassenbibliotheken waarmee een grafische gebruikersinterface kan worden opgebouwd: AWT en SWING.

Event = gebeurtenis

In vrijwel elk Windows programma kan de gebruiker m.b.v. de muis actie ondernemen. Denk hierbij bijvoorbeeld aan het klikken op een startknop, of het verslepen van het venster.
Men  zegt dat er zich een gebeurtenis (event) voordoet. Gebeurtenissen worden opgevangen (geregistreerd) door bijzondere objecten die men in Java luisteraars (listeners) noemt.
Een luisteraar bepaalt het effect van een gebeurtenis.

Een groot gedeelte van de toepassing hoef je niet echt zelf te programmeren dit is de kracht van een bibliotheek zoals Swing en één van de belangrijke verschillen tussen het programmeren van een GUI-toepassing en de ontwikkeling van een traditioneel programma.
Zo kan je in je programma een kant-en-klare comboboxcomponent uit de bibliotheek gebruiken waarin je enkel nog de lijst van mogelijke keuzes moet ‘invullen’.
Je hoeft je dus gelukkig niet druk te maken over het achterliggende programmeerwerk dat de combobox op de juiste manier ‘naar beneden laat vallen’, of dat de juiste tekstletters op het scherm tekent, op de juiste plaats en in de juiste kleuren.

Hieronder volgt een heel eenvoudig voorbeeld van een GUI: een leeg venster.

Souce code van het bestand SwingEx1.java

Resultaat
import javax.swing.JFrame;
public class SwingEx1
{
    public static void main (String[] args)
    {
        JFrame window = new JFrame ("SwingEx1: Leeg venster");
        window.setSize (300, 200);
        window.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        window.setVisible (true);
    }
}
Deze code kan men met bijvoorbeeld Notepad intypen.
Let wel: elke commandoregel wordt afgesloten met een puntcomma (;).
 
Vervolgens wordt de code gecompileerd in een command window met het commando:
javac SwingEx1.java
(javac moet wel in het 'path' staan)

Dit levert het bestand SwingEx1.class op (de bytecode).
De applicatie wordt tenslotte opgestart met het commando:
java SwingEx1



Het mooie hiervan is, dat wij nergens geprogrammeerd hebben dat het venster de drie standaard acties (iconize, beeldvullend of sluiten) moet ondersteunen, maar toch doet hij dat ?



Dit komt doordat onze eenvoudige applicatie heel wat eigenschappen erft van de standaard JFrame die in de javax.swing. JFrame bibliotheek gedefinieerd is.

Een GUI-toepassing maken met behulp van Netbeans.


We gaan een applicatie maken die de temperatuur van graden celsius omzet naar graden fahrenheid met een interface zoals hieronder is weergegeven.



Er is een textbox waarin een waarde voor een temperatuur in celsius kan worden ingevoerd.
Zodra op de Convert  knop geklikt  wordt, wordt de bijbehorende waarde in Fahrenheid uitgerekend en afgedrukt.

Stap 1: start een nieuw project op:


Start een nieuw project op:
Kies voor een standaard Java project en klik ‘next’ om verder te gaan.




Vervolgens moet u een naam voor uw project invoeren en aangeven waar uw project zal worden opgeslagen op uw harde schijf (of op een netwerkschijf).

Let op: deselecteer de optie ‘Create Main Class’.
Deze optie gebruiken we nu niet omdat de GUI die we gaan maken zal dienen als startpunt van onze applicatie.

Klik tenslotte op ‘Finish’




Vervolgens gaan we een JFrame toevoegen. Klik daartoe met de rechtermuisknop op CelciusConverter project en kies ‘New => JFrameForm’.

Dit frame wordt de achtergrond van onze applicatie.
Hier worden later elementen als labels, tekstboxen en drukknoppen op aangebracht.

Het frame element is dus een soort container waar andere objecten op geplaatst kunnen worden.

In een later stadium zullen we ervoor zorgen dat dit frame als eerst getoond wordt als de applicatie wordt opgestart.




Vul een naam in voor dit frame en kies ook een naam voor de ‘Package’.
Bij dit laatste mag elke naam gebruikt worden, het is echter raadzaam een logische naam te kiezen zoals ’Les’.



Als alles goed verloopt, wordt de frame toegevoegd en krijgen we het onderstaand beeld in de IDE


Netbean's IDE

Er zijn een aantal onderdelen van de IDE die zo belangrijk zijn dat zij nu al kort besproken zullen worden.

Het Palet

In het palet bevinden zich alle componenten van de Java Swing bibliotheek. Het is als het ware een gereedschapskist gevuld met alle elementen (knoppen, labels, panelen, enz) waarmee u uw GUI kunt maken.


Het Ontwerpgebied

In het ontwerpgebied (design area) wordt de GUI daadwerkelijk geconstrueerd.
Dit gebied kent twee vormen bron (source view) en ontwerp (design view)


Het eigenschappenvenster

Hierin kunnen op intuïtieve wijze de eigenschappen van de afzonderlijke componenten uit de GUI worden aangepast.


De Inspecteur

Dit venster geeft een grafische weergave van alle componenten in onze GUI en kan o.a. worden gebruikt om de namen van deze elementen te wijzigen.



Stap 2: JFrame vullen:


We gaan eerst de titel van ‘JFrame’ instellen. Klik daartoe op ‘JFrame’ in de inspecteurvenster en vul de gewenste naam in achter het eigenschap ‘title’ in de eigenschappenvenster.



Vervolgens wordt er een tekstveld aan de GUI toegevoegd.
Klik daartoe in het Palet op een ‘Text Field’ element en sleep deze naar het ontwerpvenster (ook wel canvas genoemd).  Zodra men aan de zijkant van het JFrame komt, verschijnen er hulplijnen op het tekstveld te helpen plaatsen.
Verander de naam van de tekstbox in txtInput

Voeg op analoge wijze twee labels en een knop toe aan de GUI.


Verschillende componenten aanpassen.
De titels van de verschillende elementen kunnen veranderd worden door elk element te selecteren in het ontwerpvenster en vervolgens de title te wijzigen in het eigenschappenvenster; men kan ook dubbelklikken op een element in het ontwerpvenster en vervolgens de naam wijzigen.

Om de afmetingen van de knop en tekstveld gelijk te maken, worden beide geselecteerd en vervolgens kan men m.b.v. de rechtermuistoets kiezen voor ‘Same Width en Same Height’ zoals hieronder is aangegeven.

Wijzig tenslotte de grootte van het JFrame door de rechtsonderhoek met de muis op te pikken en te verschuiven totdat onderstaande GUI (ongeveer) ontstaat.






Stap 3: Intelligentie toevoegen:

Het GUI ontwerp is nu in principe af maar let wel: het programma doet nog echter nog niets zinvol! Er is echter al heel wat code geschreven om deze GUI mogelijk te maken.

Open de ‘source view’ van de ontwerp omgeving om de broncode te zien.




Aan een mooie GUI die verder niets doet hebben we natuurlijk niets, dus nu moet de logica (intelligentie) nog aan het programma worden toegevoegd.
Wat moet er gebeuren als de gebruiker op de ‘Convert’ knop klikt??

Zinvolle namen

Het is verstandig (misschien zelfs noodzakelijk voor beheer) om zinvolle namen te kiezen voor de componenten van de GUI. Een tekstveld met als naam jTextField1 zegt bijzonder weinig.
Als eerste stap worden de namen van belangrijke elementen aangepast.

Nietszeggende namen

Rechtsklik op een element en pas de naam aan
Aangepaste namen.




Event listeners

Wanneer een gebruiker klikt op de knop ‘Convert’ dan wordt er een speciaal soort object (an event object) geactiveerd door de knop. Deze gebeurtenis (event) wordt opgepakt door een luisteraar.
(in het Engels: When an end-user interacts with a Swing GUI component, that component will generate a special kind of object — called an event object — which it will then broadcast to any other objects that have previously registered themselves as listeners for that event.)

Het registreren (definiëren) van zo’n ‘event listener’ gebeurt in de Netbeans IDE door met de rechtermuistoets op het bewuste element te klikken.

Geef aan dat een ‘event listener’ moet worden gedefinieerd.

De broncode editor wordt geopend zodat u kunt aangeven welke actie ondernomen moet worden.



Voer de eigen code in

De programmeur kan nu de code invoeren die uitgevoerd moet worden indien een gebruiker op de ‘Convert’ knop klikt. Hierbij geldt in Java hetvolgende:
•    Elke commandoregel moet afgesloten worden met een puntcomma (;)
•    Commentaar kan aangegeven worden door // op één regel of /*      */ over meerdere regels.

private void cmdConvertActionPerformed(java.awt.event.ActionEvent evt)
{
    // Parse degrees Celsius as a double and convert to Fahrenheit.
    Double tempFahr;
    tempFahr = (Double.parseDouble(txtInput.getText())* 1.8 + 32);
    lblFahrenheit.setText(tempFahr + " Fahrenheit");
}

Stopknop

Elke nette windows applicatie heeft een stopknop (exitbutton). Natuurlijk erft een frame altijd standaard het ‘kruisje’ in de rechterbovenhoek van de applicatie, maar het is altijd netter een aparte knop in de GUI op te nemen om de applicatie af te sluiten. De bijbehorende code ziet er als volgt uit:
private void cmdExitActionPerformed(java.awt.event.ActionEvent evt)
{
        // Close the application.
        System.exit(0);    //let op HoofdLetterGevoelig!
}

Stap 4: Compileer de applicatie:

Om de applicatie uit te kunnen voeren (draaien) moet deze eerst gecompileerd worden. In de Netbeans IDE wordt dit gedaan door  ‘Run main project’ te selecteren in het ‘Run’ pulldown menu.

Compileren en linken
.
Kies CelsiusConverterGUI as main class voor dit project.



JAR files

Het is ook mogelijk om met zogenaamde JAR-bestanden te werken. Hierbij worden al de benodigde bestanden van het project samengepakt in één bestand (soort zip-bestand).
Deze JAR besanden worden door NetBeans automatisch aangemaakt bij het compileren van het project. Zij worden in de subdirectory Dist geplaatst (Distribution).

JAR staat voor Java Archive of Java Run

Zo'n JAR bestand kan worden opgestart door in WindowsExplorer naar de subdirectory 'Dist' te gaan en vervolgens om de betreffende file te dubbelklikken of door het intypen van onderstaand commando in een console window:

 java -jar "naam.jar"




Opgaven




Schrijf een applicatie die enkele eenvoudige berekeningen uitvoert en de nevenstaande GUI heeft

Schrijf een applicatie die N! (N faculteit) uitrekent, ontwerp zelf een GUI.





Object georiënteerd programmeren in Java ( zie Deitel Hst. 3)

Objecten en klassen zijn twee fundamentele concepten in object georiënteerde programmeertalen zoals Java.

Lange, ingewikkelde programma's bestaan vaak uit een enorme hoeveelheid functies en variabelen, soms wel honderden. Het kan een haast onmogelijke opgave worden om een dergelijk programma te schrijven en te onderhouden, doordat men op zoveel dingen tegelijk moet letten.
Object georiënteerd programmeren heeft als voornaamste doel de veiligheid te vergroten. Dit wordt  bereikt door ervoor te zorgen dat variabelen niet door alles en iedereen zomaar veranderd kunnen worden.

Door gegevens en de bewerkingen op die gegevens - dat wil zeggen de functies - in een object samen te voegen, zijn deze functies en gegevens veiliger te gebruiken.
Ze worden van andere delen van het programma gescheiden en zo is het geheel beter te overzien (encapsolation).

Java-klassen.

Hoe maken we nu objecten in onze programma's ??
Hiervoor worden de klassen gebruikt. Een klasse is voor een object als een uitsteekvormpje voor een koekje; het is een soort sjabloon of mal voor het object.

Schematische weergave van een klasse.


 

De methods (class-functies) schermen de private variabelen af van de buitenwereld (encapsulation).

Naast de classes vinden we de objecten.
In de class staat de definitie (blueprint) van een fenomeen, een object is één specifiek element opgebouwd volgens die specificatie.

In het kort:

Objectgeoriënteerd programmeren is gebaseerd op de volgende drie principes:


Overpeinzingen bij het programmeren: wat maakt een programma goed?

Er zijn veel factoren die de kwaliteit van een programma beinvloeden. In deze cursus wordt slechts ingegaan op enkele daarvan, voornamelijk de factoren die te maken hebben met het programmeren zelf.
Vanuit dit gezichtspunt zijn enkele aspecten van belang:

Hieruit volgen twee regels die gedurende de cursus vaak gebruikt zullen worden.


Voorbeeld 1 van een Java-klas en object (Deitel §3.2)

Beschouw het volgende voorbeeld van een bankrekening(account in het engels).
We geven deze klas voorlopig slechts 2 kenmerken (eigenschappen):

Een klasse declaratie kan er als volgt uitzien:

public class Account header van de klas
{
    .....
    // gegevens en methoden van de klasse
    .....
}

body van de klas

Constructor.

In elke klasse moet een zogenaamde constructor aanwezig zijn.
Deze methode heeft dezelfde naam als de klasse en wordt automatisch aangeroepen bij creatie van een object.

public class Account
{
    private String name;
    private double balance;

Member of lid variabelen;
deze zijn 'private' of  'protected'

    // default constructor
    public Account()
    {
        name = "onbekend";
        balance = 0.0;        
    }
    
    // overloaded constructor
    public Account(String a, double b)
    {
        name = a;
        balance = b;        
    }
    
    //getters en setters
    
    public String getName()
    {
        return(name);
    }   
    
    public double getBalance()
    {
        return(balance);
    }   
}


De constructor heeft:
  • dezelfde naam als de klasse
  • geen type.





Member of lid methoden deze  zijn altijd Public

Deze methoden zijn altijd van een bepaald type afhankelijk van de type variabele die zij retourneren (of void indien niets geretourneerd wordt).


Afspraak (dus niet verplicht) is om  altijd zogenaamde 'getter' en setter' methoden te schrijven voor elke (private) eigenschap.

Toepassing 1 met class Account.

Een eenvoudige toepassing waarin de Class Account gebruikt wordt.





Voorbeeld van een toepassing met Account.
Gebruik van de default constructor.
 Gebruik van de 'overloaded' constructor.
Nette foutmelding bij verkeerde invoer.


De constructor wordt aangeroepen m.b.v. het keyword NEW.

Hier volgt een voorbeeld programma dat gebruik maakt van onze eenvoudige bankrekening. De 'Make Account' knop is gekoppeld aan de methode cmdMakeActionPerformed.
private void cmdMakeActionPerformed(java.awt.event.ActionEvent evt)
{                                        
   String naam = "";
   startWaarde = 0.0;
   Account MyAccount;
        
   // Get the name and start amount
   naam = txtName.getText();
   startWaarde = Double.parseDouble(txtStartAmount.getText());
       
   if(startWaarde >= 0.0)
   {
      // maak een nieuwe bankrekening aan.
      MyAccount = new Account(naam, startWaarde);
      lblOverview.setText("Bank account " + MyAccount.getName() +
                          " with start value " + MyAccount.getBalance()                              
                         );
      }
      else
      {
         // geef een nette foutmelding
         lblOverview.setText("Given value for start amount is not valid!");
      }    
}    


Toepassing 2 met class Account.

De toepassing waarin de Class Account gebruikt wordt uitgebreid met de mogelijkheid om extra geld te storten danwel van de rekening af te boeken.







New layout
Rekening aangemaakt voor P. Pietersen met een beginkapitaal van 100 (euro)
Extra storting plaatsen
Nieuw banktegoed
Geld opnemen
Banktegoed na voorgaande acties.

Class Account uitgebreid.

Naast de constructor en get/set methoden worden nu nog enkele andere public methoden gedefinierd.
Verder wordt er nu ook gebruik gemaakt van een 'wrapper class' Double.

public class Account
{
    private String name;
    private Double balance;

Member of lid variabelen;
deze zijn 'private' of  'protected'
Let op Double i.p.v. double

    /**
     * Default constructor
     */
    public Account()
    {
        name = "onbekend";
        balance = 0.0;       
    }
   
    /**
     * Overloaded constructor, takes two input parameters.
     *
     * @param a String which will be used as name
     * @param b Double which will be used as balance
     */
    public Account(String a, Double b)
    {
        name = a;
        balance = b;       
    }


De constructor heeft:
  • dezelfde naam als de klasse
  • geen type.














    //getters en setters
    /**
     *
     * @return Naam die gekoppeld is aan dit account [String].
     */
    public String getName()
    {
        return(name);
    }
    /**
     *
     * @param name Naam die gekoppeld moet worden aan dit account [String].
     */
    public void setName(String name)
    {
        this.name = name;
    }
    /**
     *
     * @return Hoogte van het banktegoed [Double]
     */
    public Double getBalance()
    {
        return(balance);
    }
    /**
     *
     * @param balance Hoogte van het banktegoed [Double]
     */
    public void setBalance(Double balance)
    {
        this.balance = balance;
    }
  
    // Other public methods
    /**
     * Deze methode zal een positieve storting bij uw kapitaal optellen.
     * Indien de invoerwaarde negatief is, zal er NIETS gebeuren.
     *
     * @param a Het stortingsbedrag.
     */
    public void makeDeposite( Double a)
    {
        if (a > 0.0)
            balance = balance + a;         
    }
    /**
     * Deze methode zal bij een geldopname lager dan of gelijk aan uw tegoed
     * dit bedrag van uw tegoed aftrekken.
     * Geldopname groter dan uw tegoed wordt niet uitgevoerd.
     *
     * @param a Het op te nemen bedrag.
     */
    public void makeWithdrawal( Double a)
    {
        if (a <= balance)
            balance = balance - a;
    }

    /**
     * Deze methode geeft algemene informatie over deze bankrekening.
     * @return Rekeningoverzicht
     */
    public String showAccountInfo()
    {
        String s;
        s = "Account name is: " + name + " balance is: ";
        s += balance.toString();
        return(s);
    }
}





Member of lid methoden deze zijn altijd Public

Deze methoden zijn altijd van een bepaald type afhankelijk van de type variabele die zij retourneren (of void indien niets geretourneerd wordt).


Afspraak (dus niet verplicht) is om  altijd zogenaamde 'getter' en setter' methoden te schrijven voor elke (private) eigenschap.

Hier volgt een voorbeeld programma dat gebruik maakt van onze vernieuwde bankrekening.

De 'Make Account' knop is gekoppeld aan de methode cmdMakeActionPerformed.
De 'Deposit' knop is gekoppeld aan de methode cmdDepositActionPerformed.
De 'Withdrawal' knop is gekoppeld aan de methode cmdWithdrawalActionPerformed.
De 'Show' knop is gekoppeld aan de methode cmdShowActionPerformed.

public class FrmAccount2 extends javax.swing.JFrame
{
    // Globale variabele die bekend is in alle subroutines (methoden)
    Account MyAccount;

   
    /**
     * Creates new form FrmAccount1
     */
    public FrmAccount2() {
        initComponents();
    }
                    

    private void cmdMakeActionPerformed(java.awt.event.ActionEvent evt) {                                       
        /*
         * Maak een object aan van het type Account waarbij de default
         * constructor wordt aangeroepen en gebruik vervolgens de setters om
         * naam en startwaarde in te voeren.
         *
         * Pas echter op:
         * gebruik 'Double' i.p.v. 'double' (Wrapper class);
         * gebruik een 'global' variabele MyAccount.
         *
         */
        Double startWaarde;
       
        MyAccount = new Account();              // default constructor used!  
        MyAccount.setName(txtName.getText());   // set the name
       
        startWaarde = Double.parseDouble(txtStartAmount.getText());
        if(startWaarde >= 0.0)
        {
            MyAccount.setBalance(startWaarde);
        }      
    }                                      

    private void cmdDepositActionPerformed(java.awt.event.ActionEvent evt) {                                           
        // use a inputbox to ask the user for a deposite value
        String text = JOptionPane.showInputDialog((Component) evt.getSource(),
                                       "How much would you like to deposit?");
         if (text != null && !text.equals(""))
         {
             Double deposit = Double.parseDouble(text);
             if (deposit > 0.0)
                 MyAccount.makeDeposite(deposit);
             else
                 JOptionPane.showMessageDialog((Component) evt.getSource(),
                                           "Enter an amount > 0.0 please");
         }
    }                                         

    private void cmdWithdrawalActionPerformed(java.awt.event.ActionEvent evt) {                                             
        Double maximum;
        maximum = MyAccount.getBalance();
       
        // Use an inputbox to ask the user for a withdrawal value
        String text = JOptionPane.showInputDialog((Component) evt.getSource(),
                                       "How much would you like to withdrawal" +
                                       " <max = " + maximum + ">?", "Withdrawal",
                                       QUESTION_MESSAGE);
         if (text != null && !text.equals(""))
         {
             Double withdrawal = Double.parseDouble(text);
             if ( (withdrawal < maximum) && (withdrawal > 0.0))
                 MyAccount.makeWithdrawal(withdrawal);
             else
                 JOptionPane.showMessageDialog((Component) evt.getSource(),
                                           "Enter an amount < " + maximum +
                                           " but > 0.0 please");
         }
    }                                            

    private void cmdShowActionPerformed(java.awt.event.ActionEvent evt) {                                       
        // Use a messagebox to give an overview
        JOptionPane.showMessageDialog((Component) evt.getSource(),
                                     MyAccount.showAccountInfo() ,
                                     "Overview", INFORMATION_MESSAGE);
    }                                      

    private void cmdExitActionPerformed(java.awt.event.ActionEvent evt) {                                       
        System.exit(0);
    }
}  


Het zou wellicht handiger zijn als we na elke bewerking een rekeningoverzicht zouden krijgen!!
En ToString overloaden i.p.v. showAccountInfo.


Voorbeeld 2 van een Java-klas en object.

Beschouw het volgende voorbeeld van een massieve staaf (bar in het Engels).

Een staaf geven we (voorlopig) een tweetal kenmerken (eigenschappen) zoals:

Bij zo'n staaf horen ook enkele acties zoals: Een klasse declaratie kan er als volgt uitzien:
class Bar header van de klas
{
    .....
    // gegevens en methoden van de klasse
    .....
}

body van de klas

Constructor.

In elke klasse moet een zogenaamde constructor aanwezig zijn. Deze methode heeft dezelfde naam als de klasse en wordt automatisch aangeroepen bij creatie van een object.

 

import static java.lang.Math.*;
class Bar
{
   private Double straal; //straal van de staaf
   private Double hoogte; //hoogte van de staaf

Member of lid variabelen;
deze zijn 'private' of  'protected'


   public Bar ()
   {
      straal = 1.0; //straal van de staaf
      hoogte = 1.0; //hoogte van de staaf
   }
   // overloaded constructor
   public Bar (Double r, Double h)
   {
      straal = r; //straal van de staaf
      hoogte = h; //hoogte van de staaf
   }

   // getters en setters
   public Double getStraal()
   {
       return(straal);
   }
   public void setStraal(Double s)
   {
       straal = s;
   }
  
   public Double getHoogte()
   {
       return(hoogte);
   }
   public void setHoogte(Double h)
   {
       hoogte = h;
   }
  
   // Other public methods
   public Double berekenVolume()
   {
     Double volume;
     volume = PI * pow(straal,2.0)* hoogte;
     return (volume);
   }

}



De constructor heeft:
  • dezelfde naam als de klasse
  • geen type.

Indien de constructor zonder argumenten wordt aangeroepen zullen de straal en de hoogte op 1 worden geïnitialiseerd. Indien de constructor met 2 argumenten wordt aangeroepen worden de straal en hoogte op de gegeven waarde gesteld.



Member of lid methoden

Public

 

De Destructor.

Zoals uitgelegd, wordt de constructor automatisch uitgevoerd wanneer een object wordt gedefinieerd. Op dezelfde wijze wordt een destructor, als deze bestaat, automatisch uitgevoerd wanneer een object wordt vernietigd.
De naam van de destructor is altijd finalize( ).

Deze functie wordt in de praktijk echter nooit gebruikt, omdat Java zeer goed in staat is het geheugen zelf weer vrij te maken.

Een eenvoudige toepassing van de klasse Bar.
De constructor wordt aangeroepen m.b.v. het keyword NEW.
Hier volgt een voorbeeld programma dat gebruik maakt van onze eenvoudige staaf.



private void cmdStartActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // TODO add your handling code here:
        Bar myBar;
        Double radius, hoogte;
        Double volume;
        
        radius = Double.parseDouble(txtRadius.getText());
        hoogte = Double.parseDouble(txtHoogte.getText());
        myBar = new Bar(radius, hoogte);
       
        volume = myBar.berekenVolume();
        // afronden
        DecimalFormat tweedecimalen = new DecimalFormat("#.##");
        tweedecimalen.setRoundingMode(RoundingMode.HALF_UP);
        txtVolume.setText(tweedecimalen.format(volume));      
    }                                       

    private void cmdEndActionPerformed(java.awt.event.ActionEvent evt) {                                      
        // TODO add your handling code here:
        System.exit(0);
    }   


Voorbeeld van het afronden van getallen in Java.

<>Afgeleide klassen ofwel erfenis (zie Deitel Hst. 9)

Het is natuurlijk zeer handig als je programma's schrijft (code genereert) die meer dan eens gebruikt kan worden (re-usable code).
Java (en andere object georiënteerde talen) biedt de mogelijkheid om bestaande klassen uit te breiden via het mechanisme van class-inheritance.

Hierbij denkt men aan:

De syntaxis van een afgeleide klasse is als volgt:

class naam2 extends naam1
{
   ....
   // nieuwe lidgegevens en lidfuncties
  ....

}

Waarbij:

Voor de afgeleide class moeten nieuwe constructors worden gedefinieerd, ook al erft hij alle constructoren van de base class, dit omdat een constructor per definitie dezelfde naam heeft als de class.
Stel we willen de bestaande klasse Bar uitbreiden met de volgende  eigenschappen en methoden:

Veronderstel verder, dat u niet beschikt over de oorspronkelijke Java-code.  Slechts de gecompileerde class-file is in uw bezit (zoals zo vaak met bibliotheken het geval is).

class ExtendedBar extends Bar
{
   private double rho;

   public double berekenMassa()
   {
     
   }
}


Waarom zal dit echter niet werken ???

Een afgeleide klasse heeft geen toegang tot de private lidgegevens van de basisklasse.
Een oplossing voor dit probleem zou kunnen zijn om ook de lidgegevens allen als public te definiëren. Dit is echter instrijd met het concept van beveiliging.
=> maak gebruik van protected elementen.

Protected leden (kenmerken of methoden) van een klasse zijn toegankelijk voor afgeleide klassen.

De listing van de klasse Bar wordt als volgt aangepast:
 
 
class Bar
{
   protected double straal; //straal van de staaf 
   protected double hoogte; //hoogte van de staaf
Member of lid variabelen

Protected, zodat ze ook voor afgeleide klassen toegankelijk zijn.


   public Bar ()
   {
      straal = 1; //default staafstraal
      hoogte = 1; //default staafhoogte
   }

   public Bar (double r, double h)
   {
      straal = r; //straal van de staaf
      hoogte = h; //hoogte van de staaf
   }

   public double berekenVolume()
   {
     return 3.1415 * straal * straal * hoogte;
   }

   public void toonGegevens()
   {
      System.out.println("\nDe straal is: " + straal);
      System.out.println("\nDe hoogte is: " + hoogte);
   }
}

De constructor heeft:
  • dezelfde naam als de klasse
  • geen type.
Indien de constructor zonder argumenten wordt aangeroepen zullen de straal en de hoogte op 1 worden geïnitialiseerd.

Indien de constructor met 2 argumenten wordt aangeroepen worden de straal en hoogte op de gegeven waarde gesteld.
 

 

De definitie van de 'ExtendedBar' komt er als volgt uit te zien:

public class ExtendedBar extends Bar
{
    private Double rho;

Eerst worden de extra Member of lid variabelen gedeclareerd indien aanwezig.
    
    // Constructors
    public ExtendedBar()
    {
        super();
        rho = 1.0;
    }
    public ExtendedBar(Double r,Double h, Double s)
    {
        super(r,h);
        rho = s;
    }
    
    //public methods
    public Double berekenBuitenOpp()
    {
      Double cilinderOpp, eindvlakOpp, buitenOpp;
      cilinderOpp = 2.0 * 3.1415 * straal * hoogte;
      eindvlakOpp = 3.1415 * straal * straal;
      buitenOpp = cilinderOpp + 2.0 * eindvlakOpp;
      return (buitenOpp);
    }
    
    public Double berekenMassa()
    {
        // bereken eerst de volume van deze staaf
        Double volume = this.berekenVolume();
        Double massa = volume * rho;
        return (massa);
    }
}

Dan volgen de constructoren.
M.b.v. het keyword super kunnen argumenten van de afgeleide klasse door worden gegeven aan de basis (super) klasse








Verder kunnen hier natuurlijk extra methoden worden gedefinieerd .......
.
.
.
extra methode toegevoegd
.
.
.
.
.
extra methode toegevoegd.
.
.
.

Met het volgend programma worden de 'Nieuwe staaf' getest.

    private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
    {                                        
        Double radius = Double.parseDouble(txtRadius.getText());
        Double hoogte = Double.parseDouble(txtHoogte.getText());
        Double rho    = Double.parseDouble(txtRho.getText());
        
        System.out.println("radius is " + radius);
        System.out.println("hoogte is " + hoogte);
        System.out.println("rho is " + rho);
        
        // maak een object aan van het type ExtendedBar
        ExtendedBar mijnStaaf = new ExtendedBar(radius, hoogte, rho);
        
        // toon enkele eigenschappen van mijnStaaf afgerond op twee decimalen
        NumberFormat Dec2 = new DecimalFormat("#0.00");
        
        txtOpp.setText(mijnStaaf.berekenBuitenOpp().toString());
        txtVolume.setText(mijnStaaf.berekenVolume().toString());
        txtMassa.setText(Dec2.format(mijnStaaf.berekenMassa()));
        
        
    }      


IS-A relatie.

In Java werkt het overerven via een zgn. IS-A relatie (is-een relatie) .
Bijvoorbeeld  we kunnen een klas vervoersmiddel definiëren en daaruit subklassen definiëren als schip, vliegtuig of auto.
Een schip is een vervoersmiddel;
Een vliegtuig is een vervoersmiddel;
Een auto is een vervoersmiddel;
Alle drie (schip, vliegtuig en auto) hebben algemene overeenkomstige eigenschappen (zoals verplaatsen van A naar B) maar daarnaast ook eigen specifieke eigenschappen.

Een ander vaak gebruikt voorbeeld dat van personen, studenten en werknemers.
Een student is een persoon, net als een werknemer een persoon is.
Grafisch kunnen zulke relaties aangegeven worden zoals hieronder getoond wordt.




UML (Unified Modeling Language).

Voor een beter begrip van object-oriented programma's maakt men vaak gebruikt van zogenaamde UML diagrammen.
De belangrijkste diagrammen in object-oriented ontwikkeling zijn:

De use case diagram.

Een use case is een scenario dat het dagelijks gebruik van het systeem door een spelers schematisch weergeeft. In use case diagram wordt beschreven hoe een specifiek doel verwezenlijkt kan worden.
Wat betekent dat? Een actor is een gebruiker die een rol met betrekking tot het systeem speelt. De actoren zijn over het algemeen mensen hoewel computersystemen ook actoren kunnen zijn. Een scenario is een opeenvolging van stappen die de interactie tussen een actor en het systeem beschrijven. Het use case diagram bestaat uit de verzameling van alle actoren en alle use cases.

Voorbeeld van een use case van een verkoopsite.

De rechthoek vertegenwoordigt de systeemgrens, de poppetjes vertegenwoordigen de actoren (gebruikers van het systeem), en de ovalen vertegenwoordigen de individuele use cases.

Jammer genoeg, vertelt dit diagram ons zeer weinig over de daadwerkelijke functionaliteit van het systeem

De use cases helpen ons met:

De sequence diagram.

Een sequence diagram beschrijft hoe groepen objecten in het verwezenlijken van het systeemgedrag samenwerken. Deze samenwerking wordt uitgevoerd als reeks berichten tussen objecten.
Het sequence diagram beschrijft de gedetailleerde implementatie van één enkele use case (of één variatie van één enkele use case).

Het sequence diagram van een veilings-site

De class diagram.

Het klassendiagram beschrijft de klassen die een systeem vormen en het statische verband tussen hen.
De klassen worden gedefinieerd in termen van hun naam, attributen (of gegevens), en gedrag (of methodes).

Voorbeeld van een klassendiagram van een veilings-site
Account klassendiagram



De state transition diagram.

De state-transition diagrammen beschrijven alle statussen die een object kan hebben, de gebeurtenissen waaronder een object status verandert (overgangen), de voorwaarden die moeten worden vervuld (guards) alvorens de overgang zal voorkomen, en de activiteiten die tijdens het leven van een object worden ondernomen (acties). De state-transition diagrammen zijn zeer nuttig om het gedrag van individuele objecten als overkoepeling boven de use cases te beschrijven die die objecten beïnvloeden.
Voorbeeld van een state transition diagram van een veilings-stite


Status.
Een conditie tijdens het leven van een object waarin het aan één of andere voorwaarde voldoet, één of andere actie uitvoert of op één of andere gebeurtenis wacht.

Gebeurtenis (Event).
Een gebeurtenis die een statusovergang teweeg kan brengen. Gebeurtenis types omvatten een expliciet signaal van buiten het systeem, een aanroep van binnen het systeem, de passage van een aangewezen tijdspanne, of een aangewezen voorwaarde die waar wordt.

Guard.
Een boolean expressie die, als waar, een gebeurtenis toelaat om een overgang te veroorzaken.

Transition.
De verandering van status binnen een object.

Actie.
Één of meerdere acties die door een object in antwoord op een statusverandering worden uitgevoerd.




Documentatie.

Vaak zijn programmeurs nogal 'lui' ...... een nieuwe class ontwikkelen is erg spannend, maar documentatie bij deze class schrijven blijft nogal eens achterwege. In Java wordt dit probleem wat verkleind door de programmeur een optie te geven waarmee commentaar in de source code meteen kan worden gebruikt voor het genereren van bijbehorende documentatie.
Alle commentaar dat begint met /** en eindigt met */ kan 'automatisch' worden gebruikt voor het genereren van documentatie.

In onze 'Bar' komt o.a. de methode BerekenBuitenOpp( ) voor. Indien nu de volgende comment wordt toegevoegd  aan onze bron-code:

/**
  * De methode BerekenBuitenOpp() berekent het omspoeld oppervlak van een staaf.
  * Omspoeld oppervlak = cilinder oppervlak + 2 X eindcirkel oppervlak.
  * @return Omspoeld oppervlak
  */


Vervolgens geven we Netbeans de opdracht een Javadoc te generenen door te rechtsklikken op projectnaam zoals hiernaast is weergegeven.

Het systeem zal dan een HTML document maken zoals hieronder wordt getoond.





Samengevat:
In onderstaand tabel worden enkele veel voorkomende tags beschreven.
@author [author name]
identifies author(s) of a class or interface
@version [version]
version info of a class or interface
@param [argument name] [argument description]
describes an argument of method or constructor
@return [description of return]
describes data returned by method (unnecessary for constructors and void methods)
@exception [exception thrown] [exception description]
describes exception thrown by method
@throws [exception thrown] [exception description]
same as @exception
Here's an example with tags:

/** Description of MyClass
*
* @author John Doe
* @author Jane Doe
* @version 6.0z Build 9000 Jan 3, 1970.
*/
public class MyClass
{
    /** Description of myIntField */
    public int myIntField;

    /** Description of MyClass()
     *
     * @throws MyException         Description of myException
     */
    public MyClass() throws myException
    {
        // Blah Blah Blah...
    }
   
    /** Description of myMethod(int a, String b)
     *
     * @param a            Description of a
     * @param b            Description of b
     * @return             Description of c
     */
    public Object myMethod(int a, String b)
    {
        Object c;
        // Blah Blah Blah...
        return c;
    }
}







Wrapper class in Java.

Een wrapper class of adapter is een hulpklasse die gebruikt wordt om  andere klassen op elkaar aan te sluiten.
Zie het als een soort koppelstukje. De wrapper zorgt voor eventuele conversies etc.
De bekenste toepassingen zijn de klassen Double en Integer.

We kunnen simpele primitieve variabele typen verheffen tot klastypen met bijvoorbeeld de volgende commando's:

Integer a = 1;
of
int i = 1;
Integer myInt2 = i;
of
int i2 = new Integer(4);
de variabele a  is nu niet een primitieve variabele, maar een object van het type Integer met alle daarbij behorende methoden zoals hieronder is weergegeven.
We kunnen nu gebruik maken van een aantal standaard methoden om bijvoorbeeld zo'n integer eenvoudig om te zetten naar een double of float.





Keuze in Java (zie Deitel § 4.6)

Het komt vaak voor dat in een programma keuzen moeten worden gemaakt; hiervoor heeft Java de  'if' of 'switch' statements.

if .... else ....
/*
 * Math.random() is een standaard methode dat een (double) getal levert tussen 0 en 1 (inclusief 0, exclusief 1)
 */

double teller = 10 * Math.random();

if(teller<5)
{
   System.out.println("Waarde van de teller is kleiner dan 5." );
}
else
{
   System.out.println("Waarde van de teller is groter of gelijk aan 5." );
}
if ......else if......else.......
double teller = 10 * Math.random();
if(teller < 5)
{
   System.out.println("Waarde van de teller is kleiner dan 5." );
}
else if (teller > 5)
{
   System.out.println("Waarde van de teller is groter dan 5." );
}
else
{
   System.out.println("Waarde van de teller is 5." );
}
Conditional operator ?:
In Java probeert men alles zo kort mogelijk op te schrijven ....
System.out.println( studentGrade >= 60 ? "Passed" : "Failed" );

De vraag 'StudentGrade >= 60 kan twee waarden opleveren (true of false);
Bij 'true' wordt de string "Passed" afgedrukt.
Bij 'false' wordt de string "Failed" afgedrukt.

switch met integers



Let op: 'break' is NOODZAKELIJK
Switch werkt met integers of Strings.

private void cmdWerpActionPerformed(java.awt.event.ActionEvent evt)
{
   /* maak een random getal tussen 1 en 6
    * Let op: (int)(5.99) = 5!
    */
   int worp = 1 + (int)(Math.random()*6);
   switch (worp)
   {
       case 1:
       {
           lblResult.setText("1");
           break;
       }
       case 2:
       {
           lblResult.setText("2");
           break;
       }
       case 3:
       {
           lblResult.setText("3");
           break;
       }
       case 4:
       {
           lblResult.setText("4");
           break;
       }
       case 5:
       {
           lblResult.setText("5");
           break;
       }
       case 6:
       {
           lblResult.setText("6");
           break;
       }
       default:
       {
           lblResult.setText("Something has gone wrong!");
       }
   }
}


switch met 'Strings'


Gelukking ondersteund Java tegenwoordig ook Strings in de swich statement.

private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
{
   // Read the input
   String input;
   input = txtInput.getText();
       
   switch (input)
   {
       case "1":
       {
           lblOutput.setText("U heeft een 1 ingevoerd.");
           break;
       }
       case "2":
       {
                lblOutput.setText("U heeft een 2 ingevoerd.");
                break;
       }
       case "3":
       {
                lblOutput.setText("U heeft een 3 ingevoerd.");
                break;
       }
       default:
       {
                lblOutput.setText("U heeft een verkeerde waarde ingevoerd.");
       }
   }
}



Herhalingslussen in Java (Zie Deitel § 4.8)

Vaak komt het voor dat opdrachten herhaald moeten worden. In plaats van dezefde opdracht vele keren te tikken kan je gebruik maken van herhalingslussen..
Het gebruik van deze lusstructuren is vrij te bepalen door de programmeur, je kan veelal zonder grote problemen dezelfde code herschrijven met een ander lustype.

while-lus int teller = 1;
while(teller<5)
{
   System.out.println("Waarde van de teller: " + teller++);
}

do-while-lus Met een do-while lus wordt de voorwaarde om te herhalen pas gecontroleerd nadat de lus is doorlopen.
Dit betekent dat bij een do...while-lus de opdrachten binnen de lus minstens 1 keer worden uitgevoerd.

int teller = 1;
do
   {
     System.out.println("Waarde van de teller: " + teller++);
   }
while(teller<5)
for-lus Bij een for-lus geef je drie argumenten op:
  1. initialisatie expressie: opdracht die uitgevoerd wordt voor de eerste lusdoorgang
  2. voorwaarde om verder te gaan
  3. iteratie expressie: opdracht die uitgevoerd wordt na elke herhaling
int teller;
for (teller = 1; teller <5; teller++)
{
   System.out.println("Waarde van de teller: " + teller);
}


for-lus alternatief
De  for-lus kent ook een alternatieve schrijfwijze die vaak wordt toegepast bij arrays.
  1. Dit is in feite een foreach - lus
  2. de for variabele neemt steeds de waarde aan van het volgende element uit de array
  3. met de for variabele wordt actie ondernomen; de array elementen blijven onaangetast.

int getallen[] = {1,12,23,34,45};
for(int i : getallen)
{

    System.out.println(i);
}

Deze lusstructuren kunnen ook genest worden.
int teller1, teller2;
for (teller1 = 1; teller1 < 5; teller1++)
{
   for (teller2 = -5; teller2 < 5; teller2 = teller2 + 2)
   {
      System.out.println("Waarde van teller1: " + teller1);
      System.out.println("Waarde van teller2: " + teller2);
   }
}

Ontsnappen uit herhalingslussen

Om lussen te onderbreken kan je gebruik maken van de instructies break en continue.

public class BreakLoop
{

    public static void main(String[] args)
    {

        int teller;
        for (teller = 1; teller < 5; teller++)
        {
            if(teller==3)
            {
                break;
            }
            System.out.println("Waarde van teller: " + teller);
        }
        System.out.println("");
        for (teller = 1; teller < 5; teller++)
        {
            if(teller==3)
            {
                continue;
            }
            System.out.println("Waarde van teller: " + teller);
        }
    }
}


Compound Assignment Operators (Zie Deitel § 4.12)

Vaak probeert men opdrachten in Java zo kort mogelijk op te schrijven. Een goed voorbeeld daarvan zijn de 'compound assignment operators' waarbij men  veel voorkomende opdrachten als:

c = c + 3;
 
opschrijft als :

c += 3;



Increment and decrement operators (Zie Deitel § 4.13)

Aangezien tellers (in herhalingslussen) vaak met de stapgrootte 1 vergroot of verkleind worden heeft men ook daarvoor een verkorte notatie wijze verzonnen:
i = i + 1;
 
wordt opgeschreven als :

i++;





Arrays in Java (zie Deitel Hst. 7)

Een array is een opeenvolging van gelijkaardige elementen

Declaratie.

Om een array te definiëren (declareren) gebruiken we de volgende syntaxis:

type[] naam of type naam []; bijvoorbeeld:
    int ArrayGeheel[];
    double [] d1, d2;
    byte [] [] tweedim;
    String Tekenreeks [];

Het eerste element van een Java-array bevindt zicht standaard op index 0 !!

Initialisatie.

    Naam []     = new type[AantalElementen];
    type Naam[] = new type[AantalElementen];
    type Naam[] = {Lijst met elementen};


Hierbij is Naam de naam van de array.
int kleine[] = new int[6];

namen = new String[]{"Filips", "Adams", "Declercq"};

klinkers = new Char[]{'a', 'e', 'i', 'o', 'u'};



In Java zijn arrays objecten => ze hebben ook eigenschappen zoals een lengte (= het aantal elementen).

public class Kwadraat
{
  public static void main (String args[])
  // Kwadraat toepassing
  {
    int C[] = new int[10];
    int i;
    for (i=0; i<10; i++)
    {
      C[i]= i*i;
    }
    for (i=0; i<C.length; i++)
    {
      System.out.println(i + " ^2 = " + C[i]);
    }
  }
}



C.length geeft het aantal elementen in array C.

Een array kopiëren

Een array kopiëren naar de andere gaat dus niet zomaar...... maar gelukkig is het ook weer niet zo ingewikkeld.
Juist omdat een array een object is in Java zijn er stanaard methoden aanwezig om het kopiëren mogelijk te maken nl:
clone en arraycopy

Voorbeeld van array kopiëren met het clone commando

/*
 ArrayClone.java:
 Maak een exacte copy van een array (clone).
*/
public class ArrayClone
{  public static void main(String[] args)
   { 
      int[] a = new int[10], b;
      int i;

      for (i=0; i<10; i++)
         a[i] = i * i;

      for (i=0; i<a.length; i++)
      {
         System.out.println(i + " ^2 = " + a[i]);
      }

      // maak een clone
      b = a.clone();
      System.out.println("b[5] = " + b[5]);
      b[5] = 123;

      System.out.println("Na de uitvoering van het commando b = a.clone;\n" +
                         "en het commando b[5] = 123;\n\ngeldt:");

      for (i=0; i<a.length; i++)
      {
         System.out.println("i = " + i + " a[" + i + "] = " + a[i] + "\t" +
                                         " b[" + i + "] = " + b[i] );
      }
   }
}


Voorbeeld van array kopiëren met het arraycopy commando
public class ArrayCopyDemo
{
    public static void main(String[] args)
    {
        char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e',
                            'i', 'n', 'a', 't', 'e', 'd' };
        char[] copyTo = new char[7];

        System.arraycopy(copyFrom, 2, copyTo, 0, 7);
        System.out.println(new String(copyTo));
    }
}

Copying Arrays
Use System's arraycopy method to efficiently copy data from one array into another. The arraycopy method requires five arguments:
public static
    void arraycopy(Object source,
                   int srcIndex,
                   Object dest,
                   int destIndex,
                   int length,

The two Object arguments indicate the array to copy from and the array to copy to. The three integer arguments indicate the starting location in each the source and the destination array, and the number of elements to copy. This diagram illustrates how the copy takes place:



Array elementen benaderen m.b.v. een herhalingslus nieuwe versie

In Java 5.0 is er een extra for-lus toegevoegd om makkelijker met arrays te werken. Er moet echter een onderscheid worden gemaakt tussen arrays van primitieve variabelen(zoals int, char, enz.) en Objecten.
Het volgende stukje programmacode laat de nieuwe for-lus werken met een array van primitieve variabelen.

int getallen[] = {1,22,33,44,55};
for(int i : getallen)
{

    System.out.println(i);
}

In dit voorbeeld is er een array van int's. Bij de for-lus is er een variabel genaamd i. Deze dient om tijdelijk de getallen van de array in te lezen.
Eerst wordt het eerste getal ingelezen en in de variabele i geplaatst vervolgens wordt die getoond op het scherm. Dan wordt het tweede genomen en zo verder.
Het nut is dat het meteen programmacode bespaart.

Echter .......

Er is echter een grote maar in dit verhaal: je kunt met deze for-lus de gegevens niet aanpassen noch nieuwe gegevens in de array plaatsen. Zie onderstaand voorbeeld.
int getallen[] = {1,2,3,4,5};
for(int i: getallen)
{
    i++;
}


Deze code zal geen effect hebben op de getallen in de array zelf, de gegevens blijven hetzelfde hier komt echter ook meteen het onderscheid met een array van objecten.

In tegenstelling tot primitieve variabelen waar de inhoud wordt gekopieerd in een nieuwe variabele wordt bij een object het adres in het werkgeheugen van het object gekopieerd naar een "nieuw" object. Hierdoor kunnen er wel bewerkingen worden gedaan bij zo'n for-lus.

Meerdimentionale arrays ofwel ArrayOfArrays

Een array kan weer een array bevattten; zie onderstaand voorbeeld voor een twee-dimensionaal voorbeeld.

public class ArrayOfArraysDemo2
{
  public static void main(String[] args)
  {
    int[][] aMatrix = new int[4][];

    //populate matrix
    for (int i = 0; i < aMatrix.length; i++)
    {
        aMatrix[i] = new int[5];    //create sub-array
        for (int j = 0; j < aMatrix[i].length; j++)
        {
            aMatrix[i][j] = i + j;
        }
    }
    //print matrix
    for (int i = 0; i < aMatrix.length; i++)
    {
        for (int j = 0; j < aMatrix[i].length; j++)
        {
            System.out.print(aMatrix[i][j] + " ");
        }
        System.out.println();
    }
  }
}



Twee dimensionale array met 4 rijen en een onbekend aantal kolommen.


Met aMatrix.length wordt het aantal rijen opgevraagd.
Met aMatrix[i].length wordt het aantal kolommen opgevraagd.

Arraylijsten in Java (zie Deitel § 7.16)

Een arraylist is één van de zogenaamde collecties in de taal Java.
Een collectie  is een verzameling van objecten die:
Aan de hand van onderstaand voorbeeld wordt  een en ander toegelicht.

import java.util.ArrayList;
import java.util.Iterator;

public class Arraylist1 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //
        ArrayList<Integer> lijstA = new ArrayList<Integer>();
        lijstA.add(225);
        lijstA.add(244);
        lijstA.add(355);
        lijstA.add(296);
        int getalA = lijstA.get(2);
        System.out.println("De lijst bevat nu: " + lijstA.size() + " getallen.");
        System.out.println("Het eerste getal van de reeks is:  " + lijstA.get(0));
        System.out.println("Het derde getal van de reeks is: " + getalA);
       
        // voeg het getal 0 toe op positie 0 = eerste element.
        lijstA.add(0, 0);      
        System.out.println("\nDe lijst bevat nu: " + lijstA.size() + " getallen.");
        System.out.println("Het eerste getal van de reeks is:  " + lijstA.get(0));
       
        // voeg het getal 10 toe op positie 4
        lijstA.add(3, 10);      
        System.out.println("\nDe lijst bevat nu: " + lijstA.size() + " getallen.");
        // print een overzicht van de lijst.
        for (int i=0; i < lijstA.size();i++)
        {
            System.out.println("Index " + i + ": " + lijstA.get(i));
        }
       
        //verwijder het 3e element uit de lijst
        lijstA.remove(2);
        System.out.println("\nNa verwijdering bevat de lijst bevat nu: " +
                            lijstA.size() + " getallen.");
        // print een overzicht van de lijst.
        Iterator it = lijstA.iterator();           //d.m.v. een iterator
        while(it.hasNext())
        {
            System.out.print(it.next() + "\t");
        }
       
        /*
         * Let op onderstaand stukje code geeft een foutmelding omdat bij het
         * tweede element i = 225 wordt en al we dan lijstA.get(225) proberen
         * uit te voeren ....
        for (int i: lijstA)
        {
            System.out.println("Index " + i + ": " + lijstA.get(i));
        }
        */
       
        ArrayList<String> personen = new ArrayList<String>();
        personen.add("Klaas Vaak");
        personen.add("Het Zandmannetje");
        personen.add("Sint-Niklaas");
        personen.add("Sint-Maarten");
        personen.add("Boe Man");
        System.out.println("\n\nNu volgt de data van de tweede lijst.");
        System.out.println("Aantal personen in de lijst i: " + personen.size());
       
        for(int i = 0;i<personen.size();i++)    //gewone for-loop
        {                      
            System.out.print((i+1) + ". " + personen.get(i) + "\t");
        }
        System.out.println("\n\nEn nu onder elkaar:");
        for(String p : personen)                //enhanced for-loop
        {                                  
            System.out.print(p + "\n");
        }

    }
}

Let op: deze twee bibliotheken moeten worden geïmporteerd.




Array van objecten.

Bij arrays zit er een groot verschil tussen 'primitive types' en zelf gedefinieerde objecten.
Bij een array van 'primitive types' zoals integers of doubles kunnen we volstaan met declaratie en (default) initialisatie. Het systeem zal  bij default de waarden van de elementen op nul (0) zetten.
Bij een array van 'objecten' zal het systeem bij default de waarden van de elementen op NULL zetten => als je zo'n element wilt benaderen dan krijg je een zgn. NullPointerException!
=> Je zal echt een constructor moeten moeten gebruiken om elk element een beginwaarde te geven; gebruik hiervoor NEW.

public class Auto
{
    private String merk;
    private int topSnelheid;
    
    // default constructor
    public Auto()
    {
        merk = "Geen merk";
        topSnelheid = 0;
    }
    
    String getMerk()
    {
        return(this.merk);
    }
    int getTopSnelheid()
    {
        return(this.topSnelheid);
    }
    /*
     * Netbeans gebruikt om een 'toString' methode te schrijven...
     * rechtermuistoets => 'Insert Code ...'
    */
    @Override
    public String toString() {
        return "Auto{" + "merk=" + merk + ", topSnelheid=" + topSnelheid + '}';
    }
    

public class ArrayOfObjects
{
    public static void main(String[] args) {
       
        int [] IntegerArray1 = new int[5];      // declaratie + initialisatie
        int [] IntegerArray2 = {10, 20, 30};    // declaratie + initialisatie
   
        double DoubleArray1[] = new double[3];  // declaratie + initialisatie
        double DoubleArray2 [];                 // declareer de DoubleArray2
        DoubleArray2 = new double[]{1.2, 3.4};  // initialiseer de DoubleArray2
       
        Auto test[];                            // declareer de Auto array test
        test = new Auto [5];                    // initialiseer de array test
       
        /*
         * Arrays van 'primitive types' zoals integers of doubles worden bij
         * default geïnitialiseerd op 0.
        */
        System.out.println("Hier komt de array IntegerArray1:");
        for(int i: IntegerArray1)
        {
            System.out.println(i);
        }
        System.out.println("\nHier komt de array IntegerArray2:");
        for(int i: IntegerArray2)
        {
            System.out.println(i);
        }
        System.out.println("\nHier komt de array DoubleArray1:");
        for(double i: DoubleArray1)
        {
            System.out.println(i);
        }
        System.out.println("\nHier komt de array DoubleArray2:");
        for(double i: DoubleArray2)
        {
            System.out.println(i);
        }
       
        System.out.println("\n\nHier komt de array test:");
        for(int i=0; i<test.length; i++ )
        {
           System.out.println(test[i]);
        }
       
        // elementen van array test benaderen zonder explicite constructor aanroep
        // Exception in thread "main" java.lang.NullPointerException
//        for(int i=0; i<test.length; i++ )
//        {
//           System.out.println(test[i].toString());
//        }       
        System.out.println("\nExpliciet de default constructor aanroepen:");
        for(int i=0; i<test.length; i++ )
        {
           test[i] = new Auto();
        }
        System.out.println("Als we nu een eigenschap van een bepaald element"
                          +" willen benaderen:");
        for(int i=0; i<test.length; i++ )
        {
           System.out.println(test[i].toString());
        }
    }
   
}



Static functions in Java.

In Java is alles opgehangen aan classes (objecten) ..... ook de functies. Voor de beginnende programmeur is dat in het begin een beetje verwarrend.
We behandelen daarom kort zogenaamde 'statische functies'; dit zijn functies die niet aan een object verbonden zijn.

Algemene vorm: static function
ReturnType methodName( ParamOneType param1, ParamTwoType param2, ... )
{

      ReturnType retType;

      ...

      return retType;

}


Elke functie heeft een naam (hier methodName) en is van een bepaald type (hier ReturnType).
Dit type wordt bepaald door het resultaat dat de functie teruggeeft aan het aanroepend programmadeel.

Geeft de functie geen waarde terug, dan is hij van het type void.

Elke functie heeft invoerparamaters; deze worden met hun type vermeld in de invoerparameterlijst (hier zijn er twee invoerparameters - param1 en param2-)

In de functie komt minstens éénmaal het keywoord return voor.
Hiermee wordt het resultaat van de functie teruggegeven aan het aanroepend programmadeel.

Static variabelen in Java a.k.a Class variables.

In object geörienteerde computertalen bestaan er grofweg gezegd twee typen variabelen:

Instance (instantie) variabelen of object variabelen behoren  toe aan één bepaald object dat gemaakt is a.h.v. een class.
Elk object heeft zijn eigen copy van de instance variabele.
De waarde van deze variabele kan dan ook per object verschillen. Voorbeeld van de definitie van een instance variabele:

Voorbeeld van een instance variabele (naam)
public class Persoon
{
    private String naam;

    Persoon(String n)
    {
        naam = n;
    }
   
    String getName()
    {
        return naam;
    }
}

 Ieder object  dat aangemaakt wordt kan in principe een andere naam hebben.


Voorbeeld van een class variabele (ID)
public class Persoon
{
    private String naam;
    private static int ID = 0;
    
    Persoon(String n)
    {
        naam = n;
        ID++;
    }
   
    String getName()
    {
        return naam;
    }
    int getID()
    {
        return ID;
    }        
}


Ieder object dat aangemaakt wordt gebruikt dezelfde class variabele ID; deze wordt dus gedeeld door alle aangemaakte objecten (instanties van de class Persoon.

private void cmdVoegToeActionPerformed(java.awt.event.ActionEvent evt)
 {                                          
        // haal tekst op en maak een object Persoon aan
        String name;
        name = txtInput.getText();
        Persoon mijnContact = new Persoon(name);
       
        System.out.println("Mijn contact heet: " + mijnContact.getName());
        System.out.println("Bijbehorend ID is: " + mijnContact.getID());
    } 

Hier wordt de statische variabele ID steeds met de waarde één verhoogt indien een nieuw object van het type Persoon wordt aangemaakt.



Eigen bibliotheek.


Bij het samenwerken met anderen is het vaak handig om een aantal basis klassen te definiëren en van daaruit speciale (sub)klassen te maken (children - parents).

Start een nieuw project in Netbeans en kies nu de optie 'Java Class Library' zoals hieronder is weergegeven.
Class Library
Kies een naam voor de bibliotheek

Vervolgens worden één of meer klassen in deze bibliotheek gedefinieerd.

Click met de rechtermuis op 'Source Packages' en kies de optie zoals hieronder is weergegeven.
Nieuwe klas


Type nu de definitie van uw klasse in; hieronder ziet u de source code van de klasse 'Bar'.
Let wel: omdat ik wil dat van deze klasse 'geërfd' kan worden, definieer ik de variabelen als 'protected'.

public class Bar
{

    protected double straal; //straal van de staaf
    protected double hoogte; //hoogte van de staaf

    public Bar ()    // defaultconstructor
    {
       straal = 1.0; //straal van de staaf
       hoogte = 1.0; //hoogte van de staaf
    }

    public Bar (double s, double h)    // constructor
    {
         straal = s; //straal van de staaf
         hoogte = h; //hoogte van de staaf
    }
   
    public double BerekenBuitenOpp()
    {
        double cilinderOpp, eindvlakOpp, buitenOpp;
        cilinderOpp = 2.0 * 3.1415 * straal * hoogte;
        eindvlakOpp = 3.1415 * straal * straal;
        buitenOpp = cilinderOpp + 2.0 * eindvlakOpp;
        return (buitenOpp);
    }
   
    public double BerekenVolume()
    {
        return (3.1415 * straal * straal * hoogte);
    }

    public void Show()
    {
         System.out.println("\nDe straal is: " + straal + " cm");
         System.out.println("De hoogte is: " + hoogte + " cm");
    }
}


Als deze klasse gecompileerd is, vindt men in de 'dist' (van distributie) een jar-bestand (Java ARchive of JAva Run). Deze kan nu 'veilig' aan anderen worden gegeven om te gebruiken in hun eigen applicaties.

Geleende bibliotheek gebruiken.

Om elementen uit een 'niet standaard' bibliotheek te kunnen gebruiken moet de locatie van deze bibliotheek wel aan 'Netbeans' worden doorgegeven. Dit gebeurd via de optie 'Libraries' in een project.

Maak een eenvoudige applicatie met een GUI zoals hieronder is aangegeven.


Indien de bibliotheek niet aan het project is toegevoegd, krijgt men natuurlijk meteen een foutmelding zoals in onderstaand figuur getoond wordt.


Vervolgens gaan we de bibliotheek met de 'Bar' aan dit project toevoegen.
Click daartoe met de rechtermuistoets op 'Libraries'



De source code kan nu vrij eenvoudig blijven:
private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
{

        // Pak de invoer en bereken het omspoeldoppervlak en volume
        Bar myBar;
        double radius, hoogte;
        double opp, volume;
       
        radius = Double.parseDouble(txtRadius.getText());
        hoogte = Double.parseDouble(txtHoogte.getText());
        myBar = new Bar(radius, hoogte);
        opp = myBar.BerekenBuitenOpp();
        volume = myBar.BerekenVolume();
       
        txtOpp.setText(opp + "");
        txtVolume.setText(volume + "");
    }




Strings in Java (zie Deitel Hst. 14)

In Java zijn Strings geen eenvoudige gegevenstypen zoals int of double. Strings worden in feite afgeleid van de klassen String en StringBuffer.
Het grootte voordeel van het feit dat String-tekenreeksen in feite objecten zijn, is dat er tal van methoden beschikbaar zijn in deze klassen die het werken met Strings heel gebruiksvriendelijk maken. Hieronder worden een aantal (niet alle) handige methoden van deze klassen getoond.

Voor de goede orde van zaken, naast Strings (een rij aan elkaar geknoopte karakters) vinden we ook nog de char.
Het gegevenstype char stelt altijd slechts één karakter voor; we kunnen echter wel een array van char declareren waar dan per element één karakter wordt opgeslagen.

Declaratie en initialisatie van Strings
String s1 = "Ik ben een adelborst";
String s2;
String s3 = new String();
String s4 = new String("String objecten hebben vele standaard methoden");
char[] c1 = {'H', 'a', 'l', 'l', 'o'};
String s5 = new String(c1);
String s6 = new String(c1, 0, 2);
double d1 = 34.3476;
String s7 = String.valueOf(d1);
s2 = " en ik volg een cursus Java";
s3 = " aan het KIM in Den Helder";

Vaak gebruikte methoden:

length()
Retourneert de lengte van een tekenreeks
concat()
Voegt twee tekenreeksen samen
charAt()
Retourneert het teken op een bepaalde positie (let op: begint bij nul)
getChars()
Opvragen van een aantal tekens en plaatsen in een char-array
subString()
Opvragen van een aantal tekens, retourneert een nieuwe String (begin en eindpunt kunnen meegegeven worden)
indexOf()
Doorzoeken: positie van de eerste optreden van een string in een andere String
lastIndexOf()
Doorzoeken: positie van de laatste optreden van een string in een andere String
replace()
Tekens binnen een String vervangen
toLowerCase()
String omzetten naar kleine letters
toUpperCase()
String omzetten naar hoofdletters
trim()
Spaties aan de voorkant en/of achterkant van een String verwijderen

Bovenstaande methoden worden in onderstaand voorbeeld toegepast.

private void cmdStartActionPerformed(java.awt.event.ActionEvent evt) {                                        
        String s1 = "Ik ben een adelborst";
        String s2;
        String s3 = new String();
        String s4 = new String("String objecten hebben vele standaard methoden");
        char[] c1 = {'H', 'a', 'l', 'l', 'o'};
        String s5 = new String(c1);
        String s6 = new String(c1, 0, 2);
        double d1 = 34.3476;
        String s7 = String.valueOf(d1);
        s2 = " en ik volg een cursus Java";
        s3 = " aan het KIM in Den Helder";
       
        txtOutput.setText(""); //clear the textarea.
        txtOutput.append(s1);
        txtOutput.append(s2);
        txtOutput.append(s3);
        txtOutput.append("\n");     // new line
        txtOutput.append("s4 = " + s4);
        txtOutput.append("\n");    
        txtOutput.append("s5 = " + s5);
        txtOutput.append("\n");    
        txtOutput.append("s6 = " + s6);
        txtOutput.append("\n");
        txtOutput.append("s7 = " + s7);
        txtOutput.append("\n");
        txtOutput.append("De lengte van s1 = " + s1.length());
        txtOutput.append("\n");
        txtOutput.append("Concatenatie van s5 en \" world\" = " + s5.concat(" world"));
        txtOutput.append("\n\n");
        txtOutput.append("s1.charAt(3) = " + s1.charAt(3));
        txtOutput.append("\n");
        txtOutput.append("s1.subString(11) = " + s1.substring(11));
        txtOutput.append("\n");
        txtOutput.append("s1.subString(11, 15) = " + s1.substring(11, 15));
        txtOutput.append("\n");
        txtOutput.append("s1.indexOf('e') = " + s1.indexOf('e'));
        txtOutput.append("\n");
        txtOutput.append("s1.lastIndexOf('e') = " + s1.lastIndexOf('e'));
        txtOutput.append("\n");
        txtOutput.append("s1.replace('e', 'E')) = " + s1.replace('e', 'E'));
        txtOutput.append("\n");
        txtOutput.append("s2.toUpperCase() = " + s2.toUpperCase());
        txtOutput.append("\n");
    }


Een hele handige methode is split; m.b.v. deze methode kan men een lange tekenreeks in kleinere stukjes 'hakken'.
Het invoer paramater is het scheidingsteken. In onderstaand programma wordt een voorbeeld getoond.

private void cmdStartActionPerformed(java.awt.event.ActionEvent evt) {                                        
        String s1 = "We beginnen met een hele lange zin en gaan die splitsen in losse woorden.";
        String[] s2;
        s2 = s1.split(" ");
       
        txtOutput.setText(""); //clear the textarea.
        txtOutput.append(s1);
        txtOutput.append("\n");     // new line
        for ( int i = 0; i < s2.length; i++)
        {
            txtOutput.append(s2[i]);
            txtOutput.append("\n");
        }      
    }     



Enkele handige voorbeeldprogramma's.

Dialoogvensters (messagebox, inputbox en confirmationbox).


Het onderstaand programma laat 3 verschillende dialoogvensters zien.
 Het programma en de drie verschillende dialoogvensters.
private void cmdMessageActionPerformed(java.awt.event.ActionEvent evt)
{
        // Show a message dialog with a text message of course!
        JOptionPane.showMessageDialog((Component) evt.getSource(),
                "Thank you!");
}

private void cmdInputActionPerformed(java.awt.event.ActionEvent evt)
{
        // Show an input dialog that will ask you to input some text
        String text = JOptionPane.showInputDialog((Component) evt.getSource(),
                                                        "What is your name?");
        if (text != null && !text.equals(""))
        {
            JOptionPane.showMessageDialog((Component) evt.getSource(),
                                                     "Hello " + text);
        }
}

private void cmdEndActionPerformed(java.awt.event.ActionEvent evt)
{
        // Show a confirmation dialog which will ask to for a YES or NO
        int result = JOptionPane.showConfirmDialog((Component) evt.getSource(),
                               "Are you sure want to close this application?");
        if (result == JOptionPane.YES_OPTION)
        {
            System.exit(0);
        }
        else if(result == JOptionPane.NO_OPTION)
        {
            // Do nothing, continue to run the application
        }
}





Tab-bladen voorbeeld.


Soms is het wel handig een GUI met verschillende tab-bladen te maken.
Met de NetBeans IDE is dit eenvoudig te realiseren.
 Het programma direct na opstarten.
private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
{

        String s;
        s = lbl1.getText() + " " + txtInput.getText();
        lblResult.setText(s);
               
}

Bij dit project maakt men gebruik van de 'Tabbed Pane' en 'Panel'uit de Palette. (zie voorbeeld film)







Opstartproces voorbeeld.


Soms is het handig/noodzakelijk om voordat de  GUI zichtbaar wordt al bepaalde opdrachten uit te voeren.
Hierbij kan handig gebruik gemaakt worden van Globale variabelen d.w.z. variabelen waarvan de scope zich over meerdere methoden heen strekt.

 Het programma direct na opstarten.
import java.awt.Component;
import javax.swing.JOptionPane;

/**
 *
 * @author raho
 */
public class frmStart extends javax.swing.JFrame {
/*
 * Hier kunnen 'globale' variabelen worden geplaatst.
 * Dit zijn variabelen die in alle onderliggende methoden gebruikt/gewijzigd
 * kunnen worden.
 */
    int herhalingen = 100;
    /**
     * Creates new form frmStart
     */
    public frmStart() {
        initComponents();
    }
.
.
.
.
.
.
        
private void formWindowOpened(java.awt.event.WindowEvent evt)
{
        // Toon een bericht tijdens window openen
        JOptionPane.showMessageDialog((Component) evt.getSource(),
                "Window is geopend " + herhalingen + " maal gefeliciteerd!");
}

private void cmdExitActionPerformed(java.awt.event.ActionEvent evt)
{
        // Close the application:
        JOptionPane.showMessageDialog((Component) evt.getSource(),
                "De waarde van herhalingen is:  " + herhalingen);
        System.exit(0);
}
Bij dit project maakt men gebruik van het event 'windowOpened'.
Klik met de rechtermuistoets op het frame en kies 'Events => Window=>windowOpened' zoals in onderstaand figuur wordt aangegeven.



Nadat op de 'Exit' knop gedrukt is ziet men:



Radiobutton voorbeeld.


Bij het gebruik van 'Radiobuttons' moet men niet vergeten ook een 'Buttongroup' te definiëren.
Wanneer de radioknoppen binnen één groep geplaatst worden, kan de gebruiker slechts één van de knoppen selecteren.

 Het programma direct na opstarten.
package Les;

import java.awt.Component;
import javax.swing.ButtonGroup;
import javax.swing.JOptionPane;

public class frmRadio extends javax.swing.JFrame
{

    /**
     * Creates new form frmRadio
     */
    public frmRadio() {
        initComponents();
        /*
         * Roep de groupButton methode aan bij het opstarten van
         * het programma. Dat wordt hier dus in de constructor van
         * het frame gedaan, direct na initComponents.
         */
        groupButton();
    }
    /*
     * Dit zorgt ervoor dat de radioknoppen samengevoegd worden
     * tot één groep zodat slechts één van de groep geselecteerd
     * kan worden.
     */
    private void groupButton( )
    {
       ButtonGroup bg1 = new ButtonGroup( );
       bg1.add(radCredit);
       bg1.add(radPayPal);
       bg1.add(radiDeal);
    }
                      

    private void cmdEndActionPerformed(java.awt.event.ActionEvent evt)
    {                                      
        // End the application
        System.exit(0);
    }                                     

    private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
    {                                        
        // Prompt which choice has been made:
        String radioText = "";
        if(radCredit.isSelected())
        {
            radioText = radCredit.getText();
        }
        if(radiDeal.isSelected())
        {
            radioText = radiDeal.getText();
        }
        if(radPayPal.isSelected())
        {
            radioText = radPayPal.getText();
        }
       
        JOptionPane.showMessageDialog( (Component) evt.getSource(), radioText );
    } 


Dit kan ook via de Netbeans IDE gerealiseerd worden.

Men brengt eerst de verschillende radiobuttons aan en een 'Button Group' element.
Vervolgens kan men van elke radiobutton via de 'Properties' aangeven dat deze radiobutton bij een bepaalde groep hoort.






Checkbox voorbeeld.


Hier wordt het gebruik van checkboxen getoond.

 
private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
{                                        

        // TODO add your handling code here:
        String output = "You have chosen:";
        if (chkJava.isSelected())
        {
            output = output + "\nJava";
        }
        if (chkVB.isSelected())
        {
            output += "\nVisualBasic";
        }
        if (chkCplus.isSelected())
        {
            output +="\nC++";
        }
        if (chkFortran.isSelected())
        {
            output +="\nFortran";
        }
        txtKeuze.setText(output);
       
}

Layout met checkboxen


Werkend programma


Picture voorbeeld.


Het onderstaand programma plaatst een foto in een label.
Deze foto is echter te groot en moet dus opgeschaald worden zodat hij wel in de labelbox past
 Het programma direct na opstarten.
import java.awt.Image;
import javax.swing.Icon;
import javax.swing.ImageIcon;

private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
{
        // Get the width and height of the label and ajust the picture accordently
        int hoogte, breedte;
        Icon plaatje;
       
        hoogte = lblPicture.getHeight();
        breedte = lblPicture.getWidth();
       
        // druk deze waarden af op het formulier
        lblHeight.setText("Height = " + hoogte);
        lblWidth.setText("Width = " + breedte);
       
        // afmetingen van de foto?
        plaatje = lblPicture.getIcon();
        Image img = ((ImageIcon) plaatje).getImage();
        ImageIcon icon = new ImageIcon(img.getScaledInstance(breedte, hoogte,
                                       Image.SCALE_AREA_AVERAGING));
       
        // plaats nu de geschaalde image in de label
        lblPicture.setIcon(icon);
}


Tijdens het maken van de GUI  is wel aangegeven welke foto gebruikt moet worden.
Het systeem kopieërt dit bestand naar de subdirectory 'Resources' van het project.




Combobox en listbox voorbeeld 1.


Hier wordt het gebruik van combo- en listboxen getoond.
De inhoud van een listbox wordt benaderd via een zogenaamde 'list model'.  Een list model is een speciaal object dat sterk lijkt op een arraylist en dat gebruikt kan worden om data toe te voegen of te verwijderen uit een listbox.  Ook is het mogelijk om op te vragen hoeveel elementen in een listbox staan of welk element van de listbox geselecteerd is.
Het is mogelijk je eigen list model class te schrijven, maar we beginnen eenvoudig door gebruik te maken van een 'DefaultListModel'. In deze DefaultListModel zijn bijvoorbeeld methoden als 'addElement( )', 'insertElementAt( )', 'remove( )', removeElementAt( )', 'size( )', en vele andere gedefinieerd.
Algemene werkwijze:
  • breng in je GUI een listbox aan; bijvoorbeeld lstMyListBox;
  • definieer een listmodel; bijvoorbeeld private DefaultListModel MyModel = new DefaultListModel();
  • koppel de listmodel aan de listbox m.b.v. de methode 'setModel( )'; bijvoorbeeld lstMyListBox.setModel(MyModel);
  • gebruik vervolgens de listmodel om elementen aan de listbox toe te voegen of te verwijderen of informatie op te vragen etc.
 
import java.awt.Component;
import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;

public class frmCombo extends javax.swing.JFrame
{
    /*
     * Aangezien de listModel in verschillende routines (achter verschillen
     * knoppen) gebruikt zal gaan worden, declareren we hem buiten alle routines
     * om => Global.
    */
    private DefaultListModel MyModel = new DefaultListModel();
   
    /**
     * Creates new form frmCombo
     */
    public frmCombo()
    {
        initComponents();
        /*
         * Nadat de (GUI)componenten zijn aangemaakt, kunnen we de DefaultListModel
         * koppelen aan de fysiek aanwezige list.
        */
        lstTest.setModel(MyModel);
    }

    private void cmdQuestionActionPerformed(java.awt.event.ActionEvent evt)
    {
        String selected_combo, selected_list;
       
        /* Display the selected item of the combo and listbox in a messagebox
         *
         * But beware: if nothing is selected in the listbox a
         * NullPointerException is thrown! => use try catch block
        */
        try
        {
            selected_combo = cbbTest.getSelectedItem().toString();
            selected_list = lstTest.getSelectedValue().toString();

            // we have the strings now display them in a messagebox
            JOptionPane.showMessageDialog((Component) evt.getSource(),
                    "In de ComboBox geselecteerd: " + selected_combo +
                    " In de Listbox geselecteerd: " + selected_list);
        }
        catch(NullPointerException ex)
        {
            JOptionPane.showMessageDialog(null,
                    " In de Listbox is niets geselecteerd!");
        }   
    }

    private void cmdAdd_endActionPerformed(java.awt.event.ActionEvent evt)
    {
        /*
         * Add an Item at the end of the listbox and combobox
         *
         * First get the item.
        */
        String input = txtInput.getText();
       
        /*
         * Get the number of elements in the list and in the combobox
        */
        int num_of_elements_list  = MyModel.getSize();
        int num_of_elements_combo = cbbTest.getItemCount();
       
        // Add item at the end of the combobox and select it.
        cbbTest.addItem(input);
        cbbTest.setSelectedIndex(num_of_elements_combo);
       
        /*
         * Add item at the end of the listbox via the listmodel and select it.
         * Also make sure the selected item is in view (visible in the list)
        */
        MyModel.addElement(input);       
        lstTest.setSelectedIndex(num_of_elements_list);
        lstTest.ensureIndexIsVisible(num_of_elements_list);
       
    }

    private void cmdClearActionPerformed(java.awt.event.ActionEvent evt)
    {
        // Clear the combo and listbox
        cbbTest.removeAllItems();
        MyModel.clear();
    }
   
    private void cmdAdd_at_PosActionPerformed(java.awt.event.ActionEvent evt)
    {
        /*
         * Add an Item at at a specified position of the listbox and combobox
         *
         * First get the item.
        */
        String input = txtInput.getText();
        int pos = (int)Double.parseDouble(txtPos.getText());
        cbbTest.insertItemAt(input, pos);
        MyModel.add(pos, input);   
    }
}



Direct na opstarten:



Na invoegen van 'Type input'




GUI 'mooier' maken (met o.a. HTML).

In Java is het mogelijk om bij bijvoorbeeld de inhoud van een label html-code te gebruiken. Zo kunnen we heel eenvoudig super- of sub-scripts in teksten aanbrengen.



Verder kunnen we een label 'misbruiken' als horizontale lijn.



Exceptionhandling voorbeeld (zie Deitel Hst.9)


Exceptionhandling is erg belangrijk om de gebruiksvriendelijkheid van een programma te verhogen
 Het programma en de eventuele foutmelding.
private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
{
        // Lets investigate whether the input is a genuine number
        double number;
       
        try
        {
            number = Double.parseDouble(txtInput.getText());
            lblOutput.setText("Input times 10 = " + number*10);
        }
        catch (NumberFormatException ex)
        {
            lblOutput.setText("Input is NOT a number!! Correct that please.");
            // Show a messagedialog
            JOptionPane.showMessageDialog((Component) evt.getSource(),
                "Input is NOT a number!! Correct that please.");
            txtInput.grabFocus();
           
        }
}



Indien de invoer niet omgezet kan worden in een getal ....



File I/O voorbeelden (zie Deitel Hst. 15)


Het onderstaand programma leest karakter voor karakter de data uit een aagewezen bestand in (inputbestand).
Het resultaat wordt in een text-area weergegeven en tevens wordt het één en ander naar een bestand met de naam inputbestand_copy weggeschreven.
 Het programma direct na opstarten.
import java.io.*;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;

private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
{
        String data;
        Integer c;
        char k;
       
        JFrame fileFrame = new JFrame();   // maak een nieuw frame    
        JPanel filePanel = new JPanel();   // maak een nieuw paneel    
        JFileChooser fileChooser = new JFileChooser();
       
        // Declareer en initialiseer de input- en outputstream
        FileReader filereader = null;
        FileWriter filewriter = null;
       
       
        fileFrame.getContentPane().add(filePanel);       
        filePanel.add(fileChooser);       
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);       
        int result = fileChooser.showOpenDialog(filePanel); 
        if (result != JFileChooser.APPROVE_OPTION)
        {           
            lblResult.setText("Verboden keuze");
        }
        else
        {
            File datafile = fileChooser.getSelectedFile();
            lblResult.setText("Gekozen bestand is: " + datafile.getName());
            try     // men is verplicht een try block te gebruiken.
            {
                //open input and outputstreams
                filereader = new FileReader(datafile.getAbsolutePath());
                filewriter = new FileWriter(datafile.getAbsolutePath()+ "_copy");
               
                txtArea1.setText(""); // clear the textarea
                while((c = filereader.read()) != -1)
                {
                    k = (char)c.intValue();
                    //write the character to the textarea
                    txtArea1.append(c.toString() + "\t" + k);
                    txtArea1.append(System.getProperty("line.separator"));
                    //write the character to file
                    filewriter.write(c.intValue());
                }
                filereader.close();
                filewriter.close();
            }
            catch (FileNotFoundException e)
            {
                lblResult.setText("Got an FileNotFoundException: "
                                                  + e.getMessage());
                //e.printStackTrace();
            } 
            catch (IOException e)
            {
                lblResult.setText("Got an IOException: "
                                       + e.getMessage());
                //e.printStackTrace();
            }
        }
    }


Selecteer m.b.v. het open popup window een bestand.


De ingelezen karakters worden getoond.




Het onderstaand programma leest per regel de data uit een aagewezen bestand in (inputbestand).
Het resultaat wordt in een text-area weergegeven.
 Het programma direct na opstarten.
import java.io.*;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;

private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
{
        String data;
       
        JFrame fileFrame = new JFrame();   // maak een nieuw frame    
        JPanel filePanel = new JPanel();   // maak een nieuw paneel    
        JFileChooser fileChooser = new JFileChooser();
       
        fileFrame.getContentPane().add(filePanel);       
        filePanel.add(fileChooser);       
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);       
        int result = fileChooser.showOpenDialog(filePanel); 
        if (result != JFileChooser.APPROVE_OPTION)
        {           
            lblResult.setText("Verboden keuze");
        }
        else
        {
            File datafile = fileChooser.getSelectedFile();
            lblResult.setText("Gekozen bestand is: " + datafile.getName());
            try     // men is verplicht een try block te gebruiken.
            {
                FileReader filereader = new FileReader(datafile.getAbsolutePath());
                BufferedReader bufferedreader = new BufferedReader(filereader);
                txtArea1.setText(""); // clear the textarea
                while((data = bufferedreader.readLine()) != null)
                {
                    txtArea1.append(data);
                    txtArea1.append(System.getProperty("line.separator"));
                }
                filereader.close();
            }
            catch (FileNotFoundException e)
            {
                lblResult.setText("Got an FileNotFoundException: "
                                                  + e.getMessage());
                //e.printStackTrace();
            } 
            catch (IOException e)
            {
                lblResult.setText("Got an IOException: "
                                       + e.getMessage());
                //e.printStackTrace();
            }
        }
}


Selecteer m.b.v. het open popup window een bestand.


De ingelezen tekt wordt getoond.






Adelborsten/cadetten database een eerste opzet.

Tot nu toe hebben slechts naar eenvoudige hulpprogramma's gekeken, maar nu gaan we een stap verder.
Stel men wil een programma schrijven waarmee de resultaten (behaalde tentamens) van de adelborsten/cadetten kan worden bijgehouden dan wel kan worden opgevraagd.
Deze data moet naar een bestand kunnen worden weggeschreven zodat de data niet verloren gaat, maar later weer kan worden opgehaald (ingelezen).

Voordat er ook maar één letter getypt is, moeten eerst de volgende vragen worden beantwoord (en globaal worden uitgewerkt): Vraagteken
  • Welke klassen en bijbehorende methoden heeft men nodig?

  • In welk formaat moet de data weggeschreven worden (protocol)?



Een mogelijke GUI wordt in onderstaande figuren getoond (let wel: niet zaligmakend!)

Direct na opstarten
Na inlezen van data
na selectie van een adelborst



Edit tab
Na selectie van een student kunnen zijn/haar gegevens gewijzigd worden
Na selectie van een vak kunnen de gegevens gewijzigd worden (wat is het nadeel van deze aanpak?)



Add tab
Voer de adelborst gegevens in
Voer de college gegevens in








Tekenen in Java met de NetBeans IDE.

Bij technische applicaties komt het regelmatig voor dat naast berekeningen ook tekeningen gemaakt moeten worden (resultaat wordt bijvoorbeeld weergegeven in een plot).
Aangezien het tekenen in Java-applicaties een ietswat omslachtig/lastig project is zal nu een eenvoudig voorbeeld worden uitgewerkt.

Hoe ziet de applicatie eruit?
We willen een afgeronde rechthoek tekenen.
De straal kan door de gebruiker worden ingesteld.
Nadat de startbutton is ingedrukt



JPanelform.

Het tekenen in Java gebeurt in een Panel (er zijn ook andere methoden, maar we beperken ons voorlopig to het paneel).
Echter in NetBeans gebruiken we NIET de standaard Panel uit het palette!

NIET de standaard Panel uit het palette gebruiken
Maar gebruik een zogenaamde JPanelFrom
Geef het paneel een bruikbare naam.




In feite wordt er een nieuwe klas aangemaakt en later gaan we een instantie van deze klas in ons programma gebruiken.

PaintComponent en Graphics

In de klas Panel zijn vele variabelen en methoden gedefinieerd .
(Index van de Java API met overzicht van alle standaardklassen is hier te vinden (http://docs.oracle.com/javase/7/docs/api/)).
Voor het tekenen is de belangrijkste methode: paintComponent


De methode paintCompnent moet worden overschreven (overridden) met onze eigen methode zodat we in het paneel kunnen tekenen.
Wanneer je de methode paintComponent van een JPanel overridet dan ontvang je een object van de klasse Graphics, meestal wordt aan dit object de naam g gegeven.
Dit object kan je gebruiken om te tekenen op het JPanel of hiervoor je eigen klasse gebruiken die overerft van JPanel.

Belangrijke methoden voor het Graphics-object, met de meest gebruikte argumenten:

methode omschrijving
drawLine(x1, y1, x2, y2) Teken een lijn
drawRect(x, y, width, height) Teken een rechthoek. x,y is de linkerbovenhoek
fillRect(x, y, width, height) Een gevulde rechthoek
drawOval(x, y, width, height) Ovaal
fillOval(x, y, width, height) Gevulde ovaal
drawArc( x, y, width, height, startAngle, arcAngle) Een cirkelboog.

Het centrum van de boog is het centrum van de rechthoek met linkerbovenhoek op positie x,y en opgegeven breedte en hoogte. De hoek die overspannen wordt geef je op in graden met een starthoek en eindhoek. O als hoekwaarde is de hoek op 3 uur. Een positieve waarde zorgt voor een hoekwaarde in tegenwijzerzin.

fillArc( x, y, width, height, startAngle, arcAngle) Een gevulde cirkelboog
setFont(Font f) Stel het lettertype in
drawString(String s, x, y) Toon een tekenreeks.
drawPolyline(int[] xPoints, int[] yPoints, nPoints) Teken een lijn die de aangegeven punten verbindt.De eindpunten worden niet automatisch gesloten. Je kan geeft ook het aantal te tekenen punten op.
drawPolygon( int[] xPoints, int[] yPoints, nPoints) Teken een lijn die de aangegeven punten verbindt en sluit de eindpunten.
fillPolygon( int[] xPoints, int[] yPoints, nPoints) Opgevulden Polygon.
drawPolygon(poly) Hier geef je een Polygon-object mee aan de methode drawPolygon. Op die manier kan je de polygoon eerste samenstellen vanuit code:
Polygon poly = new Polygon();  
//punt toevoegen aan de Polygoon
poly.addPoint(x, y);
. . .
g.drawPolygon(poly);

Dit kan je ook gebruiken bij fillPolygon.

Methoden van het JPanel

Aansluitend bij bovenstaande tabel kan je een aantal methoden toepassen op het JPanel (of een subklasse hiervan).
methode beschrijving
setPreferredSize(new Dimension(width, height)) Stel de dimensies in van het Canvas
setBackground(Color c); Stel de achtergrondkleur in.
setForeground(Color c); Stel de voorgrondkleur in (kleur van de pen).
getVisibleRect() Levert een Rectangle-object met een width en height-eigenschap om de breedte en hoogte van het tekenoppervlak te kennen
getWidth() Breedte van het tekengebied
getHeight() Hoogte van het tekengebied

Verder met NetBeans IDE

Nu moet de code van het aangemaakte JPanelForm (pnlMyPanel) worden aangepast.

Originele tekst
Onze bewerking
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Les;

/**
 *
 * @author n00i1j3
 */
public class pnlMyDrawing extends javax.swing.JPanel {

    /**
     * Creates new form pnlMyDrawing
     */
    public pnlMyDrawing() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>
    // Variables declaration - do not modify
    // End of variables declaration
}
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Les;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

/**
 *
 * @author n00i1j3
 */
public class pnlMyDrawing extends javax.swing.JPanel {
    private int radius;
   
    /**
     * Creates new form pnlMyDrawing
     */
    public pnlMyDrawing() {
        initComponents();
    }
   
    /**
     * overriden van de standaard paintComponent methode zodat we onze teken
     * commando's toe kunnen voegen.
     */
    @Override
    public void paintComponent(Graphics g)
    {

        super.paintComponent(g);
        setBackground(Color.green);
       
        // get the size of the drawingArea
        Dimension d = getSize() ;

        // draw a rounded black rectangular frame in the Panel
        g.setColor(Color.black) ;
        g.drawRoundRect(2, 2, d.width - 5, d.height - 5, radius, radius) ;
    }
   
    /*
     *  Methode om de afrondingsstraal in te stellen
     */
    public void setRadius(int r)
    {
        this.radius = r;
    }

   
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>
    // Variables declaration - do not modify
    // End of variables declaration
}

Compileren van de eigen Paneel.


Voordat de eigen paneel gebruikt kan worden in een applicatie moet deze eerst gecompileerd worden. Klik daartoe met de rechtermuistoets op de JPanel in het Projectvenster. Nadat het paneel gecompileerd is kan deze met de muis naar het formulier gesleept worden (net zoals we dat ook doen met standaard elementen vanuit de Palette).
Het resultaat is in onderstaand figuur weergegeven.
Let wel de naam van het object (instantie van pnlMyDrawing) wordt door het systeem ingesteld op: plnMyDrawing1




Met de rechtermuistoets kan weer gekozen worden om deze naam te veranderen.
Kies een logische naam die in de applicatie gebruikt gaat worden (in dit voorbeeld heb ik gekozen voor de naam: TekenGebied)




Maak de GUI van de applicatie verder af.
Ik heb o.a. een tekstveld toegevoegd waarin de gebruiker een waarde voor de afrondingstraal kan invoeren en natuurlijk een startknop om het geheel op te starten.
De namen van de elementen zijn ook weergegeven.

De code van onze applicatie wordt nu:
private void cmdStartActionPerformed(java.awt.event.ActionEvent evt) {
        // Haal de ingevoerde radius op
        int myRadius = (int)(Double.parseDouble(txtRadius.getText()));
       
        // Geef de ingevoerde radius door
        TekenGebied.setRadius(myRadius);
        TekenGebied.repaint();
    }


Resumerend:

Om een toepassing te maken met NetBeans IDE waarbij een subklasse van JPanel gebruikt wordt voor het maken van een tekening gaan we als volgt te werk:

  1. We starten een nieuw project via de Project Manager;
  2. kies new > JFrame Form ;
    Geef als naam bijvoorbeeld FiguurApp en druk finish;
  3. kies new > JPanel Form;
    Geef als naam tekenPaneel en druk finish;
  4. Override in de code van tekenPaneel de methode paintComponent:
    protected void paintComponent(java.awt.Graphics g) {
    super.paintComponent(g);
    ...uw tekenopdrachten...
    }
  5. Vul de nodige tekenopdrachten aan in paintComponent van tekenPaneel;
  6. Compileer tekenPaneel;
  7. Rechtsklik tekenPaneel kies copy,  en paste in FiguurApp of sleep het tekenPaneel naar het formulier.
  8. Vul de nodige opdrachten aan in FiguurApp
  9. Build en voer FiguurApp uit

Interactief tekenen.

In het volgend voorbeeld gaan we de eerder behandelde tekenopdrachten toepassen op door de gebruiker aangeleverde data.
Ons voorbeeld applicatie heeft onderstaand GUI.


We zien hier een applicatie die bestaat uit een tekenvlak (zwarte gedeelte), waarin met de muis punten kunnen worden ingevoerd.
Met de linkermuistoets worden nieuwe punten ingevoerd en met de rechtermuistoets wordt de invoer beeindigd.
De coördinaten van het eerste punt van de lijn worden getoond.

Voor zo'n applicatie moeten de volgende zaken afgehandeld worden:
  • een tekenoppervlak (JPanel Form);
  • een mouse click event;
  • onderscheid maken tussen linkermuis- of een rechtermuisklik;
  • coördinaten vanuit tekenpaneel naar formulier doorgeven.



Deze applicatie bevat de volgende klassen:
  1. Line class;
  2. TekenCanvas class
  3. frmMouse class
ad 1. Line class.
Elke lijn bevat twee punten (standaard Point objects).
Definitie  line class
import java.awt.Point;

/**
 *
 * @author raho
 */
public class Line
{
    private Point begin, end;
   
    // constructor
    public Line(Point a, Point b)
    {
        begin = a;
        end   = b;
    }
   
    // public methods
    public Point get_startpoint()
    {
        return begin;
    }
    public Point get_endpoint()
    {
        return end;
    }
}


ad2. TekenCanvas class
Dit is de definitie van het paneel waarop met de muis getekend gaat worden. De 'evt.getButton()' methode kan gebruikt worden om na te gaan welke muistoets de gebruiker heeft ingedrukt.

Code van de TekenCanvas class
import java.awt.Color;
import java.awt.Point;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;


/**
 *
 * @author raho
 * Aangezien we ook de eerder getekende lijnen zichtbaar willen houden,  moeten
 * we die opslaan zodat de gegegevens bij elke repaint() commando opnieuw
 * kunnen worden opgehaald. We maken daarom gebruik van een class Line en slaan
 * deze gegevens op in een List.
 *
 * Het blijkt dat je via de evt.getButton() op kunt vragen welke muistoets
 * ingedrukt is geweest. Hierbij geldt:
 * 1. = linkermuistoets
 * 3. = rechtermuistoets
 *
 */
public class TekenCanvas extends javax.swing.JPanel {
    // private variabelen van TekenCanvas
    private Point currentPosition, startPoint, endPoint;
    private List<Line> lijnen = new ArrayList<Line>();  //list om alle lijnen in op te slaan
    private frmMouse parentframe;
    private int muistoets;
    // default constructor van TekenCanvas
    /**
     * Creates new form TekenCanvas
     */
    public TekenCanvas() {
        currentPosition = null;
        startPoint = null;
        endPoint = null;
        initComponents();
    }

    public void setParentFrame(frmMouse frame)
    {
        /*
         * Met deze methode die vanuit het 'parent window' wordt aangeroepen
         * wordt een link naar het parent window gelegd.
         */
       parentframe = frame;      
    }
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                         
    private void initComponents() {

        setBackground(new java.awt.Color(0, 0, 0));
        setForeground(new java.awt.Color(255, 255, 255));
        setCursor(new java.awt.Cursor(java.awt.Cursor.CROSSHAIR_CURSOR));
        addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                formMouseClicked(evt);
            }
        });
        addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                formMouseMoved(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>
                      
    // methoden van TekenCanvas
    private void formMouseClicked(java.awt.event.MouseEvent evt) {                                 
        // print which mousebutton has been pressed
        // System.out.println("Mousebutton " + evt.getButton() + " has been pressed");
        muistoets = evt.getButton();
        if(muistoets == 1)
        {
            /*
             * Left mousebutton has been pressed.
             * Pass the coordinates to the parentframe.
             */
            if (startPoint == null)
            {
                startPoint = evt.getPoint();
                System.out.println(startPoint);
                parentframe.setCoordinates(startPoint.x, startPoint.y);
            }
            else
            {
                endPoint = evt.getPoint();
                System.out.println(endPoint);
                Line current_line = new Line(startPoint, endPoint);
                lijnen.add(current_line);
                System.out.println("Number of lines in the arraylist is: " + lijnen.size());
                repaint();
            }
        }
        else
        {
            /*
             * Right mousebutton has been pressed.
             * Stop this drawing sequence.
             */                         
            endPoint   = null;
            repaint();
        }     
    }                                

    private void formMouseMoved(java.awt.event.MouseEvent evt) {                               
        //
        // Draw a line from startPoint to current location of the mouse
        if (startPoint != null)
        {
            currentPosition = evt.getPoint();
            repaint();
         }
    }                              

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Line lijn : lijnen)
        {
            g.drawLine(lijn.get_startpoint().x, lijn.get_startpoint().y,
                       lijn.get_endpoint().x, lijn.get_endpoint().y);
        }
        if (startPoint != null && endPoint != null )
        {  
            startPoint =  endPoint;
        }
        if(startPoint != null & muistoets == 1)
        {
            g.drawLine(startPoint.x, startPoint.y,
                       currentPosition.x, currentPosition.y);
        }
        if(startPoint != null & muistoets == 3)
        {
            System.out.println("Rightmousebutton pressed; end drawing sequence!");
            startPoint = null;
        }
    }
   
   
    // Variables declaration - do not modify                    
    // End of variables declaration                  
}


ad3. frmMouse
Dit is het hoofdprogramma. Op dit formulier wordt o.a. een paneel van het type 'TekenCanvas' aangebracht. Als de gebruiker met de muis in dit paneel klikt worden de lijnen getekend.

Code van de frmMouse class
/**
 *
 * @author raho
 *
 * Om een connectie te maken tussen het tekenpaneel en dit formulier (m.a.w
 * tussen drawingArea en frmMouse) schrijven we in TekenCanvas een extra methode
 * -setParentFrame-. Deze methode roepen we vanuit de constructor van dit frame
 * aan. Hiermee is een mogelijkheid gecreëerd om vanuit het tekenpaneel data naar
 * dit formulier te zenden.
 */
public class frmMouse extends javax.swing.JFrame {

    /**
     * Creates new form frmMouse
     */
    public frmMouse() {
        initComponents();
        drawingArea.setParentFrame(this);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                         
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        lblX = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        lblY = new javax.swing.JLabel();
        cmdEnd = new javax.swing.JButton();
        drawingArea = new Les.TekenCanvas();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("The Mouse 2 application");
        setAlwaysOnTop(true);

        jLabel1.setText("X = ");

        lblX.setBackground(new java.awt.Color(255, 0, 0));
        lblX.setText("--");
        lblX.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0), 2));

        jLabel2.setText("Y = ");

        lblY.setBackground(new java.awt.Color(255, 0, 0));
        lblY.setText("--");
        lblY.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0), 2));

        cmdEnd.setText("Exit");
        cmdEnd.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cmdEndActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout drawingAreaLayout = new javax.swing.GroupLayout(drawingArea);
        drawingArea.setLayout(drawingAreaLayout);
        drawingAreaLayout.setHorizontalGroup(
            drawingAreaLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 286, Short.MAX_VALUE)
        );
        drawingAreaLayout.setVerticalGroup(
            drawingAreaLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 0, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(drawingArea, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(lblX, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(lblY, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(cmdEnd, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel1)
                            .addComponent(lblX))
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel2)
                            .addComponent(lblY))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 201, Short.MAX_VALUE)
                        .addComponent(cmdEnd))
                    .addComponent(drawingArea, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );

        getAccessibleContext().setAccessibleName("Interactive drawing");

        pack();
    }// </editor-fold>                       

    private void cmdEndActionPerformed(java.awt.event.ActionEvent evt) {                                      
        // End the application
        System.exit(0);
    }                                     

    public void setCoordinates(int X, int Y)
    {
        lblX.setText("" + X);
        lblY.setText("" + Y);
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(frmMouse.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(frmMouse.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(frmMouse.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(frmMouse.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new frmMouse().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify                    
    private javax.swing.JButton cmdEnd;
    private Les.TekenCanvas drawingArea;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel lblX;
    private javax.swing.JLabel lblY;
    // End of variables declaration                  
}




Abstract classe ofwel het generieke model (zie Deitel Hst. 10)

Tot nu toe hebben we gewerkt met 'concrete' klassen d.w.z. klassen volgens welke een object  gemaakt kan worden (instantie).
Denk bijvoorbeeld aan de klasse Persoon of Cilinder. We hebben echte instanties van deze klassen gemaakt.
Er zijn ook klassen die alleen ontwikkleld zijn zodat andere klassen hier vanaf geleid kunnen worden. Dit zijn abstracte klassen.
Van een abstracte klas kunnen geen instanties (objecten) gemaakt worden.

Logische vraag is natuurlijk ..... wat hebben we er dan aan???

Vraagje: Als je een nieuwe mobieltje gaat kopen welke aspecten zijn dan belangrijk?
  • de grootte;
  • de kleur;
  • de snelheid;
  • de ergonomie;
  • wat voor soort battery zit erin (hoe lang kan het apparaat zonder oplader)
Je bent waarschijnlijk niet zo geïnteresseerd in de chips die bij de fabricage gebruikt zijn ..... Voor een fabrikant zijn deze echter zeer belangrijk.
Als hij elders (of later in de tijd) goedkopere chips kan gebruiken kan zijn winstmarge vergroot worden zonder dat de gebruikers iets van de veranderingen merken (datahiding).

Als gebruiker ben je meer geïnteresseerd in wat en niet zo zeer in hoe.

Samenvattend:

Grote voordeel van abstracte klasse = onderhoudbaarheid

Als men twee klassen heeft die voor 90% hetzelfde doen, kan men die 90% in een abstracte klasse volledig definiëren en de overige 10% abstract laten. Vervolgens worden vanuit deze 'super class' twee subklassen afgeleid (extenden = specialisatie) en binnen deze twee klassen worden nu de resterende 10%  gedefinieerd (ieder met hun eigen specifieke eigenschappen).
90% van de code wordt dus slechts éénmaal ingetypt en nog belangrijker bij wijzigingen hoef je waarschijnlijk slechts op één plaats de code aan te passen!!

Vaste lichamen = solids

Beschouw als voorbeeld drie dimensionale geometrische lichamen (in het engels: Solids).
Hierbij kan men denken aan kubussen, bollen en cilinders. Deze geometrische lichamen hebben enkele gemeenschappelijke eigenschappen zoals: volume en omspoeld oppervlak.
Het is dus mogelijk een gemeenschappelijke super klas Solid te definiëren waarvan elk van de afzonderlijke subklassen (blok, bol of cilinder) kunnen erven .

                                   Solid                                                               super klas
                                 /    |     \
                              /       |        \
                           /          |           \
                        /             |              \
                 Blok           Bol             Cilinder                                        sub klassen



Als we deze eigenschappen (volume en oppervlak) in de klas Solid definiëren, hebben we een keuze: gebruiken we daarvoor variabelen of methoden (functies).



Het ligt natuurlijk voor de hand om methoden te definiëren waarmee de lichamen hun eigen volume/opp kunnen berekenen.
Als we gebruik zouden maken van (private) variabelen dan zou de gebruiker zelf de volume/opp moeten uitrekenen en moeten invoeren.

Maar de volgende vraag die nu meteen naar boven komt is: hoe moeten deze methoden eruit zien?
De formule voor het berekenen van de volume van een kubus ziet er heel anders uit dan het berekenen van de bol-volume zoals in onderstaande tabel is weergegeven.


Eigenschappen
Omspoeld oppervlak
Volume
Blok lengte: L
breedte: B
hoogte: H
 2 * { ( L*B) + (L*H)  + (B*H) }
 L*B*H
Bol
straal: R
 4 * * R2
 (4/3) * * R3
Cilinder
straal: R
hoogte: H
 2 * { (¶*R*H) + * R2}
 H * * R2

Merk op dat in de verschillende formules gebruik gemaakt wordt van eigenschappen die niet gemeengoed zijn van alle lichamen.
Zo heeft een bol alleen een straal en geen hoogte noch lengte welke wel noodzakelijk zijn voor het berekenen van het oppervlak en volume van een blok.
Deze eigenschappen behoren dus tot een specifieke klas maar niet tot de meer algemene klas Solid.

We kunnen zeggen dat Solid een abstracte klas is met twee abstracte methoden (volume, en surfaceArea); beide methoden hebben geen argumenten en retourneren een double waarde:

Public abstract class Solid
{
    public abstract double surfaceArea();
    public abstract double volume();
}


Een abstracte klasse wordt aangegeven m.b.v. het sleutelwoord 'abstract'

Merk op dat hier de inhoud van de methoden NIET wordt gegeven (dat kunnen we ook niet), alleen de zgn. handtekening (signature) van de functies wordt gespecificeerd.
Het zal nu ook duidelijk zijn waarom er geen instantie van een abstracte klas kan worden gemaakt (object).


Solid a = new Solid;
double Result1 = a.surfaceArea();
double Result2 = a.volume();



Totaal  zinloos

We kunnen nu echter wel de subklassen Blok, Bol en Cilinder definiëren uitgaande van Solid

Een blok is een solid

public class Cubiod extends Solid
{
    private double height, breadth, length;
    public Cubiod()
    {
        length = 0.0;
        breadth = 0.0;
        height = 0.0;
    }

    public Cubiod(double l, double b, double h)
    {
        length = l;
        breadth = b;
        height = h;
    }

    @Override
    public double volume()
    {
        return(length*breadth*height);
    }
    @Override
    public double surfaceArea()
    {
        return( 2*(length*breadth + length*height + breadth*height));
    }
}

Een bol is een solid

public class Sphere extends Solid
{
    private double radius;
    public Sphere()
    {
        radius = 0.0;
    }
    public Sphere(double r)
    {
        radius = r;
    }
    @Override
    public double volume()
    {
       return( (4.0/3.0) * Math.PI * Math.pow(radius, 3.0));
    }
    @Override
    public double surfaceArea()
    {
        return(4.0 * Math.PI * Math.pow(radius, 2.0));
    }
}

Een cilinder is een solid

public class Cylinder extends Solid{
    private double radius, height;
    public Cylinder()
    {
        radius = 0.0;
        height = 0.0;    
    }
    public Cylinder(double r, double h)
    {
        radius = r;
        height = h;    
    }
    @Override
    public double volume()
    {
       return( Math.PI * Math.pow(radius, 2.0) * height);
    }
    @Override
    public double surfaceArea()
    {
        return(2.0 * (Math.PI * Math.pow(radius, 2.0) +
                       Math.PI * radius * height));
    }
}

We kunnen nu een eenvoudige applicatie maken om e.e.a. uit te testen. In onderstaand tabel wordt een voorbeeld  getoond.


private void cmdStartActionPerformed(java.awt.event.ActionEvent evt)
   {
        NumberFormat Dec2 = new DecimalFormat("#0.00");
        // Get the user-input and do something with it

        double lengte = Double.parseDouble(txtLengte.getText());
        double breedte = Double.parseDouble(txtBreedte.getText());
        double hoogte = Double.parseDouble(txtHoogte.getText());
        
        Solid aSolid = new Cubiod(lengte, breedte, hoogte);
        txtOpp.setText("" + aSolid.surfaceArea());
        txtVolume.setText("" + aSolid.volume());
    }

Theoretisch voorbeeld

We hebben 1 abstracte klasse die we 'Gegevens' noemen, we kunnen onze gegevens echter op verschillende manieren opslaan, in een database en in een bestand. Om toegang tot de gegevens te verkrijgen zal dus óf een bestand óf een database moeten worden geopend.
We extenden dus onze 'Gegevens'-klasse en krijgen twee nieuwe klasse: 'GegevensDB' en 'GegevensBestand'. Deze klasse doen hetzelfde (ze leveren ons gegevens die we nodig hebben in ons programma, maar ze doen dit op verschillende manieren).

In onze abstracte klasse hebben we een array, en een aantal get/set-methods, deze zijn voor beide hetzelfde (we hebben immers dezelfde gegevens). Daarnaast maken we nog een abstracte method leesGegevens(), deze is voor beide anders, de ene leest zijn gegevens uit een database, de andere uit een bestand.

In onze twee 'final' klasse definiëren we nu de method leesGegevens(). Nu lijkt het gebruik van de abstracte method nog zinloos maar kijk:
In ons programma kunnen we nu het volgende doen:

Gegevens mijnGegevens; // we hebben hier een variabele (mijnGgevens) gemaakt van het type Gegevens, we hebben de klasse NIET geinstancieerd!

/*
 * Nu kunnen we verder in de code bepalen of we gegevens uit een database willen of we deze gegevens uit een bestand willen:
 *
Als we gegevens uit de database willen doen we dit:
 */

mijnGegevens = new gegevensDB( );

// Willen we de gegevens uit het bestand dan doen we dit

mijnGegevens = new gegevensBestand( );

/*
 * Nu willen we de gegevens gaan inlezen, we gebruiken de method leesGegevens( ) hiervoor,
 * nu hoeven wij ons niet meer aan te trekken van waar de gegevens komen, we roepen gewoon de method leesGegevens( ) aan,
 * als we eerder gekozen hebben voor gegevensBestand zal de method uit GegevensBestand aangeroepen worden en worden de gegevens uit een bestand gehaald,
 * idem voor de database.
 */

mijnGegevens.leesGegevens( );

/*
 * Hier kunnen we met de gemeenschappelijke get-methods gegevens uit onze klasse halen.
 * Dit mag omdat GegevenDB en GegevensBestand child-klasse zijn van gegevens.

 */





Verschillende type methoden

In Java komen we in principe 4 verschillende typen van methoden tegen:

Interfaces (zie Deitel § 10.9)

Het zal jullie wel opgevallen zijn dat in al onze voorbeelden een subclass altijd maar één superclass heeft (denk aan Militair of Student, die beide afgeleid zijn van Persoon). Er is dus altijd een hierarchische structuur.
Bij sommige talen is het mogelijk dat een subclass eigenschappen erft van meerdere ouders  (denk aan een nucleaire onderzeeër die zou eigenschappen kunnen erven van nucleaire motoren en van onderzeeërs)

Java staat echter alleen enkelvoudige erfenissen toe.

Om deze beperking echter te kunnen omzeilen maakt men in Java gebruik van interfaces.
Met een interface definiëren we het gedrag (middels een set van methoden en constanten) die men logischerwijs van verschillende klassen mag verwachten.
Een interface in de programmeertaal Java is een specifieke vorm van een abstracte klasse, namelijk één waarin alleen ongedefinieerde methoden en constanten in voorkomen.

Een klasse kan een interface implementeren met behulp van het keyword implements (vergelijkbaar met extends voor overerving) waarna de ongedefinieerde methoden van de interface in die klasse gedefinieerd moeten worden.
Een klasse die een interface implementeert maar die niet alle methoden definieert, kan omgezet worden in een abstracte klasse door het sleutelwoord abstract toe te voegen - de ongedefinieerde methoden moeten dan in een subklasse gedefinieerd worden.
 
Aangezien interfaces abstract zijn, is het niet mogelijk objecten te maken van een interface. Het sleutelwoord abstract hoeft niet voor de ongedefinieerde methoden gezet te worden aangezien alle methoden in een interface per definitie abstract zijn.
 
Een klasse kan meerdere interfaces implementeren maar alleen van één klasse (rechtstreeks) overerven.
Een verschil met abstracte klassen is dat een abstracte klasse wel gedefinieerde methoden kan bevatten maar een interface bevat alleen ongedefinieerde methoden.
Verder kan een interface niet andere interfaces implementeren maar wel overerven van een andere interface waardoor subinterfaces gemaakt kunnen worden.

Een interface dient om een bepaalde 'functionaliteit' te bewerkstelligen (definiëren). Voor deze functionaliteit zijn bepaalde methoden (en properties) nodig.
De signature van deze methoden staan gedefinieerd in de interface en wanneer men deze interface implementeerd, moet men op dat moment de inhoud van de beoogde methoden geven.
Zo kan men verschillende object toch gelijke functionaliteit geven. In Java bestaan er bijvoorbeeld interfaces om objecten te sorteren (een object is bijvoorbeeld een standaard String, of een standaard Integer of een  instantie van een zelf gedefinieerd klas). In deze interfaces vinden we de methode compareTo. Als men nu een array of collectie van deze objecten wilt sorteren, zal Java controleren of een object groter is dan een ander aan de hand van hetgeen in de methode compareTo is gedefinieerd. M.a.w. de 'overschreven' methode compareTo wordt aangeroepen.
Het is natuurlijk niet mogelijk om alle objecten op dezelfde manier te vergelijken. Als we Integers vergelijken, dan is 10 groter dan 2, maar als we Strings vergelijken is "2" groter dan "10" en hoe zouden we Personen met elkaar kunnen vergelijken?



Het ligt voor de hand om bij Personen, de leeftijd als criterium te nemen; hoe hoger de leeftijd, des te 'groter' de Persoon.
Een andere criterium is bijvoorbeeld de geboordtedatum; des te lager, des te 'groter' de Persoon.
Bij een Militair zou je iets met de rang kunnen doen.

Dus we zien hier dezelfde functionaliteit (sorteren) toegepast op totaal verschillende objecten via dezelfde interface.

Gebruik van interfaces in de praktijk.

Een interface in Java heeft de volgende vorm:
zichtbaarheid interface naamInterface [extends naamInterface, naamInterface, ...]
{
    declaraties van constanten
    declaraties van ongedefinieerde methoden
}
Een interface kan op de volgende manier gebruikt worden, waarbij de namen van meerdere interfaces door komma's gescheiden worden:
zichtbaarheid class naamKlasse implements naamInterface, naamInterface, ...
{
   implementaties van methoden in interface(s)
}

Interfaces kunnen gebruikt worden om abstractie toe te voegen aan het ontwerp van software.
Bepaalde informatie hoeft niet in het gehele programma bekend te zijn om de applicatie te kunnen laten functioneren.
 
Voorbeeld 1
 
We gaan uit van 2D-vormen zoals een ellips, cirkel, rechthoek, vierkant of driehoek.
We starten weer met het definiëren van een abstract class Shape, hieronder is e.e.a. in een hierarchie-plot schematisch weergegeven (slechts twee vormen)



 A Circle IS-A Shape

A Rectangle IS-A Shape

Definitie van de abstract class Shape
public abstract class Shape
{
   public abstract double area( );
   public abstract double perimeter( );
 
   public double semiperimeter( )
   {
      return perimeter( ) / 2;
   }
}



Er zijn hier twee abstract methoden gedefiniëerd die in de subclasses verder gespecificeerd moeten worden.




Eén 'gewonde' methode die in de subclasses gebruikt mag worden.
Definitie van de subclass Circle.
Hierin moeten de abstract methoden uit de superclass gespecificeerd worden
Definitie van de subclass Rectangle.
Hierin moeten de abstract methoden uit de superclass gespecificeerd worden
public class Circle extends Shape
{
   private double radius;

   public Circle( double rad )
   { radius = rad; }

   public double area( )
   { return (Math.PI * radius * radius); }

   public double perimeter( )
   { return (2 * Math.PI * radius); }

   public String toString( )
   { return ("Circle: " + radius); }
public class Rectangle extends Shape
{
   private double length;
   private double width;

   public Rectangle( double len, double wid )
   { length = len; width = wid; }

   public double area( )
   { return (length * width); }
 
   public double perimeter( )
   { return (2 * ( length + width )); }
 
   public String toString( )
   { return ("Rectangle: " + length + " " + width); }
 
   public double getLength( )
   { return length; }
 
   public double getWidth( )
   { return width; }

Uitrekbaar
So far so good, maar wat als we nu het geheel willen uitbreiden met een extra functionaliteit, bijvoorbeeld het uitrekbaar maken van elementen.
We zouden nu een tweede abstract class kunnen maken 'Stretchable' met daarin de abstract methode 'stretch'.

Het is duidelijk dat deze functionaliteit wel toepasbaar is voor bijvoorbeeld een rechthoek of ellips, maar zeker niet voor een cirkel of vierkant.
Grafisch zou e.e.a. er als volgt uit kunnen komen te zien.


Rectangle, Ellipse en Triangle zouden van beide abstract classes willen erfen ........ dit is echter verboden in Java!

Oplossing => gebruik een speciale abstract class: de interface

De interface is de ultieme abstract class in Java, het bestaat per definitie alleen uit public abstract methoden en public static final variabelen (die dus niet zo variabel zijn).

De Stretchable interface

/**
* Interface that defines stretch method to lengthen the longest
* dimension of a Shape
*/
public interface Stretchable
{
  void stretch( double factor );
}



Sleutelwoord is hier: interface

De methoden zijn per definitie public abstract dus dit hoeft men er niet meer bij te zetten (mag wel :-)


Definitie van de class rectangle wordt nu
public class Rectangle extends Shape implements Stretchable
{
    private double length;
    private double width;

    public Rectangle( double len, double wid )
    { length = len; width = wid; }
 
    @Override
    public double area( )
    { return length * width; }
 
    @Override
    public double perimeter( )
    { return 2 * ( length + width ); }
 
    @Override
    public String toString( )
    { return "Rectangle: " + length + " " + width; }
 
    public double getLength( )
    { return length; }
 
    public double getWidth( )
    { return width; }
   
    @Override
    public void stretch( double factor )
    {
        if( factor <= 0 )
        {
            throw new IllegalArgumentException( );
        }
        if( length > width )
        {
            length *= factor;
        }
        else
        {
            width *= factor;
        }
    }
   
}

Let op:
de superclass wordt 'ge-extends' en de interface wordt 'ge-implements' .

Per difinitie wordt indien van toepassing eerst het sleutelwoord 'extends' gebruikt en daarna pas het sleutelwoord 'implements'.


NetBeans eist de @Override  statement.







Voorbeeld 2
 
Stel dat een programma informatie kan laden van verschillende plekken, zoals een database, een XML-bestand of een tekstbestand.
Als de informatie geladen moet worden, zou men kunnen kijken welke situatie het geval is en vervolgens de bijbehorende code uitvoeren. Het is ook mogelijk om een interface hiervoor te gebruiken:

public interface InformatieLader
{
    public Informatie laadInformatie();
}
 
public class DatabaseLader implements InformatieLader
{
    public Informatie laadInformatie()
    {
        // haal de informatie uit een database
    }
}
 
public class XMLLader implements InformatieLader
{
    public Informatie laadInformatie()
    {
        // haal de informatie uit een XML-bestand
    }
}
 
public class TekstLader implements InformatieLader
{
    public Informatie laadInformatie()
    {
        // haal de informatie uit een tekstbestand
    }
}



Op het moment dat de informatie geladen moet worden, hoeft men alleen de methode laadInformatie() aan te roepen voor de beschikbare InformatieLader.
Op deze plek in het programma hoeft men dan niet te bepalen vanaf welke plek de informatie geladen wordt: er is een abstractie ingebouwd waardoor men zich nu niet hoeft bezig te houden met de exacte details van het laden van de informatie:


Informatie informatie = informatieLader.laadInformatie();


Vanaf welke plek de informatie geladen wordt, hangt af van welke InformatieLader gebruikt wordt. Het kan zijn dat dit op een hele andere plek in het programma bepaald wordt, bijvoorbeeld bij het inlezen van enkele configuratiebestanden.
Door een van de volgende regels te gebruiken, wordt een InformatieLader aangemaakt die de rest van het programma kan gebruiken:


InformatieLader informatieLader = new DatabaseLader(); // 1
InformatieLader informatieLader = new XMLLader();      // 2
InformatieLader informatieLader = new TekstLader();    // 3


Ook kan de werking van de rest van het programma aangepast worden door alleen die regel aan te passen (dat wil zeggen: door een andere InformatieLader te gebruiken, haalt de rest van het programma de informatie opeens vanaf een andere plek).


 

De Object class

Volgens de Java specificatie is elke klas die geen subclass is van een andere klas (it doesnot extends another class) per definitie een subclass van de klas Object. => elke klas is dus direct of indirect een subclass van Object!
De Object klas bevat vele methoden die we dus altijd kunnen gebruiken of overschrijven. Een bekende is toString dus als we onze eigen toString methode schrijven dan moet er in NetBeans altijd @Override voor (let op : hoofdletter O).


Timer Object

Tot nu toe hebben we ons beperkt tot het schrijven van programma's die 'event driven' zijn. D.w.z. pas nadat de gebruiker actie onderneemt (meestal het klikken op een startknop) gaat ons programma 'iets' doen.
Vooral bij het schrijven van spelprogramma's wil je echter dat de computer (onafhankelijk van de gebruiker) bepaalde acties uit gaat voeren. Hiervoor is het 'Timer object' ontwikkeld.
Zo'n Timer kan na een bepaalde tijd of na een bepaalde tijdsinterval 'afgevuurd' worden. En men kan definiëren welke commando's dan uitgevoerd moeten worden.

De Timer zit in de bibliotheek:  javax.swing.Timer (er zit ook een Timer gedefinieerd in de bibliotheek java.util, maar die wordt niet gebruikt bij GUI's).
De tijd bij zo'n timer wordt opgegeven in milli-seconden.

Het gebruik van een Timer laat zich het best uitleggen via een voorbeeld. Beschouw een programma waarbij de gebruiker een beginwaarde opgeeft (positieve integer) en vervolgens op de 'start' knop drukt.
Het programma gaat dan rustig aftellen tot nul.

GUI
Code




De startknop heeft als naam: cmdStart.

De invoer textbox heeft de naam txtInput.

De label  waarin wordt afgeteld heeft de naam: lblOutput.

Deze Timer wordt om de 300/1000 = 0.3 seconden afgevuurd.
private void cmdStartActionPerformed(java.awt.event.ActionEvent evt) {                                        
        counter = Integer.parseInt(txtInput.getText());
       
        // Start a Timer
        myTimer = new Timer(300,new ActionListener()
        {
           @Override
           public void actionPerformed(ActionEvent e)
           {
               //Hier moeten we dus definieren wat er moet gebeuren als de timer
               // afgevuurd wordt.
               counter--;
               lblOutput.setText("" + counter);
               if (counter == 0)
               {
                    myTimer.stop();
               }
           }
        });
        myTimer.start();
       
    }
Swing timers are very easy to use. When you create the timer, you specify an action listener to be notified when the timer "goes off". The actionPerformed method in this listener should contain the code for whatever task you need to be performed. When you create the timer, you also specify the number of milliseconds between timer firings. If you want the timer to go off only once, you can invoke setRepeats(false) on the timer. To start the timer, call its start method. To suspend it, call stop.




doClick

Het is ook mogelijk een knop (button) softwarematig in te drukken (i.p.v. met de muis).
De Class JButton heeft daartoe de methode doClick.

Beschouw het volgende voorbeeld (uitbreiding van de bovenstaande timer).


ppackage Les;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
import javax.swing.Timer;


public class frmSoft extends javax.swing.JFrame {
    //global variables
    private Timer myTimer;
    private int counter;
    /**
     * Creates new form frmSoft
     */
    public frmSoft() {
        initComponents();
    }
                                 

    private void cmdExitActionPerformed(java.awt.event.ActionEvent evt) {                                       
        System.exit(0);
    }                                      

    private void cmdStartActionPerformed(java.awt.event.ActionEvent evt) {                                        
        counter = Integer.parseInt(txtInput.getText());
       
        // Start a Timer
        myTimer = new Timer(500,new ActionListener()
        {
           @Override
           public void actionPerformed(ActionEvent e)
           {
               //Hier moeten we dus definieren wat er moet gebeuren als de timer
               // afgevuurd wordt.
               counter--;
               lblOutput.setText("" + counter);
               if (counter == 0)
                {
                    myTimer.stop();
                    int result = JOptionPane.showConfirmDialog(null,
                                               "Wilt u opnieuw beginnen?",
                                               "Herhalen?", JOptionPane.YES_NO_OPTION);
                    if (result == JOptionPane.YES_OPTION)
                    {
                            // druk de Herstart knop programatisch in
                            cmdStart.doClick();
                    }
                    else if(result == JOptionPane.NO_OPTION)
                    {
                        int result2 = JOptionPane.showConfirmDialog(null,
                                               "Wilt u het programma stoppen?",
                                               "Stoppen?", JOptionPane.YES_NO_OPTION);
                        if (result2 == JOptionPane.YES_OPTION)
                        {
                            // druk de stop knop programatisch in
                            cmdExit.doClick();
                        }
                        else
                        {
                            // do nothing
                        }
                    }
                }
           }
        });
        myTimer.start();
    }





Key Bindings

Kijk voor de officiële handleiding hier.

Om een applicatie te laten reageren op invoer vanaf het toetstenbord kan men gebruik maken van zgn. keylisteners of key binding.
Key binding heeft de voorkeur (keylisteners werken op een lager niveau).
Bij key bindings wordt gebruik gemaakt van de InputMap en ActionMap klassen.

In een InputMap worden toetsaanslagen verbonden met actienamen (String); bij een bepaalde toets hoort een bepaalde actienaam.
In een ActionMap wordt aangegeven welke actie hoort bij een specifieke actienaam.

Elke JComponen (JPanel, JTextField, etc) heeft één ActionMap en drie InputMaps. Deze InputMaps komen overeen met de volgende situaties:
In het navolgend voorbeeld wordt e.e.a. toegelicht.
We schrijven een applicatie die voor enkele toetsaanslagen aangeeft welke toets aangeslagen is.






Bij deze applicatie werken we weer met een JFrame (met naam FrmKey1), maar in dit JFrame plaatsen we een JPanel (hier met de naam pnlMyPanel) en van dat element gaan we de InputMap en ActionMap aanpassen.

Hieronder staan de belangrijkste items weergegeven. Download het volledige programma via de ELO.
package Les;

import java.awt.event.KeyEvent;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;

public class FrmKey1 extends javax.swing.JFrame {
    private  final int IFW = JComponent.WHEN_IN_FOCUSED_WINDOW;
    private final  InputMap myInputMap;
    private final  ActionMap myActionMap;  
   
    /**
     * Creates new form FrmKey1
     */
    public FrmKey1() {
        initComponents();
        myInputMap = pnlMyPanel.getInputMap(IFW);
        myActionMap = pnlMyPanel.getActionMap();
       
        // Geef nu aan welke keybordtoetsen afgevangen moeten worden
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "Space");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_0, 0), "Nul");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Escape");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "F1");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "Left");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "Right");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Up");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Down");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "A");
        myInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), "Num0");
       
        // Geef nu aan welke actie ondernomen moet worden
        myActionMap.put("Space", new MyDesiredAction(lblKeypressed, "The spacebar"));
        myActionMap.put("Nul", new MyDesiredAction(lblKeypressed, "The Nul key"));
        myActionMap.put("Escape", new MyDesiredAction(lblKeypressed, "The Escape key"));
        myActionMap.put("Enter", new MyDesiredAction(lblKeypressed, "The Enter key"));
        myActionMap.put("F1", new MyDesiredAction(lblKeypressed, "The F1 function key"));
        myActionMap.put("Left", new MyDesiredAction(lblKeypressed, "The Left arrow key"));
        myActionMap.put("Right", new MyDesiredAction(lblKeypressed, "The Right arrow key"));
        myActionMap.put("Up", new MyDesiredAction(lblKeypressed, "The Up arrow key"));
        myActionMap.put("Down", new MyDesiredAction(lblKeypressed, "The Down arrow key"));
        myActionMap.put("A", new MyDesiredAction(lblKeypressed, "The A key"));
        myActionMap.put("Num0", new MyDesiredAction(lblKeypressed, "The Numpad 0 key"));       
    }              
 
}

Om dit geheel te laten werken, is nog een laatste stap noodzakelijk ..... we moeten een actie schrijven! Hier met de naam: 'MyDesiredAction'
Een actie is (hoe kan het ook anders) in Java een Class, en wel een Class die erft van de abstract Class AbstractAction.

Zoals eerder verteld, moet je alle methoden van een abstracte klasse overschrijven als je daar van erft. Hier is er slechts één methode die overschreven moet worden: actionPerformed

package Les;

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JLabel;

public class MyDesiredAction extends AbstractAction
{
    JLabel myLabel;
    String text;
    MyDesiredAction(JLabel label, String t)
    {
        myLabel = label;
        text = t;
       
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        System.out.println(e.getActionCommand());
        myLabel.setText(text);
    }
   
}

We zien dus dat in de myInPutMap gedefinieerd wordt, dat de toets 'VK_SPACE' gekoppeld wordt aan de string "Space" en deze string wordt in myActionMap gekoppeld aan de actie new MyDesiredAction(lblKeypressed, "The spacebar").  D.w.z. er wordt een nieuwe instantie aangemaakt van de class MyDesiredAction met als invoerparameters lblKeypressed en de tekst "The spacebar".
Kijken we naar de definitie van de class MyDesiredAction dan zien we dat daar een constructor gedefinieerd is die twee invoerparameters gebruikt. De eerste parameter is van het type JLabel en de tweede is van het type String. Zodra een object van het type MyDesiredAction wordt aangemaakt, wordt automatisch de methode actionPerformed aangeroepen (uitgevoerd).