27. juli 2005 - 09:55Der er
30 kommentarer og 1 løsning
TableModel og void MoveRow()
Hej
Jeg har fået mig et lille problem med min tablemodel. Jeg skal lave en applet, som indeholder en jtable, hvori felter i 4 kolonner er editerbare og jeg sørger for at gemme de indtastede data i en seperat klasse der extender DefaultCellEditor. Brugeren har ligeledes mulighed for at markere en eller flere rækker i tabellen og flytte rundt på disse vha en knap og det er her mit problem starter, da et kald til "minTableModel".moverow(start, end, to) ikke flytter rundt på dataene som forventet. De bliver slet ikke flyttet.....
public class IntegerEditor extends DefaultCellEditor { JFormattedTextField ftf; NumberFormat integerFormat; private Integer minimum, maximum; private boolean DEBUG = true;
public IntegerEditor(int min, int max) {
super(new JFormattedTextField()); ftf = (JFormattedTextField)getComponent(); minimum = new Integer(min); maximum = new Integer(max);
//Set up the editor for the integer cells. integerFormat = NumberFormat.getIntegerInstance(); NumberFormatter intFormatter = new NumberFormatter(integerFormat); intFormatter.setFormat(integerFormat); intFormatter.setMinimum(minimum); intFormatter.setMaximum(maximum);
//React when the user presses Enter while the editor is //active. (Tab is handled as specified by //JFormattedTextField's focusLostBehavior property.) ftf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check"); ftf.getActionMap().put("check", new AbstractAction() { public void actionPerformed(ActionEvent e) { if (!ftf.isEditValid()) { //The text is invalid. if (userSaysRevert()) { //reverted ftf.postActionEvent(); //inform the editor } } else try { //The text is valid, ftf.commitEdit(); //so use it. ftf.postActionEvent(); //stop editing } catch (java.text.ParseException exc) { System.out.println("parse exception"); } } }); }
//Override to invoke setValue on the formatted text field. public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { JFormattedTextField ftf = (JFormattedTextField)super.getTableCellEditorComponent(table, value, isSelected, row, column); ftf.setValue(value); return ftf; }
//Override to ensure that the value remains an Integer. public Object getCellEditorValue() { JFormattedTextField ftf = (JFormattedTextField)getComponent(); Object o = ftf.getValue(); if (o instanceof Integer) { return o; } else if (o instanceof Number) { return new Integer(((Number)o).intValue()); } else { if (DEBUG) { System.out.println("getCellEditorValue: o isn't a Number"); } try { return integerFormat.parseObject(o.toString()); } catch (ParseException exc) { System.err.println("getCellEditorValue: can't parse o: " + o); return null; } } }
//Override to check whether the edit is valid, //setting the value if it is and complaining if //it isn't. If it's OK for the editor to go //away, we need to invoke the superclass's version //of this method so that everything gets cleaned up. public boolean stopCellEditing() { JFormattedTextField ftf = (JFormattedTextField)getComponent(); if (ftf.isEditValid()) { try { ftf.commitEdit(); } catch (java.text.ParseException exc) { }
} else { //text is invalid if (!userSaysRevert()) { //user wants to edit return false; //don't let the editor go away } } return super.stopCellEditing(); }
/** * Lets the user know that the text they entered is * bad. Returns true if the user elects to revert to * the last good value. Otherwise, returns false, * indicating that the user wants to continue editing. */ protected boolean userSaysRevert() { Toolkit.getDefaultToolkit().beep(); ftf.selectAll(); Object[] options = {"Edit", "Revert"}; int answer = JOptionPane.showOptionDialog( SwingUtilities.getWindowAncestor(ftf), "The value must be an integer between " + minimum + " and " + maximum + ".\n" + "You can either continue editing " + "or revert to the last valid value.", "Invalid Text Entered", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[1]);
public class DataTableModel extends DefaultTableModel {
private static String[] columnNames = { "Urgent", "Order #", "Design", "Dlv. date", "Order size", "Produced", "Tool", "Board", "Customer", "Text", "Sheet status", "Order location", "Comment", "#1", "#2", "#3", "#4" }; private static Object[][] data = { {new Boolean(true), "8562232", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.GREEN, Color.red, "", new Integer(0), new Integer(0), new Integer(0), new Integer(0)}, {new Boolean(false), "9900909", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.red, Color.GREEN, "", "", "", "", ""}, {new Boolean(false), "1110011", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.GREEN, Color.red, "", "", "", "", ""}, {new Boolean(true), "7775577", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.red, Color.GREEN, "", "", "", "", ""}, {new Boolean(false), "12345678", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.red, Color.green, "", "", "", "", ""}, };
public DataTableModel(){ super(data, columnNames); }
public int getColumnCount() {return columnNames.length;} public int getRowCount() {return data.length;} public String getColumnName(int col) {return columnNames[col];} public Object getValueAt(int row, int col) {return data[row][col];} public Class getColumnClass(int c) {return getValueAt(0, c).getClass();}
public boolean isCellEditable(int row, int col) { if(col > 12 && col < 17){return true;} return false; }
public void setValueAt(Object value, int row, int col) { if (GUI.DEBUG) { System.out.println("Setting value at " + row + "," + col + " to " + value + " (an instance of " + value.getClass() + ")"); }
public void packColumns(JTable table, int margin) { for (int c = 0; c < table.getColumnCount()-7; c++) { packColumn(table, c, 2); } }
public void packColumn(JTable table, int colIndex, int margin) { DefaultTableColumnModel colModel = (DefaultTableColumnModel)table.getColumnModel(); TableColumn col = colModel.getColumn(colIndex); int width = 0;
// Get width of column header TableCellRenderer renderer = col.getHeaderRenderer(); if (renderer == null) {renderer = table.getTableHeader().getDefaultRenderer();} Component comp = renderer.getTableCellRendererComponent(table, col.getHeaderValue(), false, false, 0, 0); width = comp.getPreferredSize().width;
// Get maximum width of column dataTable for (int r=0; r<table.getRowCount(); r++) { renderer = table.getCellRenderer(r, colIndex); comp = renderer.getTableCellRendererComponent(table, table.getValueAt(r, colIndex), false, false, r, colIndex); width = Math.max(width, comp.getPreferredSize().width); }
// Add margin width += 2*margin;
// Set the width col.setPreferredWidth(width); } } ----------------------------------------------------------------------
Denne side indeholder artikler med forskellige perspektiver på Identity & Access Management i private og offentlige organisationer. Artiklerne behandler aktuelle IAM-emner og leveres af producenter, rådgivere og implementeringspartnere.
nu er det jo så ikke en kolonne, jeg vil flytte men en eller flere rækker :-) og disse kan jeg godt flytte med moveRow metoden, men fordi jeg har en anden cellEditor end default, så kommer jeg i problemer.....
Du har ret - fik lige set at moveRow() er en metode i DefaultTableModel, og den flytter rent faktisk data i modellen for derefter at opdatere tabellen.
Skal nok kigge på din kode senere på aftenen - håber at nå det!
ups, koden hvor jeg kalder moverow() har jeg lige glemt, den kommer i morgen, men den bliver kaldt fra min main klasse, hvor jeg har en knap hvis actionlistener fyrer den af således :
//DataTableModel dtm dtm.moverow(start, end, to)
nej, jeg får sjovt nok ingen fejl når den bliver kaldt.....
public static boolean DEBUG = true; DataTable dataTable = null; static JButton moveRowsBtn; private final java.text.DateFormat dateFormat = new java.text.SimpleDateFormat("dd.MM.yy HH:mm");
int start = 0; //pointers used for movings tablerows int end = 0; //pointers used for movings tablerows int to = 0; //pointers used for movings tablerows
//Create the scroll pane and add the table to it. JScrollPane scrollPane = new JScrollPane(dataTable);
//Set up renderer and editor for the Favorite Color column. dataTable.setDefaultRenderer(Color.class, new ColorRenderer(true)); dataTable.getColumnModel().getColumn(13).setCellEditor(new IntegerEditor(0, 1000)); dataTable.getColumnModel().getColumn(14).setCellEditor(new IntegerEditor(0, 1000)); dataTable.getColumnModel().getColumn(15).setCellEditor(new IntegerEditor(0, 1000)); dataTable.getColumnModel().getColumn(16).setCellEditor(new IntegerEditor(0, 1000));
//Add the scroll pane to this panel. JPanel topPanel = new JPanel();
JComboBox machines = new JComboBox(); machines.addItem("Machine #1");
JLabel lastUpdated = new JLabel(); java.sql.Timestamp d = new java.sql.Timestamp(System.currentTimeMillis()); lastUpdated.setText("Last updated : " + dateFormat.format(d));
moveRowsBtn = new JButton("Move"); moveRowsBtn.addActionListener(actionListener);
private void move(java.awt.event.ActionEvent evt) { DefaultTableModel model = (DefaultTableModel)table.getModel(); int to = table.getRowCount() - 1; int[] selected = table.getSelectedRows(); int moved = 0;
for(int i = 0; i < table.getRowCount(); i++){ for(int x = 0; x < table.getColumnCount(); x++){ System.out.print("\t" + model.getValueAt(i, x).toString());
} for(int x = 0; x < selected.length; x++){ if(i == selected[x]) System.out.print("\tmoved !"); } System.out.println(""); }
for(int y = 0; y < selected.length ; y++){ model.moveRow(selected[y - moved], selected[y - moved], to); moved++;
System.out.println(""); } }
public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new TestRowMove().setVisible(true); } }); }
hej igen det eksempel virker som du siger, men det løser ikke mit problem.....jeg kan nemt få min model til at flytte data også på den måde jeg har lavet min knap på (jeg er jo nødt til at vide hvor jeg skal flytte rækkerne hen og ikke bare til bunden af tabellen)
problemet kommer først når jeg ligger en cellEditor på og en cellRender og overskriver getValueAt og setValueAt metoderne på min tablemodel
Hvis du vil indsætte en række, skal du ikke bruge moveRow(), men insertRow().
"problemet kommer først når jeg ligger en cellEditor på og en cellRender". - Så er det jo din implementation af dem vil skal se, for det bør ikke være et problem.
Se nedenstående eksempel med insertRow(), indsætter en række over valgt række.
hej igen, jeg kan godt se jeg ikke er god til at forklare mig, min "insert" betyder stadig væk, hvor jeg skal flytte de(n) markerede felter hen og ikke "insert" som i "insertrow".
Hvis du har tålmodighed til det, kunne jeg godt tænke mig om du gad at tilføje klassen IntegerEditor til dit eksempel og se om du stadig kan få skidtet til at flytte rundt på rækkerne, da jeg først får problemet efter at have tilføjet min nye celleditor (IntegerEditor) :-)
private void move(java.awt.event.ActionEvent evt) { DefaultTableModel model = (DefaultTableModel)table.getModel(); int to = table.getRowCount() - 1; int[] selected = table.getSelectedRows(); int moved = 0;
for(int i = 0; i < table.getRowCount(); i++){ for(int x = 0; x < table.getColumnCount(); x++){ System.out.print("\t" + model.getValueAt(i, x).toString());
} for(int x = 0; x < selected.length; x++){ if(i == selected[x]) System.out.print("\tmoved !"); } System.out.println(""); }
for(int y = 0; y < selected.length ; y++){ model.moveRow(selected[y - moved], selected[y - moved], to); moved++;
System.out.println(""); } }
public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new TestRowMove().setVisible(true); } }); }
super(new JFormattedTextField()); ftf = (JFormattedTextField)getComponent(); minimum = new Integer(min); maximum = new Integer(max);
//Set up the editor for the integer cells. integerFormat = NumberFormat.getIntegerInstance(); NumberFormatter intFormatter = new NumberFormatter(integerFormat); intFormatter.setFormat(integerFormat); intFormatter.setMinimum(minimum); intFormatter.setMaximum(maximum);
//React when the user presses Enter while the editor is //active. (Tab is handled as specified by //JFormattedTextField's focusLostBehavior property.) ftf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check"); ftf.getActionMap().put("check", new AbstractAction() { public void actionPerformed(ActionEvent e) { if (!ftf.isEditValid()) { //The text is invalid. if (userSaysRevert()) { //reverted ftf.postActionEvent(); //inform the editor } } else try { //The text is valid, ftf.commitEdit(); //so use it. ftf.postActionEvent(); //stop editing } catch (java.text.ParseException exc) { System.out.println("parse exception"); } } }); }
protected boolean userSaysRevert() { Toolkit.getDefaultToolkit().beep(); ftf.selectAll(); Object[] options = {"Edit", "Revert"}; int answer = JOptionPane.showOptionDialog( SwingUtilities.getWindowAncestor(ftf), "The value must be an integer between " + minimum + " and " + maximum + ".\n" + "You can either continue editing " + "or revert to the last valid value.", "Invalid Text Entered", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[1]);
hmm, jeg har vist husket fejl.....problemet opstår når jeg laver min egen tablemodel og overskriver de default metoder klassen har til data udtræk..... :
package test;
import java.awt.Color; import java.util.Date;
import javax.swing.table.DefaultTableModel;
public class DataTableModel extends DefaultTableModel {
private static boolean DEBUG = false;
private static String[] columnNames = { "Urgent", "Order #", "Design", "Dlv. date", "Order size", "Produced", "Tool", "Board", "Customer", "Text", "Sheet status", "Order location", "Comment", "#1", "#2", "#3", "#4" }; private static Object[][] data = { {new Boolean(true), "8562232", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.GREEN, Color.red, "", new Integer(0), new Integer(0), new Integer(0), new Integer(0)}, {new Boolean(false), "9900909", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.red, Color.GREEN, "", "", "", "", ""}, {new Boolean(false), "1110011", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.GREEN, Color.red, "", "", "", "", ""}, {new Boolean(true), "7775577", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.red, Color.GREEN, "", "", "", "", ""}, {new Boolean(false), "12345678", "K9415-12121", new Date(), new Integer(30000), new Integer(400), "", "", "", "", Color.red, Color.green, "", "", "", "", ""}, };
public DataTableModel(){ super(data, columnNames); }
public int getColumnCount() {return columnNames.length;} public int getRowCount() {return data.length;} public String getColumnName(int col) {return columnNames[col];} public Object getValueAt(int row, int col) {return data[row][col];} public Class getColumnClass(int c) {return getValueAt(0, c).getClass();}
public boolean isCellEditable(int row, int col) { if(col > 12 && col < 17){return true;} return false; }
public void setValueAt(Object value, int row, int col) { if (DEBUG) { System.out.println("Setting value at " + row + "," + col + " to " + value + " (an instance of " + value.getClass() + ")"); }
Du overrider setValueAt(), selvom der egentlig ikke er nogen grund til det, da det kun er debugging du kigger på.
Men - hvis du gør det skal den se sådan ud - prøv lige det!
public void setValueAt(Object value, int row, int col) { if (DEBUG) { System.out.println("Setting value at " + row + "," + col + " to " + value + " (an instance of " + value.getClass() + ")"); }
hej igen (håber jeg kan lokke med dig igen, vil naturligvis gerne give flere point)
Har fået lidt problemer igen
Jeg vil gerne lave mig en klasse mere der extender min normale tablemodel som jo igen extender defaulttablemodel. Det skyldes jeg gerne vil holde et pænt snit mellem mine klasser der har med GUI/Server del at gøre
Jeg har altså lavet en ny klasse DataTableGUIModel der extender min DataTableServerModel der extender DefaultTableModel
Jeg kommer igen i klemme med "moverow" metoden :-(
Koden :
package test;
import java.awt.Color; import java.util.Date;
/** * @author Jan Gravgaard * */ public class DataTableGUIModel extends DataTableServerModel {
public DataTableGUIModel(Object[][] objects, String[] strings){ super(objects, strings); }
public int getColumnCount() { return super.getColumnNames().length; }
public int getRowCount() { if(super.getRowdata()==null)return 0; return super.getRowdata().length; } public String getColumnName(int col) {return super.getColumnNames()[col];} public Object getValueAt(int row, int col) {return super.getRowdata()[row][col];} public Class getColumnClass(int c) {return super.getValueAt(0, c).getClass();}
/** * @author Jan Gravgaard * */ /** * @author Jan Gravgaard * This class extends the DefaultTableModel */ public abstract class DataTableServerModel extends DefaultTableModel {
public DataTableServerModel(Object[][] data, String[] columnNames2){ setRowdata(data); setColumnNames(columnNames2); } public int getColumnCount() { if(columnNames==null)return 0; return columnNames.length; } public int getRowCount() { if(rowdata==null)return 0; return rowdata.length; } public String getColumnName(int col) { return columnNames[col]; } public Object getValueAt(int row, int col) { return rowdata[row][col]; } public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); }
public void setValueAt(Object value, int row, int col) { super.setValueAt(value, row, col); fireTableCellUpdated(row, col); }
public boolean isCellEditable(int row, int col) { if(col > 12 && col < 17){return true;} return false; }
public static String[] getColumnNames() { return columnNames; }
public static void setColumnNames(String[] headers) { DataTableServerModel.columnNames = headers; }
public static Object[][] getRowdata() { return rowdata; }
public class TestRowMove extends javax.swing.JFrame {
int start = 0; //pointers used for movings tablerows int end = 0; //pointers used for movings tablerows int to = 0; //pointers used for movings tablerows
public TestRowMove() { initComponents(); // HER TILFØJES EDITOR !!! TableColumn col = table.getColumnModel().getColumn(0); col.setCellEditor(new IntegerEditor(5,5)); }
private void initComponents() { scroll = new javax.swing.JScrollPane(); table = new javax.swing.JTable(); jButton1 = new javax.swing.JButton(); Object[][] data = new Object [][] { {"q", "w", "e", "r"}, {"Q", "W", "E", "R"}, {"z", "x", "c", "v"}, {"Z", "X", "C", "V"} }; String[] headers = new String [] { "Title 1", "Title 2", "Title 3", "Title 4" }; setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); DataTableGUIModel dtm = new DataTableGUIModel(data,headers); table.setModel(dtm); scroll.setViewportView(table);
super(new JFormattedTextField()); ftf = (JFormattedTextField)getComponent(); minimum = new Integer(min); maximum = new Integer(max);
//Set up the editor for the integer cells. integerFormat = NumberFormat.getIntegerInstance(); NumberFormatter intFormatter = new NumberFormatter(integerFormat); intFormatter.setFormat(integerFormat); intFormatter.setMinimum(minimum); intFormatter.setMaximum(maximum);
//React when the user presses Enter while the editor is //active. (Tab is handled as specified by //JFormattedTextField's focusLostBehavior property.) ftf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check"); ftf.getActionMap().put("check", new AbstractAction() { public void actionPerformed(ActionEvent e) { if (!ftf.isEditValid()) { //The text is invalid. if (userSaysRevert()) { //reverted ftf.postActionEvent(); //inform the editor } } else try { //The text is valid, ftf.commitEdit(); //so use it. ftf.postActionEvent(); //stop editing } catch (java.text.ParseException exc) { System.out.println("parse exception"); } } }); }
protected boolean userSaysRevert() { Toolkit.getDefaultToolkit().beep(); ftf.selectAll(); Object[] options = {"Edit", "Revert"}; int answer = JOptionPane.showOptionDialog( SwingUtilities.getWindowAncestor(ftf), "The value must be an integer between " + minimum + " and " + maximum + ".\n" + "You can either continue editing " + "or revert to the last valid value.", "Invalid Text Entered", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[1]);
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1 >= 0 at java.util.Vector.elementAt(Unknown Source) at javax.swing.table.DefaultTableModel.rotate(Unknown Source) at javax.swing.table.DefaultTableModel.moveRow(Unknown Source) at test.TestRowMove.move(TestRowMove.java:86)
Det her er hamrende svært at forklare så det er forståeligt, men jeg prøver alligevel
Hvis du skal have det til at virke på den måde, er du nødt til at override metoden moveRow() i din DataTableServerModel.
Forklaring: DataTableServerModel har sit EGET array af typen Object til at holde tabeldata og et String object til at holde kolonnetekster, MEN - MEN det har klassen som du extender OGSÅ !! Du initierer altså Object[][] rowdata i DataTableServerModel med tabeldata == 4 rækker, vectoren i DefaultTableModel initieres IKKE med data, da metoden moveRow() i klassen DefaultTableModel IKKE overrides i DataTableServerModel, så er det altså den metode der kaldes, metoden begynder at flytte rækker i vectoren i DefaultTableModel (IKKE DATAENE I DataTableServerModel), da vectoren er tom, er der ikke nogen rækker at flytte rundt på, derfor får du fejlen java.lang.ArrayIndexOutOfBoundsException: 1 >= 0
Det eneste du tilsyneladende er interesseret i er at nogle kolonner må redigeres og andre ikke, du overrider en del metoder, men kun hvad der er default i fht. DefaultTableModel, så din DataTableServerModel bør se sådan ud.
public abstract class DataTableServerModel extends DefaultTableModel {
public DataTableServerModel(Object[][] data, String[] columnNames2){ super(data, columnNames2); }
public boolean isCellEditable(int row, int col) { if(col > 12 && col < 17) return true; return false; } }
Din DataTableGUIModel ser jeg som et overflødigt/generende element - den gør INTET som i forvejen ikke standard/default i DefaultTableModel
LØSNING:
Fjern klassen: DataTableGUIModel Ret DataTableServerModel til ovenstående
Jeg kan ikke helt gennemskue din move() "Insert" delen, så pt. står jeg af på den
Jeg ved ikke om det rækker, ellers må spørge igen.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.