package elte.java2_utikalauz5.swing; /** Fastruktúrák használata Swingben.

A felhasználói felület tetején a naplózó komponens látható, ahol a fastruktúra adatmodelljének, valamit a kiválasztás változását követhetjük nyomon. Alatta egy végtelen, teljes 10-áris fastruktúra látható, amely kezdetben az adott fapont útvonalát reprezentáló szöveget tartalmaz minden fapontjában. A fastruktúra fapontjai szerkeszthetőek (jobb egérgombbal kattintás hatására), elrejthetőek, egy adott fapont gyermekei pedig növekvő ABC-rendben jelennek meg. Legalul a vezérlő panel látható, melynek gombjai lehetővé teszik a fastruktúra jellemzőinek szabályozását, valamint a megjelenítési stílus váltását. A fastruktúra megjelenítése nyomkövethető. @link.forrásfájl {@docRoot}/../data/swing/src JTreeTeszt.java @link.letöltés {@docRoot}/../data/swing JTreeTeszt.jar @since Java 2 Útikalauz programozóknak */ public class JTreeTeszt extends SwingTeszt implements javax.swing.event. TreeModelListener,javax.swing.event.TreeExpansionListener, javax.swing. event.TreeWillExpandListener,javax.swing.event.TreeSelectionListener { /** Verziószám. */ private final static long serialVersionUID = 15L; /** Indítás alkalmazásként. @param argumentumok Az indításkor megadott paraméterek. */ public static void main(String argumentumok[]) { new JTreeTeszt().init(argumentumok); } /** Applet leírása. @return A példaprogram leírása */ @Override public String getAppletInfo() { return "Fastruktúrák használatát bemutató tesztprogram"; } /** Fastruktúra adatmodellje */ private Modell modell; /** Fastruktúra komponens */ private javax.swing.JTree fa; /** Levélikon használati kapcsolója */ private javax.swing.JCheckBox levélikon; /** Ágikon használati kapcsolója */ private javax.swing.JCheckBox ágikon; /** GUI felépítése */ @Override protected void felépít() { modell = new Modell(10); modell.addTreeModelListener(this); //adatmodell figyelése fa = new javax.swing.JTree(modell); levélikon = new javax.swing.JCheckBox("levélikon", true); ágikon = new javax.swing.JCheckBox("ágikon", true); add(new javax.swing.JScrollPane(fa)); fa.putClientProperty("JTree.lineStyle", "Angled"); fa.setSelectionModel(new javax.swing.tree.DefaultTreeSelectionModel() { /** Verziószám. */ private final static long serialVersionUID = 15L; /** Kiválasztás folyamatban van */ private boolean kiválasztás = false; /** Kiválasztások beállítása. @param utak A kiválasztandó fapontok. */ @Override public void setSelectionPaths(javax.swing.tree.TreePath[] utak) { if (kiválasztás) super.setSelectionPaths(utak); else { clearSelection(); addSelectionPaths(utak); } } /** Kiválasztások hozzáadása. @param utak A kiválasztandó fapontok. */ @Override public void addSelectionPaths(javax.swing.tree.TreePath[] utak) { if (utak==null || utak.length==0) return; java.util.Vector újutak = new java.util.Vector(utak.length); javax.swing.tree.TreePath szülő = getLeadSelectionPath(); if (szülő==null) szülő=utak[0]; if (szülő!=null) szülő = szülő.getParentPath(); //csak ezen for (javax.swing.tree.TreePath út : utak) //szülő gyermekei if (út!=null && út.getParentPath()==szülő) újutak.add(út); kiválasztás = true; if (újutak.size()>0) super.addSelectionPaths(újutak.toArray( new javax.swing.tree.TreePath[újutak.size()])); kiválasztás = false; } }); fa.addTreeSelectionListener(this); //kiválasztás figyelése fa.addTreeExpansionListener(this); //fapont kinyitásának figyelése fa.addTreeWillExpandListener(this); javax.swing.tree.DefaultTreeCellRenderer dtcr = new javax.swing.tree.DefaultTreeCellRenderer() { /** Verziószám. */ private final static long serialVersionUID = 15L; /** Az érték nélküli fapontok betűtípusa */ private java.awt.Font alapbetűtípus; /** Megjelenítés felkonfigurálása. @param fa A megjelenítendő fastruktúra. @param érték A megjelenítendő érték. @param kiválasztva Adott fapont kiválasztott állapota. @param kinyitva Adott fapont kinyitott állapota. @param levél Megadja hogy a fapont levél-e. @param sor Megjelenítendő fapont sorszáma. @param fókuszált Adott fapont fókuszált állapota. @param return A megjelenítést végző grafikus komponens. */ @Override public java.awt.Component getTreeCellRendererComponent(javax.swing. JTree fa, Object érték, boolean kiválasztva, boolean kinyitva, boolean levél, int sor, boolean fókuszált) { Modell.Fapont pont = (Modell.Fapont)érték; if (alapbetűtípus==null) alapbetűtípus=fa.getFont().deriveFont( java.awt.Font.ITALIC, fa.getFont().getSize()*0.8f); if (pont.tartalom == null) { //érték nélküli fapont setBackground(fa.getBackground()); setBackgroundNonSelectionColor(fa.getBackground()); setFont(alapbetűtípus); } else { //értékkel rendelkező fapont setBackground(java.awt.Color.yellow); //színes háttérrel setBackgroundNonSelectionColor(java.awt.Color.yellow); setFont(fa.getFont()); } //megjelenítés elvégeztetése return super.getTreeCellRendererComponent(fa,érték, kiválasztva, kinyitva, levél, sor, fókuszált); } /** Nyitott belső fapont ikonja. @return Alapértelmezett ikon, csak ha megjelenítése engedélyezett. */ @Override public javax.swing.Icon getOpenIcon() { if (ágikon.isSelected()) return getDefaultOpenIcon(); return null; //nincs a belső pontokhoz ikon } /** Zárt belső fapont ikonja. @return Alapértelmezett ikon, csak ha megjelenítése engedélyezett. */ @Override public javax.swing.Icon getClosedIcon() { if (ágikon.isSelected()) return getDefaultClosedIcon(); return null; //nincs a belső pontokhoz ikon } /** Levélikon. @return Alapértelmezett ikon, csak ha megjelenítése engedélyezett. */ @Override public javax.swing.Icon getLeafIcon() { if (levélikon.isSelected()) return getDefaultLeafIcon(); return null; } }; fa.setCellRenderer( dtcr ); fa.setCellEditor(new Editor( fa, dtcr )); add(new javax.swing.JScrollPane(napló), java.awt.BorderLayout.NORTH); javax.swing.JPanel panel = new javax.swing.JPanel(); //vezérlő panel add(panel, java.awt.BorderLayout.SOUTH); panel.setPreferredSize(new java.awt.Dimension(450, 200)); javax.swing.AbstractButton gomb = new javax.swing.JButton("elrejt"); panel.add(gomb); gomb.setActionCommand("elrejt"); gomb.addActionListener(this); //nyomógomb figyelése gomb = new javax.swing.JButton("megmutat"); //megmutat panel.add(gomb); gomb.setActionCommand("megmutat"); gomb.addActionListener(this); //nyomógomb figyelése gomb = new javax.swing.JButton("visszaállít"); //visszaállít panel.add(gomb); gomb.setActionCommand("visszaállít"); gomb.addActionListener(this); //nyomógomb figyelése javax.swing.JLabel címke = new javax.swing.JLabel("kiválasztási mód:"); panel.add(címke); címke.setToolTipText("selectionMode"); javax.swing.JComboBox legördülőlista = new javax.swing.JComboBox( new Object[] {"DISCONTIGUOUS", "CONTIGUOUS", "SINGLE"}); panel.add(legördülőlista); legördülőlista.setToolTipText("_TREE_SELECTION"); legördülőlista.setActionCommand("kiválaszt"); legördülőlista.addActionListener(this); //kiválasztás figyelése gomb = new javax.swing.JCheckBox("gyökér látható?", fa.isRootVisible()); panel.add(gomb); gomb.setActionCommand("root"); gomb.setToolTipText("rootVisible"); gomb.addActionListener(this); //gomb kiválasztásának figyelése panel.add(ágikon); ágikon.setActionCommand("folder"); ágikon.addActionListener(this); //gomb kiválasztásának figyelése panel.add(levélikon); levélikon.setActionCommand("leaf"); levélikon.addActionListener(this); //gomb kiválasztásának figyelése gomb = new javax.swing.JCheckBox("szerkeszthető?", fa.isEditable()); panel.add(gomb); //szerkeszthető gomb.setActionCommand("editable"); gomb.setToolTipText("editable"); gomb.addActionListener(this); //gomb kiválasztásának figyelése for (javax.swing.Action váltás : stílusváltások) panel.add(new javax.swing.JButton(váltás)); //stílusváltásgombok nyomkövetés(fa); //nyomkövethető a megjelenítés } /** Adatváltozás naplózása. @param tme Faesemény. */ public void treeNodesChanged(javax.swing.event.TreeModelEvent tme) { naplóz("treeNodesChanged", tme); } /** Beszúrás naplózása. @param tme Faesemény. */ public void treeNodesInserted(javax.swing.event.TreeModelEvent tme) { naplóz("treeNodesInserted", tme); } /** Törlés naplózása. @param tme Faesemény. */ public void treeNodesRemoved(javax.swing.event.TreeModelEvent tme) { naplóz("treeNodesRemoved", tme); } /** Struktúraváltozás naplózása. @param tme Faesemény. */ public void treeStructureChanged(javax.swing.event.TreeModelEvent tme) { naplóz("treeStructureChanged", tme); } /** Faesemény naplózása. @param tme Faesemény. */ private void naplóz(String esemény, javax.swing.event.TreeModelEvent tme) { napló.append("TreeModelEvent: "+esemény+", fapont="+tme.getTreePath(). getLastPathComponent()+", indexek="); int[] indexek = tme.getChildIndices(); //indexek listázása if (indexek==null) napló.append("null"); else { napló.append("["); for (int index : indexek) napló.append(index+","); napló.append("]"); } napló.append(", pontok="); //fapontok listázása Object[] pontok = tme.getChildren(); if (pontok==null) napló.append("null"); else { napló.append("["); for (Object pont : pontok) napló.append(pont+","); napló.append("]"); } naplóz(""); } /** Fapont kinyitásának naplózása. @param tee Kinyitási esemény. */ public void treeExpanded(javax.swing.event.TreeExpansionEvent tee) { naplóz("TreeExpansionEvent: treeExpanded, fapont="+ tee.getPath(). getLastPathComponent()); } /** Fapont bezárásának naplózása. @param tee Bezárási esemény. */ public void treeCollapsed(javax.swing.event.TreeExpansionEvent tee) { naplóz("TreeExpansionEvent: treeCollapsed, fapont="+ tee.getPath(). getLastPathComponent()); } /** Fapont kinyitási igényének naplózása. @param tee Kinyitási esemény. */ public void treeWillExpand(javax.swing.event.TreeExpansionEvent tee) { naplóz("TreeExpansionEvent: treeWillExpand, fapont="+ tee.getPath(). getLastPathComponent()); } /** Fapont bezárási igényének naplózása. @param tee Bezárási esemény. */ public void treeWillCollapse(javax.swing.event.TreeExpansionEvent tee) { naplóz("TreeExpansionEvent: treeWillCollapse, fapont="+ tee.getPath(). getLastPathComponent()); } /** Fapont kiválasztásának naplózása. @param tse Kiválasztási esemény. */ public void valueChanged(javax.swing.event.TreeSelectionEvent tse) { naplóz("TreeSelectionEvent: megváltozott kiválasztások száma="+ tse. getPaths().length); } /** Gombnyomások kezelése. @param ae Gombnyomás esemény. */ public void actionPerformed(java.awt.event.ActionEvent ae) { if (ae.getActionCommand().equals("kiválaszt")) { String választás = (String)((javax.swing.JComboBox)ae.getSource()). getSelectedItem(); int mód = 0; if (választás.equals("DISCONTIGUOUS")) mód = javax.swing.tree. TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION; else if (választás.equals("CONTIGUOUS")) mód = javax.swing.tree. TreeSelectionModel.CONTIGUOUS_TREE_SELECTION; else if (választás.equals("SINGLE")) mód = javax.swing.tree. TreeSelectionModel.SINGLE_TREE_SELECTION; fa.getSelectionModel().setSelectionMode(mód); return; } javax.swing.AbstractButton gomb = (javax.swing.AbstractButton)ae. getSource(); if (ae.getActionCommand().equals("elrejt")) { javax.swing.tree.TreePath[] pontok = fa.getSelectionPaths(); if (pontok==null) return; //kiválasztott fapontok elrejtése for (int i=0; i=0;) if (pontok.get(azonosító+i).látható) szám++; return szám; } /** Rendezettséget megadó objektum */ private java.text.Collator collator = java.text.Collator.getInstance(); /** Fapont gyermekeinek rendezése és realizálása. @param pont A rendezendő fapont. */ private void rendez( Fapont pont ) { pont.rendezett = true; String azonosító = pont.azonosító+JEL; Fapont[] rendezés = new Fapont[ágakszáma]; for (int i=0; i<ágakszáma; i++) { //beszúrásos rendezés pont = pontok.remove(azonosító+i); if (pont==null) pont = new Fapont(azonosító+i); int kezdőindex = 0; //beszúrási pozíció int végindex = i; //logaritmikus keresése int újindex = (kezdőindex + végindex) >> 1; while (végindex>kezdőindex) { if (collator.compare(pont.toString(), rendezés[újindex]. toString())>0) kezdőindex = újindex+1; else végindex = újindex; újindex = (kezdőindex + végindex) >> 1; } for (int j=i; --j>=újindex;) rendezés[j+1]=rendezés[j]; rendezés[újindex]=pont; //beszúrás } for (int i=0; i<ágakszáma; i++) { //rendezett fapontok felvétele rendezés[i].azonosító = azonosító + i; pontok.put(rendezés[i].azonosító, rendezés[i]); } } /** Adott gyermek lekérdezése. @param szülő A kérdéses fapont. @param index A keresett gyermek indexe. @return A keresett gyermek. */ public Object getChild(Object szülő, int index) { Fapont pont = (Fapont)szülő; if (!pont.rendezett) rendez(pont); String azonosító = pont.azonosító+JEL; for (int i=0; i<ágakszáma; i++) if (pontok.get(azonosító+i).látható) { if (index == 0) return pontok.get(azonosító+i); index--; } return null; //nincs ilyen indexű gyermek } /** Adott gyermek indexének lekérdezése. @param szülő A kérdéses fapont. @param gyermek A keresett gyermek. @return A keresett gyermek indexe. */ public int getIndexOfChild(Object szülő, Object gyermek) { Fapont pont = (Fapont)gyermek; if (!pont.látható) return -1; //nem látszik String azonosító = ((Fapont)szülő).azonosító+JEL; int index = 0; try { //valóban gyermeke az adott fapontnak index=Integer.parseInt(pont.azonosító.substring(azonosító.length())); } catch (Exception e) { return -1; } //index korrigálása a nemlátható for (int i=index;--i>=0;) if (!pontok.get(azonosító+i).látható) index--; return index; } /** Akkor levél, ha nincs látható gyermeke. @param fapont A kérdéses fapont. @return Adott fapont levél-e. */ public boolean isLeaf(Object fapont) { return getChildCount(fapont)==0; } /** Eredeti érték visszaállítása. @param útvonal A visszaállítandó fapont. */ public void resetNode(javax.swing.tree.TreePath útvonal) { removeNode((Fapont)útvonal.getLastPathComponent()); fireTreeStructureChanged(útvonal); //fastruktúra újraépítése } /** Adott fapont és realizált gyermekeinek törlése. @param pont A törlendő fapont. */ private void removeNode(Fapont pont) { if (pontok.remove(pont.azonosító)!=null) naplóz("Fapont törölve! azonosító="+pont.azonosító+ ", tárolt fapontok száma="+pontok.size()); if (pont.rendezett) { String azonosító = pont.azonosító+JEL; for (int i=ágakszáma; --i>=0;) removeNode(pontok.get(azonosító+i)); } if (getRoot()==null) initRoot(); //gyökér újrainicializálása } /** Adott fapont elrejtése. @param útvonal Az elrejtendő ág. */ public void hideNode(javax.swing.tree.TreePath útvonal) { Fapont pont = (Fapont)útvonal.getLastPathComponent(); if (pont == getRoot()) return; //gyökér mindig látszik pont.látható = false; fireTreeStructureChanged(útvonal); //fastruktúra újraépítése } /** Fapont elrejtett gyermekeinek újra megmutatása. @param útvonal A megjelenítendő ág. */ public void showChildren(javax.swing.tree.TreePath útvonal) { Fapont pont = (Fapont)útvonal.getLastPathComponent(); boolean változás = false; //fastruktúrát újra kell építeni? if (pont.rendezett) { String azonosító = pont.azonosító+JEL; for (int i=ágakszáma; --i>=0;) if (!pontok.get(azonosító+i).látható) pontok.get(azonosító+i).látható = változás = true; } if (változás) fireTreeStructureChanged(útvonal); } /** Adott fapont tartalomváltozásának jelzése. @param útvonal A megváltozott fapont. @param újérték A megváltozott tartalom. */ public void valueForPathChanged(javax.swing.tree.TreePath útvonal, Object újérték) { Fapont pont = (Fapont)útvonal.getLastPathComponent(); if (!pont.toString().equals(újérték.toString())) { pont.tartalom = újérték.toString(); //valóban megváltozott fireTreeStructureChanged(útvonal); //fastruktúra újraépítése } } /** Adatmodell változását figyelők listája */ private java.util.Vector figyelők = new java.util.Vector(); /** Modellfigyelők felvétele. @param figyelő Adatmodell figyelő. */ public void addTreeModelListener(javax.swing.event.TreeModelListener figyelő ) { figyelők.add(figyelő); //figyelő felvétele } /** Modellfigyelők törlése. @param figyelő Adatmodell figyelő. */ public void removeTreeModelListener(javax.swing.event.TreeModelListener figyelő) { figyelők.remove(figyelő); //figyelő törlése } /** Fastruktúra újraépíttetése. @param útvonal Az újraépíttetendő részfa. */ private void fireTreeStructureChanged(javax.swing.tree.TreePath útvonal) { if (útvonal.getPathCount()>1) útvonal = útvonal.getParentPath(); Fapont pont = (Fapont)útvonal.getLastPathComponent(); rendez( pont) ; //újra kell rendezni javax.swing.event.TreeModelEvent esemény = new javax.swing.event. TreeModelEvent(this, útvonal); for (javax.swing.event.TreeModelListener figyelő : figyelők) figyelő.treeStructureChanged(esemény); //változás jelzése } } /** Szerkesztést végző osztály */ class Editor extends javax.swing.tree.DefaultTreeCellEditor { /** Verziószám. */ private final static long serialVersionUID = 15L; /** Konstruktor. @param fa A szerkesztendő fa. @param dtcr A használandó megjelenítő. */ Editor(javax.swing.JTree fa, javax.swing.tree.DefaultTreeCellRenderer dtcr){ super( fa, dtcr ); } /** Szerkesztés megkezdésének jelzése. @param esemény A szerkesztést indító esemény. @return Igaz ha az esemény hatására indítható a szerkesztés. */ @Override public boolean isCellEditable(java.util.EventObject esemény) { if (!fa.isEditable()) return false; //csak ha szerkeszthető a fa if (esemény instanceof java.awt.event.MouseEvent && javax.swing.SwingUtilities.isRightMouseButton(//jobbegérgomb (java.awt.event.MouseEvent)esemény)) { prepareForEditing(); //esetén indulhat a szerkesztés return true; } return super.isCellEditable(esemény); } }}