Grafiska gränssnitt, forts.

JPanel

Komponenten JPanel har inget eget innehåll men kan användas bl.a. till att fylla med andra komponenter. Man kan ställa in en layoutmodell för JPanel som skiljer sig från huvudfönstrets. Med JPanel kan man skapa en hierarki av grafiska element där olika delar är organiserade enligt olika layoutmodeller.

JCheckBox

En JCheckBox är en kryssruta som antingen kan vara vald eller inte. Metoden isSelected() används för att avgöra dess status.

JTextField

JTextField är en komponent för inmatning av enradig text. En ActionListener till en sådan komponent anropas då användaren har tryckt på enter. getText() ger aktuellt innehåll i rutan.

Egna komponenter och grafik

Genom att ärva existerade komponenter kan man modifiera dem, t.ex. förändra utseendet.

Vill man rita grafik, t.ex. diagram eller bilder så är det bra att utgå från JPanel eftersom man vill bestämma innehållet helt själv.

Alla komponenter har en metod som ritar innehållet varje gång detta behövs, paintComponent. Denna tar som argument ett objekt av typen Graphics som är en miljö för komponentens yta som tillåter grafiska operationer.

Man överlagrar (definierar en ny) uppritningsmetod

    @Override
    public void paintComponent(Graphics g) {
...

}

@Override är inte nödvändigt men rekommenderat för att göra det tydligt att man ersätter en metod i någon superklass. Mer om detta vid ett annat tillfälle.

I Graphics finns metoder för att rita linjer (drawLine), cirklar och andra figurer, bilder och text.

Om lyssnare till händelser ändrar på något som gör att en egen komponent behöver ritas om så anropar man repaint(). Man ska aldrig direkt anropa paintComponent. Detta görs av Swings egen loop som hanterar händelser, lyssnare och omritning av komponenter.

Input från mus och tangentbord

Om man vill hantera input från mus använder man en speciell lyssnare, MouseListener, och händelser, MouseEvent. En lyssnare kopplas till den komponent som ska hantera mushändelser. Positionen för musen anges relativt denna komponent. Detta är ett gränssnitt med många metoder för olika typer av händelser; mouseClicked, mouseMover etc. Är man bara intresserad av att hantera några få typer så kan man för bekvämlighets skull utgår från motsvarande adapter, MouseAdapter. Där har alla metoder getts en tom implementation och man behöver bara överskugga dem man vill använda.

För tangentbordshändelser finns på motsvarande sätt interfacet KeyListener och KeyEvent.

Tidsstyrda händelser

Ibland, t.ex. i spel, vill man att saker ska förändras bara av att tiden går, inte att användaren ger något input. För program som använder Swing kan man använda klassen Timer. Den har en konstruktor som tar en heltal som anger i millisekunder hur ofta den ska generera en händelse och en ActionListener som anropas.

Menyer

Till en JFrame kan man koppla en JMenuBar med metoden setJMenuBar. Till en JMenuBar kan man addera flera JMenu. Till en JMenu kan man addera flera JMenuItem.

Det går att skapa undermenyer, kortkommandon som automatiskt visas, ikoner, checkbox-alternativ i menyer och det mesta annat man ser i applikationer.

Actions

Ofta finns det flera sätt i GUIt att utföra ett visst kommando, t.ex. både en knapp och i menyerna. Det finns ett koncept Action som abstraherar ett kommando bort från hur användaren startat det. Samma Action kan startas på flera olika sätt. Action är ett interface som, liksom MouseListener, innehåller många metoder medan man ofta bara vill implementera en. Liksom MouseAdapter finns AbstractAction, en klass som låter definiera bara det nödvändiga.

För att säga ett en komponent, Button eller MenuItem, ska utföra en viss Action, använd metoden setAction. Knappar och menyalternativ som har en Action satt tar sin titel från denna, så tänk på att ställa in titeln på Action. Det finns en konstruerare för detta i AbstractAction.

Dialogfönster

Det finns några klasser och metoder i Swing för att enkelt visa dialogfönster, t.ex.:

Man kan också bygga egna dialogfönster genom att utgå från klassen JDialog.

Designmönstret Observer

Sättet att implementera interaktionen i ett GUI med händelser och lyssnare är besläktat med ett designmönster (design pattern) för OOP, nämligen Observer. Den går ut på att objekt kan ha två roller, Observable eller Observer. Observable-objekt representerar värden vars förändringar är intressant för Observer-objekt. Därför har Observable-objekt en lista med Observer-objekt. I denna lista kan objekt som vill veta när något ändras i Observable-objektets värde/tillstånd registrera sig. När Observable-objektet ändrar sitt tillstånd så anropas en metod i de registrerade Observer-objekten som hanterar förändringen.

Detta kan man implementera enkelt genom ett interface för Observer som specificerar en metod som ska anropas vid förändring, på samma sätt som t.ex. ActionEventListener som vi sett tidigare. Varje klass som ska vara Observable tillhandahåller metoder för att lägga till sig till och ta bort sig från listan av Observers.

PropertyChange

Ett exempel på designmönstret Observer är en mekanism som finns implementerad i de olika komponentklasserna i Swing. De egenskaper objekt av dessa klasser har, t.ex. bakgrundsfärgen, har enhetliga setters och getters, setBackground, getBackground.

Men man kan också i andra objekt få reda på när någon egenskap har förändrats. Detta genom att klassen som vill ha informationen implementerar PropertyChangeListener som har en metod propertyChange. Alla komponentklasser har metoder för att registrera och avregistrera lyssnare/observers som implementerar detta interface. De metoderna heter addPropertyChangeListener och removePropertyChangeListener.

När någon egenskap i komponent-objekt förändras så skapas en PropertyChangeEvent och alla lyssnare/observers anropas. En PropertyChangeEvent innehåller information om namnet på egenskapen som förändrats, samt egenskapens gamla och nya värde.