Avatar billede funkyloonie Nybegynder
19. februar 2003 - 22:06 Der er 17 kommentarer og
1 løsning

Keylistener på en JTable.

Jeg prøver at lave en keylistener til den enkelte celle i en JTable. Problemet er at jeg ikke kan få tabellen til at stoppe med at fylde flere tegn ind i sig når max værdien nås. Min keylistener ser sådan ud:

protected class CellHandler extends KeyAdapter {
  int fieldSize, code;
  String sign = "";
  JTable table;
  public CellHandler(int size, JTable table) {
    this.fieldSize = size;
    this.table = table;
  }

  public void keyPressed(KeyEvent e) {  this.code = e.getKeyCode(); sign = ""+e.getKeyChar();}

  public void keyTyped(KeyEvent e) {   
    String g = (String) table.getModel().getValueAt(table.getEditingRow(), table.getEditingColumn());

    System.out.println(g.length() +" > "+ this.fieldSize);
    if(g.length() > this.fieldSize) {
      e.consume();
    }

  }

Jeg har ikke den store erfaring med JTable så jeg ved ikke om det er den forkerte måde at gøre det på. Måske skal der addes en keylistener pr celle istedet for en fælles til tabellen. Jeg har lavet min egen TableModel ved at arve fra AbstractTableModel. Håber der er nogen har lidt erfaring at dele ud af.
Avatar billede magoo20000 Nybegynder
20. februar 2003 - 11:33 #1
Måske kan du bruge (noget af) dette!
http://www.eksperten.dk/spm/73581
Avatar billede viht Nybegynder
20. februar 2003 - 18:24 #2
Det er ikke optimalt at bruge en KeyListener. Bedre er det at anvende en DocumentListener på cellen og lade cellen være repræsenteret af et JTextField.

//TableElement.java:
public class TableElement {
   
    private String navn;
    private String adresse;
    private String telefonNummer;


    public TableElement(String navn, String adresse, String telefonNummer) {
        this.navn = navn;
        this.adresse = adresse;
        this.telefonNummer = telefonNummer;
    }
   
    public void setNavn(String navn) { this.navn = navn; }
    public void setAdresse(String adresse) { this.adresse = adresse; }
    public void setTelefonNummer(String telefonNummer) { this.telefonNummer = telefonNummer; }
    public String getNavn() { return (this.navn); }
    public String getAdresse() { return (this.adresse); }
    public String getTelefonNummer() { return (this.telefonNummer); }

    public String toString() {

        StringBuffer toString = new StringBuffer();
        toString.append("\nnavn = ");
        toString.append(navn);
        toString.append("\nadresse = ");
        toString.append(adresse);
        toString.append("\ntelefonNummer = ");
        toString.append(telefonNummer);
        toString.append("\n");
       
        return new String(toString);
    }
}
//ATableModel.java:
import javax.swing.table.AbstractTableModel;
import javax.swing.*;

import java.util.Vector;

public class ATableModel extends AbstractTableModel {
    private String[] columns = { "Navn", "Adresse", "Telefonnummer" };
      private Vector data;

    public ATableModel() {
        data = new Vector();
    }

  public int getColumnCount() {
      return columns.length;
  }
   
  public int getRowCount() {
      return data.size();
  }

  public String getColumnName(int column) {
      return columns[column];
  }

  public Object getValueAt(int row, int column) {
      TableElement element = (TableElement)data.elementAt(row);
      String value = "";
      switch( column ) {
          case 0: {
              value = element.getNavn();
          } break;
          case 1: {
              value = element.getAdresse();
          } break;
          case 2: {
              value = element.getTelefonNummer();
          } break;
      }
      return value;
  }

  public Class getColumnClass(int column) {
      return getValueAt(0, column).getClass();
  }

  public boolean isCellEditable(int row, int column) {
      switch( column ) {
          case 0: {
              return false;
          }
          case 1: {
              return true;
          }
          case 2: {
              return false;
          }
      }
      return false;
  }

