2011-12-05 3 views
1

以下の例では、JTableJListと2つのJButton(追加と削除)があります。リストには、追加ボタンをクリックすると6つの項目(文字列)があり、選択した値が表に追加されます。
テーブル内の文字列は、カスタムレンダラー(ボタンとラベル付きのJPanel)を使用して表示されます。ボタンのテキストとラベルのテキストは、Stringの値に変更されます。
編集者がエントリーするまでは、すべてうまくいく。エディタを使用すると、ボタンをクリックすることが可能になります。
テーブルに文字列を初めて追加すると、行の高さがパネルの適切な高さに調整され、ボタンとラベルのテキストが設定されます。
行をクリックしてテーブルからエントリを削除し、[削除]ボタンをクリックすると、すべて期待どおりになります。
ここに問題があります:行の高さがあり、ラベルとボタンのテキストが設定されていない(レンダラーとエディタの両方が呼び出されていないため)ブレークポイントを使ってチェックしています)。
もちろん、私はカスタムレンダラを使って新しい行を表示したいのですが、どうしたらいいですか?追加テーブルの前のエントリを表示するカスタムTableCellEditor

package test; 

import java.awt.Component; 
import java.awt.event.ActionEvent; 
import java.util.EventObject; 
import javax.swing.AbstractAction; 
import javax.swing.DefaultListModel; 
import javax.swing.JButton; 
import javax.swing.JLabel; 
import javax.swing.JList; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.UIManager; 
import javax.swing.event.CellEditorListener; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellEditor; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 

public class MainForm 
     extends javax.swing.JFrame 
{ 
    private JTable table; 
    private JScrollPane tableScrollPane; 
    private JList list; 
    private JScrollPane listScrollPane; 
    private JButton add; 
    private JButton remove; 

    public MainForm() 
    { 
     tableScrollPane = new JScrollPane(); 
     table = new JTable(); 
     listScrollPane = new JScrollPane(); 
     list = new JList(); 
     add = new JButton(new AbstractAction() 
     { 
      public void actionPerformed(ActionEvent e) 
      { 
       add(); 
      } 
     }); 
     add.setText("add"); 
     remove = new JButton(new AbstractAction() 
     { 
      public void actionPerformed(ActionEvent e) 
      { 
       remove(); 
      } 
     }); 
     remove.setText("remove"); 

     setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.LINE_AXIS)); 

     tableScrollPane.setViewportView(table); 
     listScrollPane.setViewportView(list); 

     add(tableScrollPane); 

     DefaultTableModel model = new DefaultTableModel(); 
     model.addColumn("test"); 
     table.setModel(model); 

     TableColumn col = table.getColumn("test"); 
     col.setCellRenderer(new CustomTableCellRenderer()); 
     col.setCellEditor(new CustomTableCellEditor()); 

     DefaultListModel listModel = new DefaultListModel(); 
     listModel.addElement("test1"); 
     listModel.addElement("test2"); 
     listModel.addElement("test3"); 
     listModel.addElement("test4"); 
     listModel.addElement("test5"); 
     listModel.addElement("test6"); 
     list.setModel(listModel); 

     add(listScrollPane); 
     add(add); 
     add(remove); 
    } 

    private void add() 
    { 
     DefaultTableModel model = (DefaultTableModel) table.getModel(); 
     model.addRow(new Object[] 
       { 
        list.getSelectedValue() 
       }); 
    } 

    private void remove() 
    { 
     int selectedRow = table.getSelectedRow(); 
     DefaultTableModel model = (DefaultTableModel) table.getModel(); 
     model.removeRow(selectedRow); 
    } 

    public static void main(String[] args) 
    { 
     new MainForm().setVisible(true); 
    } 

    public class CustomTableCellRenderer 
      extends customPanel 
      implements TableCellRenderer 
    { 
     public Component getTableCellRendererComponent(JTable table, 
                 Object value, 
                 boolean isSelected, 
                 boolean hasFocus, int row, 
                 int column) 
     { 
      setText((String) value); 
      if (isSelected || hasFocus) 
      { 
       setBackground(UIManager.getColor("List.selectionBackground")); 
       setForeground(UIManager.getColor("List.selectionForeground")); 
      } 
      else 
      { 
       setBackground(UIManager.getColor("Panel.background")); 
       setForeground(UIManager.getColor("Panel.foreground")); 
      } 
      table.setRowHeight(row, (int)getPreferredSize().height); 
      return this; 
     } 
    } 

    public class CustomTableCellEditor 
      extends customPanel 
      implements TableCellEditor 
    { 
     Object value; 

     public Component getTableCellEditorComponent(JTable table, Object value, 
                boolean isSelected, int row, 
                int column) 
     { 
      this.value = value; 
      setText((String) value); 
      setBackground(UIManager.getColor("List.selectionBackground")); 
      setForeground(UIManager.getColor("List.selectionForeground")); 
      table.setRowHeight(row, (int)getPreferredSize().height); 
      return this; 
     } 

     public Object getCellEditorValue() 
     { 
      return value; 
     } 

     public boolean isCellEditable(EventObject anEvent) 
     { 
      return true; 
     } 

     public boolean shouldSelectCell(EventObject anEvent) 
     { 
      return true; 
     } 

     public boolean stopCellEditing() 
     { 
      setBackground(UIManager.getColor("Panel.background")); 
      setForeground(UIManager.getColor("Panel.foreground")); 
      return true; 
     } 

     public void cancelCellEditing() 
     { 
     } 

     public void addCellEditorListener(CellEditorListener l) 
     { 
     } 

     public void removeCellEditorListener(CellEditorListener l) 
     { 
     } 
    } 

    public class customPanel 
      extends JPanel 
    { 
     private JLabel label; 
     private JButton button; 

     public customPanel() 
     { 
      label = new JLabel(); 
      button = new JButton(); 
      add(label); 
      add(button); 
     } 

     public void setText(String text) 
     { 
      label.setText(text); 
      button.setText(text); 
     } 
    } 
} 
+1

あなたのカスタムエディタの実装は_invalid_です(問題の可能性があります)。契約によって、内部的な理由で編集が終了したときにリスナーに通知する必要があります。あなたはその契約に自明に従うことができません... – kleopatra

+0

Java命名規則を覚えておいてください。(常に!) – kleopatra

+0

読みやすさに影響しない場合は、テスト目的以外は常に命名規則を使用します。私は欠けている通知のために撃つでしょう、それが動作する場合は意味をなさない。 – siebz0r

答えて

2

あなたは使用しないでください:

table.setRowHeight(row, (int)getPreferredSize().height); 

をレンダラに。これにより、行の高さを変更するたびにテーブルが再描画され、レンダラーが呼び出されたときに再度行の高さが変更されるため、無限ループが発生します。

コードの行を削除します。代わりに、行を表に追加するときに行の高さを計算できます。あなたのadd()メソッドの最後に次のコードを追加します。

int row = table.getRowCount() - 1; 
Component comp = table.prepareRenderer(table.getCellRenderer(row, 0), row, 0); 
int rowHeight = comp.getPreferredSize().height; 
table.setRowHeight(row, rowHeight); 

更新:

コードがカスタムエディタなしで正常に動作します。だから問題はエディタです。 AbstractCellEditorのソースコードを見て、編集が停止したときにどうなるかを確認してください。エディターを削除できるように、イベントを発生させてテーブルに通知します。このコードはありません。ですから、customPanelを拡張するのではなく、AbstractCellEditorを拡張して、適切なイベントを簡単に実行できるようにすることをお勧めします。

また、行をクリックするとエディタが呼び出されるため、モデルから行を削除する前にエディタを削除する必要があります。これを行うには、いくつかの方法についてTable Stop Editingを参照してください。

+1

+ 1バンプ、私はそれを木材へのキツツキのように見た... – mKorbel

+0

ありがとう、それはあまりにも悪いことは、問題を解決しないことを知らなかった。 – siebz0r

+0

@ siebz0r、確かにそうです。私が返信する前に投稿されたコードをテストしました。 SSCCEを新しいコードで更新してください。 – camickr

0

addCellEditorListener()、removeCellEditorListener()、stopCellEditing()およびcancelCellEditing()メソッドの実装は、魅力的です。選択したオブジェクトを削除する前に、エディタを「切断」する必要があります。
私のテーブルの1つでは、テーブルエントリを変更するためのコンテキストメニューがあります。削除する前にcancelCellEditing()またはstopCellEditing()を呼び出す必要があります。そうしないと、テーブルはエントリを解放しません。

関連する問題