Cell renderer and the lost focus - java

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();
}
}

Related

Jtable Appearance: How to write a code with jtable properties that can be use to multiple jtables to have a similar appearance?

I am working with a simple crud with 5 tables, I already change the properties of Table_1 like (background color, foreground color, row height and etc.) What I want is that my Table_2, Table_3 and other tables to be look like the Table_1.
I have tried to create a custom TableCellRenderer
This is my code:
package com.table.design.Default;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.util.Hashtable;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
public class StrippedTable implements TableCellRenderer {
private TableCellRenderer mWrappedRenderer;
public StrippedTable(TableCellRenderer pWrappedRenderer) {
mWrappedRenderer = pWrappedRenderer;
DefaultTableCellRenderer DEFAULT_RENDERER = new DefaultTableCellRenderer();
}
public Component getTableCellRendererComponent(JTable pTable, Object pValue, boolean pIsSelected,
boolean pHasFocus, int pRow, int pColumn) {
Component c = mWrappedRenderer.getTableCellRendererComponent(pTable, pValue, pIsSelected, pHasFocus,
pRow, pColumn);
if ( pTable.isCellSelected(pRow, pColumn) == false ) {
c.setBackground(colorForRow(pRow));
// c.setForeground(UIManager.getColor("Table.foreground"));
} else {
// c.setBackground(new java.awt.Color(242, 242, 242));
// c.setForeground(UIManager.getColor("Table.selectionForeground"));
}
// setting global table properties
pTable.setRowHeight(45);
pTable.setShowVerticalLines(false);
return c;
}
protected Color colorForRow(int row) {
return (row % 2 == 0) ? new java.awt.Color(245, 245, 245) : Color.WHITE;
}
}
is it ok to add the code
// setting global table properties
pTable.setRowHeight(45);
pTable.setShowVerticalLines(false);
to
public Component getTableCellRendererComponent(JTable pTable, Object pValue, boolean pIsSelected,
boolean pHasFocus, int pRow, int pColumn) {
Component c = mWrappedRenderer.getTableCellRendererComponent(pTable, pValue, pIsSelected, pHasFocus,
pRow, pColumn);
if ( pTable.isCellSelected(pRow, pColumn) == false ) {
c.setBackground(colorForRow(pRow));
// c.setForeground(UIManager.getColor("Table.foreground"));
} else {
// c.setBackground(new java.awt.Color(242, 242, 242));
// c.setForeground(UIManager.getColor("Table.selectionForeground"));
}
// setting global table properties
pTable.setRowHeight(45);
pTable.setShowVerticalLines(false);
return c;
}
because it is working.. and i use this code to my tables to have the same properties
TableModel s = (DefaultTableModel) jTable1.getModel();
StrippedTable cellRenderer = new StrippedTable(jTable1.getDefaultRenderer(Object.class));
jTable1.setDefaultRenderer(Object.class, cellRenderer);
Thank you very much!!
-------EDITED------
I worked another class which extends jtable,
package com.table.design;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.MouseInputAdapter;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
public class CustomTable extends JTable {
public CustomTable(TableModel model, JScrollPane scrollpane) {
super(model);
getTableHeader().setDefaultRenderer(new customHeaderRenderer());
customTableProperties(scrollpane);
}
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if (isCellSelected(row, column) == false) {
c.setBackground(colorForRow(row));
}
return c;
}
protected Color colorForRow(int row) {
return (row % 2 == 0) ? new java.awt.Color(245, 245, 245) : Color.WHITE;
}
private void customTableProperties(JScrollPane sp) {
setForeground(new java.awt.Color(100, 100, 100));
setShowVerticalLines(false);
setFont(new Font("Open Sans", Font.PLAIN, 14));
setIntercellSpacing(new java.awt.Dimension(0, 0));
setSelectionBackground(new java.awt.Color(242, 242, 242));
setGridColor(new java.awt.Color(240, 240, 240));
setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
setRowHeight(45);
setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
setBorder(BorderFactory.createEmptyBorder());
setRowSelectionAllowed(false);
setFocusable(false);
setAutoCreateRowSorter(true);
/**
* *** JscrollPane*******
*/
sp.setBorder(BorderFactory.createEmptyBorder());
sp.getViewport().setBackground(Color.decode("#FFFFFF"));
sp.setOpaque(false);
}
/**
* Code for JtableHeaderRenderer
*
*/
public class customHeaderRenderer extends JLabel implements TableCellRenderer {
public customHeaderRenderer() {
setAutoCreateRowSorter(true);
setAutoResizeMode(0);
setFont(new Font("Open Sans", Font.BOLD, 15));
setForeground(new java.awt.Color(95, 95, 95));
setOpaque(false);
getTableHeader().setBackground(new java.awt.Color(255, 255, 255));
setPreferredSize(new Dimension(this.getWidth(), 65));
getTableHeader().setReorderingAllowed(false);
getTableHeader().setBorder(BorderFactory.createMatteBorder(1, 0, 2, 0, new java.awt.Color(235, 235, 235)));
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setText(value.toString());
return this;
}
}
}
Then I will call the table like this
private static CustomTable customTable;
private DefaultTableModel tbm;
tbm = (DefaultTableModel) customTable.getModel();
customTable = new CustomTable (tbm, /*Jscrollpane*/);
Is my code above correct?
It is generally bad practice to modify parent component's appearance from cell renderers (mostly because they are called every time a cell update happens like stated in this thread).
In your case, I would simply create another class that extends JTable with a constructor that calls the desired super's constructor and then applies desired changes.
Your new class would look something like this:
import javax.swing.*;
public class JCustomTable extends JTable {
public JCustomTable(/* parameters of your desired JTable constructor */){
super(/* parameters of your desired JTable constructor */);
//setting desired global table properties
setRowHeight(45);
setShowVerticalLines(false);
}
}
Now just use JCustomTable or whatever you want to call it anytime you would normally use a JTable object.
Much like in your first case, it isn't a good practice modifying other objects from within another one. In this case, it would be best to leave the custom table's constructor with a fingerprint like this (I added a few words to the first part in order to improve clarity):
CustomTable(TableModel)
The JScrollPane settings can, again, be done in the same way as JCustomTable, in order to keep the code object-oriented and generally cleaner.

Using TableCellRenderer in XdevSortableTable, XdevAggregateTable

Well, I'm trying to render some components in the tables mentioned above. I know thats done with implementing a custom TableCellRenderer, and that works just fine in normal JTable, e.g. doing something like this:
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
public class Test
{
public static void main(String[] argv)
{
String[] columnNames = {"First Name","Last Name","nr"};
Object[][] data = {{"Homer","Simpson","1"},{"Madge","Simpson","2"},{"Bart","Simpson","3"},
{"Lisa","Simpson","4"},};
DefaultTableModel model = new DefaultTableModel(data,columnNames);
JTable table = new JTable(model);
table.getColumnModel().getColumn(2).setCellRenderer(new TableCellRenderer(){
final JButton button = new JButton();
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
button.setText(value.toString());
return button;
}
});
JFrame f = new JFrame();
f.setSize(300,300);
f.add(new JScrollPane(table));
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
It also works with JIDE's Sortable- and AggregateTable, but as soon as I replace those tables with Xdev's, the component isn't rendered anymore, so it seems the CellRenderer isn't set properly, even though TableColumn.getCellRenderer() returns the correct class.
So does anyone know how to render a component in Xdev's tables?
Thanks in advance!

different font for combo box in Java

I would make a little rft text editor in Java and I would have that the different kind of fonts are show in my combo box in that font. The reason is because the user can see that font.
I know that you can use a combo box item for C#. But I didn't know for Java.
Can anyone help me?
Edit:
Sounds like you need to implement a custom renderer for your combo box.
See the java tutorial here: http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer
i.e. Something like this (assuming the Objects in your combo box are Fonts):
class CustomRenderer implements ListCellRenderer
{
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = new JLabel();
label.setFont(((Font) value).deriveFont(12f));
label.setText(((Font) value).getFontName());
return label;
}
}
Custom Combo box for font selection in java
Here is code :
package stack;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
public class CustomComboBox {
JComboBox fontComboBox;
JFrame frame;
String fontName[];
Integer array[];
public CustomComboBox() {
JFrame.setDefaultLookAndFeelDecorated(true);
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
fontName = ge.getAvailableFontFamilyNames();
array = new Integer[fontName.length];
for(int i=1;i<=fontName.length;i++) {
array[i-1] = i;
}
fontComboBox = new JComboBox(array);
ComboBoxRenderar renderar = new ComboBoxRenderar();
fontComboBox.setRenderer(renderar);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(fontComboBox);
frame.pack();
frame.setVisible(true);
}
public class ComboBoxRenderar extends JLabel implements ListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
int offset = ((Integer)value).intValue() - 1 ;
String name = fontName[offset];
setText(name);
setFont(new Font(name,Font.PLAIN,20));
return this;
}
}
public static void main(String args[]) {
new CustomComboBox();
}
}
and preview of the code see the Image
:

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 do I render a JTable inside of a JTable?

I am trying to nest a JTable inside of another JTable's column (using a CellRenderer).
Example (erroneous) output:
Why does the following example not output a table within a table?
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class Test {
public static void main(String[] args) {
JTable table = new JTable(new CustomTableModel());
table.setDefaultRenderer(Person.class, new CustomRenderer());
JPanel panel = new JPanel();
panel.add(new JScrollPane(table));
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
}
#SuppressWarnings("serial")
class CustomTableModel extends AbstractTableModel {
#Override
public int getColumnCount() {
return 2;
}
#Override
public int getRowCount() {
return 1;
}
#Override
public Object getValueAt(int row, int col) {
if (col == 0) {
return new Person("Bob");
} else {
return "is awesome!";
}
}
}
#SuppressWarnings("serial")
class CustomRenderer extends JPanel implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
JTable t = new JTable(new CustomTableModel());
add(new JScrollPane(t));
return this;
}
}
class Person {
public String name = "";
public Person(String name) {
this.name = name;
}
}
Don't add the sub table to a scroll pane. Instead, try adding the table to the center position of a JPanel with a BorderLayout, then add the tables header to the NORTH position
The main reason for this is the scroll pane will not be interactive and may hide data
Updated
I'm on phone, so it's hard to read the code :P
In your main table model, you need to override the getColumnClass method and make sure you are retuning Person.class for the required column (and the correct class types for the other columns to)

Categories

Resources