{"id":371,"date":"2011-11-03T12:36:33","date_gmt":"2011-11-03T10:36:33","guid":{"rendered":"http:\/\/www.kristiansborg.dk\/bibliotek\/?page_id=371"},"modified":"2011-11-03T14:09:50","modified_gmt":"2011-11-03T12:09:50","slug":"kapitel-3-swing-og-grafik","status":"publish","type":"page","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/","title":{"rendered":"Kapitel 3 Swing og grafik"},"content":{"rendered":"<div style=\"border: 1px solid red; color: red;\"><strong>Du l\u00e6ser en gammel bog<\/strong><\/p>\n<p>Den bog, du l\u00e6ser her, er fra 1998, og mange ting kan have \u00e6ndret sig siden da.<br \/>\nVi h\u00e5ber, at du stadig kan finde relevant information i den.<br \/>\nHvis du vil l\u00e6se aktuelle oplysninger om de avancerede dele af Java, anbefaler vi<br \/>\nbogen <a href=\"http:\/\/clk.tradedoubler.com\/click?p(197229)a(2029446)g(19172914)url(http:\/\/www.adlibris.com\/dk\/product.aspx?isbn=0132354799)\" target=\"_blank\">Core Java &#8211; Advanced Features<\/a><img decoding=\"async\" src=\"http:\/\/impdk.tradedoubler.com\/imp?type(inv)g(19172914)a(2029446)\" alt=\"\" \/><\/div>\n<p>De to forrige kapitler har gennemg\u00e5et de fleste af komponenterne i Swing. I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter.<\/p>\n<p>&nbsp;<\/p>\n<h1><strong>Ikoner<\/strong><\/h1>\n<p>&nbsp;<\/p>\n<p>Ikonerne er den mest grundl\u00e6ggende del af grafikken i Swing. Et ikon repr\u00e6senteres som en instans af en klasse, der implementerer interfacet Icon:<\/p>\n<p>&nbsp;<\/p>\n<p>public interface Icon<\/p>\n<p>{<\/p>\n<p>public int getIconHeight ();<\/p>\n<p>public int getIconWidth ();<\/p>\n<p>public void paintIcon (java.awt.Component, java.awt.Graphics, int, int);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Icon-interfacet implementeres blandt andet af klassen ImageIcon:<\/p>\n<p>&nbsp;<\/p>\n<p>public class ImageIcon extends Object implements Icon, Serializable<\/p>\n<p>{<\/p>\n<p>public java.awt.swing.ImageIcon();<\/p>\n<p>public java.awt.swing.ImageIcon(java.awt.Image);<\/p>\n<p>public java.awt.swing.ImageIcon(java.awt.Image, java.lang.String);<\/p>\n<p>public java.awt.swing.ImageIcon(java.lang.String);<\/p>\n<p>public java.awt.swing.ImageIcon(java.lang.String, java.lang.String);<\/p>\n<p>public java.awt.swing.ImageIcon(java.net.URL);<\/p>\n<p>public java.awt.swing.ImageIcon(java.net.URL, java.lang.String);<\/p>\n<p>public java.awt.swing.ImageIcon(byte[]);<\/p>\n<p>public java.awt.swing.ImageIcon(byte[], java.lang.String);<\/p>\n<p>&nbsp;<\/p>\n<p>public java.lang.String getDescription ();<\/p>\n<p>public int getIconHeight ();<\/p>\n<p>public int getIconWidth ();<\/p>\n<p>public java.awt.Image getImage ();<\/p>\n<p>public int getImageLoadStatus ();<\/p>\n<p>public java.awt.image.ImageObserver getImageObserver ();<\/p>\n<p>public synchronized void paintIcon (java.awt.Component, java.awt.Graphics, int, int);<\/p>\n<p>&nbsp;<\/p>\n<p>public void setDescription (java.lang.String);<\/p>\n<p>public void setImage (java.awt.Image);<\/p>\n<p>public void setImageObserver (java.awt.image.ImageObserver);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen har \u2013 som det ses \u2013 mange constructors. Mange af constructorerne tager en tekststreng med som parameter \u2013 det er en beskrivelse af ikonet. Den f\u00f8rste opretter et uinitialiseret objekt, mens de to n\u00e6ste opretter et ikon p\u00e5 baggrund af et billede. Dern\u00e6st kommer to constructors, der opretter et ikon p\u00e5 baggrund af en URL. De to sidste konverterer et byte-array til et ikon.<\/p>\n<p>ImageIcon-klassen best\u00e5r hovedsageligt af set- og get-metoder. Den mest interessante metode er nok getImageLoadStatus. Den kan bruges, hvis man indl\u00e6ser ikonet over en langsom forbindelse \u2013 for eksempel Internet. Funktionen returnerer en int, der angiver, om billedet er indl\u00e6st. De mulige returv\u00e6rdier, der er statiske konstanter i java.awt.MediaTracker, er:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>ABORTED<br \/>\nIndl\u00e6sningen af ikonet er blevet afbrudt.<\/li>\n<li>ERRORED<br \/>\nDer opstod en fejl under indl\u00e6sningen af ikonet.<\/li>\n<li>COMPLETE<br \/>\nIkonet er indl\u00e6st.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h2><strong>Brug af ikoner<\/strong><\/h2>\n<p>&nbsp;<\/p>\n<p>De forrige to kapitler har vist, hvordan man kan bruge de forskellige Swing-komponenter. Dette afsnit opsummerer p\u00e5 de to forrige kapitler og viser, hvordan man tilf\u00f8jer grafik til forskellige Swing-komponenter<\/p>\n<p>&nbsp;<\/p>\n<p><strong><em>Knapper<\/em><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>Ikonerne kan bruge flere forskellige steder. For eksempel beh\u00f8ver knapper ikke at v\u00e6re s\u00e5 kedelige. Man kan erstatte teksten med et ikon eller v\u00e6lge at have et ikon ved siden af teksten. Det angives alt sammen i Jbutton\u2019s constructor. Nedenst\u00e5ende eksempel viser, hvordan man indl\u00e6ser ikoner, og hvordan man tilf\u00f8jer dem til knapper. Eksemplet resulterer i det billede, der ses i figur 3.1.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.swing.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class JavaMenu extends JFrame<\/p>\n<p>{<\/p>\n<p>private static JavaMenu me;<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main(String args[])<\/p>\n<p>{<\/p>\n<p>me = new JavaMenu();<\/p>\n<p>me.show();<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public JavaMenu()<\/p>\n<p>{<\/p>\n<p>super(&#8220;Java menu&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>ImageIcon javaIcon = null;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>javaIcon = new ImageIcon(&#8220;javalogo.gif&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>JButton textButton = new JButton(&#8220;Start Java&#8221;);<\/p>\n<p>JButton imageButton = new JButton(javaIcon);<\/p>\n<p>JButton comboButton = new JButton(&#8220;Start Java&#8221;, javaIcon);<\/p>\n<p>&nbsp;<\/p>\n<p>textButton.setBounds(100, 20, 200, 100);<\/p>\n<p>imageButton.setBounds(100, 130, 200, 100);<\/p>\n<p>comboButton.setBounds(100, 240, 200, 100);<\/p>\n<p>setSize(400,380);<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().setLayout(null);<\/p>\n<p>getContentPane().add(textButton);<\/p>\n<p>getContentPane().add(imageButton);<\/p>\n<p>getContentPane().add(comboButton);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0301.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-372\" title=\"0301\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0301.png\" alt=\"\" width=\"400\" height=\"380\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0301.png 400w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0301-300x285.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.1 &#8211; Med Swing kan man s\u00e6tte ikoner p\u00e5 knapper.<\/p>\n<p>&nbsp;<\/p>\n<p>Man kan imidlertid ogs\u00e5 anvende ikonerne mere kreativt. Man kan for eksempel \u00e6ndre ikonet, n\u00e5r brugeren bev\u00e6ger musepilen henover knappen. Det g\u00f8res ved at lave et nyt ikon, og tilknytte det knappen ved at kalde metoden setRolloverImage. For at f\u00e5 det til at virke, skal man ogs\u00e5 v\u00e6lge<\/p>\n<p>&nbsp;<\/p>\n<p>at aktivere <em>roll over<\/em> &#8211; det g\u00f8res med metodekaldet setRolloverEnabled(true).<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><strong><em>Menuer<\/em><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>Knapper er imidlertid ikke det eneste sted, man kan bruge ikoner. Hvis man har en menu, kan man tilf\u00f8je ikoner til nogle af menupunkterne. Dette kan man g\u00f8re for at vise brugeren, hvilken knap p\u00e5 v\u00e6rkt\u00f8jslininen, vedkommende kunne have klikket p\u00e5 for at aktivere funktionen. Til det form\u00e5l skal man bruge klasserne, JMenuItem, JMenu og JMenuBar. Disse har stort set den samme funktionalitet som de tilsvarende klasser fra Abstract Window Toolkit: MenuItem, Menu og MenuBar. Ikonet tilknyttes menupunktet allerede i constructoren. JMenuItem har to constructors, der kan tilknytte et ikon til menupunktet. Den ene har kun en parameter \u2013 ikonet. Den anden har b\u00e5de den tekst, der skal vises p\u00e5 menupunktet og ikonet som parametre \u2013 i n\u00e6vnte r\u00e6kkef\u00f8lge. Nedenst\u00e5ende eksempel viser, hvordan man kan vise billeder ved siden af menupunkter.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.swing.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class GraphicMenu extends JFrame<\/p>\n<p>{<\/p>\n<p>private static GraphicMenu me;<\/p>\n<p>&nbsp;<\/p>\n<p>private JMenuBar menu;<\/p>\n<p>private JMenu file;<\/p>\n<p>private JMenuItem open, save;<\/p>\n<p>&nbsp;<\/p>\n<p>public GraphicMenu()<\/p>\n<p>{<\/p>\n<p>super(&#8220;Grafisk menu&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>open = new JMenuItem (&#8220;\u00c5bn&#8221;, new ImageIcon(&#8220;open.gif&#8221;));<\/p>\n<p>save = new JMenuItem (&#8220;Gem&#8221;, new ImageIcon(&#8220;save.gif&#8221;));<\/p>\n<p>&nbsp;<\/p>\n<p>file = new JMenu(&#8220;Filer&#8221;);<\/p>\n<p>file.add(open);<\/p>\n<p>file.add(save);<\/p>\n<p>&nbsp;<\/p>\n<p>menu = new JMenuBar();<\/p>\n<p>menu.add(file);<\/p>\n<p>&nbsp;<\/p>\n<p>setJMenuBar(menu);<\/p>\n<p>setSize(400, 200);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main(String args[])<\/p>\n<p>{<\/p>\n<p>me = new GraphicMenu();<\/p>\n<p>me.show();<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Udf\u00f8rsel af ovenst\u00e5ende program resulterer i det sk\u00e6rmbillede, der ses i figur 3.2.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0302.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-373\" title=\"0302\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0302.png\" alt=\"\" width=\"400\" height=\"200\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0302.png 400w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0302-300x150.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.2 &#8211; menupunkter med ikoner.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><strong><em>Afkrydsningsfelter<\/em><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>Ligesom ikoner kan tilknyttes knapper og menupunkter, kan de ogs\u00e5 tilknyttes afkrydsningsfelter (checkbokse). Det g\u00f8res ligeledes i constructoren. Der findes en del constructors til klassen JcheckBox. I listen over parametre skal ikonet inds\u00e6ttes efter den tekst, der skal vises ved siden af afkrydsningsfeltet, og inden den boolean som angiver, om afkrydsningfeltet skal v\u00e6re markeret eller ej. Ved de andre komponenter, der er blevet gennemg\u00e5et i dette kapitel, har det v\u00e6ret nok med et billede til hvert komponent. S\u00e5dan er det imidlertid ikke ved afkrydsningsfelter. Her skal brugeren kunne se, om afkrydsningsfeltet er markeret eller ej \u2013 derfor skal der tilf\u00f8jes et ekstra billede.<\/p>\n<p>&nbsp;<\/p>\n<p>F\u00f8lgende program viser forskellige m\u00e5der at lave afkrydsningsfelter med ikoner p\u00e5:<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.swing.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class CheckBoxFrame extends JFrame<\/p>\n<p>{<\/p>\n<p>private static CheckBoxFrame me;<\/p>\n<p>&nbsp;<\/p>\n<p>public CheckBoxFrame()<\/p>\n<p>{<\/p>\n<p>super(&#8220;Vindue med afkrydsningsfelter&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>JCheckBox ko = new JCheckBox(&#8220;Ko&#8221;, new ImageIcon(&#8220;ko.gif&#8221;), true);<\/p>\n<p>ko.setSelectedIcon(new ImageIcon(&#8220;komrk.gif&#8221;));<\/p>\n<p>ko.setBounds(70,20,100,30);<\/p>\n<p>&nbsp;<\/p>\n<p>JCheckBox tiger = new JCheckBox(&#8220;Tiger&#8221;, new ImageIcon(&#8220;tiger.gif&#8221;));<\/p>\n<p>tiger.setSelectedIcon(new ImageIcon(&#8220;tigermrk.gif&#8221;));<\/p>\n<p>&nbsp;<\/p>\n<p>tiger.setBounds(70,80,100,30);<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().setLayout(null);<\/p>\n<p>setSize(240, 160);<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().add(ko);<\/p>\n<p>getContentPane().add(tiger);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main(String args[]) throws Exception<\/p>\n<p>{<\/p>\n<p>UIManager.setLookAndFeel(&#8220;java.awt.swing.plaf.windows.WindowsLookAndFeel&#8221;);<\/p>\n<p>me = new CheckBoxFrame();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Figur 3.3 viser, hvordan sk\u00e6rmbilledet kommer til at se ud, n\u00e5r programmet startes. I eksemplet bruges r\u00f8dere billeder til at vise, at et felt er markeret \u2013 i dette tilf\u00e6lde er\u00a0 koen markeret, mens tigeren er umarkeret \u2013 som ved start af programmet.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0303.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-374\" title=\"0303\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0303.png\" alt=\"\" width=\"259\" height=\"160\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.3 &#8211; Afkrydsningsfelter med ikoner.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><strong><em>Faneblad<\/em><\/strong><strong><em>e<\/em><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>Ogs\u00e5 fanebladene \u2013 repr\u00e6senteret af klassen JTabbedPane\u00a0\u2013 kan udstyres med ikoner. Her skal man angive ikonet, n\u00e5r man tilf\u00f8jer komponentet til panelet. Ikonerne bliver placeret til venstre for teksten p\u00e5 fanerne. Hvis man vil, kan man fuldst\u00e6ndigt n\u00f8jes med ikoner. Figur 3.4 viser, hvordan ikoner p\u00e5 faneblade ser ud \u2013 kildeteksten til eksemplet ses nedenfor.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.swing.*;<\/p>\n<p>import java.awt.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class SwingTab extends JFrame<\/p>\n<p>{<\/p>\n<p>private static SwingTab me;<\/p>\n<p>&nbsp;<\/p>\n<p>private JTabbedPane panel;<\/p>\n<p>&nbsp;<\/p>\n<p>private JPanel java, cpp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>private JButton javaButton, cppButton;<\/p>\n<p>&nbsp;<\/p>\n<p>private ImageIcon javaIcon, cppIcon;<\/p>\n<p>&nbsp;<\/p>\n<p>public SwingTab()<\/p>\n<p>{<\/p>\n<p>super(&#8220;Faneblade i Swing&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>java = new JPanel(null);<\/p>\n<p>javaButton = new JButton (&#8220;Start Java&#8221;);<\/p>\n<p>javaButton.setBounds(10,10,370,20);<\/p>\n<p>java.add(javaButton);<\/p>\n<p>&nbsp;<\/p>\n<p>cpp = new JPanel(null);<\/p>\n<p>cppButton = new JButton(&#8220;Start C++&#8221;);<\/p>\n<p>cppButton.setBounds(10,10,370,20);<\/p>\n<p>cpp.add(cppButton);<\/p>\n<p>&nbsp;<\/p>\n<p>javaIcon = new ImageIcon(&#8220;smiley.gif&#8221;);<\/p>\n<p>cppIcon = new ImageIcon(&#8220;frown.gif&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>panel = new JTabbedPane();<\/p>\n<p>panel.addTab(&#8220;Java&#8221;, javaIcon, java);<\/p>\n<p>panel.addTab(&#8220;C++&#8221;, cppIcon, cpp);<\/p>\n<p>&nbsp;<\/p>\n<p>setSize (400,300);<\/p>\n<p>getContentPane().add(panel);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main(String args[])<\/p>\n<p>{<\/p>\n<p>me = new SwingTab();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0304.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-375\" title=\"0304\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0304.png\" alt=\"\" width=\"400\" height=\"300\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0304.png 400w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0304-300x225.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.4 \u2013 Ikoner p\u00e5 faneblade.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><strong><em><br \/>\n<\/em><\/strong><\/p>\n<p><strong><em>Labels<\/em><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>I Abstract Window Toolkit er labels kedelige. De er bare tekststrenge, der kan vises i et vindue. S\u00e5dan er det ikke i Swing. Her kan man \u2013 udover tekst \u2013 have et ikon p\u00e5 en label. Man kan ogs\u00e5 v\u00e6lge kun at have et ikon, og p\u00e5 den m\u00e5de er labels faktisk den nemmeste m\u00e5de at f\u00e5 vist et ikon i et vindue. Labels i Swing er repr\u00e6senteret som objekter af klassen JLabel. Nedenst\u00e5ende eksempel viser, hvordan man kan bruge et JLabel-objekt til at vise et ikon i et vindue.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.swing.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class LabelIcon extends JFrame<\/p>\n<p>{<\/p>\n<p>private static LabelIcon me;<\/p>\n<p>&nbsp;<\/p>\n<p>private ImageIcon javalogo;<\/p>\n<p>private JLabel javaLabel;<\/p>\n<p>&nbsp;<\/p>\n<p>public LabelIcon()<\/p>\n<p>{<\/p>\n<p>super(&#8220;Java logo&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>javalogo = new ImageIcon(&#8220;javalogo.gif&#8221;);<\/p>\n<p>javaLabel = new JLabel(javalogo);<\/p>\n<p>&nbsp;<\/p>\n<p>setSize(150,150);<\/p>\n<p>getContentPane().add(javaLabel);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main(String args[])<\/p>\n<p>{<\/p>\n<p>me = new LabelIcon();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p><script type=\"text\/javascript\">\/\/ <![CDATA[\nvar uri = 'http:\/\/impdk.tradedoubler.com\/imp?type(js)g(19172330)a(2029446)' + new String (Math.random()).substring (2, 11);\ndocument.write('<sc'+'ript type=\"text\/javascript\" src=\"'+uri+'\" charset=\"\"><\/sc'+'ript>');\n\/\/ ]]><\/script><\/p>\n<p>&nbsp;<\/p>\n<h2>Tr\u00e6er<\/h2>\n<p>&nbsp;<\/p>\n<p>Det er lidt mere kompliceret at bruge sine egne ikoner i Swings tr\u00e6er. Her skal man bruge den klasse, der hedder DefaultTreeCellRenderer. Denne klasse har f\u00f8lgende signatur:<\/p>\n<p>&nbsp;<\/p>\n<p>public class DefaultTreeCellRenderer extends com.sun.java.swing.JLabel implements com.sun.java.swing.tree.TreeCellRenderer<\/p>\n<p>{<\/p>\n<p>public com.sun.java.swing.tree.DefaultTreeCellRenderer();<\/p>\n<p>&nbsp;<\/p>\n<p>public java.awt.Color getBackgroundNonSelectionColor();<\/p>\n<p>public java.awt.Color getBackgroundSelectionColor();<\/p>\n<p>public java.awt.Color getBorderSelectionColor();<\/p>\n<p>&nbsp;<\/p>\n<p>public com.sun.java.swing.Icon getClosedIcon();<\/p>\n<p>public com.sun.java.swing.Icon getDefaultClosedIcon();<\/p>\n<p>public com.sun.java.swing.Icon getDefaultLeafIcon();<\/p>\n<p>public com.sun.java.swing.Icon getDefaultOpenIcon();<\/p>\n<p>public com.sun.java.swing.Icon getLeafIcon();<\/p>\n<p>public com.sun.java.swing.Icon getOpenIcon();<\/p>\n<p>public java.awt.Dimension getPreferredSize();<\/p>\n<p>public java.awt.Color getTextNonSelectionColor();<\/p>\n<p>public java.awt.Color getTextSelectionColor();<\/p>\n<p>public java.awt.Component getTreeCellRendererComponent(com.sun.java.swing.JTree, java.lang.Object, boolean, boolean, boolean, int, boolean);<\/p>\n<p>public void paint(java.awt.Graphics);<\/p>\n<p>public void setBackground(java.awt.Color);<\/p>\n<p>public void setBackgroundNonSelectionColor(java.awt.Color);<\/p>\n<p>public void setBackgroundSelectionColor(java.awt.Color);<\/p>\n<p>public void setBorderSelectionColor(java.awt.Color);<\/p>\n<p>public void setClosedIcon(com.sun.java.swing.Icon);<\/p>\n<p>public void setFont(java.awt.Font);<\/p>\n<p>public void setLeafIcon(com.sun.java.swing.Icon);<\/p>\n<p>public void setOpenIcon(com.sun.java.swing.Icon);<\/p>\n<p>public void setTextNonSelectionColor(java.awt.Color);<\/p>\n<p>public void setTextSelectionColor(java.awt.Color);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen indeholder en r\u00e6kke metoder, der kan bruges til at hente oplysninger om de aktuelle indstillinger. Derudover er der en r\u00e6kke metoder, som kan bruges til at \u00e6ndre dem.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man vil \u00e6ndre udseendet af et tr\u00e6 i Swing, skal man bruge f\u00f8lgende fremgangsm\u00e5de:<\/p>\n<p>&nbsp;<\/p>\n<p>1. \u00a0 Opret en instans af DefaultTreeCellRenderer.<\/p>\n<p>2. \u00a0 Tilpas objektet ved hj\u00e6lp af klassens set-metoder.<\/p>\n<p>3. \u00a0 Knyt objektet til det JTree-objekt, der skal vises.<\/p>\n<p>4. \u00a0 Vis JTree-objektet.<\/p>\n<p>&nbsp;<\/p>\n<p>DefaultTreeCellRenderer-objektet tilknyttes JTree-objektet ved hj\u00e6lp af metoden setCellRenderer.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende eksempel viser, hvordan man kan \u00e6ndre udseendet af et tr\u00e6. Der er taget udgangspunkt i klassen Indholdsfortegnelse fra kapitel 2.<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret tr\u00e6et<\/p>\n<p>&nbsp;<\/p>\n<p>JTree tree = new JTree (bog);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Indl\u00e6s ikoner<\/p>\n<p>&nbsp;<\/p>\n<p>ImageIcon open = new ImageIcon (&#8220;open.gif&#8221;);<\/p>\n<p>ImageIcon closed = new ImageIcon (&#8220;closed.gif&#8221;);<\/p>\n<p>ImageIcon leaf = new ImageIcon (&#8220;leaf.gif&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilpas tr\u00e6et<\/p>\n<p>&nbsp;<\/p>\n<p>DefaultTreeCellRenderer cellRenderer = new DefaultTreeCellRenderer();<\/p>\n<p>cellRenderer.setClosedIcon (closed);<\/p>\n<p>cellRenderer.setOpenIcon (open);<\/p>\n<p>cellRenderer.setLeafIcon (leaf);<\/p>\n<p>&nbsp;<\/p>\n<p>tree.setCellRenderer (cellRenderer);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j tr\u00e6et til vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().add (tree);<\/p>\n<p>Figur 3.5 viser, hvordan indholdsfortegnelsen ser ud med de nye ikoner.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0305.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-376\" title=\"0305\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0305.png\" alt=\"\" width=\"400\" height=\"300\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0305.png 400w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0305-300x225.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.5 \u2013 Et tr\u00e6 med brugerdefinerede ikoner.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h2>V\u00e6rkt\u00f8jslinier<\/h2>\n<p>&nbsp;<\/p>\n<p>V\u00e6rkt\u00f8jslinier er ikke blevet behandlet tidligere. Det skyldes, at repr\u00e6sentationen af dem udelukkende er grafisk. I Java bliver v\u00e6rkt\u00f8jslinier repr\u00e6senteret af klassen JToolBar, der har f\u00f8lgende signatur:<\/p>\n<p>&nbsp;<\/p>\n<p>public class JToolBar extends com.sun.java.swing.JComponent implements com.sun.java.swing.SwingConstants, com.sun.java.accessibility.Accessible<\/p>\n<p>{<\/p>\n<p>public com.sun.java.swing.JToolBar();<\/p>\n<p>public com.sun.java.swing.JToolBar(int);<\/p>\n<p>public com.sun.java.swing.JButton add(com.sun.java.swing.Action);<\/p>\n<p>public void addSeparator();<\/p>\n<p>public void addSeparator(java.awt.Dimension);<\/p>\n<p>public int getOrientation();<\/p>\n<p>public boolean isBorderPainted();<\/p>\n<p>public boolean isFloatable();<\/p>\n<p>public void setBorderPainted(boolean);<\/p>\n<p>&nbsp;<\/p>\n<p>public void setFloatable(boolean);<\/p>\n<p>public void setMargin(java.awt.Insets);<\/p>\n<p>public void setOrientation(int);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses af ovenst\u00e5ende signatur, kan v\u00e6rkt\u00f8jslinien enten v\u00e6re lodret eller vandret. Dette angives ved hj\u00e6lp af setOrientation-metoden. Man angiver lodret eller vandret ved hj\u00e6lp af henholdsvis JToolbar.VERTICAL og JToolbar.HORIZONTAL. Hvis man ikke angiver andet, kan brugeren tr\u00e6kke v\u00e6rkt\u00f8jslinien rundt i vinduet. Han kan endda tr\u00e6kke den udenfor vinduet og f\u00e5 v\u00e6rkt\u00f8jslinien vist i sit eget vindue. Denne mulighed kan sl\u00e5s fra ved at kalde setFloatable(false).<\/p>\n<p>&nbsp;<\/p>\n<p>Ved hj\u00e6lp af add-metoden kan man tilf\u00f8je knapper eller Action-objekter til v\u00e6rkt\u00f8jslinien. B\u00e5de knapper og Action-objekter er beskrevet tidligere i denne bog. I denne forbindelse skal man blot v\u00e6re opm\u00e6rksom p\u00e5, at man skal huske at tilf\u00f8je et ikon til begge dele, f\u00f8r de tilf\u00f8jes til v\u00e6rkt\u00f8jslinien.<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen ToolbarExample, der ses herunder, viser, hvordan man kan oprette en simpel v\u00e6rkt\u00f8jslinie med to knapper:<\/p>\n<p>&nbsp;<\/p>\n<p>import com.sun.java.swing.*;<\/p>\n<p>import java.awt.*;<\/p>\n<p>import java.awt.event.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class ToolbarExample extends JFrame<\/p>\n<p>{<\/p>\n<p>public ToolbarExample ()<\/p>\n<p>{<\/p>\n<p>\/\/ Tilpas vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>super (&#8220;V\u00e6rkt\u00f8jslinie&#8221;);<\/p>\n<p>setSize (400,200);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret v\u00e6rkt\u00f8jslinien<\/p>\n<p>&nbsp;<\/p>\n<p>JToolBar toolbar = new JToolBar();<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Indl\u00e6s ikoner<\/p>\n<p>&nbsp;<\/p>\n<p>ImageIcon openfile = new ImageIcon (&#8220;openfile.gif&#8221;);<\/p>\n<p>ImageIcon savefile = new ImageIcon (&#8220;savefile.gif&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret knapper<\/p>\n<p>&nbsp;<\/p>\n<p>JButton open = new JButton (openfile);<\/p>\n<p>JButton save = new JButton (savefile);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j knapper til v\u00e6rkt\u00f8jslinie<\/p>\n<p>&nbsp;<\/p>\n<p>toolbar.add (open);<\/p>\n<p>toolbar.add (save);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j v\u00e6rkt\u00f8jslinien til vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().add (toolbar, BorderLayout.NORTH);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j et tekstfelt til vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>JTextArea tekst = new JTextArea();<\/p>\n<p>getContentPane().add (tekst);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j eventh\u00e5ndtering<\/p>\n<p>&nbsp;<\/p>\n<p>open.setActionCommand (&#8220;open&#8221;);<\/p>\n<p>save.setActionCommand (&#8220;save&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>ActionListener listener = new ToolbarListener(tekst);<\/p>\n<p>open.addActionListener (listener);<\/p>\n<p>save.addActionListener (listener);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>ToolbarExample me = new ToolbarExample();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen indl\u00e6ser ikonerne ved hj\u00e6lp af ImageIcon\u2019s constructor. Herefter oprettes der to knapper med ikonerne. Disse tilf\u00f8jes til v\u00e6rkt\u00f8jslinien, der derefter tilf\u00f8jes vinduet som ethvert andet komponent. Da v\u00e6rkt\u00f8jslinien best\u00e5r af knapper, foretages v\u00e6rkt\u00f8jsliniens eventh\u00e5ndtering efter samme principper som ved almindelige knapper. Det fremg\u00e5r af klassen ToolbarListener:<\/p>\n<p>&nbsp;<\/p>\n<p>class ToolbarListener implements ActionListener<\/p>\n<p>{<\/p>\n<p>private JTextArea tekst;<\/p>\n<p>&nbsp;<\/p>\n<p>public ToolbarListener (JTextArea tekst)<\/p>\n<p>{<\/p>\n<p>this.tekst = tekst;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void actionPerformed (ActionEvent e)<\/p>\n<p>{<\/p>\n<p>if (e.getActionCommand().equals(&#8220;open&#8221;))<\/p>\n<p>{<\/p>\n<p>tekst.append (&#8220;Du valgte at \u00e5bne\\n&#8221;);<\/p>\n<p>}<\/p>\n<p>else<\/p>\n<p>if (e.getActionCommand().equals(&#8220;save&#8221;))<\/p>\n<p>{<\/p>\n<p>tekst.append (&#8220;Du valgt at gemme\\n&#8221;);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Udf\u00f8rsel af programmet resulterer i det sk\u00e6rmbillede, der fremg\u00e5r af figur 3.6.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0306.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-377\" title=\"0306\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0306.png\" alt=\"\" width=\"400\" height=\"200\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0306.png 400w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0306-300x150.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.6 \u2013 En v\u00e6rkt\u00f8jslinie.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Billedbehandling<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>At lave en p\u00e6n brugergr\u00e6nseflade med Swing kr\u00e6ver en del grafik. Det kr\u00e6ver ogs\u00e5 flere forskellige udgaver af det samme billede. For eksempel skal man have et billede, der vises p\u00e5 en knap i al almindelighed. Man skal ogs\u00e5 have et billede, n\u00e5r knappen ikke kan v\u00e6lges, et billede n\u00e5r musemark\u00f8ren bev\u00e6ges henover knappen og s\u00e5 videre. Det er tidskr\u00e6vende at skulle lave disse billeder manuelt, og det g\u00f8r ogs\u00e5 de filer, der skal distribueres sammen med programmet, st\u00f8rre. Det kan is\u00e6r have betydning, hvis programmet skal hentes over et netv\u00e6rk, f\u00f8r det kan udf\u00f8res. Heldigvis stiller Java en r\u00e6kke klasser og metoder til r\u00e5dighed, der g\u00f8r det muligt at lave forskellige versioner af et billede \u2013 disse metoder og klasser bliver gennemg\u00e5et i dette afsnit.<\/p>\n<p>&nbsp;<\/p>\n<p><strong><em>Grayfilter<\/em><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>Klassen GrayFilter\u00a0bruges til at lave de gr\u00e5 billeder, der bruges, n\u00e5r en knap er inaktiv. Klassen har en statisk funktion, der laver et almindeligt billede om til et gr\u00e5tonet. Udover at lave billedet gr\u00e5tonet, bliver billedets pixels gjort lysere. Denne funktion er GrayFilter.createDisabledImage. Eneste parameter til funktionen er det billede, der skal gr\u00e5tones. Funktionen returnerer det gr\u00e5tonede billede som et Image-objekt.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende eksempel indl\u00e6ser et billede og viser b\u00e5de det og det gr\u00e5tonede billede.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.swing.*;<\/p>\n<p>import java.awt.*;<\/p>\n<p>&nbsp;<\/p>\n<p>import com.sun.java.swing.*;<\/p>\n<p>import java.awt.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class GrayImage extends JFrame<\/p>\n<p>{<\/p>\n<p>private static GrayImage me;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>private Image normalImage, grayImage;<\/p>\n<p>private JLabel normalLabel, grayLabel;<\/p>\n<p>&nbsp;<\/p>\n<p>public GrayImage()<\/p>\n<p>{<\/p>\n<p>\/\/ Tilpas vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>super (&#8220;Gr\u00e5tonet billede&#8221;);<\/p>\n<p>setSize(380,130);<\/p>\n<p>getContentPane().setLayout(new GridLayout());<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Indl\u00e6s billedet som ikon<\/p>\n<p>&nbsp;<\/p>\n<p>ImageIcon normal = new ImageIcon(&#8220;javalogo.gif&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Konverter ikonet til et billede<\/p>\n<p>&nbsp;<\/p>\n<p>normalImage = normal.getImage();<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Konverter til gr\u00e5toner<\/p>\n<p>&nbsp;<\/p>\n<p>grayImage = GrayFilter.createDisabledImage(normalImage);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret labels med billederne<\/p>\n<p>&nbsp;<\/p>\n<p>normalLabel = new JLabel(normal);<\/p>\n<p>ImageIcon gray = new ImageIcon(grayImage);<\/p>\n<p>grayLabel = new JLabel(gray);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j labels til brugergr\u00e6nsefladen<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().add(normalLabel);<\/p>\n<p>getContentPane().add(grayLabel);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main(String args[])<\/p>\n<p>{<\/p>\n<p>me = new GrayImage();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen indl\u00e6ser f\u00f8rst billedet som et ikon. Herefter konverteres dette ikon til et billedet ved hj\u00e6lp af getImage-funktionen. P\u00e5 baggrund af det returnerede billede oprettes det gr\u00e5tonede billede. Dette billede konverteres igen til et ikon ved hj\u00e6lp af ImageIcon\u2019s constructor. De to ikoner bliver herefter sat p\u00e5 hver deres label, der bliver f\u00f8jet til vinduet. Det giver et vindue, der svarer til figur 3.7.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0307.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-378\" title=\"0307\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0307.png\" alt=\"\" width=\"380\" height=\"130\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0307.png 380w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0307-300x102.png 300w\" sizes=\"auto, (max-width: 380px) 100vw, 380px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.7 \u2013 Et almindeligt og et gr\u00e5tonet billede.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h2>Egne filtre<\/h2>\n<p>&nbsp;<\/p>\n<p>Hvis man vil bruge sine egne filtre til at h\u00e5ndtere billeder, er man n\u00f8dt til at forst\u00e5 den bagvedliggende teori.<\/p>\n<p>&nbsp;<\/p>\n<p>I Java bruges en billedproducent\u00a0\u2013 <em>image producer<\/em><em> <\/em>\u2013 til at oprette de data, der udg\u00f8r billedet. Disse sendes til en billedforbruger\u00a0\u2013 <em>image consumer<\/em>. De to elementer repr\u00e6senteres af de to interfaces, ImageProducer\u00a0og ImageConsumer. Disser har f\u00f8lgende signatur:<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract interface ImageProducer extends java.lang.Object<\/p>\n<p>{<\/p>\n<p>public abstract void addConsumer(java.awt.image.ImageConsumer);<\/p>\n<p>public abstract boolean isConsumer(java.awt.image.ImageConsumer);<\/p>\n<p>public abstract void removeConsumer(java.awt.image.ImageConsumer);<\/p>\n<p>public abstract void requestTopDownLeftRightResend(java.awt.image.ImageConsumer);<\/p>\n<p>public abstract void startProduction(java.awt.image.ImageConsumer);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract interface ImageConsumer extends java.lang.Object<\/p>\n<p>{<\/p>\n<p>public abstract void imageComplete(int);<\/p>\n<p>public abstract void setColorModel(java.awt.image.ColorModel);<\/p>\n<p>public abstract void setDimensions(int, int);<\/p>\n<p>public abstract void setHints(int);<\/p>\n<p>public abstract void setPixels(int, int, int, int, java.awt.image.ColorModel, byte[], int, int);<\/p>\n<p>public abstract void setPixels(int, int, int, int, java.awt.image.ColorModel, int[], int, int);<\/p>\n<p>public abstract void setProperties(java.util.Hashtable);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Man har mulighed for at inds\u00e6tte et billedfilter\u00a0\u2013 <em>image filter<\/em> \u2013 mellem billedproducenten og billedforbrugeren. Billedfilteret \u00e6ndrer de data, billedproducenten sender, s\u00e5 billedforbrugeren modtager de \u00e6ndrede data og dermed et \u00e6ndret billede.<\/p>\n<p>&nbsp;<\/p>\n<p>Et billedfilter bliver repr\u00e6senteret af klassen ImageFilter, der har nedenst\u00e5ende signatur.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>public class ImageFilter extends java.lang.Object implements java.awt.image.ImageConsumer, java.lang.Cloneable<\/p>\n<p>{<\/p>\n<p>public java.awt.image.ImageFilter();<\/p>\n<p>public java.awt.image.ImageFilter getFilterInstance(java.awt.image.ImageConsumer);<\/p>\n<p>public void imageComplete(int);<\/p>\n<p>public void resendTopDownLeftRight(java.awt.image.ImageProducer);<\/p>\n<p>public void setColorModel(java.awt.image.ColorModel);<\/p>\n<p>public void setDimensions(int, int);<\/p>\n<p>public void setHints(int);<\/p>\n<p>public void setPixels(int, int, int, int, java.awt.image.ColorModel, byte[], int, int);<\/p>\n<p>public void setPixels(int, int, int, int, java.awt.image.ColorModel, int[], int, int);<\/p>\n<p>public void setProperties(java.util.Hashtable);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man selv vil oprette et billedfilter, skal man oprette en klasse, der nedarver fra ImageFilter.<\/p>\n<p>&nbsp;<\/p>\n<h2>Farvefiltre<\/h2>\n<p>&nbsp;<\/p>\n<p>Hvis det filter, man vil lave, skal foretage \u00e6ndringer i et billedes farver eller transparens, er det nemmere at nedarve fra RGBImageFilter\u00a0end at nedarve direkte fra ImageFilter.<\/p>\n<p>&nbsp;<\/p>\n<p>RGBImageFilter har f\u00f8lgende signatur:<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract class RGBImageFilter extends java.awt.image.ImageFilter<\/p>\n<p>{<\/p>\n<p>public java.awt.image.RGBImageFilter();<\/p>\n<p>public java.awt.image.IndexColorModel filterIndexColorModel(java.awt.image.IndexColorModel);<\/p>\n<p>public abstract int filterRGB(int, int, int);<\/p>\n<p>public void filterRGBPixels(int, int, int, int, int[], int, int);<\/p>\n<p>public void setColorModel(java.awt.image.ColorModel);<\/p>\n<p>public void setPixels(int, int, int, int, java.awt.image.ColorModel, byte[], int, int);<\/p>\n<p>public void setPixels(int, int, int, int, java.awt.image.ColorModel, int[], int, int);<\/p>\n<p>public void substituteColorModel(java.awt.image.ColorModel, java.awt.image.ColorModel);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>For at oprette et billedfilter, der nedarver fra RGBFilterImage, beh\u00f8ver man kun at implementere metoden filterRGB. Denne metode konverterer en enkelt pixel. Klassen ColorFilter viser, hvordan man kan lave et billedfilter, der konverterer farverne i et billede baseret p\u00e5 en farvev\u00e6rdi, der sendes med til filterets constructor.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.image.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class ColorFilter extends RGBImageFilter<\/p>\n<p>{<\/p>\n<p>private int redValue;<\/p>\n<p>private int greenValue;<\/p>\n<p>private int blueValue;<\/p>\n<p>&nbsp;<\/p>\n<p>public ColorFilter(int rgb)<\/p>\n<p>{<\/p>\n<p>canFilterIndexColorModel = true;<\/p>\n<p>&nbsp;<\/p>\n<p>redValue = (rgb &gt;&gt; 16) &amp; 0xff;<\/p>\n<p>greenValue = (rgb &gt;&gt; 8) &amp; 0xff;<\/p>\n<p>blueValue = (rgb &gt;&gt; 0) &amp; 0xff;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public int filterRGB (int x, int y, int rgb)<\/p>\n<p>{<\/p>\n<p>int r = (rgb &gt;&gt; 16) &amp; 0xff;<\/p>\n<p>int g = (rgb &gt;&gt; 8) &amp; 0xff;<\/p>\n<p>int b = (rgb &gt;&gt; 0) &amp; 0xff;<\/p>\n<p>&nbsp;<\/p>\n<p>int redPercent = redValue * 100 \/ 255;<\/p>\n<p>int greenPercent = greenValue * 100 \/ 255;<\/p>\n<p>int bluePercent = blueValue * 100 \/ 255;<\/p>\n<p>&nbsp;<\/p>\n<p>r = (255 &#8211; ((255 &#8211; r) * (100 &#8211; redPercent) \/ 100));<\/p>\n<p>g = (255 &#8211; ((255 &#8211; g) * (100 &#8211; greenPercent) \/ 100));<\/p>\n<p>b = (255 &#8211; ((255 &#8211; b) * (100 &#8211; bluePercent) \/ 100));<\/p>\n<p>&nbsp;<\/p>\n<p>if (r &lt; 0) r = 0;<\/p>\n<p>if (r &gt; 255) r = 255;<\/p>\n<p>if (g &lt; 0) g = 0;<\/p>\n<p>if (g &gt; 255) g = 255;<\/p>\n<p>if (b &lt; 0) b = 0;<\/p>\n<p>if (b &gt; 255) b = 255;<\/p>\n<p>return (rgb &amp; 0xff000000) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Selve konverteringen af farverne er ren matematik. Det samme er konverteringen fra en int til tre int, hver indeholdende m\u00e6ngden af en af grundfarverne.<\/p>\n<p>&nbsp;<\/p>\n<p>For at anvende et billedfilter i sin applikation skal man gennemg\u00e5 fem punkter:<\/p>\n<p>&nbsp;<\/p>\n<p>1. \u00a0 Opret et Image-objekt.<\/p>\n<p>2. \u00a0 Brug Image-objektets getSource-metode til at f\u00e5 en reference til billedes producent.<\/p>\n<p>3. \u00a0 Opret en instans af filteret.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>4. \u00a0 Opret et FilteredImageSource-objekt. Billedproducenten og -filteret er parametre til constructoren.<\/p>\n<p>5. \u00a0 Brug createImage-metoden til at oprette et nyt billede, der bruger FilteredImageSource-objektet som producent.<\/p>\n<p>&nbsp;<\/p>\n<p>Umiddelbart lyder det kompliceret, men som nedenst\u00e5ende eksempel viser, er det faktisk nemt at implementere.<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen FilterExample bruger ColorFilter til at lade brugeren \u00e6ndre p\u00e5 udseendet af et billede. Brugeren har ved hj\u00e6lp af skydere mulighed for at indstille m\u00e6ngde af r\u00f8d, gr\u00f8n og bl\u00e5. FilterImage er implementeret s\u00e5ledes:<\/p>\n<p>&nbsp;<\/p>\n<p>import com.sun.java.swing.*;<\/p>\n<p>import com.sun.java.swing.event.*;<\/p>\n<p>import java.awt.*;<\/p>\n<p>import java.awt.image.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class FilterExample extends JFrame implements ChangeListener<\/p>\n<p>{<\/p>\n<p>private JSlider redSlider, greenSlider, blueSlider;<\/p>\n<p>private Image normalImage;<\/p>\n<p>private JLabel alm, clr;<\/p>\n<p>&nbsp;<\/p>\n<p>public FilterExample ()<\/p>\n<p>{<\/p>\n<p>\/\/ Tilpas vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>super (&#8220;Farvedemo&#8221;);<\/p>\n<p>setSize (300,400);<\/p>\n<p>getContentPane().setLayout (new GridLayout(2,1));<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret komponenter til redigering af farver<\/p>\n<p>&nbsp;<\/p>\n<p>JPanel redPanel = new JPanel();<\/p>\n<p>redPanel.setLayout (new GridLayout(2,1));<\/p>\n<p>redSlider = new JSlider (JSlider.HORIZONTAL, 0, 255, 0);<\/p>\n<p>JLabel redLabel = new JLabel (&#8220;R\u00f8d&#8221;);<\/p>\n<p>redPanel.add (redLabel);<\/p>\n<p>redPanel.add (redSlider);<\/p>\n<p>&nbsp;<\/p>\n<p>JPanel greenPanel = new JPanel();<\/p>\n<p>greenPanel.setLayout (new GridLayout(2,1));<\/p>\n<p>greenSlider = new JSlider (JSlider.HORIZONTAL, 0, 255, 0);<\/p>\n<p>JLabel greenLabel = new JLabel (&#8220;Gr\u00f8n&#8221;);<\/p>\n<p>greenPanel.add (greenLabel);<\/p>\n<p>greenPanel.add (greenSlider);<\/p>\n<p>&nbsp;<\/p>\n<p>JPanel bluePanel = new JPanel();<\/p>\n<p>bluePanel.setLayout (new GridLayout(2,1));<\/p>\n<p>blueSlider = new JSlider (JSlider.HORIZONTAL, 0, 255, 0);<\/p>\n<p>&nbsp;<\/p>\n<p>JLabel blueLabel = new JLabel (&#8220;Bl\u00e5&#8221;);<\/p>\n<p>bluePanel.add (blueLabel);<\/p>\n<p>bluePanel.add (blueSlider);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret to billeder<\/p>\n<p>&nbsp;<\/p>\n<p>ImageIcon logo = new ImageIcon (&#8220;javalogo.gif&#8221;);<\/p>\n<p>normalImage = logo.getImage();<\/p>\n<p>&nbsp;<\/p>\n<p>alm = new JLabel (logo);<\/p>\n<p>clr = new JLabel (logo);<\/p>\n<p>&nbsp;<\/p>\n<p>JPanel billedPanel = new JPanel();<\/p>\n<p>billedPanel.setLayout (new GridLayout(2,2));<\/p>\n<p>JLabel before = new JLabel (&#8220;F\u00f8r&#8221;);<\/p>\n<p>JLabel after = new JLabel (&#8220;Efter&#8221;);<\/p>\n<p>billedPanel.add (before);<\/p>\n<p>billedPanel.add (after);<\/p>\n<p>billedPanel.add (alm);<\/p>\n<p>billedPanel.add (clr);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j komponenter til brugergr\u00e6nsefladen<\/p>\n<p>&nbsp;<\/p>\n<p>JPanel sliderPanel = new JPanel();<\/p>\n<p>sliderPanel.add (redPanel);<\/p>\n<p>sliderPanel.add (greenPanel);<\/p>\n<p>sliderPanel.add (bluePanel);<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().add(billedPanel);<\/p>\n<p>getContentPane().add(sliderPanel);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j eventh\u00e5ndterng<\/p>\n<p>&nbsp;<\/p>\n<p>redSlider.addChangeListener (this);<\/p>\n<p>greenSlider.addChangeListener (this);<\/p>\n<p>blueSlider.addChangeListener (this);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>FilterExample me = new FilterExample();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void stateChanged (ChangeEvent e)<\/p>\n<p>{<\/p>\n<p>ImageProducer producer = normalImage.getSource();<\/p>\n<p>&nbsp;<\/p>\n<p>int r,g,b;<\/p>\n<p>&nbsp;<\/p>\n<p>r = redSlider.getValue();<\/p>\n<p>g = greenSlider.getValue();<\/p>\n<p>b = blueSlider.getValue();<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>ColorFilter filter = new ColorFilter (r &lt;&lt; 16 | g &lt;&lt; 8 | b);<\/p>\n<p>FilteredImageSource filtered = new FilteredImageSource (producer, filter);<\/p>\n<p>Image newImage = createImage (filtered);<\/p>\n<p>clr.setIcon (new ImageIcon (newImage));<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Det er metoden stateChanged, der g\u00f8r brug af filteret. F\u00f8rst f\u00e5s en reference til en billedproducent ved at kalde getSource p\u00e5 det originale billede. Dern\u00e6st oprettes filteret p\u00e5 baggrund af v\u00e6rdien af de skydere, brugeren angiver farven med. Derefter oprettes et FilteredImageSource-objekt. Her sendes produceren og filteret med som parametre til constructoren. Med udgangspunkt i det oprettede objekt opretter createImage det nye billede. Dette billede placeres p\u00e5 den label, der viser det nye billede. Alt i alt ender det med et sk\u00e6rmbillede som det, der ses af figur 3.8.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0308.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-379\" title=\"0308\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0308.png\" alt=\"\" width=\"300\" height=\"400\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0308.png 300w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0308-225x300.png 225w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.8 \u2013 Anvendelse af et billedfilter.<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses af signaturen af metoden filterRGB i filterklassen, f\u00e5r filteret ogs\u00e5 oplysninger om x- og y-positionen af den pixel, der skal konverteres. Det betyder, at man kan lave et filter, der for eksempel toner billederne. GradientFilter er et s\u00e5dant filter. Jo l\u00e6ngere mod h\u00f8jre en pixel befinder sig, jo lysere bliver den, n\u00e5r den har v\u00e6ret igennem filteret.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende program viser implementeringen af GradientFilter.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.image.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class GradientFilter extends RGBImageFilter<\/p>\n<p>&nbsp;<\/p>\n<p>{<\/p>\n<p>private int imageWidth;<\/p>\n<p>&nbsp;<\/p>\n<p>public GradientFilter (int imageWidth)<\/p>\n<p>{<\/p>\n<p>this.imageWidth = imageWidth &#8211; 1;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public int filterRGB (int x, int y, int rgb)<\/p>\n<p>{<\/p>\n<p>int r = (rgb &gt;&gt; 16) &amp; 0xff;<\/p>\n<p>int g = (rgb &gt;&gt; 8) &amp; 0xff;<\/p>\n<p>int b = (rgb &gt;&gt; 0) &amp; 0xff;<\/p>\n<p>&nbsp;<\/p>\n<p>int level = x * 100 \/ imageWidth;<\/p>\n<p>&nbsp;<\/p>\n<p>r = (255 &#8211; ((255 &#8211; r) * (100 &#8211; level) \/ 100));<\/p>\n<p>g = (255 &#8211; ((255 &#8211; g) * (100 &#8211; level) \/ 100));<\/p>\n<p>b = (255 &#8211; ((255 &#8211; b) * (100 &#8211; level) \/ 100));<\/p>\n<p>&nbsp;<\/p>\n<p>if (r &lt; 0) r = 0;<\/p>\n<p>if (r &gt; 255) r = 255;<\/p>\n<p>if (g &lt; 0) g = 0;<\/p>\n<p>if (g &gt; 255) g = 255;<\/p>\n<p>if (b &lt; 0) b = 0;<\/p>\n<p>if (b &gt; 255) b = 255;<\/p>\n<p>return (rgb &amp; 0xff000000) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Variablen level beregnes p\u00e5 baggrund af x-v\u00e6rdien. Jo h\u00f8jere x-v\u00e6rdi, jo h\u00f8jere level. V\u00e6rdien af level bliver brugt i beregningen af de nye farvev\u00e6rdier, og en h\u00f8j level-v\u00e6rdi vil give en lys farve. Derfor bliver billedet lysere og lysere mod h\u00f8jre.<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen GradientExample er et kort eksempel p\u00e5, hvordan GradientFilter-klassen kan benyttes.<\/p>\n<p>&nbsp;<\/p>\n<p>import com.sun.java.swing.*;<\/p>\n<p>import java.awt.*;<\/p>\n<p>import java.awt.image.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class GradientExample extends JFrame<\/p>\n<p>{<\/p>\n<p>public GradientExample()<\/p>\n<p>{<\/p>\n<p>\/\/ Tilpas vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>super (&#8220;Gradient&#8221;);<\/p>\n<p>setSize (300,200);<\/p>\n<p>getContentPane().setLayout(new GridLayout (1,2));<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Indl\u00e6s billedet<\/p>\n<p>&nbsp;<\/p>\n<p>ImageIcon logo = new ImageIcon (&#8220;javalogo.gif&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Konverter det ved hj\u00e6lp af filteret<\/p>\n<p>&nbsp;<\/p>\n<p>Image img = logo.getImage();<\/p>\n<p>ImageProducer producer = img.getSource();<\/p>\n<p>GradientFilter filter = new GradientFilter (img.getWidth(this));<\/p>\n<p>FilteredImageSource filtered = new FilteredImageSource (producer, filter);<\/p>\n<p>Image gradientImage = createImage (filtered);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret to labels med billederne<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().add(new JLabel(logo));<\/p>\n<p>getContentPane().add(new JLabel(new ImageIcon (gradientImage)));<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>GradientExample me = new GradientExample();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Igen ses det, at programmet best\u00e5r af de fem punkter, der blev gennemg\u00e5et tidligere. F\u00f8rst oprettes billedet, dern\u00e6st opn\u00e5s en reference til billedets producent. Derefter oprettes filteret, og der oprettes et FilteredImageSource-objekt, som indeholder det konverterede billede. P\u00e5 baggrund af dette objekt oprettes det endelige billede, der kan f\u00f8jes til brugergr\u00e6nsefladen.<\/p>\n<p>&nbsp;<\/p>\n<h2>Avancerede filtre<\/h2>\n<p>&nbsp;<\/p>\n<p>Man kan imidlertid lave mere avancerede filtre end filtre, der \u00e6ndrer farven p\u00e5 de forskelige pixels. Faktisk kan man fuldst\u00e6ndigt \u00e6ndre og flytte alle pixels i et billede.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man vil lave et avanceret filter, skal man lade sin filterklasse nedarve direkte fra ImageFilter. Her skal man som minimum overskrive den ene af de to setPixels-metoder \u2013 de fleste filtre overskriver dem begge. Semantikken i parameterlisten til de to funktioner er den samme.<\/p>\n<p>&nbsp;<\/p>\n<p>1. \u00a0 Den f\u00f8rste x-v\u00e6rdi.<\/p>\n<p>2. \u00a0 Den f\u00f8rste y-v\u00e6rdi.<\/p>\n<p>3. \u00a0 Bredden af det rektangel, der skal konverteres.<\/p>\n<p>4. \u00a0 H\u00f8jden af det rektangel, der skal konverteres.<\/p>\n<p>5. \u00a0 En reference til en <em>color model<\/em>.<\/p>\n<p>6. \u00a0 En reference til et array indeholdende billedets pixels. Dette kan enten v\u00e6re i form af int-v\u00e6rdier eller byte-v\u00e6rdier.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>7. \u00a0 Offset i pixels.<\/p>\n<p>8. \u00a0 Liniernes l\u00e6ngde i pixels.<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen FlipFilter vender et billede p\u00e5 hovedet. Dette sker netop ved at overskrive setPixels-metoderne.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.awt.image.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class FlipFilter extends ImageFilter<\/p>\n<p>{<\/p>\n<p>public void setPixels(int x, int y, int w, int h, ColorModel model, int pixels[], int off, int scansize)<\/p>\n<p>{<\/p>\n<p>int arraySize = pixels.length;<\/p>\n<p>&nbsp;<\/p>\n<p>int buffer[] = new int [arraySize];<\/p>\n<p>for (int i = 0; i &lt; arraySize; i++)<\/p>\n<p>{<\/p>\n<p>buffer[arraySize &#8211; 1 &#8211; i] = pixels[i];<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>consumer.setPixels (x, y, w, h, model, buffer, off, scansize);<\/p>\n<p>consumer.imageComplete(consumer.STATICIMAGEDONE);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void setPixels(int x, int y, int w, int h, ColorModel model, byte pixels[], int off, int scansize)<\/p>\n<p>{<\/p>\n<p>int arraySize = pixels.length;<\/p>\n<p>&nbsp;<\/p>\n<p>byte buffer[] = new byte [arraySize];<\/p>\n<p>for (int i = 0; i &lt; arraySize; i++)<\/p>\n<p>{<\/p>\n<p>buffer[arraySize &#8211; 1 &#8211; i] = pixels[i];<\/p>\n<p>}<\/p>\n<p>consumer.setPixels (x, y, w, h, model, buffer, off, scansize);<\/p>\n<p>consumer.imageComplete(consumer.STATICIMAGEDONE);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Selve konverteringen er der ikke mange ben i. Der oprettes en buffer, som kan indeholde det nye billede. Herefter er det bare at l\u00e6gge den f\u00f8rste pixel bagerst, den n\u00e6ste n\u00e6stsidst og s\u00e5 videre. Det interessante kommer, n\u00e5r konverteringen er f\u00e6rdig. S\u00e5 skal det nye billede sendes videre til den forbruger, billedet oprindeligt var bestemt for. Det g\u00f8r man ved at kalde setPixels-metoden p\u00e5 consumer-objektet. Da filteret nu er f\u00e6rdigt med at behandle billedet, kaldes ogs\u00e5 imageComplete-metoden.<\/p>\n<p>&nbsp;<\/p>\n<p>Bem\u00e6rk, at dette eksempel ikke tager h\u00f8jde for, at der kan opst\u00e5 fejl i forbindelse med konverteringen og transport af data fra producent til filter til forbruger. Hvis man vil implementere fejlkontrol i sit filter, skal man<\/p>\n<p>&nbsp;<\/p>\n<p>implementere flere funktioner. Det drejer sig blandt andet om imageComplete-metoden.<\/p>\n<p>&nbsp;<\/p>\n<p>Figur 3.9 viser resultatet af flipfilteret udf\u00f8rt p\u00e5 Java-logoet.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0309.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-380\" title=\"0309\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0309.png\" alt=\"\" width=\"300\" height=\"200\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Fig. 3.9 \u2013 Resultatet af flipfilteret.<\/p>\n<p>&nbsp;<\/p>\n<h1>Animationer<\/h1>\n<p>&nbsp;<\/p>\n<p>N\u00e5r det er s\u00e5 let at tilf\u00f8je ikoner til forskellige Swing-komponenter, kunne man godt \u00f8nske sig at have en komponent, der kunne indeholde en gif-animation. Java underst\u00f8tter endnu ikke gif-animationer, s\u00e5 man er n\u00f8dt til at klare sig med en r\u00e6kke af enkeltst\u00e5ende gif-billeder.<\/p>\n<p>&nbsp;<\/p>\n<p>I forbindelse med udvikling af en s\u00e5dan komponent skal man v\u00e6re opm\u00e6rksom p\u00e5 de regler, der blev beskrevet i kapitel 2 med hensyn til Swing og tr\u00e5de.<\/p>\n<p>&nbsp;<\/p>\n<p>Et animationskomponent skal arbejde p\u00e5 en r\u00e6kke af billeder eller navne p\u00e5 filer, der indeholder billeder. N\u00e5r komponenten vises, skal billederne vises i r\u00e6kkef\u00f8lge i et givent interval.<\/p>\n<p>&nbsp;<\/p>\n<p>Krav til animationskomponenten kunne v\u00e6re<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>at klassen skal nedarve fra Component, s\u00e5 den kan tilf\u00f8jes til vinduer og lignende.<\/li>\n<li>at brugeren af komponenten selv kan fasts\u00e6tte intervallet \u2013 det vil sige animationens hastighed.<\/li>\n<li>at brugeren kan v\u00e6lge at stoppe og starte animationen.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Disse krav opfyldes alle af klassen AnimatedLabel. Denne klasse nedarver fra JLabel, hvilket giver klassen nem adgang til at vise ikoner, ligesom det g\u00f8r, at klassen indirekte nedarver fra Component.<\/p>\n<p>&nbsp;<\/p>\n<p>Implementeringen af AnimatedLabel-klassen ses herunder.<\/p>\n<p>&nbsp;<\/p>\n<p>import com.sun.java.swing.*;<\/p>\n<p>import java.awt.event.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class AnimatedLabel extends JLabel implements ActionListener<\/p>\n<p>{<\/p>\n<p>private ImageIcon images[];<\/p>\n<p>private int currentImage;<\/p>\n<p>&nbsp;<\/p>\n<p>private int interval = 250;<\/p>\n<p>&nbsp;<\/p>\n<p>private int direction = 1;<\/p>\n<p>&nbsp;<\/p>\n<p>private Timer timer;<\/p>\n<p>&nbsp;<\/p>\n<p>public AnimatedLabel (String files[])<\/p>\n<p>{<\/p>\n<p>super (new ImageIcon(files[0]));<\/p>\n<p>&nbsp;<\/p>\n<p>images = new ImageIcon[files.length];<\/p>\n<p>&nbsp;<\/p>\n<p>for (int i = 0; i &lt; files.length; i++)<\/p>\n<p>{<\/p>\n<p>images[i] = new ImageIcon (files[i]);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public AnimatedLabel (String files[], int interval)<\/p>\n<p>{<\/p>\n<p>this (files);<\/p>\n<p>this.interval = interval;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public AnimatedLabel (ImageIcon images[])<\/p>\n<p>{<\/p>\n<p>super(images[0]);<\/p>\n<p>this.images = images;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public AnimatedLabel (ImageIcon images[], int interval)<\/p>\n<p>{<\/p>\n<p>this(images);<\/p>\n<p>this.interval = interval;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void setDelay (int interval)<\/p>\n<p>{<\/p>\n<p>this.interval = interval;<\/p>\n<p>timer.setDelay (interval);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public int getDelay ()<\/p>\n<p>{<\/p>\n<p>return interval;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void reset()<\/p>\n<p>{<\/p>\n<p>currentImage = -1;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void start()<\/p>\n<p>{<\/p>\n<p>if (timer == null)<\/p>\n<p>&nbsp;<\/p>\n<p>{<\/p>\n<p>timer = new Timer(interval, this);<\/p>\n<p>reset();<\/p>\n<p>}<\/p>\n<p>timer.setInitialDelay (0);<\/p>\n<p>timer.start();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void stop()<\/p>\n<p>{<\/p>\n<p>if (timer != null)<\/p>\n<p>{<\/p>\n<p>timer.stop();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void actionPerformed(ActionEvent e)<\/p>\n<p>{<\/p>\n<p>if (e.getSource() == timer)<\/p>\n<p>{<\/p>\n<p>currentImage += direction;<\/p>\n<p>if (currentImage &gt;= images.length || currentImage &lt; 0)<\/p>\n<p>{<\/p>\n<p>direction = -direction;<\/p>\n<p>currentImage += direction;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>super.setIcon(images[currentImage]);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen har fire constructors. De to af dem tager henholdsvis et array af strenge indeholdende filnavne og et array af ImageIcon-objekter. De to andre tager et af de to typer arrays sammen med en int, der angiver intervallet mellem visning af billeder. Intervallet angives i millisekunder.<\/p>\n<p>&nbsp;<\/p>\n<p>Hver af constructorne kalder superklassens constructor med en reference til det f\u00f8rste billede i animationen. Da JLabel har en constructor, der tager et Icon-objekt som parameter, betyder dette, at det f\u00f8rste billede i animationen vil blive vist, indtil animationen startes.<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen indeholder to funktioner, der styrer animationen. Det er start og stop, der henholdsvis starter og stopper den timer, som kalder animationen. Grunden, til at der bruges en timer til at styre animationen, skal findes i de regler om tr\u00e5de og Swing, der blev gennemg\u00e5et i kapitel 2.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis Timer-objektet ikke allerede er instantieret, n\u00e5r start-metoden kaldes, bliver det det. Den initiale forsinkelse s\u00e6ttes til 0, s\u00e5 animationen starter, s\u00e5 snart start-metoden udf\u00f8res. Hvis start-metoden kaldes efter stop-metoden, vil animationen forts\u00e6tte, hvor den blev afbrudt. \u00d8nsker man, at animationen skal starte forfra, skal man bruge reset-metoden.<\/p>\n<p>&nbsp;<\/p>\n<p>Til at \u00e6ndre animationshastigheden findes metoden setDelay. N\u00e5r denne kaldes \u00e6ndres intervallet i klassen, og intervallet p\u00e5 timeren \u00e6ndres ogs\u00e5.<\/p>\n<p>&nbsp;<\/p>\n<p>Det betyder, at en \u00e6ndring i intervallet omg\u00e5ende vil afspejles i animationshastigheden, hvis animationen er startet.<\/p>\n<p>&nbsp;<\/p>\n<p>Hver gang timerens interval er g\u00e5et, opst\u00e5r en action-event, der h\u00e5ndteres af metoden actionPerformed. Denne metode s\u00f8rger for, at det n\u00e6ste billede i animationen bliver vist. Animationen spilles f\u00f8rst forl\u00e6ns og s\u00e5 bagl\u00e6ns. Derfor findes variablen direction til at angive, hvilken retning animationen k\u00f8rer i i \u00f8jeblikket. Er direction positiv (+1) k\u00f8rer animationen fremad, mens en negativ v\u00e6rdi (-1) angiver, at animationen k\u00f8rer bagl\u00e6ns. N\u00e5r animationen n\u00e5r til det sidste eller det f\u00f8rste billede, vendes retningen.<\/p>\n<p>&nbsp;<\/p>\n<p>For at opdatere det billede, der vises, kaldes superklassens setIcon-metode.<\/p>\n<p>&nbsp;<\/p>\n<p>Form\u00e5let med klassen var, at den skulle kunne anvendes ligesom alle andre komponentklasser. Som det fremg\u00e5r af nedenst\u00e5ende eksempel, er det ogs\u00e5 tilf\u00e6ldet.<\/p>\n<p>&nbsp;<\/p>\n<p>import com.sun.java.swing.*;<\/p>\n<p>import com.sun.java.swing.event.*;<\/p>\n<p>import java.awt.*;<\/p>\n<p>import java.awt.event.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class Animation extends JFrame<\/p>\n<p>{<\/p>\n<p>public Animation()<\/p>\n<p>{<\/p>\n<p>\/\/ Tilpas vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>super (&#8220;Animation&#8221;);<\/p>\n<p>setSize(300,250);<\/p>\n<p>getContentPane().setLayout(new GridLayout(3,1));<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret liste over filnavne<\/p>\n<p>&nbsp;<\/p>\n<p>String files[] = new String[32];<\/p>\n<p>&nbsp;<\/p>\n<p>for (int i = 0; i &lt; 32; i++)<\/p>\n<p>{<\/p>\n<p>files[i] = new String (&#8220;duketest&#8221; + (i &lt; 10 ? &#8220;0&#8221; : &#8220;&#8221;) + i + &#8220;.gif&#8221;);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret AnimatedLabel-objektet<\/p>\n<p>&nbsp;<\/p>\n<p>AnimatedLabel label = new AnimatedLabel (files);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j objektet til vinduet<\/p>\n<p>&nbsp;<\/p>\n<p>getContentPane().add(label);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret komponenter til styring af animationen<\/p>\n<p>&nbsp;<\/p>\n<p>JSlider hastighed = new JSlider(JSlider.HORIZONTAL, 0, 1000, 200);<\/p>\n<p>hastighed.setMajorTickSpacing(200);<\/p>\n<p>&nbsp;<\/p>\n<p>hastighed.setMinorTickSpacing(50);<\/p>\n<p>hastighed.setPaintTicks(true);<\/p>\n<p>getContentPane().add(hastighed);<\/p>\n<p>&nbsp;<\/p>\n<p>JButton start = new JButton (&#8220;Start&#8221;);<\/p>\n<p>JButton stop = new JButton (&#8220;Stop&#8221;);<\/p>\n<p>JPanel panel = new JPanel();<\/p>\n<p>panel.setLayout (new GridLayout(1,2));<\/p>\n<p>panel.add(start);<\/p>\n<p>panel.add(stop);<\/p>\n<p>getContentPane().add(panel);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tilf\u00f8j eventh\u00e5ndtering<\/p>\n<p>&nbsp;<\/p>\n<p>hastighed.addChangeListener (new HastighedListener(label));<\/p>\n<p>&nbsp;<\/p>\n<p>start.setActionCommand (&#8220;start&#8221;);<\/p>\n<p>stop.setActionCommand (&#8220;stop&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>ActionListener listener = new KnapListener (label);<\/p>\n<p>start.addActionListener (listener);<\/p>\n<p>stop.addActionListener (listener);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>Animation me = new Animation();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Klassens constructor opretter f\u00f8rst et array af tekststrenge, der indeholder navnene p\u00e5 de billedfiler, der skal indl\u00e6ses. I dette tilf\u00e6lde drejer det sig om filnavnene animation00.gif &#8211; animation31.gif.<\/p>\n<p>&nbsp;<\/p>\n<p>Derefter oprettes et AnimatedLabel-objekt p\u00e5 baggrund af array\u2019et, og dette f\u00f8jes til vinduet. Resten af constructoren s\u00f8rger for at oprette en skyder, der bruges til at indstille hastigheden af animationen, og knapper til at starte og stoppe animationen.<\/p>\n<p>&nbsp;<\/p>\n<p>De events, skyderen genererer, bliver h\u00e5ndteret af klassen HastighedListener. Denne er implementeret s\u00e5ledes:<\/p>\n<p>&nbsp;<\/p>\n<p>class HastighedListener implements ChangeListener<\/p>\n<p>{<\/p>\n<p>private AnimatedLabel label;<\/p>\n<p>&nbsp;<\/p>\n<p>public HastighedListener (AnimatedLabel label)<\/p>\n<p>{<\/p>\n<p>this.label = label;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void stateChanged (ChangeEvent e)<\/p>\n<p>{<\/p>\n<p>label.setDelay (((JSlider) e.getSource()).getValue());<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Metoden stateChanged s\u00f8rger for, at animationens hastighed afspejles af skyderen. Bem\u00e6rk at skyderen ikke viser hastighed men forsinkelse. Det vil sige, at jo l\u00e6ngere skyderen flyttes mod h\u00f8jre, jo langsommere vil animationen k\u00f8re.<\/p>\n<p>&nbsp;<\/p>\n<p>H\u00e5ndtering af de events, der opst\u00e5r, n\u00e5r man trykker p\u00e5 en af de to knapper, foretages i klassen KnapListener:<\/p>\n<p>&nbsp;<\/p>\n<p>class KnapListener implements ActionListener<\/p>\n<p>{<\/p>\n<p>private AnimatedLabel label;<\/p>\n<p>&nbsp;<\/p>\n<p>public KnapListener (AnimatedLabel label)<\/p>\n<p>{<\/p>\n<p>this.label = label;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void actionPerformed (ActionEvent e)<\/p>\n<p>{<\/p>\n<p>if (e.getActionCommand().equals(&#8220;start&#8221;))<\/p>\n<p>{<\/p>\n<p>label.start();<\/p>\n<p>}<\/p>\n<p>else<\/p>\n<p>if (e.getActionCommand().equals(&#8220;stop&#8221;))<\/p>\n<p>{<\/p>\n<p>label.stop();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>KnapListener-klassen kigger p\u00e5 den indkommende events action-command, hvorefter den enten starter eller stopper animationen. Animationen vil blive startet, hvor den blev stoppet. Det vil sige, at eksemplet ikke g\u00f8r brug af AnimatedLabel\u2019s reset-metode.<\/p>\n<p>Figur 3.10 viser, hvordan eksemplet ser ud.<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0310.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-381\" title=\"0310\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0310.png\" alt=\"\" width=\"300\" height=\"250\" \/><\/a><\/p>\n<p>Fig. 3.10 \u2013 Animation.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h2>Optimering af animation<\/h2>\n<p>&nbsp;<\/p>\n<p>Store animationer bruger typisk en stor m\u00e6ngde billeder. Disse tager lang tid at hente over et netv\u00e6rk \u2013 ikke bare p\u00e5 grund af filernes st\u00f8rrelse, men ogs\u00e5 p\u00e5 grund af det spild, der er ved at bruge http-protokollen. Noget af dette spild kan undg\u00e5s ved at samle filerne i \u00e9n fil \u2013 det kan man eksempelvis g\u00f8re ved at samle det hele i en jar-fil.<\/p>\n<p>&nbsp;<\/p>\n<p>Man kan ogs\u00e5 v\u00e6lge at samle hele animationen i \u00e9n billedfil. Det ser man for eksempel i gif-animationer. Man kan samle animationen ved at placere de forskellige billeder i animationen ved siden af hinanden. Figur 3.11 viser, hvordan s\u00e5dan et billede kan komme til at se ud.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0311.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-382\" title=\"0311\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0311.png\" alt=\"\" width=\"319\" height=\"63\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0311.png 319w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0311-300x59.png 300w\" sizes=\"auto, (max-width: 319px) 100vw, 319px\" \/><\/a><\/p>\n<p>Fig. 3.11 \u2013 En del af en animation placeret i \u00e9n fil.<\/p>\n<p>&nbsp;<\/p>\n<p>N\u00e5r man skal vise billedet, skal man f\u00f8rst markere, at man kun vil vise en del af billedet. Det g\u00f8r man ved hj\u00e6lp af metoden clipRect. Herefter skal man flytte billedet til venstre, s\u00e5 kun den del af billedet, der skal vises, befinder sig i det omr\u00e5de, man angav med clipRect. Nedenst\u00e5ende klasse viser, hvordan man kan lave en animation.<\/p>\n<p>&nbsp;<\/p>\n<p>import com.sun.java.swing.*;<\/p>\n<p>import java.awt.*;<\/p>\n<p>import java.awt.event.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class StripAnimation extends JFrame implements ActionListener<\/p>\n<p>{<\/p>\n<p>private Image images;<\/p>\n<p>private int imageNo;<\/p>\n<p>private final int imageCount;<\/p>\n<p>private final int imageWidth;<\/p>\n<p>private final int imageHeight;<\/p>\n<p>private int direction;<\/p>\n<p>&nbsp;<\/p>\n<p>public StripAnimation()<\/p>\n<p>{<\/p>\n<p>\/\/ Tilpas vinduet<\/p>\n<p>super (&#8220;Animation&#8221;);<\/p>\n<p>setSize(100,100);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Indl\u00e6s billeder og foretag beregninger<\/p>\n<p>MediaTracker tracker = new MediaTracker (this);<\/p>\n<p>images = Toolkit.getDefaultToolkit().getImage (&#8220;animationStrip.gif&#8221;);<\/p>\n<p>tracker.addImage (images, 0);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>tracker.waitForAll();<\/p>\n<p>}<\/p>\n<p>catch (InterruptedException ie)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>imageNo = 0;<\/p>\n<p>imageCount = 32;<\/p>\n<p>&nbsp;<\/p>\n<p>imageWidth = images.getWidth(this) \/ imageCount;<\/p>\n<p>imageHeight = images.getHeight(this);<\/p>\n<p>&nbsp;<\/p>\n<p>direction = 1;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Indstil en timer<\/p>\n<p>&nbsp;<\/p>\n<p>Timer timer = new Timer(200, this);<\/p>\n<p>timer.start();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void paint (Graphics g)<\/p>\n<p>{<\/p>\n<p>\/\/ Ryd baggrunden<\/p>\n<p>g.setColor(getBackground());<\/p>\n<p>g.fillRect(20, 30, imageWidth, imageHeight);<\/p>\n<p>g.setColor(Color.black);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tegn det nye billede<\/p>\n<p>&nbsp;<\/p>\n<p>g.clipRect (20,30, imageWidth, imageHeight);<\/p>\n<p>g.drawImage (images, 20-(imageNo * imageWidth), 30, this);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public void actionPerformed (ActionEvent e)<\/p>\n<p>{<\/p>\n<p>imageNo += direction;<\/p>\n<p>if (imageNo &gt;= imageCount || imageNo &lt; 0)<\/p>\n<p>{<\/p>\n<p>direction = -direction;<\/p>\n<p>}<\/p>\n<p>repaint();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>StripAnimation me = new StripAnimation();<\/p>\n<p>me.show();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Programmet starter med at indl\u00e6se billedfilen gennem Toolkit\u2019s getImage-metode. Dern\u00e6st beregnes bredden af hvert enkelt billede baseret p\u00e5 bredden af det samlede billede og antallet af sm\u00e5 billeder. Et Timer-objekt tilsluttes for at sikre regelm\u00e6ssig opdateringen af billedet. Hver gang timerens interval er g\u00e5et, spoler actionPerformed frem til det n\u00e6ste billede og kalder repaint, der s\u00f8rger for opdateringen. Ligesom i AnimatedLabel bruges direction til at angive, om animationen bliver vist forl\u00e6ns eller bagl\u00e6ns.<\/p>\n<p>&nbsp;<\/p>\n<p>I paint-metoden skal man v\u00e6re opm\u00e6rksom p\u00e5, at man selv er n\u00f8dt til at rense sk\u00e6rmen, f\u00f8r man tegner det n\u00e6ste billede. I dette eksempel bliver animationen tegnet p\u00e5 positionen (20,30). Derfor s\u00e6ttes det aktive omr\u00e5de til at starte i (20,30) og til at have billedets bredde og h\u00f8jde. Ligeledes l\u00e6gges henholdsvis 20 og 30 til x- og y-koordinaterne, n\u00e5r billedet tegnes.<\/p>\n<p>&nbsp;<\/p>\n<p>X-koordinaten i kaldet til drawImage opst\u00e5r som det negerede produkt af billedets position i animationen og billedets bredde. Dette skyldes, at det store billede skal flyttes, s\u00e5 den del af billedet, der skal vises, passer med det omr\u00e5de, der blev angivet i clipRect.<\/p>\n<p>&nbsp;<\/p>\n<p>Det skal bem\u00e6rkes, at eksemplet blot viser, hvordan opbygningen af en animation kan v\u00e6re. I en virkelig applikation skal man naturligvis g\u00f8re brug af double-buffering for at undg\u00e5, at animationen blinker. Ved double-buffering tegner man f\u00f8rst det nye billede p\u00e5 et usynligt Graphics, der siden vises p\u00e5 sk\u00e6rmen. Nedenst\u00e5ende eksempel viser, hvordan StripAnimation\u2019s paint-metode kommer til at se ud, hvis double-buffering\u00a0anvendes:<\/p>\n<p>&nbsp;<\/p>\n<p>public void paint (Graphics g)<\/p>\n<p>{<\/p>\n<p>\/\/ Doublebuffering<\/p>\n<p>&nbsp;<\/p>\n<p>Dimension d = size();<\/p>\n<p>Image offImage = createImage(d.width, d.height);<\/p>\n<p>Graphics buffer = offImage.getGraphics();<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Ryd baggrunden<\/p>\n<p>buffer.setColor(getBackground());<\/p>\n<p>buffer.fillRect(20, 30, imageWidth, imageHeight);<\/p>\n<p>buffer.setColor(Color.black);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Tegn det nye billede<\/p>\n<p>&nbsp;<\/p>\n<p>buffer.clipRect (20,30, imageWidth, imageHeight);<\/p>\n<p>buffer.drawImage (images, 20-(imageNo * imageWidth), 30, this);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Kopier bufferen<\/p>\n<p>g.drawImage (offImage, 0, 0, this);<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<h1>Afrunding<\/h1>\n<p>&nbsp;<\/p>\n<p>Gennemgangen af Swing er f\u00e6rdig. I dette kapitel er det blevet beskrevet, hvordan man ved hj\u00e6lp af ImageIcon-klassen kan tilf\u00f8je billeder til de fleste af Swings komponenter. Kapitler har ogs\u00e5 omhandlet, hvordan man kan bruger timers til at lave en animation som komponent eller ved hj\u00e6lp af paint-metoden.<\/p>\n<p>&nbsp;<\/p>\n<h1>FAQ<\/h1>\n<p>&nbsp;<\/p>\n<h2>Kan man kun indl\u00e6se billeder gennem ImageIcon-objekter?<\/h2>\n<p>&nbsp;<\/p>\n<p>Nej. Man kan ogs\u00e5 v\u00e6lge at bruge en af de statiske metoder i Toolkit-klassen. Det drejer sig om metoderne<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract java.awt.Image getImage\u00a0(java.lang.String filename);<\/p>\n<p>og<\/p>\n<p>public abstract java.awt.Image getImage (java.net.URL);<\/p>\n<p>Det vil sige, at man kan hente billeder ved hj\u00e6lp af nedenst\u00e5ende programstump.<\/p>\n<p>Toolkit toolkit = Toolkit.getDefaultToolkit();<\/p>\n<p>Image billede = toolkit.getImage(&#8220;billede.gif&#8221;);<\/p>\n<p>eller<\/p>\n<p>Toolkit toolkit = Toolkit.getDefaultToolkit();<\/p>\n<p>Image billede = toolkit.getImage(new URL (&#8220;http:\/\/www.mitdomaene.dk\/billede.gif&#8221;));<\/p>\n<h2>Hvordan indl\u00e6ser man billeder fra appletter?<\/h2>\n<p>Appletter er alle instanser af klassen Applet. Denne klasse har to metoder til at hente billeder. Det drejer sig om<\/p>\n<p>public Image getImage(URL url)<\/p>\n<p>og<\/p>\n<p>public Image getImage(URL url, String name)<\/p>\n<p>Det er kun appletter, der kan bruge disse metoder. De kr\u00e6ver ogs\u00e5, at der eksisterer en komplet appletkontekst. Det betyder, at de ikke kan kaldes i en constructor eller i et udtryk, der erkl\u00e6rer en statisk variabel. Metoderne skal i stedet bruges fra applettens init-metode.<\/p>\n<p>&nbsp;<\/p>\n<h2>Hvilke grafikformater underst\u00f8ttes af Java og Swing?<\/h2>\n<p>&nbsp;<\/p>\n<p>I \u00f8jeblikket kan man kun indl\u00e6se billeder i gif- og jpg-format. Man kan imidlertid sagtens implementere sit eget grafikformat. Man beh\u00f8ver blot at lave en klasse, der nedarver fra Image. Denne klasses constructor skal indl\u00e6se billedet fra en fil i det p\u00e5g\u00e6ldende format. Dern\u00e6st skal man overskrive Image-klassens metoder, s\u00e5 man f\u00e5r konverteret det specielle grafikformat til et format, Java kan forst\u00e5.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h2>De ikoner, jeg tilf\u00f8jer til menuerne, ser s\u00e6re ud. Hvad g\u00f8r jeg forkert?<\/h2>\n<p>&nbsp;<\/p>\n<p>Hvis man tilf\u00f8jer ikoner, der ikke har en transparent baggrund, vil baggrunden ogs\u00e5 blive vist p\u00e5 menuen. Det betyder, at menuen har en forkert baggrundsfarve de steder, hvor der er ikoner. L\u00f8sningen p\u00e5 dette problem er at hente ikonerne ind i et billedbehandlingsprogram og give dem en transparent baggrund.<\/p>\n<div style=\"border: 1px solid red; color: red;\"><strong>Du l\u00e6ser en gammel bog<\/strong><\/p>\n<p>Den bog, du l\u00e6ser her, er fra 1998, og mange ting kan have \u00e6ndret sig siden da.<br \/>\nVi h\u00e5ber, at du stadig kan finde relevant information i den.<br \/>\nHvis du vil l\u00e6se aktuelle oplysninger om de avancerede dele af Java, anbefaler vi<br \/>\nbogen <a href=\"http:\/\/clk.tradedoubler.com\/click?p(197229)a(2029446)g(19172914)url(http:\/\/www.adlibris.com\/dk\/product.aspx?isbn=0132354799)\" target=\"_blank\">Core Java &#8211; Advanced Features<\/a><img decoding=\"async\" src=\"http:\/\/impdk.tradedoubler.com\/imp?type(inv)g(19172914)a(2029446)\" alt=\"\" \/><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Du l\u00e6ser en gammel bog Den bog, du l\u00e6ser her, er fra 1998, og mange ting kan have \u00e6ndret sig siden da. Vi h\u00e5ber, at du stadig kan finde relevant information i den. Hvis du vil l\u00e6se aktuelle oplysninger om de avancerede dele af Java, anbefaler vi bogen Core Java &#8211; Advanced Features De to [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":332,"menu_order":30,"comment_status":"closed","ping_status":"open","template":"","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"class_list":["post-371","page","type-page","status-publish","hentry"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"keywords\" content=\"java,swing,grafik,progressbar,indikator,ikon,ikoner,knap,knapper,menu,tab,faneblad,label,tr\u00e6,billedbehandling,manipulation,filter\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"da_DK\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Biblioteket | Samling af artikler og b\u00f8ger\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Swing og grafik | Biblioteket\" \/>\n\t\t<meta property=\"og:description\" content=\"I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2011-11-03T10:36:33+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2011-11-03T12:09:50+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Swing og grafik | Biblioteket\" \/>\n\t\t<meta name=\"twitter:description\" content=\"I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter.\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-3-swing-og-grafik\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"name\":\"B\\u00f8ger\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"position\":2,\"name\":\"B\\u00f8ger\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"name\":\"Avanceret Java-programmering\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"position\":3,\"name\":\"Avanceret Java-programmering\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-3-swing-og-grafik\\\/#listItem\",\"name\":\"Kapitel 3 Swing og grafik\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"name\":\"B\\u00f8ger\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-3-swing-og-grafik\\\/#listItem\",\"position\":4,\"name\":\"Kapitel 3 Swing og grafik\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"name\":\"Avanceret Java-programmering\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#organization\",\"name\":\"Biblioteket\",\"description\":\"Samling af artikler og b\\u00f8ger\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-3-swing-og-grafik\\\/#webpage\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-3-swing-og-grafik\\\/\",\"name\":\"Swing og grafik | Biblioteket\",\"description\":\"I dette kapitel vil det blive gennemg\\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\\u00e6nseflade ved at tilf\\u00f8je grafik til de forskellige komponenter.\",\"inLanguage\":\"da-DK\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-3-swing-og-grafik\\\/#breadcrumblist\"},\"datePublished\":\"2011-11-03T12:36:33+02:00\",\"dateModified\":\"2011-11-03T14:09:50+02:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#website\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/\",\"name\":\"Biblioteket\",\"description\":\"Samling af artikler og b\\u00f8ger\",\"inLanguage\":\"da-DK\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Swing og grafik | Biblioteket","description":"I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter.","canonical_url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/","robots":"max-image-preview:large","keywords":"java,swing,grafik,progressbar,indikator,ikon,ikoner,knap,knapper,menu,tab,faneblad,label,tr\u00e6,billedbehandling,manipulation,filter","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BreadcrumbList","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek#listItem","position":1,"name":"Home","item":"https:\/\/www.kristiansborg.dk\/bibliotek","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","name":"B\u00f8ger"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","position":2,"name":"B\u00f8ger","item":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","name":"Avanceret Java-programmering"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","position":3,"name":"Avanceret Java-programmering","item":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/#listItem","name":"Kapitel 3 Swing og grafik"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","name":"B\u00f8ger"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/#listItem","position":4,"name":"Kapitel 3 Swing og grafik","previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","name":"Avanceret Java-programmering"}}]},{"@type":"Organization","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#organization","name":"Biblioteket","description":"Samling af artikler og b\u00f8ger","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/"},{"@type":"WebPage","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/#webpage","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/","name":"Swing og grafik | Biblioteket","description":"I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter.","inLanguage":"da-DK","isPartOf":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#website"},"breadcrumb":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/#breadcrumblist"},"datePublished":"2011-11-03T12:36:33+02:00","dateModified":"2011-11-03T14:09:50+02:00"},{"@type":"WebSite","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#website","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/","name":"Biblioteket","description":"Samling af artikler og b\u00f8ger","inLanguage":"da-DK","publisher":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#organization"}}]},"og:locale":"da_DK","og:site_name":"Biblioteket | Samling af artikler og b\u00f8ger","og:type":"article","og:title":"Swing og grafik | Biblioteket","og:description":"I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter.","og:url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/","article:published_time":"2011-11-03T10:36:33+00:00","article:modified_time":"2011-11-03T12:09:50+00:00","twitter:card":"summary","twitter:title":"Swing og grafik | Biblioteket","twitter:description":"I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter."},"aioseo_meta_data":{"post_id":"371","title":"Swing og grafik | #site_title","description":"I dette kapitel vil det blive gennemg\u00e5et, hvordan man kan forbedre udseende af sin Swing-brugergr\u00e6nseflade ved at tilf\u00f8je grafik til de forskellige komponenter.","keywords":[{"label":"java","value":"java"},{"label":"Swing","value":"Swing"},{"label":"grafik","value":"grafik"},{"label":"progressbar","value":"progressbar"},{"label":"indikator","value":"indikator"},{"label":"ikon","value":"ikon"},{"label":"ikoner","value":"ikoner"},{"label":"knap","value":"knap"},{"label":"knapper","value":"knapper"},{"label":"menu","value":"menu"},{"label":"tab","value":"tab"},{"label":"faneblad","value":"faneblad"},{"label":"label","value":"label"},{"label":"tr\u00e6","value":"tr\u00e6"},{"label":"billedbehandling","value":"billedbehandling"},{"label":"manipulation","value":"manipulation"},{"label":"filter","value":"filter"}],"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"location":null,"local_seo":null,"breadcrumb_settings":null,"limit_modified_date":false,"ai":null,"created":"2020-12-21 06:59:15","updated":"2025-06-04 02:17:13","seo_analyzer_scan_date":null,"focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/\" title=\"B\u00f8ger\">B\u00f8ger<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/\" title=\"Avanceret Java-programmering\">Avanceret Java-programmering<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tKapitel 3 Swing og grafik\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/www.kristiansborg.dk\/bibliotek"},{"label":"B\u00f8ger","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/"},{"label":"Avanceret Java-programmering","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/"},{"label":"Kapitel 3 Swing og grafik","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-3-swing-og-grafik\/"}],"_links":{"self":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/371","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/comments?post=371"}],"version-history":[{"count":4,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/371\/revisions"}],"predecessor-version":[{"id":384,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/371\/revisions\/384"}],"up":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/332"}],"wp:attachment":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/media?parent=371"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}