  public void setValueAt(Object value, int row, int column) {
      switch( column ) {
          case 0: {
              ((TableElement)data.elementAt(row)).setNavn((String)value);
          } break;
          case 1: {
              ((TableElement)data.elementAt(row)).setAdresse((String)value);
          } break;
          case 2: {
              ((TableElement)data.elementAt(row)).setTelefonNummer((String)value);
          } break;
      }
      fireTableCellUpdated(row, column);
    }
   
    public void addTableElement(TableElement element) {
        data.add(element);
        fireTableRowsInserted(data.size(), data.size());
    }
   
    public void removeTableElement(int index) {
        if( !(index == -1) ) {
            data.removeElementAt(index);
            fireTableRowsDeleted(index, index);
        }
    }
}
//TableTest.java:
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.awt.*;

public class TableTest extends JFrame {
   
    private JTable table;
    private ATableModel tableModel;
   
    private JButton addButton;
    private JPopupMenu popup;
    private JMenuItem sletItem;
   
    public TableTest() {
      super("TableTest");
      setSize(400,400);
      getContentPane().setLayout(new BorderLayout());
     
      tableModel = new ATableModel();
      table = new JTable(tableModel);
      table.addMouseListener(new PopupListener());
      table.getTableHeader().setReorderingAllowed(false);
        table.getTableHeader().setResizingAllowed(false);

        TableColumn textFieldColumn = table.getColumnModel().getColumn(1);
        JTextField field = new JTextField(new FixedSizeDocument(10), "", 20);
        textFieldColumn.setCellEditor(new DefaultCellEditor(field));
       
      getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);
     
      JPanel buttons = new JPanel();
      addButton = new JButton("Tilføj");
      addButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
            addElement();
        }
      });
        buttons.add(addButton);
        getContentPane().add(buttons, BorderLayout.SOUTH);
       
        popup = new JPopupMenu("Valgmuligheder");
        sletItem = new JMenuItem("Slet felt");
        sletItem.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent event) {
              removeElement();
          }
        });
        popup.add(sletItem);
    }
   
    private void addElement() {

        JTextField navn = new JTextField("Navn");
        JTextField adresse = new JTextField("Adresse");
        JTextField telefon = new JTextField("Telefonnummer");
       
        Object[] messages = new Object[3];
        messages[0] = navn;
        messages[1] = adresse;
        messages[2] = telefon;
        String[] options = { "Ok", "Annuller" };
       
        int result = JOptionPane.showOptionDialog(this,
                                                        messages,
                                                          "Indtast",
                                                          JOptionPane.DEFAULT_OPTION,
                                                          JOptionPane.INFORMATION_MESSAGE,
                                                          null,
                                                          options,
                                                          options[0] );
        if( result == 0)
            tableModel.addTableElement(new TableElement(navn.getText(), adresse.getText(), telefon.getText()));
    }
    private void removeElement() {
        tableModel.removeTableElement(table.getSelectedRow());
    }
    private  class PopupListener extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            maybeShowPopup(e);
        }

        public void mouseReleased(MouseEvent e) {
            maybeShowPopup(e);
        }

        public void mouseClicked(MouseEvent e) {
          maybeShowPopup(e);
        }

        public void maybeShowPopup(MouseEvent e) {
            if (e.isPopupTrigger()) {

                JTable table = (JTable)e.getComponent();
                Point point = new Point(e.getX(), e.getY());
            table.setRowSelectionInterval(table.rowAtPoint( point ),table.rowAtPoint( point ));
            table.setColumnSelectionInterval(table.columnAtPoint( point ),table.columnAtPoint( point ));
                String columnName = table.getColumnName(table.getSelectedColumn());
            popup.show(e.getComponent(), point.x, point.y);
            }
        }
    }
  private class FixedSizeDocument extends PlainDocument {
   
        private int limit;
   
        public FixedSizeDocument(int limit) {
            this.limit = limit;
        }
   
        public void insertString (int offs, String str, AttributeSet a) throws BadLocationException {
            if (getLength() + str.length() <= limit)
                super.insertString(offs, str, a);
        }
    }
}

