Issue with clickable buttons in JTable column - java

I am trying to create a JTable which has clickable buttons in one column. I have been following a tutorial found here: https://www.youtube.com/watch?v=3LiSHPqbuic. Essentially, when you click one of the buttons a message box pops up. My code almost works but I have to double click the buttons rather than single click. I have been playing around with it for quite sometime and not made much progress. Can anyone see where I'm going wrong?
package buttoncolumn;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.TableCellRenderer;
public class ButtonColumn extends JFrame {
public ButtonColumn() {
super("Button Column Example");
//Data for table
Object[][] data=
{
{"1","Man Utd",new Integer(2013),"21"},
{"2","Man City",new Integer(2014),"3"},
{"3","Chelsea",new Integer(2015),"7"},
{"4","Arsenal",new Integer(1999),"10"},
{"5","Liverpool",new Integer(1990),"19"},
{"6","Everton",new Integer(1974),"1"},
};
//Column header
String columnHeaders[]={"Position","Team","Last Year Won","Trophies"};
//Create table object
JTable table=new JTable(data,columnHeaders);
//Set custom renderer to teams column
table.getColumnModel().getColumn(1).setCellRenderer(new ButtonRenderer());;
//Set custom editor to team column
table.getColumnModel().getColumn(1).setCellEditor(new ButtonEditor(new JTextField()));
//Scroll pane
JScrollPane pane=new JScrollPane(table);
getContentPane().add(pane);
setSize(450,100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
ButtonColumn bc = new ButtonColumn();
bc.setVisible(true);
}
}
//Button renderer class
class ButtonRenderer extends JButton implements TableCellRenderer
{
//Constructir
public ButtonRenderer(){
setOpaque(true);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object obj,
boolean selected, boolean focused, int row, int col) {
setText((obj==null) ? "":obj.toString());
return this;
}
}
//Button editor class
class ButtonEditor extends DefaultCellEditor
{
protected JButton btn;
private String lbl;
private Boolean clicked;
public ButtonEditor(JTextField txt){
super(txt);
btn=new JButton();
btn.setOpaque(true);
//When button is clicked
btn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
fireEditingStopped();
}
});
}
//Overide a couple of methods
public Component getTableCellEditorComponent(JTable table, Object obj,
boolean selected, int row, int col) {
//Set button text
lbl=(obj==null) ? "":obj.toString();
btn.setText(lbl);
clicked=true;
return btn;
}
//If button cell value changes (clicked)
#Override
public Object getCellEditorValue(){
if(clicked)
{
JOptionPane.showMessageDialog(btn, lbl+" Clicked");
}
clicked = false;
return new String(lbl);
}
#Override
public boolean stopCellEditing(){
clicked=false;
return super.stopCellEditing();
}
#Override
protected void fireEditingStopped(){
super.fireEditingStopped();
}
}

Make sure you consult the documentation for more information about the classes you are creating.
Have a look at the JavaDocs for DefaultCellEditor and Using Other Editors for more details.
Essentially, you need to modify the isCellEditable method of the DefaultCellEditor
class ButtonEditor extends DefaultCellEditor {
//...
#Override
public boolean isCellEditable(EventObject anEvent) {
return anEvent instanceof MouseEvent && ((MouseEvent) anEvent).getClickCount() == 1 && SwingUtilities.isLeftMouseButton((MouseEvent) anEvent);
}
}
Or, if you really want it simple, just use setClickCountToStart
class ButtonEditor extends DefaultCellEditor {
//...
public ButtonEditor(JTextField txt) {
super(txt);
setClickCountToStart(1);
//...
}
}

Related

How to give keyboard focus to Custom panel in JTable?

I am working on making the Arduino IDE fully accessible for people using access software. This means adding keyboard accessibility to two of the dialogs that currently do not work with access software under windows. The two dialogs are the Board Manager and the LibraryManager. If you want a real example of what I am posting you can get teh Arduino IDE on the Windows Store or download it on line. Just search for Arduino IDE and download the windows version. .
doing all that might be to much for most of you so I have created a more simple table that shows the same problem. If someone can help me understand how to add keyboard and focus access to the below Custom JTable and its custom column which is a JPanel I can work on fixing the Arduino IDE tables.
I understand that the Arduino IDE should probably be made into a
better table but I have yet to figure out a cleaner way to do what they are doing with these tables so I am trying to make what they have accessible.
So below is my problem table. It has two rows and two columsn. The
second column of each row is a panel of controls. I have borrowed
this code from some other stack posts and modified it to fit my
question. So if you think you have seen some of this code before that
is why. The problem is the code works for a mouse. At least I think
it does because I am blind and can not select the controls on the
second column because they can not get keyboard focus.
So Can someone out there help me figure out how to get keyboard focus
to move through this entire table. I have tried using focus
listeners, keyboard listeners, Focus Traversal policies, property
changes, and combinations between all of the above. I have taken out
my terrible attempts. Swing really should work without having to do
all this extra work but Java is what java is.
So if you are great at Java with swing please put away your mouse and run this
code and see if you can make the buttons activate without the mouse.
If you can and you can explain to me how to do it many blind users will
be in your debt.
Note that you should be able to Shift+Control+tab tot he table if the table is not the only control. On my sample it is. Then you should be able to arrow through the rows and columns and tab and shift+tab through the controls on the JPanel.
You can get the zip group of these files if you don't want to
put this all together yourself at this dropbox link:
https://www.dropbox.com/s/h4bdfu1mlo0jsvr/TableAccessTest.zip?dl=0
Here is the files. Each class has a comment with the file name before it. Again get the zip if you don't want to play block and copy.
//TableAccessTest.java
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
public class TableAccessTest extends JPanel
{
TableModel customRendererEditorTableModel = new TableModel();
JTable table;
public TableAccessTest()
{
setLayout(new BorderLayout());
table = new JTable(customRendererEditorTableModel);
table.setPreferredScrollableViewportSize(new Dimension(500, 600));
table.setRowSelectionAllowed(false);
table.setRowHeight(300);
table.getColumn("Custom JPanel").setCellRenderer(new CustomJPanelRenderer());
table.getColumn("Custom JPanel").setCellEditor(new CustomJPanelEditor());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Custom JPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new TableAccessTest();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
//CustomJPanel.java
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.*;
public class CustomJPanel extends JPanel
{
JPanel colorPanel = new JPanel(new BorderLayout());
JButton jButton = new JButton("Change Color");
JSlider jSlider = new JSlider(JSlider.VERTICAL);
JTextField jTextField = new JTextField("");
public CustomJPanel()
{
jButton.setOpaque(true);
jButton.setFocusable(true);
jTextField.setEditable(false);
jTextField.setFocusable(true);
setFocusable(true);
jButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(4);
switch (randomInt)
{
case (0):
colorPanel.setBackground(Color.BLUE);
jTextField.setText("blue");
break;
case (1):
colorPanel.setBackground(Color.BLACK);
jTextField.setText("black");
break;
case (2):
colorPanel.setBackground(Color.CYAN);
jTextField.setText("cyan");
break;
default:
colorPanel.setBackground(Color.GREEN);
jTextField.setText("green");
break;
}
}
});
jSlider.setOpaque(true);
setLayout(new BorderLayout());
add(colorPanel, BorderLayout.CENTER);
add(jButton, BorderLayout.SOUTH);
add(jTextField, BorderLayout.NORTH);
add(jSlider, BorderLayout.EAST);
}
}
//TableModel.java
import javax.swing.table.AbstractTableModel;
public class TableModel extends AbstractTableModel
{
private String[] columnNames =
{
"First Column",
"Custom JPanel",
};
private Object[][] data =
{
{"Foo", new CustomJPanel()},
{"Bar", new CustomJPanel()}
};
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)
{
return col >= 1;
}
public void setValueAt(Object value, int row, int col)
{
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
//CustomJPanelEditor.java
import javax.swing.AbstractCellEditor;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
public class CustomJPanelEditor extends AbstractCellEditor implements TableCellEditor
{
CustomJPanel customJPanel;
public CustomJPanelEditor()
{
customJPanel = new CustomJPanel();
}
#Override
public java.awt.Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
{
customJPanel = (CustomJPanel) value;
return customJPanel;
}
#Override public Object getCellEditorValue()
{
return customJPanel;
}
}
//CustomJPanelRenderer.java
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
public class CustomJPanelRenderer implements TableCellRenderer
{
CustomJPanel rendererJPanel;
public CustomJPanelRenderer()
{
rendererJPanel = new CustomJPanel();
}
#Override
public java.awt.Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
rendererJPanel = (CustomJPanel) value;
return rendererJPanel;
}
}

How to take value of JComboBox value that is inside JTable?

I have tried this part of code to get values from a JComboBox that is inside of a JTable, but it doesn't work!
I want to get the value of selected cell in order to insert into DB.
package fx;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class ComboInTable extends JFrame {
private static JFrame jFrame;
public ComboInTable() throws HeadlessException {
jFrame=this;
JTable table=new JTable();
DefaultTableModel model= (DefaultTableModel) table.getModel();
model.addColumn("A",new Object[]{"item1"});
model.addColumn("B",new Object[]{"item2"});
JScrollPane scrollPane=new JScrollPane(table);
String[] value1=new String[]{"1","2","3"};
String[] value2=new String[]{"a","b","c"};
TableColumn col0=table.getColumnModel().getColumn(0);
TableColumn col1=table.getColumnModel().getColumn(1);
col0.setCellEditor(new MyComboBoxEditor(value1));
col0.setCellRenderer(new MyComboBoxRenderer(value1));
col1.setCellEditor(new MyComboBoxEditor(value2));
col1.setCellRenderer(new MyComboBoxRenderer(value2));
JComboBox comboBox=new JComboBox(value1);
comboBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getStateChange() == ItemEvent.SELECTED)
{
System.out.println(e.getItem());
}
}
});
jFrame.setLayout(new FlowLayout());
jFrame.add(scrollPane);
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.setSize(400, 400);
jFrame.setVisible(true);
}
public static void main(String[] args) {
ComboInTable comboInTable=new ComboInTable();
}
}
I have MyComboBoxEditor and MyComboBoxRenderer classes.
package fx;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
public class MyComboBoxRenderer extends JComboBox implements TableCellRenderer {
public MyComboBoxRenderer(String[] items) {
super( items);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if(isSelected){
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
}
else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSelectedItem(value);
return this;
}
}
package fx;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
public class MyComboBoxEditor extends DefaultCellEditor {
public MyComboBoxEditor(String[] items) {
super(new JComboBox(items));
}
}
I have tried this part of code to get values from a JComboBox that is inside of a JTable,
You don't get the value from the combo box.
You get the value from the JTable using the getValueAt(...) method.
I also have no idea why you are creating a custom renderer and editor. Just use the default renderer/editor provided by the table.
Start by reading the section from the Swing tutorial on How to Use Tables. You will find an example that shows how to use a combo box as an editor.

JTable component access before row selection

I'm using a jtable and i need to access a component locate in a row different from the selected one.
The problem i have is that when i click the component the row selection change come before the component click event.
This is a SSCE that explain the problem.
package test;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
public class Main extends JFrame {
public static void main(String[] args) {
new Main();
}
public Main() {
JButton btnTest = new JButton("test");
btnTest.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.err.println("btnTest clicked!");
}
});
JButton btnTest2 = new JButton("test2");
btnTest2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.err.println("btnTest2 clicked!");
}
});
JTable table = new JTable(new Object[][] {
{ btnTest, "test"},
{ btnTest2, "test2"},
}, new Object[] {"btn", "desc"});
table.setDefaultEditor(Object.class, new Editor());
table.setDefaultRenderer(JComponent.class, new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
return (JComponent)(value);
}
});
ListSelectionModel rowSM = table.getSelectionModel();
rowSM.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
System.err.println("new Selection!");
}
});
table.setSelectionModel(rowSM);
add(table);
setSize(300, 300);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
}
class Editor extends AbstractCellEditor implements TableCellEditor {
private static final long serialVersionUID = 1L;
private JComponent item;
#Override
public Object getCellEditorValue() {
return item;
}
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
item = (JComponent)value;
item.setBackground(table.getSelectionBackground());
return item;
}
}
}
When i click the button the row unselected this is the console result:
new Selection!
btnTest clicked!
new Selection!
Is possible to fire the "btnTest clicked!" first?
Thanks

Is there any way to right align the text in a JCombobox

I want to have a JComboBox with right align. how can I do that?
someone before said "You can set a renderer to the JComboBox which can be a JLabel having JLabel#setHorizontalAlignment(JLabel.RIGHT)" but I don't know how can I do that?
someone before said "You can set a renderer to the JComboBox which can be a JLabel having JLabel#setHorizontalAlignment(JLabel.RIGHT)"
Yes, the default renederer is a JLabel so you don't need to create a custom renderer. You can just use:
((JLabel)comboBox.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);
Well, you can do with ListCellRenderer, like this:
import java.awt.Component;
import java.awt.ComponentOrientation;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.SwingUtilities;
public class ComboboxDemo extends JFrame{
public ComboboxDemo(){
JComboBox<String> comboBox = new JComboBox<String>();
comboBox.setRenderer(new MyListCellRenderer());
comboBox.addItem("Hi");
comboBox.addItem("Hello");
comboBox.addItem("How are you?");
getContentPane().add(comboBox, "North");
setSize(400, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private static class MyListCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
component.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
return component;
}
}
public static void main(String [] args){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ComboboxDemo().setVisible(true);
}
});
}
}
This worked for me nice and short
comboFromDuration.setRenderer(new DefaultListCellRenderer() {
#Override
public void paint(Graphics g) {
setHorizontalAlignment(DefaultListCellRenderer.CENTER);
setBackground(Color.WHITE);
setForeground(Color.GRAY);
setEnabled(false);
super.paint(g);
}
});
To avoid the setters on every paint(Graphics) call, you could also use an anonymous constructor block:
comboFromDuration.setRenderer(new DefaultListCellRenderer() {
{
setHorizontalAlignment(DefaultListCellRenderer.CENTER);
setBackground(Color.WHITE);
setForeground(Color.GRAY);
setEnabled(false);
}
});

