Java felhasználói felület Táblázat Elek Tibor
Szerep: táblázatos adatok megjelenítése, szerkesztése Fogalmak: - Adatmodell (TableModel): szolgáltatja az adatokat és változásait, illetve az adatok típusait - Oszlop (TableColumn): egy oszlop jellemzőit tartalmazza (modell oszlopindex, fejléc információk, szélesség, renderer, editor, stb.) - Renderer (TableCellRenderer): szolgáltatja az adott cella megjelenítését. Típusokhoz megadható.
Fogalmak: - Editor (TableCellEditor): cella editálásakor megjelenő editor. Típusokhoz megadható. - Rendező (RowSorter): Egy oszlop összehasonlító algoritmusát tartalmazza. - Kiválasztás modell: Az adat (sor, oszlop) kiválasztási módot írja le.
Szolgáltatások: - DefaultTableModel generálása (csak Object adatokhoz érdemes) - DefaultCellRenderer az egyes típusokhoz (boolean, szám, Object) - DefaultCellEditor az egyes típusokhoz (boolean, szám, String) - RowSorter-ek automatikus generálása - DefaultSelectionModel
TableModel AbstractTableModel: addtablemodellistener(): Modell (adatok) változásai getcolumnclass(): egy adat típusát adja. Fontos felüldefiniálni! getvalueat(): egy adott sor, oszlop adatát adja setvalueat(): adatot beállítja iscelleditable(): editálható-e a cella
TableModel DefaultTableModel: Az adatok tárolását Vector-ral oldja meg. Oszlopok típusaként Object-et ad. (Leszármaztatás, getcolumnclass() felüldefiniálás.) Funkciói: sor, oszlop hozzáadás, törlés, lekérdezés, stb. Pl. addrow(object[]), addrow(vector), addcolumn(string), stb.
TableModel DefaultTableModel használat: definiálás pl.: private class SajatTableModel extends DefaultTableModel { private Class[] oszloptip = new Class[] { String.class, Integer.class }; public SajTableModel(Object[] columnnames, int rowcount) { super(columnnames, rowcount); } @Override public Class<?> getcolumnclass(int columnindex) { return oszloptipusok[columnindex]; } }
TableModel DefaultTableModel használat: létrehozás, hozzárendelés: Object[] oszlopok = new Object[] { Név, Kor }; SajatTableModel stm = new SajatTableModel(oszlopok, 0); this.jtable1.setmodel(stm); Sorok hozzáadása: stm.addrow(new Object[] { Béla, 24});
TableModel Egy másik tablemodel példa: private class SajatTableModel extends AbstractTableModel { private String[] oszlopnevek = new String[] { "Név", "Kor", "Születési dátum" }; private Class[] oszloptipusok = new Class[] { String.class, Integer.class, Date.class }; private ArrayList<Szemely> szemelyek; public SajatTableModel() { this.szemelyek = new ArrayList<Szemely>(); } public ArrayList<Szemely> getszemelyek() { return szemelyek; } public Class<?> getcolumnclass(int columnindex) { return oszloptipusok[columnindex]; } public int getrowcount() { return this.szemelyek.size(); } public int getcolumncount() { return this.oszlopnevek.length; } public String getcolumnname(int column) { return this.oszlopnevek[column]; } public boolean iscelleditable(int rowindex, int columnindex) { return true; }
TableModel Egy másik tablemodel példa folytatás: public Object getvalueat(int rowindex, int columnindex) { if (columnindex == 0) return this.szemelyek.get(rowindex).getnev(); if (columnindex == 1) return this.szemelyek.get(rowindex).getkor(); if (columnindex == 2) return this.szemelyek.get(rowindex).getszul(); return new Object(); } public void setvalueat(object avalue, int rowindex, int columnindex) { if (columnindex == 0) this.szemelyek.get(rowindex).setnev((string)avalue); if (columnindex == 1) this.szemelyek.get(rowindex).setkor((integer)avalue); if (columnindex == 2) this.szemelyek.get(rowindex).setszul((date)avalue); firetablerowsupdated(rowindex, columnindex); } }
Oszlopok Automatikus generálás: setautocreatecolumnsfrommodel(boolean) Oszlop modell: addcolumn(), removecolumn()!!! getcolumn(), movecolumn() Oszlop műveletek: get(set) HeaderValue, MinWidth, MaxWidth, PreferredWidth, ModelIndex, HeaderRenderer, CellRenderer, CellEditor
Oszlopok - Az oszlopok bővítésére, törlésére az adatmodellnek is fel kell készülni. (A példa adatmodell esetén nem szabad változtatni az oszlopokat.) - Oszlopok elrejtése funkció nem létezik. Megoldása oszlopok törlésével, hozzáadásával. - Példa: 2. oszlop szélesség, felirat beállítás TableColumn a = jtable1.getcolumnmodel().getcolumn(1); oszlopszélesség: a.setpreferredwidth(150); fejléc: a.setheadervalue( Életkor );
TableCellRenderer DefaultTableCellRenderer: - Boolean: checkbox - Number: label, jobbra igazított tartalom, NumberFormat.getXXXInstance()-tal formázva - Date: label, jobbra igazítva, DateFormat.getDateInstance(DateFormat.SHOR T)-al formázva - ImageIcon: label, középre igazítva - egyéb: label, balra igazítva (a tartalom tostring())
TableCellRenderer Saját renderer a Defaultból példa short dateformat helyett long: private class DateRenderer extends DefaultTableCellRenderer { DateFormat formatter; protected void setvalue(object value) { if (this.formatter == null) this.formatter = DateFormat.getDateInstance(DateFormat.LONG); } } this.settext(value == null? "" : this.formatter.format(value));
TableCellRenderer Saját renderer a Defaultból példa short dateformat helyett long folytatás: Használat: jtable1.setdefaultcellrenderer(date.class, new DateRenderer()); vagy TableColumn a = jtable1.getcolumnmodel().getcolumn(2); a.setcellrenderer(new DateRenderer());
TableCellRenderer Saját renderer TableCellRenderer-ből: lásd. Swing tutorial példák lásd példák editornál
Cella editálás DefaultCellEditor - Boolean: JCheckBox - Number: JFormattedTextField - Egyéb: JTextField Saját editorral megtöltött Default: Három konstruktor: JCheckBox, JComboBox, JTextField JComboBox cmb = new JComboBox(); cmb.additem("egyik"); cmb.additem("másik"); egyikcolumn.setcelleditor(new DefaultCellEditor(cmb));
Cella editálás Saját editor az AbstractCellEditor-ból: felüldefiniálandó metódusok: Component gettablecelleditorcomponent() : visszaadja a belső editor-t. Object getcelleditorvalue() : editálás végén visszaadja az értéket iscelleditable(eventobject evt) : editálás feltétele (pl. hány klikkre) boolean stopcellediting() : meghívódik mielőtt befejeződne az editálás, pl. validálásra használható
Cella editálás Saját editor az AbstractCellEditor-ból: Példa: JSpinner cell editorként private class SpinnerEditor extends AbstractCellEditor implements TableCellEditor { final JSpinner spinner = new JSpinner(); public SpinnerEditor() { spinner.setmodel(new SpinnerDateModel()); } public Component gettablecelleditorcomponent( JTable table, Object value, boolean isselected, int row, int column) { spinner.setvalue(value); return spinner; }
Cella editálás Saját editor az AbstractCellEditor-ból: Példa: JSpinner cell editorként folytatás public boolean iscelleditable(eventobject evt) { if (evt instanceof MouseEvent) { return ((MouseEvent)evt).getClickCount() >= 2; } return true; } public Object getcelleditorvalue() { return spinner.getvalue(); } } }
Rendezés table.setautocreaterowsorter(true); minden oszlopra az alapértelmezett Comparatorral TableRowSorter funkciók: get(set), is(set) Comparator : egy java.util.comparator, Sortable : rendezhető-e, SortKeys : a jelenlegi rendezés, MaxSortKeys: hány oszlop szerint lehet rendezve
Rendezés Példa: jtable1.setautocreaterowsorter(true); Sorter lekérdezése: TableRowSorter<TableModel> so = (TableRowSorter<TableModel>)jTable1.getRowSort er(); A 0. oszlop szerinti rendezés letíltása: so.setsortable(0, false); Saját comparator az 1. oszlophoz: so.setcomparator(1, new SajatComparator()); Rendezés beállítása kódból (2. oszlop növekvő): ArrayList <RowSorter.SortKey> keys = new ArrayList<RowSorter.SortKey>(); keys.add(new RowSorter.SortKey(2, SortOrder.ASCENDING)); so.setsortkeys(sortkeys);
Szűrés A rendezőnek megadható szűrési feltétel is. Létező Filter-ek: datefilter, numberfilter, regexfilter: dátumra, számra, szövegre andfilter, orfilter, notfilter: több filter összekapcsolása Pl. az 1. vagy 3. oszlopban al -t tartalmaz so.setrowfilter( RowFilter.regexFilter(".*al.*",0,2)); a második oszlopban 20-nál kisebb: so.setrowfilter(rowfilter.numberfilter( RowFilter.ComparisonType.BEFORE, 20, 1));
Kiválasztás Sor, oszlop, cellatartomány kiválasztás. DefaultListSelectionModel-t használ. (lásd JList.) DefaultListSelectionModel beállítása: setselectionmode(): egy, folytonos, több kiválasztás setxxxselectionallowed() : Cell, Column, Row kiválaszthatóság (egymást befolyásoló lehetőségek!)
Kiválasztás Kiválasztás kezelése:xxx: Row, Column int getselectedxxx(), int getselectedxxxcount(), int[] getselectedxxxs(), boolean iscellselected(int row, int col), boolean isxxxselected(int index), void addxxxselectioninterval(int tol, int ig), void setxxxselectioninterval(int tol, int ig), void changeselection(int row, int col, boolean toggle, boolean extend), void clearselection(), void selectall()
Model vs View Fontos: A táblázat kezelő metódusai a view sor, oszlop, cella sorszámát használják nem a modellbeli sorszámát!! Rendezéskor, szűréskor, oszlopmozgatáskor a kettő eltér egymástól!! Az egyikből a másikba: int convertxxxindextomodel(int viewindex) int convertxxxindextoview(int modelindex)
Model vs View Például a táblázat get(set)valueat() metódusa a view indexeket használja, a modell get(set)valueat() metódusa a modell indexeket. Például a getselectedxxx() metódus a view sorszámot adja vissza.
Gyakran használt események - Adat modell változások: a model metódusával getmodel().addtablemodellistener() - Kiválasztás változások: a selection modellek metódusaival getselectionmodel().addlistselectionlistener() és az oszlop kiválasztásra getcolumnmodel().getselectionmodel().addlistse lectionlistener()
Egyebek Adat: get(set)valueat() Kinézet: get(set) ShowGrid, ShowHorizontalLines, ShowVerticalLines, GridColor RowHeight, RowMargin Scrollozás: JScrollPane-be kell rakni
Példa
Gyakorlat Készítsen egy űrlapot, amelyben egy táblázatban lehet könyv író, cím, stílus, oldalszám, ár adatokat megjeleníteni, módosítani, újat felvinni, törölni. Használjon DefaultTableModel leszármazottat. A stílus megadásához készítsen egy combobox-t celleditorként. Az ár megjelenítéshez egy cell renderer-t, amely az alapértelmezett pénz formátumban jeleníti meg az árat.