How to implement checkbox list java - java

Probably a noob question, but im new to java. I have a need for a checkbox list which I found is not supported in swing, but I found this custom control here
http://www.devx.com/tips/Tip/5342
So I created a class file named CheckBoxList, and copied the code from the link into it:
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class CheckBoxList extends JList
{
protected static Border noFocusBorder =
new EmptyBorder(1, 1, 1, 1);
public CheckBoxList()
{
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox)
getModel().getElementAt(index);
checkbox.setSelected(
!checkbox.isSelected());
repaint();
}
}
}
);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
protected class CellRenderer implements ListCellRenderer
{
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus)
{
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected ?
getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected ?
getSelectionForeground() : getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ?
UIManager.getBorder(
"List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}
The problem is I don't know how to implement it in my GUI file. I tried a lot of code, but they never showed an example. Just
To use the class, simply instantiate it, then pass it an array of
JCheckBox objects (or subclasses of JCheckBox objects) by calling
setListData
So does that mean that I will not see the control in the Graphical Design view? My client wants to be able to edit it himself and add stuff so I want it to be easy and graphical if possible. If someone could show an example of instantiating it or give a good hint I would appreciate it. Thanks!

Can you just tell me how?
Use a one column JTable and an appropriate renderer and editor. Based on this example, the code below relies on the default renderer for a data value of type Boolean.Class. A more general example is cited here.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
/** #see https://stackoverflow.com/a/13919878/230513 */
public class CheckTable {
private static final CheckModel model = new CheckModel(5000);
private static final JTable table = new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(150, 300);
}
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
JCheckBox jcb = (JCheckBox) super.prepareRenderer(renderer, row, column);
jcb.setHorizontalTextPosition(JCheckBox.LEADING);
jcb.setText(String.valueOf(row));
return jcb;
}
};
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("CheckTable");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1, 0));
f.add(new JScrollPane(table));
f.add(new DisplayPanel(model));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class DisplayPanel extends JPanel {
private DefaultListModel dlm = new DefaultListModel();
private JList list = new JList(dlm);
public DisplayPanel(final CheckModel model) {
super(new GridLayout());
this.setBorder(BorderFactory.createTitledBorder("Checked"));
this.add(new JScrollPane(list));
model.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
dlm.removeAllElements();
for (Integer integer : model.checked) {
dlm.addElement(integer);
}
}
});
}
}
private static class CheckModel extends AbstractTableModel {
private final int rows;
private List<Boolean> rowList;
private Set<Integer> checked = new TreeSet<Integer>();
public CheckModel(int rows) {
this.rows = rows;
rowList = new ArrayList<Boolean>(rows);
for (int i = 0; i < rows; i++) {
rowList.add(Boolean.FALSE);
}
}
#Override
public int getRowCount() {
return rows;
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public String getColumnName(int col) {
return "Column " + col;
}
#Override
public Object getValueAt(int row, int col) {
return rowList.get(row);
}
#Override
public void setValueAt(Object aValue, int row, int col) {
boolean b = (Boolean) aValue;
rowList.set(row, b);
if (b) {
checked.add(row);
} else {
checked.remove(row);
}
fireTableRowsUpdated(row, row);
}
#Override
public Class<?> getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
return true;
}
}
}