How to get the selected RadioButton from JTable

i'm workin on programe and i need to get the selected radio buttom from a Jtable
I found an exemple that i'm workin on
there is to class
the 1st :
import java.awt.Component;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JRadioButton;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
class RadioButtonRenderer implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null)
return null;
return (Component) value;
}
}
class RadioButtonEditor extends DefaultCellEditor implements ItemListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private JRadioButton button;
public RadioButtonEditor(JCheckBox checkBox) {
super(checkBox);
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (value == null)
return null;
button = (JRadioButton) value;
button.addItemListener(this);
return (Component) value;
}
public Object getCellEditorValue() {
button.removeItemListener(this);
return button;
}
public void itemStateChanged(ItemEvent e) {
super.fireEditingStopped();
}
}
and the 2nd class is :
package TP2;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
import net.miginfocom.swing.MigLayout;
public class tablesDesEtudiants extends JFrame {
public tablesDesEtudiants(Object[][] objt) {
super("List des etudiants");
// UIDefaults ui = UIManager.getLookAndFeel().getDefaults();
// UIManager.put("RadioButton.focus", ui.getColor("control"));
DefaultTableModel dm = new DefaultTableModel();
dm.setDataVector(objt , new Object[] {"Nom","Prénom","Année","Succs","Type","Select"});
JTable table = new JTable(dm) {
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
repaint();
}
};
final ButtonGroup group1 = new ButtonGroup();
for(int i =0 ; i<objt.length;i++){
if(objt[i][1]!=null)
group1.add((JRadioButton) dm.getValueAt(i, 5));
}
// System.out.println(objt.length);
table.getColumn("Select").setCellRenderer(new RadioButtonRenderer());
table.getColumn("Select").setCellRenderer(new RadioButtonRenderer());
table.getColumn("Select").setCellRenderer(new RadioButtonRenderer());
table.getColumn("Select").setCellRenderer(new RadioButtonRenderer());
table.getColumn("Select").setCellRenderer(new RadioButtonRenderer());
table.getColumn("Select").setCellEditor(new RadioButtonEditor(new JCheckBox()));
JScrollPane scroll = new JScrollPane(table);
JButton bView = new JButton("View");
bView.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ButtonModel choix = group1.getSelection();
if (choix != null) {
System.out.println( choix.getActionCommand());
}
else System.out.println("nullll");
}
});
JPanel pp =new JPanel();
MigLayout layout = new MigLayout(
"", // Layout Constraints
"[][]20[]", // Column constraints
"[]20[]"); // Row constraint
pp.setLayout(layout);
pp.add(scroll,"cell 1 2");
pp.add(bView,"cell 2 3");
getContentPane().add(pp);
setSize(600, 400);
setVisible(true);
}
/* public static void main(String[] args) {
JRadioButtonTableExample frame = new JRadioButtonTableExample();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}*/
}
in the 2nd class i'm trying to add all the radio button on ButtonGroup
like this :
final ButtonGroup group1 = new ButtonGroup();
for(int i =0 ; i<objt.length;i++){
if(objt[i][1]!=null)
group1.add((JRadioButton) dm.getValueAt(i, 5));
}
and my problem is that i can't get selected RadioButton :
ButtonModel choix = group1.getSelection();
if (choix != null) {
System.out.println( choix.getActionCommand());
}
else System.out.println("nullll");
}
i alwayse get nullll
any help plz !!
Read my answer to this question. You shouldn't store components in a table. Store booleans. You should then configure a renderer to display the boolean as a radio button, and an editor to change the value of the checked cell as well as the value of the previously checked one. And understand that the same instance of renderer is used to render/edit all the cells of the same class.
I think that not easy job, TableCellEditor for JRadioButtons in the ButtonGroup
use JCheckBox if is possible
use JComboBox as TableCellEditor instead of JRadioButtons in the ButtonGroup if is possible, for TableCellRenderer you can use JRadioButtons in the ButtonGroup

Categories

Resources