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);
}
});
Related
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;
}
}
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);
//...
}
}
I am using a JTable and in order to change the format of numbers. I have extended the DefaultTableRenderer class.
In the method getTableCellRenderedComponent, I retrun a new JLabel with the proper format.
My problem is by doing this the rectangle (border) that underlines the cell which has the focus has disappeared.
Is there a way to get the default border displayed whenever a cell has the focus with my custom render?
in order to change the format of numbers. I have extended the DefaultTableRenderer class.
Check out Table Format Renderers for an easier way to customize the renderer when all you need to do is format the data. That is you should override the setValue(...) method instead of the getTableCellRenderer(...) method.
If you use DefaultTableRenderer you can call super() method and get Border from returned component. Try next example:
import java.awt.Component;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
public class TestFrame extends JFrame {
public TestFrame() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void init() {
JTable t = new JTable(3,3);
t.getColumnModel().getColumn(0).setCellRenderer(getRenderer());
add(new JScrollPane(t));
}
private TableCellRenderer getRenderer() {
return new DefaultTableCellRenderer(){
private JLabel l = new JLabel();
{
l.setOpaque(true);
}
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
JComponent tableCellRendererComponent = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus,row, column);
l.setText(value == null ? "" : value.toString());
l.setBorder(tableCellRendererComponent.getBorder());
l.setBackground(tableCellRendererComponent.getBackground());
l.setForeground(tableCellRendererComponent.getForeground());
return l;
}
};
}
public static void main(String... s){
new TestFrame();
}
}
I have the following Java code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class EnumsRightVisible {
public void show() {
JFrame frame = new JFrame("Combo box");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String[] items = {"aaaaaaaaa__________zzzzzzzzz",
"aaaaaaaaa__________zzzzzzzzz",
"aaaaaaaaa__________zzzzzzzzz"};
JComboBox combo = new JComboBox(items);
combo.setPreferredSize(new Dimension(100,20));
frame.add(combo, BorderLayout.CENTER);
frame.setLocation(600, 100);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
EnumsRightVisible enumsRightVisible = new EnumsRightVisible();
enumsRightVisible.show();
}
}
Running it you can see that the visible text is left oriented.
Please note that this code does not solve my problem (it aligns the text to the right, but only when the combo box is expanded):
((JLabel)comboBox.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);
How can I display the right end of the text in the same window (...__zzzzzz)?
Thanks in advance!
Use a custom renderer that uses FontMetrics to measure the String's width and does the ellipsis (...) manually. More info here: http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer
Method 1
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class ComboBoxDemo extends JFrame {
public ComboBoxDemo() {
JComboBox comboBox = new JComboBox();
((JLabel)comboBox.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);
comboBox.addItem("Apple");
comboBox.addItem("Orange");
comboBox.addItem("Mango");
getContentPane().add(comboBox, "North");
setSize(200, 100);
this.setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new ComboBoxDemo().setVisible(true);
}
}
Method 2 (Oviously, First is better)
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.ListCellRenderer;
public class ComboBoxDemo extends JFrame {
public ComboBoxDemo() {
JComboBox comboBox = new JComboBox();
setListCellRendererOf(comboBox);
comboBox.addItem("Apple");
comboBox.addItem("Orange");
comboBox.addItem("Mango");
getContentPane().add(comboBox, "North");
setSize(200, 100);
this.setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void setListCellRendererOf(JComboBox comboBox) {
comboBox.setRenderer(new ListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component component = new DefaultListCellRenderer()
.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
component.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
return component;
}
});
}
public static void main(String[] args) {
new ComboBoxDemo().setVisible(true);
}
}
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