The code is expecting a list of JCheckBox objects - so this works
CheckBoxList cbList = new CheckBoxList(); // the class you have
JCheckBox check1 = new JCheckBox("One");
JCheckBox check2 = new JCheckBox("two");
JCheckBox[] myList = { check1, check2}; list of checkbox object
cbList.setListData(myList); // set the list data for the object
Small Swing program using your class below
util;
import javax.swing.*;
public class HelloWorldSwing {
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CheckBoxList cbList = new CheckBoxList();
JCheckBox check1 = new JCheckBox("One");
JCheckBox check2 = new JCheckBox("two");
JCheckBox[] myList = { check1, check2};
cbList.setListData(myList);
frame.getContentPane().add(cbList);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Related

Java swing : update a JTable every time a loop adds a row

In this code, perfs is a String[] and model is a DefaultTableModel associated to a JTable.
for(int i =0; i<100000; i++){
model.addRow(perfs);
}
I would like the rows to appear as they are added, but they only appear once the loop is over. Could this have something to do with te fact the table is in a JScrollPane ?
Here's the full code in case it might be useful
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class gwy implements ActionListener{
private JFrame frame;
private JPanel panel;
private JButton button;
String[] nomsColonnes = {"INSTANCE","Solvabilité","Profondeur(ms)","Largeur(ms)", "Heur. basique(ms)", "Heur. opérations variées", "Heur. distances au carré"};
private DefaultTableModel model = new DefaultTableModel(nomsColonnes, 0);
private JTable tableResultats = new JTable(model);
JScrollPane scrollPane;
public gwy(){
frame = new JFrame();
button = new JButton("Résoudre");
button.addActionListener(this);
scrollPane = new JScrollPane(tableResultats);
tableResultats.setFillsViewportHeight(true);
panel = new JPanel();
panel.setSize(70,50);
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10,10));
panel.setLayout(new BoxLayout(panel,BoxLayout.PAGE_AXIS));
panel.add(button);
panel.add(scrollPane);
frame.add(panel, BorderLayout.CENTER);
//frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("GUI");
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args){
new gwy();
}
#Override
public void actionPerformed(ActionEvent e) {
for(int i =0; i<10000000; i++){
model.addRow(nomsColonnes);
}
}
}
The problem is, Swing is single threaded. This means that until your loops completes, it's blocking the Event Dispatching Thread from processing any new events, which would otherwise update the UI.
Swing is also not thread safe, meaning you should not update the UI, or any state the UI depends on, from out the context of the Event Dispatching Thread.
See Concurrency in Swing for more details.
A common way to achieve this would be to use a SwingWorker which can be used to create new rows in a seperate thread, but which can sync the updates back to the Event Dispatching Thread safely.
See Worker Threads and SwingWorker for more details
Runnable example
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private MyTableModel model;
public TestPane() {
setLayout(new BorderLayout());
model = new MyTableModel();
JTable table = new JTable(model);
model.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.INSERT) {
int row = e.getFirstRow();
table.scrollRectToVisible(table.getCellRect(row, 0, true));
}
}
});
add(new JScrollPane(table));
JButton populate = new JButton("Populate");
populate.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
populate.setEnabled(false);
PopulateWorker worker = new PopulateWorker(model);
worker.execute();
}
});
add(populate, BorderLayout.SOUTH);
}
}
public class PopulateWorker extends SwingWorker<Void, MyRowData> {
private MyTableModel model;
public PopulateWorker(MyTableModel model) {
this.model = model;
}
public MyTableModel getModel() {
return model;
}
#Override
protected void process(List<MyRowData> chunks) {
for (MyRowData row : chunks) {
model.addRow(row);
}
}
#Override
protected Void doInBackground() throws Exception {
for (int index = 0; index < 10_000; index++) {
publish(new MyRowData(Integer.toString(index)));
// Decrease this to make it faster
Thread.sleep(125);
}
return null;
}
}
public class MyRowData {
private String identifer;
public MyRowData(String identifer) {
this.identifer = identifer;
}
public String getIdentifer() {
return identifer;
}
}
public class MyTableModel extends AbstractTableModel {
private String[] columnNames = new String[]{"INSTANCE"};
private List<MyRowData> data = new ArrayList<>(32);
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public String getColumnName(int column) {
return columnNames[column];
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
MyRowData row = data.get(rowIndex);
switch (columnIndex) {
case 0: return row.getIdentifer();
}
return null;
}
public void addRow(MyRowData row) {
data.add(row);
fireTableRowsInserted(data.size() - 1, data.size() - 1);
}
}
}
nb:: There is a Thread.sleep inside the doInBackground method of the SwingWorker, this is very important. If you remove it, the worker will complete before the UI get's updated. Instead, you can modify the Thread.sleep to increase or decrease the speed at which the updates occur. Just beware, if it's low enough, you might end up with multiple rows appearing at the same time, depending on the thread load.

JComboBox in Custom table model

I have got question about adding JComboBox, to Column in Custom table model which extends ObjectTableModel (Table is OmniJTable). I work on it 2 days and cannot solve this problem.
One thing I solved is displaying JComboBox in Column, but right now I have got problem with selecting anything from it (seems it's not editable, and anything like "setEditable()" not working).
Here is code which one I add jComboBox to my OmniJTable with ObjectTableModel.
class CheckBoxCellRenderer extends JComboBox implements TableCellRenderer {
JComboBox combo;
public CheckBoxCellRenderer(JComboBox comboBox) {
this.combo = new JComboBox();
for (int i=0; i<comboBox.getItemCount(); i++){
combo.addItem(comboBox.getItemAt(i));
}
}
#Override
public Component getTableCellRendererComponent(JTable jtable, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
combo.setSelectedItem(value);
return combo;
}
}
private void addComboBoxToStatusColumn(JTable table)
{
final int statusColumnIndex = bazaTelefonowOmniJTable.getColumnModel().getColumnIndex("Status");
TableColumn tmpColum = bazaTelefonowOmniJTable.getColumnModel().getColumn(statusColumnIndex);
final JComboBox comboBox = new JComboBox();
comboBox.setEditable(true);
comboBox.setEnabled(true);
loadRecordStatusFromDictionary(comboBox);
DefaultCellEditor defaultCellEditor=new DefaultCellEditor(comboBox);
tmpColum.setCellEditor(defaultCellEditor);
tmpColum.setCellRenderer(new CheckBoxCellRenderer(comboBox));
bazaTelefonowOmniJTable.setEditable(true);
//table.repaint();
}
As i said, this one adding jComboBox to Column, but i don't know how to make this one to allow me to choose items in jComboBox.
PS: Sry for my english, it's not my primary language.
The simplest thing is not to add a CellRenderer. In that case, the Table renders it as a Label and when clicked the combo box is shown. Here is an example:
package snippet;
import java.awt.Component;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class JTableTest extends JFrame {
public JTableTest() {
super(JTableTest.class.getName());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents();
}
private void initComponents() {
JTable table = new JTable(new Object[][] { { "1", "One" }, { "2", "Two" } }, new Object[] { "Column One", "Status" });
addComboBoxToStatusColumn(table);
add(new JScrollPane(table));
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
new JTableTest().setVisible(true);
}
});
}
private void addComboBoxToStatusColumn(JTable table) {
final int statusColumnIndex = table.getColumnModel().getColumnIndex("Status");
TableColumn tmpColum = table.getColumnModel().getColumn(statusColumnIndex);
final JComboBox comboBox = new JComboBox();
loadRecordStatusFromDictionary(comboBox);
DefaultCellEditor defaultCellEditor = new DefaultCellEditor(comboBox);
tmpColum.setCellEditor(defaultCellEditor);
}
private void loadRecordStatusFromDictionary(JComboBox comboBox) {
comboBox.addItem("Two");
comboBox.addItem("Four");
comboBox.addItem("Six");
}
}
You also need to override the isCellEditable method from your model.
model = DaneTableModel(some arg) {
public boolean isCellEditable(int row, int col) {
if(col == STATUS_COLUMN) return true ;
return false;
}
}

How to delete a row from jtable

I want to change the action of the button to delete. I have this code:
package buttonexample;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
public class ButtonExample {
public JTable table;
public static void main(String[] args) {
final ButtonExample example = new ButtonExample();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
example.createAndShowGUI();
}
});
}
private void createAndShowGUI() {
JFrame frame = new JFrame("Button Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table = new JTable(new JTableModel());
JScrollPane scrollPane = new JScrollPane(table);
table.setFillsViewportHeight(true);
TableCellRenderer buttonRenderer = new JTableButtonRenderer();
//table.getColumn("Button1").setCellRenderer(buttonRenderer);
table.getColumn("Button2").setCellRenderer(buttonRenderer);
table.addMouseListener(new JTableButtonMouseListener(table));
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.getContentPane().setPreferredSize(new Dimension(500, 200));
frame.pack();
frame.setVisible(true);
}
public static class JTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private static final String[] COLUMN_NAMES = new String[] {"Id", "Stuff", "Asdfsdf", "Button2"};
private static final Class<?>[] COLUMN_TYPES = new Class<?>[] {Integer.class, String.class, String.class, JButton.class};
#Override public int getColumnCount() {
return COLUMN_NAMES.length;
}
#Override public int getRowCount() {
return 4;
}
#Override public String getColumnName(int columnIndex) {
return COLUMN_NAMES[columnIndex];
}
#Override public Class<?> getColumnClass(int columnIndex) {
return COLUMN_TYPES[columnIndex];
}
#Override public Object getValueAt(final int rowIndex, final int columnIndex) {
switch (columnIndex) {
case 0: return rowIndex;
case 1: return "Text for "+rowIndex;
case 2: return "Column for "+rowIndex;
case 3: final JButton button = new JButton(COLUMN_NAMES[columnIndex]);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// When this is clicked the whole row will be deleted.
JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(button),
"Button clicked for row "+rowIndex);
}
});
return button;
default: return "Error";
}
}
}
private static class JTableButtonRenderer implements TableCellRenderer {
#Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JButton button = (JButton)value;
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(UIManager.getColor("Button.background"));
}
return button;
}
}
private static class JTableButtonMouseListener extends MouseAdapter {
private final JTable table;
public JTableButtonMouseListener(JTable table) {
this.table = table;
}
public void mouseClicked(MouseEvent e) {
int column = table.getColumnModel().getColumnIndexAtX(e.getX());
int row = e.getY()/table.getRowHeight();
if (row < table.getRowCount() && row >= 0 && column < table.getColumnCount() &&
column >= 0) {
Object value = table.getValueAt(row, column);
if (value instanceof JButton) {
((JButton)value).doClick();
}
}
}
}
}
But the (DefaultTableModel)someTable.getModel(); model.removeRow(row); I can't make it work because the table model does not have any name and I don't know what to name it. I have tried initializing a table model and I get error saying non-static variable model cannot be reference to a static context. Is there a way to delete the row in a static context?
The example by camickr is probably a more reusable solution, but for the sake of education...
Rendering of cells is the domain of the view
Model's should never contain components, especially if you're thinking about rendering them to the screen, this is simply the wrong approach to take...
You need to set up a TableCellEditor which will act as the means by which you can retrieve notification of the edit actions (mouse click or keypress)
This is a basic example, for simplicity, I've used a DefaultTableModel as it has a nice removeRow method, but conceivably, you could use any TableModel, so long as you provided the means to remove a row and modified by the editor to support it...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.event.CellEditorListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
public class ButtonExample {
public JTable table;
public static void main(String[] args) {
final ButtonExample example = new ButtonExample();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
example.createAndShowGUI();
}
});
}
private void createAndShowGUI() {
JFrame frame = new JFrame("Button Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table = new JTable(new ExampleTableModel());
JScrollPane scrollPane = new JScrollPane(table);
table.setFillsViewportHeight(true);
table.getColumn("action").setCellRenderer(new ButtonCellRenderer());
table.getColumn("action").setCellEditor(new ButtonCellEditor());
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public static class ExampleTableModel extends DefaultTableModel {
public ExampleTableModel() {
super(new Object[]{"id", "stuff", "blah", "action"}, 0);
for (int index = 0; index < 10; index++) {
addRow(new Object[]{index, "Text for " + index, "Na na", index});
}
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 3;
}
}
public static class ButtonCellRenderer extends JButton implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value != null) {
setText("Delete row " + value.toString());
} else {
setText("Delete Me");
}
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(UIManager.getColor("Button.background"));
}
return this;
}
}
public static class ButtonCellEditor extends AbstractCellEditor implements TableCellEditor {
private JButton editor;
private Object value;
private int row;
private JTable table;
public ButtonCellEditor() {
editor = new JButton();
editor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (table != null) {
fireEditingStopped();
TableModel model = table.getModel();
if (model instanceof DefaultTableModel) {
((DefaultTableModel) model).removeRow(row);
}
}
}
});
}
#Override
public boolean isCellEditable(EventObject e) {
return true;
}
#Override
public Object getCellEditorValue() {
return value;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
this.table = table;
this.row = row;
this.value = value;
if (value != null) {
editor.setText("Delete row " + value.toString());
} else {
editor.setText("Delete Me");
}
if (isSelected) {
editor.setForeground(table.getSelectionForeground());
editor.setBackground(table.getSelectionBackground());
} else {
editor.setForeground(table.getForeground());
editor.setBackground(UIManager.getColor("Button.background"));
}
return editor;
}
}
}
Take a closer look at How to Use Tables for more details
This is just a personal preference, but I prefer to use a toolbar or menu item and key bindings to provide this support. Buttons in a table just seem so...dated - IMHO

How do I make it possible to select text in a JTable cell with editing disabled?

Imagine I'm building an IRC client with Java and I'd like rich text in the chat view to show IRC colors and colored nicks. I'd like to build this with a JTable. I can do that, but the text is then not selectable. Making the table editable doesn't make sense.
I've also investigated:
TextArea - no rich text formatting
JEditPane - can't append, only replace which is bad performance wise
JList - can't select text
So I got a table working I just need the text to be selectable without making it editable. I'd also would only like the text contents, and none of the HTML to be copied into the clipboard upon copying the text selection.
I have tried various iterations of setRowSelectionAllowed(), setColumnSelectionEnabled() and setCellSelectionEnabled() and setSelectionMode the table model returns false for isCellEditable(). Nothing has made the text selectable.
EDIT: as per answer 1 I was wrong about text editor panes so I'm trying those solutions.
I don't know why you don't want to use a JTextPane or JEditorPane. You insert text by its document. Examples here --> How to use Editor Panes and Text Panes.
But for your purpose you can for example do something like this. I override changeSelection to selectAll text when is clicking, the cells are editable but its cellEditors are not editable.
public class JTableTest {
private final DefaultCellEditor cellEditor;
private final JTextField textfield;
private JPanel panel;
private MyTableModel tableModel = new MyTableModel();
private JTable table = new JTable() {
#Override
public TableCellEditor getCellEditor(int row, int column) {
return JTableTest.this.cellEditor;
}
#Override
public void changeSelection(
final int row, final int column, final boolean toggle, final boolean extend) {
super.changeSelection(row, column, toggle, extend);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if ((getCellEditor(row, column) != null && !editCellAt(row, column))) {
JTextField textfield=(JTextField)JTableTest.this.cellEditor.getComponent();
textfield.selectAll();
}
}
});
}
};
public JTableTest() {
JScrollPane scroll = new JScrollPane(table);
table.setModel(tableModel);
panel = new JPanel(new BorderLayout());
panel.add(scroll, BorderLayout.CENTER);
textfield = new JTextField();
textfield.setEditable(Boolean.FALSE);
textfield.setBorder(null);
cellEditor = new DefaultCellEditor(textfield);
tableModel.insertValue(new ItemRow("nonEditable", "Editable"));
}
private class ItemRow {
private String column1;
private String column2;
public ItemRow(String column1, String column2) {
this.column1 = column1;
this.column2 = column2;
}
public String getColumn1() {
return column1;
}
public void setColumn1(String column1) {
this.column1 = column1;
}
public String getColumn2() {
return column2;
}
public void setColumn2(String column2) {
this.column2 = column2;
}
}
private class MyTableModel extends AbstractTableModel {
public static final int COLUMN1_INDEX = 0;
public static final int COLUMN2_INDEX = 1;
private final List<ItemRow> data = new ArrayList<>();
private final String[] columnsNames = {
"Column1",
"Column2",};
private final Class<?>[] columnsTypes = {
String.class,
String.class
};
public MyTableModel() {
super();
}
#Override
public Object getValueAt(int inRow, int inCol) {
ItemRow row = data.get(inRow);
Object outReturn = null;
switch (inCol) {
case COLUMN1_INDEX:
outReturn = row.getColumn1();
break;
case COLUMN2_INDEX:
outReturn = row.getColumn2();
break;
default:
throw new RuntimeException("invalid column");
}
return outReturn;
}
#Override
public void setValueAt(Object inValue, int inRow, int inCol) {
System.out.println("Gets called ");
if (inRow < 0 || inCol < 0 || inRow >= data.size()) {
return;
}
ItemRow row = data.get(inRow);
switch (inCol) {
case COLUMN1_INDEX:
row.setColumn1(inValue.toString());
break;
case COLUMN2_INDEX:
row.setColumn2(inValue.toString());
break;
}
fireTableCellUpdated(inRow, inCol);
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columnsTypes.length;
}
#Override
public String getColumnName(int inCol) {
return this.columnsNames[inCol];
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return this.columnsTypes[columnIndex];
}
/**
*
* #param row
*/
public void insertValue(ItemRow row) {
data.add(row);
fireTableRowsInserted(data.size() - 1, data.size() - 1);
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
}
private static void createAndShowGUI(final Container container, final String title) {
//Create and set up the window.
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(Boolean.TRUE);
frame.add(container);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI(new JTableTest().panel, "Test");
}
});
}
}
I accomplished this by enabling the editing and then making the component responsible for the edition ignore any changes. For this I created a TableCellEditor and intercepted the key types to the JTextField, the component used for editing.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
public class TableCellSelectionTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
new TableCellSelectionTest().initUI();
}
});
}
public void initUI()
{
JFrame frame = new JFrame();
int N = 5;
int M = 3;
Object[][] data = new Object[N][M];
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
data[i][j] = "This is the cell (" + i + ", " + j +")";
}
}
String[] columnNames = { "Column 1", "Column 2", "Column 3" };
DefaultTableModel model = new DefaultTableModel(data, columnNames);
final MyTableCellEditor editor = new MyTableCellEditor();
JTable table = new JTable(model) {
#Override
public TableCellEditor getCellEditor(int row, int column)
{
return editor;
}
};
frame.add(new JScrollPane(table), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class MyTableCellEditor extends AbstractCellEditor implements
TableCellEditor
{
Object _value;
#Override
public Object getCellEditorValue()
{
return _value;
}
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column)
{
_value = value;
JTextField textField = new JTextField(_value.toString());
textField.addKeyListener(new KeyAdapter()
{
public void keyTyped(KeyEvent e) {
e.consume(); //ignores the key
}
#Override
public void keyPressed(KeyEvent e)
{
e.consume();
}});
textField.setEditable(false); //this is functionally irrelevent, makes slight visual changes
return textField;
}
}
}
I tried both the answers here... but one problem at least is that you can tell when you've entered the "editing" mode.
This might be of interest... uses a combination of Editor magic and cheeky rendering to make it look like no editing is going on: editor's click-count-to-start is set to 1, and the component (JTextPane) delivered by the editor's method does setEditable( false ).
If this tickles your fancy, you might be interested at looking at my implementation of a JTable which adjusts (perfectly, harnessing the JTextPane's powerful wrapping power) the row height to the text, for individual rows, including when you change the columns: How to wrap lines in a jtable cell?
public class SelectableNonEditableTableTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame main_frame = new JFrame();
main_frame.setPreferredSize(new Dimension(1200, 300));
main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ArrayList<String> nonsense = new ArrayList<String>(
Arrays.asList(
"Lorem ipsum dolor sit amet, sed dolore vivendum ut",
"pri an soleat causae doctus.",
"Alienum abhorreant mea ea",
"cum malorum diceret ei. Pri oratio invidunt consequat ne.",
"Ius tritani detraxit scribentur et",
"has detraxit legendos intellegat at",
"quo oporteat constituam ex"));
JTable example_table = new JTable(10, 4);
example_table.setRowHeight( example_table.getRowHeight() * 2 );
DefaultCellEditor cell_editor = new SelectableNonEditableCellEditor(
new JTextField());
cell_editor.setClickCountToStart(1);
example_table.setDefaultEditor(Object.class, cell_editor);
TableCellRenderer renderer = new SelectableNonEditableTableRenderer();
example_table.setDefaultRenderer(Object.class, renderer);
for (int i = 0; i < 10; i++) {
example_table.setValueAt(nonsense.get(i % nonsense.size()),
i, i % 4);
}
main_frame.getContentPane().add(new JScrollPane(example_table));
main_frame.pack();
main_frame.setVisible(true);
}
});
}
}
class SelectableNonEditableCellEditor extends DefaultCellEditor {
public SelectableNonEditableCellEditor(JTextField textField) {
super(textField);
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int col) {
Component comp = super.getTableCellEditorComponent(table, value,
isSelected, row, col);
if (value instanceof java.lang.String) {
DefaultStyledDocument sty_doc = new DefaultStyledDocument();
try {
sty_doc.insertString(0, (String) value, null);
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JTextPane jtp_comp = new JTextPane(sty_doc);
jtp_comp.setEditable(false);
return jtp_comp;
}
return comp;
}
}
class SelectableNonEditableTableRenderer extends JTextPane implements
TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof DefaultStyledDocument) {
setDocument((DefaultStyledDocument) value);
} else {
setText((String) value);
}
return this;
}
}
Maybe you can implement your own TableCellRenderer that extends JTextField in your table.

How to fix a JButton in JTable? Because After pressing the button is suspended in its last position in the table

I have got a problem with JTable and JButton.
After pressing the button, is suspended in its last position in the table.
Try to run the code below.
Firs I open row "Open 4" and Close by button "Close 4".
After that if I Open row "Open 3" the button "4" is still there...
How to fix this?
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventObject;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.*;
import javax.swing.table.*;
class MyRenderer implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasValue, int row, int column) {
DefaultTableModel model =((DefaultTableModel)table.getModel());
if (model.getValueAt(row,0)!=null && column==0) {
String DATA= "Close "+(model.getValueAt(row,0)).toString();
JButton b = new JButton(DATA);
return b;
}
else return null;
}
}
class MyEditor implements TableCellEditor {
public Component getTableCellEditorComponent(final JTable table, Object value,
boolean isSelected, final int row, int column){
final DefaultTableModel model =((DefaultTableModel)table.getModel());
if (model.getValueAt(row,0)!=null && column==0 ){
String text =model.getValueAt(row,0).toString();
final JButton b = new JButton(text);
ActionListener AKCJA = new ActionListener(){
public void actionPerformed(ActionEvent e) {
if(model.getValueAt(row+1,0)==null)
while(model.getValueAt(row+1,0)==null)
((DefaultTableModel)table.getModel()).removeRow(row+1);
}
};
b.addActionListener(AKCJA);
return b;
}
else return null;
}
public void removeCellEditorListener(CellEditorListener cl) { }
public void addCellEditorListener(CellEditorListener cl) { }
public boolean shouldSelectCell(EventObject ev) { return true; }
public boolean isCellEditable(EventObject ev) {return true;}
public Object getCellEditorValue() { return null;}
public boolean stopCellEditing() { return true;}
public void cancelCellEditing() { }
}
#SuppressWarnings("serial")
class MyJpanel extends JPanel{
public MyJpanel(){
super(new GridLayout(1,0));
final DefaultTableModel model = new DefaultTableModel();
model.addColumn("Col1");
model.addColumn("Col2");
for(int kk=0;kk<8;kk++)
model.addRow(new Object[]{kk, "Open "+kk});
final JTable table = new JTable(model);
TableColumn td = table.getColumnModel().getColumn(0);
MyRenderer mojRenderer = new MyRenderer();
td.setCellRenderer(mojRenderer);
MyEditor mojEditor = new MyEditor();
td.setCellEditor(mojEditor);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent event) {
int viewRow = table.getSelectedRow();
if(event.getValueIsAdjusting())
if((model.getValueAt(viewRow,0))!=null)
for(int i=0;i<2;i++)
model.insertRow(viewRow+i+1,new Object[]{null, "b"});
}
}
);
add(table );
}
}
public class Test{
public static void main(String[] args)
{
final JFrame ramka=new JFrame("xxx");
ramka.getContentPane().add(new MyJpanel());
ramka.setSize(500,200);
ramka.setVisible(true);
ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
The solution is remove button in Jtable container by using for example table.removeAll(); before button ActionListener().
Very usefull to find problem was:
Component[] Komponenty = table.getComponents();
You can print Array Komponenty and found components which you forgot to delete or hide;

Categories