class TestTableTest {
   
    public static void main(String[] args) {
        new TableTest().show();
    }
}
Avatar billede viht Nybegynder
20. februar 2003 - 18:28 #3
P.S.
Du kan slette elementer i tabellen ved at højreklikke på en celle.
Avatar billede funkyloonie Nybegynder
20. februar 2003 - 20:22 #4
Damm. viht>> du har bare styr på det med tabeller. dit FixedSizeDocument er lige til at bygge videre på. jeg takker.
Avatar billede viht Nybegynder
20. februar 2003 - 20:23 #5
Jeg takker for point ;)
Avatar billede funkyloonie Nybegynder
20. februar 2003 - 20:35 #6
Når man skriver i cellen er der en lille kant fra JTextField. jeg synes det ser bedst ud hvis den ikke er der da der er kant "nok" pga tabellen. derfor kan man skrive field.setBorder(null); lige efter man opretter field i koden. derved forsvinder kanten. viht du ved det sikekrt men måske andre kan få glæde af det ;-)
Avatar billede viht Nybegynder
20. februar 2003 - 20:36 #7
Det havde jeg faktisk godt bemærket, og det er da en udmærket ide at fjerne borderen! :)
Avatar billede funkyloonie Nybegynder
22. februar 2003 - 02:30 #8
jeg har lige et opfølgende spørgsmål til dig viht. jeg har bemærket den sidste værdi man indtaster i en celle før man afvikler kommadoen getValueAt(row,column) ikke er opdateret med den sidst indtastede værdi. jeg har ikke lige selv kunnet gennemskue den. Vædien fås fint nok med getSelected..() men i en løkke er det ikke optimalt at skulle tage hensyn til en manglende opdatering af værdi. håber du har svaret. på forhånd tak.
Avatar billede funkyloonie Nybegynder
22. februar 2003 - 02:49 #9
i dit eksempel indtaster du selvfølgelig ikke direkte i boksen men ved at indsætte før du kalder metoden addElement i din button-handler vil du kunne se mit problem. For at se det skal du først tilføje en række, dernæst ændre i feks adressen og dernæst klikek på tilføj. Hvis du har en ide til hvordan det løses så skriv lige et par linier.

for(int i = 0; i < table.getRowCount(); i++) {
            for(int j = 0; j < table.getColumnCount(); j++) {
                  System.out.println(i + "  " + j + "  " + table.getModel().getValueAt(i,j));

            }
          }


Min tabelmodel ser sådan ud:

import javax.swing.table.AbstractTableModel;
import java.util.Vector;
import java.awt.event.*;

public class TableModelEdit extends AbstractTableModel {
  private String[] columns = {"Udstyr", "Indkøbspris", "Udsalgspris", "Dansk navn", "Engelsk navn", "Tysk navn"};
  private Vector data;

  public TableModelEdit() {
    data = new Vector();
  }

  public int getColumnCount() {
      return columns.length;
  }

  public int getRowCount() {
      return data.size();
  }

  public String getColumnName(int column) {
      return columns[column];
  }

  public Object getValueAt(int row, int column) {
    String[] tableRow = (String[]) data.elementAt(row);
    return tableRow[column];
  }

  public Class getColumnClass(int c) {
      return getValueAt(0, c).getClass();
  }

  public boolean isCellEditable(int row, int col) {
    if (col == 0){
      return false;
    }
    else {
      return true;
    }
  }

  public void setValueAt(Object value, int row, int column) {
    String[] tableRow = (String[]) data.elementAt(row);
    tableRow[column] = value.toString();
    fireTableCellUpdated(row, column);
  }

  public void addTableRow(String[] row) {
    data.add(row);
    fireTableRowsInserted(data.size(), data.size());
  }

