Addの前のエントリを示すカスタムTableCelleditor
-
28-10-2019 - |
質問
以下の例には、aがあります JTable
a JList
と2 JButton
s(追加して削除)。リストには、追加ボタンをクリックすると、選択した値がテーブルに追加されます。
テーブルの文字列は、カスタムレンダラー( JPanel
ボタンとラベル付き)。ボタンのテキストとラベルのテキストは、文字列の値に変更されます。
編集者が彼のエントリを作るまで、すべてがうまくいきます。編集者は、ボタンをクリックすることを可能にするため、必要です。
テーブルに最初に正しく表示されるときに文字列を追加すると、行の高さがパネルの好ましい高さに調整され、テキストがボタンとラベルに設定されます。
行をクリックして[削除]ボタンをクリックしてテーブルからエントリを削除すると、すべてが期待どおりになります。
ここに問題が発生します。テーブルに(異なる)文字列を追加した場合、行の高さはラベルとボタンのテキストが設定されていません(レンダラーと編集者の両方が呼び出されないため、チェックしましたブレークポイントの使用)。
もちろん、カスタムレンダラーを使用して新しい行を表示したいのですが、これを行うにはどうすればよいですか?
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);
}
}
}
解決
使用しないでください:
table.setRowHeight(row, (int)getPreferredSize().height);
レンダラーで。これは、行の高さを変更するたびにテーブルがrepaint()を塗り直し、レンダラーが呼び出されると、再び行の高さが変更されるため、無限のループが発生します。
そのコード行を取り除きます。代わりに、テーブルに行を追加するときに行の高さを計算できます。このコードを追加()メソッドの下部に追加します。
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
したがって、適切なイベントを簡単に発射できます。
また、行をクリックするとエディターが呼び出されるため、モデルから行を削除する前にエディターを削除する必要があると思います。見る 編集を停止します これを行ういくつかの方法のために。
他のヒント
AddCellEditorListener()、RemoveCellEditorListener()、StopCellediting()、CancelCelleDiting()の実装メソッドは、魅力のように機能します。選択したオブジェクトを削除する前に、エディターを「切断」する必要があります。
テーブルの1つには、テーブルエントリを変更するコンテキストメニューがあり、削除する前にcancelcellediting()またはstopcellediting()を呼び出す必要があります。