I have a jtable with a custom editor and renderer applied to a column to turn the column's contents into a Button, however once i press on any of the buttons, the table loses focus, and the only interactive object in the panel is the button that was just clicked on, which can be clicked on repeatedly.
Here is the button renderer code:
public class ButtonRenderer implements TableCellRenderer {
private Border dsd_originalBorder;
private int in_mnemonic;
private Border dsd_focusBorder;
private JButton dsd_renderButton;
/**
* empty constructor
*/
public ButtonRenderer() {
dsd_renderButton = new JButton();
}
public Component getTableCellRendererComponent(JTable dsd_table, Object dsd_value,
boolean bo_isSelected, boolean bo_hasFocus, int in_row, int in_column) {
if (!WorkplaceConstants.STR_INACTIVE.equals(dsd_table.getValueAt(in_row, dsd_table
.getColumn(Main.hm_language.get(Language.STATUS))
.getModelIndex())))
return new JLabel("");
if (bo_isSelected) {
dsd_renderButton.setForeground(dsd_table.getSelectionForeground());
dsd_renderButton.setBackground(dsd_table.getSelectionBackground());
} else {
dsd_renderButton.setForeground(dsd_table.getForeground());
dsd_renderButton.setBackground(UIManager.getColor("Button.background"));
}
if (bo_hasFocus) {
dsd_renderButton.setBorder(dsd_focusBorder);
} else {
dsd_renderButton.setBorder(dsd_originalBorder);
}
// renderButton.setText( (value == null) ? "" : value.toString() );
if (dsd_value == null) {
dsd_renderButton.setText("");
dsd_renderButton.setIcon(null);
} else if (dsd_value instanceof Icon) {
dsd_renderButton.setText("");
dsd_renderButton.setIcon((Icon) dsd_value);
} else {
dsd_renderButton.setText(dsd_value.toString());
dsd_renderButton.setIcon(null);
}
return dsd_renderButton;
}
/**
* returns the mnemonic to activate the button when the cell has focus
*
* #return the mnemonic
*/
public int m_getMnemonic() {
return in_mnemonic;
}
/**
* The mnemonic to activate the button when the cell has focus
*
* #param p_in_mnemonic
* the mnemonic
*/
public void m_setMnemonic(int p_in_mnemonic) {
this.in_mnemonic = p_in_mnemonic;
dsd_renderButton.setMnemonic(p_in_mnemonic);
}
/**
* Get foreground color of the button when the cell has focus
*
* #return the foreground color
*/
public Border m_getFocusBorder() {
return dsd_focusBorder;
}
/**
* The foreground color of the button when the cell has focus
*
* #param dsd_focusBorder
* the foreground color
*/
public void m_setFocusBorder(Border dsd_focusBorder) {
this.dsd_focusBorder = dsd_focusBorder;
}
Here is the button Editor code:
public class ButtonEditor extends AbstractCellEditor implements TableCellEditor, ActionListener, MouseListener{
private JTable dsd_table;
private int in_mnemonic;
private Border dsd_originalBorder;
private Border dsd_focusBorder;
private JButton dsd_editButton;
private Object dsd_editorValue;
private boolean bo_isButtonColumnEditor;
/**
* Constructor
* #param dsdp_table the table to which the editor is going to be applied.
* #param action the action which is to be executed when the button is clicked
*/
public ButtonEditor(JTable dsdp_table) {
this.dsd_table = dsdp_table;
dsd_editButton = new JButton();
dsd_editButton.setFocusPainted( false );
dsd_editButton.addActionListener( this );
dsd_originalBorder = dsd_editButton.getBorder();
m_setFocusBorder( new LineBorder(Color.BLUE) );
dsdp_table.addMouseListener( this );
}
public Object getCellEditorValue() {
return dsd_editorValue;
}
/**
* returns the mnemonic to activate the button when the cell has focus
*
* #return the mnemonic
*/
public int m_getMnemonic()
{
return in_mnemonic;
}
/**
* The mnemonic to activate the button when the cell has focus
*
* #param in_mnemonic the mnemonic
*/
public void m_setMnemonic(int in_mnemonic)
{
this.in_mnemonic = in_mnemonic;
dsd_editButton.setMnemonic(in_mnemonic);
}
/**
* Get foreground color of the button when the cell has focus
*
* #return the foreground color
*/
public Border m_getFocusBorder() {
return dsd_focusBorder;
}
/**
* The foreground color of the button when the cell has focus
*
* #param dsdp_focusBorder
* the foreground color
*/
public void m_setFocusBorder(Border dsdp_focusBorder) {
this.dsd_focusBorder = dsdp_focusBorder;
dsd_editButton.setBorder(dsdp_focusBorder);
}
public void actionPerformed(ActionEvent arg0) {
int in_modelRow = dsd_table.convertRowIndexToModel( dsd_table.getEditingRow() );
fireEditingStopped();
// Here i start a custom thread to run in the background.
}
public void mouseClicked(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent arg0) {
if (dsd_table.isEditing() && dsd_table.getCellEditor() == this)
bo_isButtonColumnEditor = true;
}
public void mouseReleased(MouseEvent arg0) {
if (bo_isButtonColumnEditor && dsd_table.isEditing())
dsd_table.getCellEditor().stopCellEditing();
bo_isButtonColumnEditor = false;
}
public void addCellEditorListener(CellEditorListener arg0) {
}
public void cancelCellEditing() {
}
public void removeCellEditorListener(CellEditorListener arg0) {
}
public boolean shouldSelectCell(EventObject arg0) {
return false;
}
public boolean stopCellEditing() {
return false;
}
public Component getTableCellEditorComponent(JTable dsd_table, Object dsd_value,
boolean bo_isSelected, int in_row, int in_column) {
if (!WorkplaceConstants.STR_INACTIVE.equals(dsd_table.getValueAt(in_row, dsd_table
.getColumn(Main.hm_language.get(Language.STATUS))
.getModelIndex())))
return new JLabel("");
if (dsd_value == null)
{
dsd_editButton.setText( "" );
dsd_editButton.setIcon( null );
}
else if (dsd_value instanceof Icon)
{
dsd_editButton.setText( "" );
dsd_editButton.setIcon( (Icon)dsd_value );
}
else
{
dsd_editButton.setText( dsd_value.toString() );
dsd_editButton.setIcon( null );
}
bo_isButtonColumnEditor = true;
this.dsd_editorValue = dsd_value;
dsd_editButton.setBorder(dsd_originalBorder);
return dsd_editButton;
}
public boolean isCellEditable(EventObject e){
return true;
}
public Border m_getoriginalBorder() {
return dsd_originalBorder;
}
public void m_set_originalBorder(Border dsd_originalBorder) {
this.dsd_originalBorder = dsd_originalBorder;
}
}
Here is how i am assigning the editor and renderer to the table
public static void m_setButtonColumnConfiguration(JTable table) {
ButtonEditor dsd_btn_edit = new ButtonEditor(table);
dsd_btn_edit.m_setMnemonic(KeyEvent.VK_D);
table.getColumn(/*i get the identifier for the column here*/).setCellEditor(dsd_btn_edit);
ButtonRenderer dsd_btn_rend = new ButtonRenderer();
dsd_btn_rend.m_setMnemonic(KeyEvent.VK_D);
table.getColumn(/*i get the identifier for the column here*/)
.setCellRenderer(dsd_btn_rend);
}
Button, however once i press on any of the buttons, the table loses focus
Yes, anytime you click on a component it gets focus, so this makes sense.
and the only interactive object in the panel is the button that was just clicked on,
Not sure I understand this statement. You can click on the table again and it will regain focus. You can then navigate around the table.
Maybe you are just suggesting the button renderer/editor isn't working the way you expect. We can't test this because you didn't post a SSCCE.
Anyway, check out Table Button Column for another example of a button renderer/editor that responds to mouse clicks or key board events.
Related
I've been trying to put a clickable button in a JTable, and I'm not doing great.
Im using the ButtonColumn class to do so, but the actions are ignored - the buttons are showing but nothing is happening on click.
/**
* The ButtonColumn class provides a renderer and an editor that looks like a
* JButton. The renderer and editor will then be used for a specified column
* in the table. The TableModel will contain the String to be displayed on
* the button.
*
* The button can be invoked by a mouse click or by pressing the space bar
* when the cell has focus. Optionally a mnemonic can be set to invoke the
* button. When the button is invoked the provided Action is invoked. The
* source of the Action will be the table. The action command will contain
* the model row number of the button that was clicked.
*
*/
public class ButtonColumn extends AbstractCellEditor
implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener{
/**
*
*/
private static final long serialVersionUID = -6737467999355167233L;
private JTable table;
private Action action;
private int mnemonic;
private Border originalBorder;
private Border focusBorder;
private JButton renderButton;
private JButton editButton;
private Object editorValue;
private boolean isButtonColumnEditor;
/**
* Create the ButtonColumn to be used as a renderer and editor. The
* renderer and editor will automatically be installed on the TableColumn
* of the specified column.
*
* #param table the table containing the button renderer/editor
* #param action the Action to be invoked when the button is invoked
* #param column the column to which the button renderer/editor is added
*/
public ButtonColumn(JTable table, Action action, int column)
{
this.table = table;
this.action = action;
renderButton = new JButton();
editButton = new JButton();
editButton.setFocusPainted( false );
editButton.addActionListener( this );
originalBorder = editButton.getBorder();
setFocusBorder( new LineBorder(Color.BLUE) );
TableColumnModel columnModel = table.getColumnModel();
columnModel.getColumn(column).setCellRenderer( this );
columnModel.getColumn(column).setCellEditor( this );
table.addMouseListener( this );
}
/**
* Get foreground color of the button when the cell has focus
*
* #return the foreground color
*/
public Border getFocusBorder()
{
return focusBorder;
}
/**
* The foreground color of the button when the cell has focus
*
* #param focusBorder the foreground color
*/
public void setFocusBorder(Border focusBorder)
{
this.focusBorder = focusBorder;
editButton.setBorder( focusBorder );
}
public int getMnemonic()
{
return mnemonic;
}
/**
* The mnemonic to activate the button when the cell has focus
*
* #param mnemonic the mnemonic
*/
public void setMnemonic(int mnemonic)
{
this.mnemonic = mnemonic;
renderButton.setMnemonic(mnemonic);
editButton.setMnemonic(mnemonic);
}
#Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
if (value == null)
{
editButton.setText( "" );
editButton.setIcon( null );
}
else if (value instanceof Icon)
{
editButton.setText( "" );
editButton.setIcon( (Icon)value );
}
else
{
editButton.setText( value.toString() );
editButton.setIcon( null );
}
this.editorValue = value;
return editButton;
}
#Override
public Object getCellEditorValue()
{
return editorValue;
}
//
// Implement TableCellRenderer interface
//
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
if (isSelected)
{
renderButton.setForeground(table.getSelectionForeground());
renderButton.setBackground(table.getSelectionBackground());
}
else
{
renderButton.setForeground(table.getForeground());
renderButton.setBackground(UIManager.getColor("Button.background"));
}
if (hasFocus)
{
renderButton.setBorder( focusBorder );
}
else
{
renderButton.setBorder( originalBorder );
}
// renderButton.setText( (value == null) ? "" : value.toString() );
if (value == null)
{
renderButton.setText( "" );
renderButton.setIcon( null );
}
else if (value instanceof Icon)
{
renderButton.setText( "" );
renderButton.setIcon( (Icon)value );
}
else
{
renderButton.setText( value.toString() );
renderButton.setIcon( null );
}
return renderButton;
}
//
// Implement ActionListener interface
//
/*
* The button has been pressed. Stop editing and invoke the custom Action
*/
#Override
public void actionPerformed(ActionEvent e)
{
int row = table.convertRowIndexToModel( table.getEditingRow() );
fireEditingStopped();
// Invoke the Action
ActionEvent event = new ActionEvent(
table,
ActionEvent.ACTION_PERFORMED,
"" + row);
action.actionPerformed(event);
}
//
// Implement MouseListener interface
//
/*
* When the mouse is pressed the editor is invoked. If you then then drag
* the mouse to another cell before releasing it, the editor is still
* active. Make sure editing is stopped when the mouse is released.
*/
#Override
public void mousePressed(MouseEvent e)
{
if (table.isEditing()
&& table.getCellEditor() == this)
isButtonColumnEditor = true;
}
#Override
public void mouseReleased(MouseEvent e)
{
if (isButtonColumnEditor
&& table.isEditing())
table.getCellEditor().stopCellEditing();
isButtonColumnEditor = false;
}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
My code of actually doing so:
ButtonColumn deleteColumn = new ButtonColumn(eventTable, new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("It works!!!!");
}
}, 3);
That never seems to be printed. I could really use some help. Thanks in advance!
EDIT: I've also tried this code and it also doesn't seem to work.
eventTable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
JTable target = (JTable)e.getSource();
int row = target.getSelectedRow();
int column = target.getSelectedColumn();
System.out.println("Event table was clicked in row "+row+", column "+column);
}
});
Have a look at TableCellRenderer explained.
And the interface TableCellRenderer.
My guess is that the column is not editable which means the editor is never invoked so the Action is never invoked.
If this doesn't help then post a proper SSCCE demonstrating the problem.
I have a JTable where I have inserted two buttons (delete, search) in each row.
For each button I specify the proper action in my constructor like this:
Action search = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTable table = (JTable) e.getSource();
int modelRow = Integer.valueOf(e.getActionCommand());
System.out.println("Search action for row: " + modelRow);
// do some processing here
// tb.searchMore(modelRow);
}
};
And then I specify to which column the button should be created like this:
// column 4 of JTable table should implement action 'search'
ButtonColumn searchButtonColumn = new ButtonColumn(table, search, 4);
searchButtonColumn.setMnemonic(KeyEvent.VK_D);
And I have a proper Button Renderer Class.
The delete button (which is being created and initialized exactly the same way) works just fine. So does a similar save button I created for another table.
The problem is with the search button. It creates the graphic button in the table, but its action is never actualluy being called. I noticed that this happens when I place it in a column other that the very first one. Any ideas for this strange behaviour? The column I am placing it is not out of bounds. Is there a problem with placing two buttons in tha same row?
Below is the Button Renderer code:
public class ButtonColumn extends AbstractCellEditor
implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener {
private JTable table;
private Action action;
private int mnemonic;
private Border originalBorder;
private Border focusBorder;
private JButton renderButton;
private JButton editButton;
private Object editorValue;
private boolean isButtonColumnEditor;
/**
* Create the ButtonColumn to be used as a renderer and editor. The
* renderer and editor will automatically be installed on the TableColumn
* of the specified column.
*
* #param table the table containing the button renderer/editor
* #param action the Action to be invoked when the button is invoked
* #param column the column to which the button renderer/editor is added
*/
public ButtonColumn(JTable table, Action action, int column) {
this.table = table;
this.action = action;
renderButton = new JButton();
editButton = new JButton();
editButton.setFocusPainted(false);
editButton.addActionListener(this);
originalBorder = editButton.getBorder();
setFocusBorder(new LineBorder(Color.BLUE));
TableColumnModel columnModel = table.getColumnModel();
columnModel.getColumn(column).setCellRenderer(this);
columnModel.getColumn(column).setCellEditor(this);
table.addMouseListener(this);
}
/**
* Get foreground color of the button when the cell has focus
*
* #return the foreground color
*/
public Border getFocusBorder() {
return focusBorder;
}
/**
* The foreground color of the button when the cell has focus
*
* #param focusBorder the foreground color
*/
public void setFocusBorder(Border focusBorder) {
this.focusBorder = focusBorder;
editButton.setBorder(focusBorder);
}
public int getMnemonic() {
return mnemonic;
}
/**
* The mnemonic to activate the button when the cell has focus
*
* #param mnemonic the mnemonic
*/
public void setMnemonic(int mnemonic) {
this.mnemonic = mnemonic;
renderButton.setMnemonic(mnemonic);
editButton.setMnemonic(mnemonic);
}
#Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
if (value == null) {
editButton.setText("");
editButton.setIcon(null);
} else if (value instanceof Icon) {
editButton.setText("");
editButton.setIcon((Icon) value);
} else {
editButton.setText(value.toString());
editButton.setIcon(null);
}
this.editorValue = value;
return editButton;
}
#Override
public Object getCellEditorValue() {
return editorValue;
}
//
// Implement TableCellRenderer interface
//
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
renderButton.setForeground(table.getSelectionForeground());
renderButton.setBackground(table.getSelectionBackground());
} else {
renderButton.setForeground(table.getForeground());
renderButton.setBackground(UIManager.getColor("Button.background"));
}
if (hasFocus) {
renderButton.setBorder(focusBorder);
} else {
renderButton.setBorder(originalBorder);
}
// renderButton.setText( (value == null) ? "" : value.toString() );
if (value == null) {
renderButton.setText("");
renderButton.setIcon(null);
} else if (value instanceof Icon) {
renderButton.setText("");
renderButton.setIcon((Icon) value);
} else {
renderButton.setText(value.toString());
renderButton.setIcon(null);
}
return renderButton;
}
//
// Implement ActionListener interface
//
/*
* The button has been pressed. Stop editing and invoke the custom Action
*/
public void actionPerformed(ActionEvent e) {
int row = table.convertRowIndexToModel(table.getEditingRow());
fireEditingStopped();
// Invoke the Action
ActionEvent event = new ActionEvent(table,
ActionEvent.ACTION_PERFORMED, "" + row);
action.actionPerformed(event);
}
//
// Implement MouseListener interface
//
/*
* When the mouse is pressed the editor is invoked. If you then then drag
* the mouse to another cell before releasing it, the editor is still
* active. Make sure editing is stopped when the mouse is released.
*/
public void mousePressed(MouseEvent e) {
if (table.isEditing()
&& table.getCellEditor() == this) {
isButtonColumnEditor = true;
}
}
public void mouseReleased(MouseEvent e) {
if (isButtonColumnEditor
&& table.isEditing()) {
table.getCellEditor().stopCellEditing();
}
isButtonColumnEditor = false;
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
I guess you forgot to set the action command to the rendered button. You rely on that command in your action. Try something like
editButton.setActionCommand(String.valueOf(column));
in your cell renderer.
This is probably an elementary question. However, I have completed reading the 12th Chapter of Java Programming for the Absolute Beginner and have approached the Challenges section. I cannot quite get the progam to display a labeled button with the extended class.
The specification states:
Extend the JPRButton3D class to create a button that displays a label just like
the AWT Button class you're so familiar with by now. As an extra test, override
the isFocusable() method so that your button class can be traversed and make sure you
paint some special graphic to make it obvious when your button has focus.
How can I edit my code of LabelButton3D and LabelButton3DTest to accomplish this task?
An answer to this specification can potentially aid many new Java programmers in extending their own classes.
Thank you very much for your time and cooperation reagrding this matter.
HERE IS THE CODE FOR JPRButton3D:
package jpr.lightweight;
import java.awt.*;
import java.awt.event.*;
/**
* A lightweight 3D Button class that fires actions when clicked.
* When it is enabled it appears {#link #RAISED RAISED}, when
* it is pressed it appears {#link #SUNK SUNK}, and when it is
* not enabled, it appears {#link #FLAT FLAT}.
*/
public class JPRButton3D extends JPRRectComponent3D {
private boolean pressed;
/**
* This <code>JPRButton3D</code>'s <code>ActionListener</code>.
*/
protected ActionListener actionListener;
private String actionCommand;
/**
* Constructs a new <code>JPRButton3D</code> with minimum size
*/
public JPRButton3D() {
this(ABSOLUTE_MIN_WIDTH, ABSOLUTE_MIN_HEIGHT, 1);
}
/**
* Constructs a new <code>JPRButton3D</code> with the given dimensions.
* #param wide the width
* #param high the height
*/
public JPRButton3D(int wide, int high) {
this(wide, high, 1);
}
/**
* Constructs a new <code>JPRButton3D</code> with the given dimensions
* and border magnitude.
* #param wide the width
* #param high the height
* #param border_magnitude the border's magnitude
*/
public JPRButton3D(int wide, int high, int border_magnitude) {
super(wide, high, RAISED, border_magnitude);
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
public void processMouseEvent(MouseEvent e) {
if (isEnabled() & e.getModifiers() == MouseEvent.BUTTON1_MASK) {
switch(e.getID()) {
case MouseEvent.MOUSE_PRESSED:
pressed = true;
current_appearance = SUNK;
repaint();
break;
case MouseEvent.MOUSE_EXITED:
if (pressed) {
pressed = false;
current_appearance = RAISED;
repaint();
}
break;
case MouseEvent.MOUSE_RELEASED:
if (pressed) {
current_appearance = RAISED;
repaint();
if (actionListener != null) {
actionListener.actionPerformed(new ActionEvent(this,
ActionEvent.ACTION_PERFORMED, actionCommand,
e.getModifiers()));
}
}
break;
}
}
super.processMouseEvent(e);
}
/**
* Adds the specified <code>ActionListener</code>
* #param listener <code>ActionListener</code> to add
*/
public void addActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.add(actionListener, listener);
}
/**
* Removes the specified <code>ActionListener</code>
* #param listener <code>ActionListener</code> to remove
*/
public void removeActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.remove(actionListener,
listener);
}
/**
* Sets the action command associated with action events.
* #param command The action command.
*/
public void setActionCommand(String command) {
actionCommand = command;
}
/**
* Gets the action command associated with action events.
* #return the action command
*/
public String getActionCommand() {
return actionCommand;
}
/**
* Enables or disables this <code>JPRButton3D</code>.
* #param b <code>true</code> to enable, <code>false</code> to disable
*/
public void setEnabled(boolean b) {
if (b) current_appearance = RAISED;
else current_appearance = FLAT;
repaint();
super.setEnabled(b);
}
}
HERE IS MY CODE FOR LabelButton3DTest (to extend JPRButton3D):
import java.awt.*;
import java.awt.event.*;
import jpr.lightweight.JPRButton3D;
public class LabelButton3DTest extends GUIFrame {
LabelButton3D[] b;
String s;
public LabelButton3DTest() {
super("LabelButton3D Test");
setLayout(new FlowLayout());
b = new LabelButton3D[1];
b[0] = new LabelButton3D("Favorite Button");
b[0] = new LabelButton3D(75, 35, 1);
add(b[0]);
pack();
setVisible(true);
}
public static void main(String args[]) {
new LabelButton3DTest();
}
}
HERE IS MY CODE FOR LabelButton3D:
public class LabelButton3D extends JPRButton3D {
public LabelButton3D(String label) {
}
public LabelButton3D(int wide, int high, int border_magnitude) {
super(wide, high, border_magnitude);
}
}
I am making a hospital project in Java, I have made a JTable which is fetching Hospital Name and a Hospital image link i.e "Click to see more" from SQL database. My problem is that the data is successfully fetched from database to the table, but I can't click the link which is in the table cell.
How to make the link active?
Consider using JXTable (a class of SwingX): it supports a hyperlink renderer which can be configured to do any action, based on the cell value
JXTable table = new JXTable(myModel);
AbstractHyperlinkAction<Object> simpleAction = new AbstractHyperlinkAction<Object>(null) {
public void actionPerformed(ActionEvent e) {
// here goes what you want to do on activating the hyperlink
//LOG.info("hit: " + getTarget());
}
};
TableCellRenderer renderer = new DefaultTableRenderer(
new HyperlinkProvider(simpleAction));
table.getColumnExt(0).setEditable(false);
table.getColumnExt(0).setCellRenderer(renderer);
You can either make a TableCellEditor whose isCellEditable method could be used to activate on a single mouse click. Frankly, this just get messy.
Or, you could attach a MouseListener to the table directly and monitor for the mouseClicked event.
On the clicked event, you could need to getSelectedColumn and getSelectedRow to determine if they've clicked on the column you want and get the link value from the selected cell, using getValueAt
You'll need to take into consideration that the table may be sorted or the columns are no longer in the order you started them in (the user may have moved them).
Then you'll need convertColumnIndexToView and convertRowIndexToModel
Simple :D
I think that avoiding an external library is a better way to go as MadProgrammer suggests, but I guess swingx is still pure java. Anyway, I would use the mouseClicked listener and then open uri in the way described in this question How to add hyperlink in JLabel.
JTable table = new JTable();
table.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int row = table.getSelectedRow();
int col = table.getSelectedColumn();
//build your address / link
URI uri = new URI("http: your link here");
//see below
open(uri);
}
});
//Then elsewhere as from the McDowell answer
private static void open(URI uri) {
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(uri);
} catch (IOException e) { /* TODO: error handling */ }
} else { /* TODO: error handling */ }
}
I solved adding a button inside the cells clickable, I followed this tutorial Table Button Column from Rob Camick:
String[] columnNames = {"First Name", "Last Name", ""};
Object[][] data =
{
{"Homer", "Simpson", "delete Homer"},
{"Madge", "Simpson", "delete Madge"},
{"Bart", "Simpson", "delete Bart"},
{"Lisa", "Simpson", "delete Lisa"},
};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable( model );
Then:
Action delete = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
JTable table = (JTable)e.getSource();
int modelRow = Integer.valueOf( e.getActionCommand() );
((DefaultTableModel)table.getModel()).removeRow(modelRow);
}
};
ButtonColumn buttonColumn = new ButtonColumn(table, delete, 2);
buttonColumn.setMnemonic(KeyEvent.VK_D);
Where ButtonColumn class is:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
/**
* The ButtonColumn class provides a renderer and an editor that looks like a
* JButton. The renderer and editor will then be used for a specified column
* in the table. The TableModel will contain the String to be displayed on
* the button.
*
* The button can be invoked by a mouse click or by pressing the space bar
* when the cell has focus. Optionally a mnemonic can be set to invoke the
* button. When the button is invoked the provided Action is invoked. The
* source of the Action will be the table. The action command will contain
* the model row number of the button that was clicked.
*
*/
public class ButtonColumn extends AbstractCellEditor
implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener
{
private JTable table;
private Action action;
private int mnemonic;
private Border originalBorder;
private Border focusBorder;
private JButton renderButton;
private JButton editButton;
private Object editorValue;
private boolean isButtonColumnEditor;
/**
* Create the ButtonColumn to be used as a renderer and editor. The
* renderer and editor will automatically be installed on the TableColumn
* of the specified column.
*
* #param table the table containing the button renderer/editor
* #param action the Action to be invoked when the button is invoked
* #param column the column to which the button renderer/editor is added
*/
public ButtonColumn(JTable table, Action action, int column)
{
this.table = table;
this.action = action;
renderButton = new JButton();
editButton = new JButton();
editButton.setFocusPainted( false );
editButton.addActionListener( this );
originalBorder = editButton.getBorder();
setFocusBorder( new LineBorder(Color.BLUE) );
TableColumnModel columnModel = table.getColumnModel();
columnModel.getColumn(column).setCellRenderer( this );
columnModel.getColumn(column).setCellEditor( this );
table.addMouseListener( this );
}
/**
* Get foreground color of the button when the cell has focus
*
* #return the foreground color
*/
public Border getFocusBorder()
{
return focusBorder;
}
/**
* The foreground color of the button when the cell has focus
*
* #param focusBorder the foreground color
*/
public void setFocusBorder(Border focusBorder)
{
this.focusBorder = focusBorder;
editButton.setBorder( focusBorder );
}
public int getMnemonic()
{
return mnemonic;
}
/**
* The mnemonic to activate the button when the cell has focus
*
* #param mnemonic the mnemonic
*/
public void setMnemonic(int mnemonic)
{
this.mnemonic = mnemonic;
renderButton.setMnemonic(mnemonic);
editButton.setMnemonic(mnemonic);
}
#Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
if (value == null)
{
editButton.setText( "" );
editButton.setIcon( null );
}
else if (value instanceof Icon)
{
editButton.setText( "" );
editButton.setIcon( (Icon)value );
}
else
{
editButton.setText( value.toString() );
editButton.setIcon( null );
}
this.editorValue = value;
return editButton;
}
#Override
public Object getCellEditorValue()
{
return editorValue;
}
//
// Implement TableCellRenderer interface
//
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
if (isSelected)
{
renderButton.setForeground(table.getSelectionForeground());
renderButton.setBackground(table.getSelectionBackground());
}
else
{
renderButton.setForeground(table.getForeground());
renderButton.setBackground(UIManager.getColor("Button.background"));
}
if (hasFocus)
{
renderButton.setBorder( focusBorder );
}
else
{
renderButton.setBorder( originalBorder );
}
// renderButton.setText( (value == null) ? "" : value.toString() );
if (value == null)
{
renderButton.setText( "" );
renderButton.setIcon( null );
}
else if (value instanceof Icon)
{
renderButton.setText( "" );
renderButton.setIcon( (Icon)value );
}
else
{
renderButton.setText( value.toString() );
renderButton.setIcon( null );
}
return renderButton;
}
//
// Implement ActionListener interface
//
/*
* The button has been pressed. Stop editing and invoke the custom Action
*/
public void actionPerformed(ActionEvent e)
{
int row = table.convertRowIndexToModel( table.getEditingRow() );
fireEditingStopped();
// Invoke the Action
ActionEvent event = new ActionEvent(
table,
ActionEvent.ACTION_PERFORMED,
"" + row);
action.actionPerformed(event);
}
//
// Implement MouseListener interface
//
/*
* When the mouse is pressed the editor is invoked. If you then then drag
* the mouse to another cell before releasing it, the editor is still
* active. Make sure editing is stopped when the mouse is released.
*/
public void mousePressed(MouseEvent e)
{
if (table.isEditing()
&& table.getCellEditor() == this)
isButtonColumnEditor = true;
}
public void mouseReleased(MouseEvent e)
{
if (isButtonColumnEditor
&& table.isEditing())
table.getCellEditor().stopCellEditing();
isButtonColumnEditor = false;
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
In windows it is possible to show a grayed out JCheckbox, to show that the collection of data which it represents not all items have the same value.
Is this even possible with a JCheckBox?
How do i go about this?
(Hoping there's a way to not override it)
Thanks
JIDE Common Layer has a TristateCheckBox.
It's possible with some of work.
I have this code from some years ago. Is based in some examples I found in internet, but I cannot find any reference to the original creator, so I apologize
import javax.swing.*;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ActionMapUIResource;
import java.awt.event.*;
/**
* Maintenance tip - There were some tricks to getting this code
* working:
*
* 1. You have to overwite addMouseListener() to do nothing
* 2. You have to add a mouse event on mousePressed by calling
* super.addMouseListener()
* 3. You have to replace the UIActionMap for the keyboard event
* "pressed" with your own one.
* 4. You have to remove the UIActionMap for the keyboard event
* "released".
* 5. You have to grab focus when the next state is entered,
* otherwise clicking on the component won't get the focus.
* 6. You have to make a TristateDecorator as a button model that
* wraps the original button model and does state management.
*/
public class TristateCheckBox extends JCheckBox {
/** This is a type-safe enumerated type */
public static class State { private State() { } }
public static final State NOT_SELECTED = new State();
public static final State SELECTED = new State();
public static final State DONT_CARE = new State();
private final TristateDecorator model;
public TristateCheckBox(String text, Icon icon, State initial){
super(text, icon);
// Add a listener for when the mouse is pressed
super.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
grabFocus();
model.nextState();
}
});
// Reset the keyboard action map
ActionMap map = new ActionMapUIResource();
map.put("pressed", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
grabFocus();
model.nextState();
}
});
map.put("released", null);
SwingUtilities.replaceUIActionMap(this, map);
// set the model to the adapted model
model = new TristateDecorator(getModel());
setModel(model);
setState(initial);
}
public TristateCheckBox(String text, State initial) {
this(text, null, initial);
}
public TristateCheckBox(String text) {
this(text, DONT_CARE);
}
public TristateCheckBox() {
this(null);
}
/** No one may add mouse listeners, not even Swing! */
public void addMouseListener(MouseListener l) { }
/**
* Set the new state to either SELECTED, NOT_SELECTED or
* DONT_CARE. If state == null, it is treated as DONT_CARE.
*/
public void setState(State state) { model.setState(state); }
/** Return the current state, which is determined by the
* selection status of the model. */
public State getState() { return model.getState(); }
public void setSelected(boolean b) {
if (b) {
setState(SELECTED);
} else {
setState(NOT_SELECTED);
}
}
/**
* Exactly which Design Pattern is this? Is it an Adapter,
* a Proxy or a Decorator? In this case, my vote lies with the
* Decorator, because we are extending functionality and
* "decorating" the original model with a more powerful model.
*/
private class TristateDecorator implements ButtonModel {
private final ButtonModel other;
private TristateDecorator(ButtonModel other) {
this.other = other;
}
private void setState(State state) {
if (state == NOT_SELECTED) {
other.setArmed(false);
setPressed(false);
setSelected(false);
} else if (state == SELECTED) {
other.setArmed(false);
setPressed(false);
setSelected(true);
} else { // either "null" or DONT_CARE
other.setArmed(true);
setPressed(true);
setSelected(true);
}
}
/**
* The current state is embedded in the selection / armed
* state of the model.
*
* We return the SELECTED state when the checkbox is selected
* but not armed, DONT_CARE state when the checkbox is
* selected and armed (grey) and NOT_SELECTED when the
* checkbox is deselected.
*/
private State getState() {
if (isSelected() && !isArmed()) {
// normal black tick
return SELECTED;
} else if (isSelected() && isArmed()) {
// don't care grey tick
return DONT_CARE;
} else {
// normal deselected
return NOT_SELECTED;
}
}
/** We rotate between NOT_SELECTED, SELECTED and DONT_CARE.*/
private void nextState() {
State current = getState();
if (current == NOT_SELECTED) {
setState(SELECTED);
} else if (current == SELECTED) {
setState(DONT_CARE);
} else if (current == DONT_CARE) {
setState(NOT_SELECTED);
}
}
/** Filter: No one may change the armed status except us. */
public void setArmed(boolean b) {
}
/** We disable focusing on the component when it is not
* enabled. */
public void setEnabled(boolean b) {
setFocusable(b);
other.setEnabled(b);
}
/** All these methods simply delegate to the "other" model
* that is being decorated. */
public boolean isArmed() { return other.isArmed(); }
public boolean isSelected() { return other.isSelected(); }
public boolean isEnabled() { return other.isEnabled(); }
public boolean isPressed() { return other.isPressed(); }
public boolean isRollover() { return other.isRollover(); }
public void setSelected(boolean b) { other.setSelected(b); }
public void setPressed(boolean b) { other.setPressed(b); }
public void setRollover(boolean b) { other.setRollover(b); }
public void setMnemonic(int key) { other.setMnemonic(key); }
public int getMnemonic() { return other.getMnemonic(); }
public void setActionCommand(String s) {
other.setActionCommand(s);
}
public String getActionCommand() {
return other.getActionCommand();
}
public void setGroup(ButtonGroup group) {
other.setGroup(group);
}
public void addActionListener(ActionListener l) {
other.addActionListener(l);
}
public void removeActionListener(ActionListener l) {
other.removeActionListener(l);
}
public void addItemListener(ItemListener l) {
other.addItemListener(l);
}
public void removeItemListener(ItemListener l) {
other.removeItemListener(l);
}
public void addChangeListener(ChangeListener l) {
other.addChangeListener(l);
}
public void removeChangeListener(ChangeListener l) {
other.removeChangeListener(l);
}
public Object[] getSelectedObjects() {
return other.getSelectedObjects();
}
}
}
My colleague who this question came from thought of this;
Create a dummy JCheckBox which is disabled and selected. set the same size as the real one.
Create an Icon which' paint method actually paints the dummy JCheckbox.
Set the original JCheckBox' Icon to the one painting the dummy.
Remove the icon as soon as the JCheckBox is clicked.
++ No overridden JCheckBox
-- not a real tri-state Combo
I think he's satisfied.
Thanks for the help