  public void removeTableRow(int index) {
    if( !(index == -1) ) {
      data.removeElementAt(index);
      fireTableRowsDeleted(index, index);
    }
  }
}
Avatar billede funkyloonie Nybegynder
22. februar 2003 - 02:51 #10
det der skal indsættes før addElement er selvfølgelig løkken som som jeg har pastet. (skrev lidt stærkt før...)
Avatar billede viht Nybegynder
22. februar 2003 - 09:56 #11
Jeg ved ikke om jeg forstår dit spørgsmål rigtig.. men hvis jeg først indsætter vha addElement() værdierne: "Navn", "Adresse" og "Telefonnummer". Derefter går jeg ind og ændrer adressen til "jesper". Jeg trykker så på tilføj og din løkke skriver følgende:
0  0  Navn
0  1  jesper
0  2  Telefonnummer

Det er da den nyeste indtastede værdi?
Jeg har sikkert misforstået dit spørgsmål, men uddyb gerne hvis jeg ikke er med.
Avatar billede funkyloonie Nybegynder
22. februar 2003 - 13:13 #12
Det jeg får er:

0  0  Navn
0  1  Adresse
0  2  Telefonnummer

Prøv at indsætet dette:
addButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
          for(int i = 0; i < table.getRowCount(); i++) {
            for(int j = 0; j < table.getColumnCount(); j++) {             
                System.out.println(i + "  " + j + "  " + table.getModel().getValueAt(i,j));
            }
          }

          addElement();
            for(int i = 0; i < table.getRowCount(); i++) {
              for(int j = 0; j < table.getColumnCount(); j++) {
                  System.out.println(i + "  " + j + "  " + table.getModel().getValueAt(i,j));

              }
            }
        }
      });


Problemet opstår når man ændrer indholdet i cellen og derefter klikker på tilføj inden man har trykket på enter mens markøren stadig er aktiv i cellen. Håber du kan se hvad jeg mener ved at skrive din actionlistener over. jeg tror ikke at det bare er mig...
Avatar billede viht Nybegynder
22. februar 2003 - 14:37 #13
Jamen tabellens indhold bliver ikke opdateret før du har trykket enter og kaldt setValueAt(...);
Ellers skal du kalde setValueAt(..) hver gang brugeren indtaster noget i feltet, det kan du jo gøre med den DocumentListener der er på JTextField'et.
Avatar billede funkyloonie Nybegynder
22. februar 2003 - 17:27 #14
hmm. jeg har lavet en documentlistener men jeg kan ikke rigtigt få den indtastede værdi sat. hvor skal jeg få den indtastede værdi fra?
Avatar billede viht Nybegynder
22. februar 2003 - 19:22 #15
Sådan her:
        TableColumn textFieldColumn = table.getColumnModel().getColumn(1);
        JTextField field = new JTextField(new FixedSizeDocument(10), "", 20);
        final Document document = field.getDocument();
        document.addDocumentListener(new DocumentListener() {
            public void changedUpdate(DocumentEvent e ) {
                  getInput(document);
            } 
           
            public void insertUpdate( DocumentEvent e ){
                getInput(document);
            } 
           
            public void removeUpdate( DocumentEvent e ){
                  getInput(document);
            } 
           
            public void getInput(Document d) {
                try {
                    String text = document.getText(0, document.getLength());
                    System.out.println ("user typing: "+text);
                    tableModel.setValueAt(text, table.getSelectedRow(), table.getSelectedColumn());
                }
                catch( BadLocationException ble ) {
                    System.out.println (ble);
                }               
            }
        });
        textFieldColumn.setCellEditor(new DefaultCellEditor(field));
Avatar billede funkyloonie Nybegynder
23. februar 2003 - 21:03 #16
jeg takker mange gange igen for din hjælp. jeg håber ikke du synes jeg har været for besværlig. :-) hygge
Avatar billede funkyloonie Nybegynder
23. februar 2003 - 21:12 #17
og lige en detalje... parameteren i Document d er vist ikek så nødvendig da der jo refereres direkte til document i getInput(). Tak igen!
Avatar billede viht Nybegynder
23. februar 2003 - 22:27 #18
Glad to be of service :-)
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester