I have a JTable with some data like this SSCCE:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.*;
import java.awt.Color;
class kanji{
public static void main(String args[]){
JFrame frame = new JFrame("Kanji");
JPanel pane = new JPanel();
JTable table = new JTable();
pane.setLayout(new BorderLayout());
JButton agreg = new JButton("Agregar");
DefaultTableModel model = new DefaultTableModel(get_data(), get_header());
JFrame hk = new JFrame("Historial de Significados");
Image icon = Toolkit.getDefaultToolkit().getImage("JLPT.jpg");
ImageIcon ima = new ImageIcon("JLPT.jpg");
table = new JTable(model){
#Override
public boolean isCellEditable(int row, int col){
switch(col){
case 0:
return false;
case 1:
return false;
case 2:
return true;
default:
return false;
}
}
#Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return String.class;
case 1:
return String.class;
case 2:
return Boolean.class;
default:
return Boolean.class;
}
}
};
DefaultTableCellRenderer r = new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setForeground(Color.blue);
setHorizontalAlignment(JLabel.CENTER);
setFont(new Font("Microsoft JhengHei", Font.BOLD, 50));
return this;
}
};
DefaultTableCellRenderer r2 = new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setHorizontalAlignment(JLabel.LEFT);
setFont(new Font("Microsoft JhengHei", Font.BOLD, 13));
return this;
}
};
table.getColumnModel().getColumn(0).setCellRenderer(r);
table.getColumnModel().getColumn(1).setCellRenderer(r2);
TableColumn column = null;
for (int i = 0; i < 3; i++) {
column = table.getColumnModel().getColumn(i);
if (i==0) {
column.setMaxWidth(80);
column.setMinWidth(80);
}
else{
if(i==1){
column.setPreferredWidth(470);
}
else{
column.setMaxWidth(50);
column.setMinWidth(50);
}
}
}
table.setRowHeight(table.getRowHeight()+70);
table.setModel(model);
table.getTableHeader().setReorderingAllowed(false);
JScrollPane scroll = new JScrollPane(table);
pane.add(scroll, BorderLayout.CENTER);
pane.add(agreg, BorderLayout.SOUTH);
frame.add(pane);
frame.setTitle("Historial de Significados");
frame.setSize(1350, 700);
frame.setIconImage(icon);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
scroll.setViewportView(table);
}
public static Object [][]get_data(){
Object data[][] = new Object[][]{
{"\u4e00", "Uno, 1", true},
{"\u4e01", "Uno, 1", true},
{"\u4e02", "Uno, 1", true},
{"\u4e03", "Uno, 1", true},
{"\u4e04", "Uno, 1", true},
{"\u4e05", "Uno, 1", true},
{"\u4e06", "Uno, 1", true},
{"\u4e07", "Uno, 1", true},
{"\u4e08", "Uno, 1", true},
{"\u4e09", "Uno, 1", true}
};
return data;
}
public static String []get_header(){
String header [] = new String[]{"KANJI", "SIGNIFICADO", "Agregar"};
return header;
}
}
But I want to add 3 JButton after JTable is created, I want to have a JTable that don't take all JFrame size, in my code I get a Button but I want to have the possibility to set buttons bounds.
I've tried adding a JPanel and with another try with "setPreferredSize" where JScrollPane don't work, I mean I doesn't appear so I can't see all table content; and I also tried with "setSize" that doesn't work for me.
Maybe I have to make a second panel or something like that, I hope you can help me solving this issue.
I guess an Image says more than 1,000 words, so:
This is what I get and have and what I want to have
So in plain english, all I want to know is how to render table and add button at the bottom after rendered table (but I don't want buttons to have all the frame width, I want them away from table, not together as I have them and with the possibility to change their size and position).
private void createUI() {
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
final JTable table = new JTable(10, 4);
JPanel btnPnl = new JPanel(new BorderLayout());
JPanel topBtnPnl = new JPanel(new FlowLayout(FlowLayout.TRAILING));
JPanel bottombtnPnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
topBtnPnl.add(new JButton("Select All"));
bottombtnPnl.add(new JButton("Cancel"));
bottombtnPnl.add(new JButton("Add Selected"));
btnPnl.add(topBtnPnl, BorderLayout.NORTH);
btnPnl.add(bottombtnPnl, BorderLayout.CENTER);
table.getTableHeader().setReorderingAllowed(false);
frame.add(table.getTableHeader(), BorderLayout.NORTH);
frame.add(table, BorderLayout.CENTER);
frame.add(btnPnl, BorderLayout.SOUTH);
frame.setTitle("JTable Example.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
CheckABunch is an example that shows how to update the TableModel based on the current selection.
You could take a look at GridLayout.
In short I've made some changes to your class, and I've got this:
First group all JButtons into a JPanel, which have a GridLayout inside
Also, your JFrame container must have a BorderLayout
So you need add each button to the auxiliary pane and at the end add both JPanels to the frame.
Here's the code:
//Another import sentences
import java.awt.GridLayout;
class kanji{
public static void main(String args[]){
// More code goes here
JPanel allowedOperations = new JPanel(new GridLayout(2, 2));
pane.setLayout(new BorderLayout());
// More code goes here
// All buttons are grouped here
allowedOperations.add(new JButton()); // Here's a trick
allowedOperations.add(agreg);
allowedOperations.add(new JButton("Save selected"));
allowedOperations.add(new JButton("Cancel"));
// Add the pane object to the frame
frame.add(pane, BorderLayout.CENTER);
// And finally add the allowedOperations object to the frame
frame.add(allowedOperations, BorderLayout.SOUTH);
// More code goes here
} //End class
I've just posted the modifications, so you need to group the whole class.
I know it isn't the best approach, but you can improve your code from here. Also note you can create your buttons before added to the allowedOperations pane, as the agreg button
Related
Happy new year everyone, i've a problem chaning the height of a JTable header, I appreciate if someone can help. The Method I'am using is changing also the backgroundcolor etc.
Thanks
public static void ChangeJTableBackgroundColor(JTable InTable){
JTable mytable = InTable;
Color mycolor = new Color(248, 201, 171);
mytable.setOpaque(true);
mytable.setFillsViewportHeight(true);
mytable.setBackground(mycolor);
Color mycolorhead = new Color(249, 168, 117);
mytable.getTableHeader().setBackground(mycolorhead);
mytable.getTableHeader().setPreferredSize(new Dimension(1,50));
}
There are lots of ways you "might" increase the height of the header, which you choose will depend on what you want to achieve. One thing to keep in mind though, is trying to find a solution which respects the diverse rendering environments which you program might need to run in.
You could...
Simple change the font size. This might sound silly, but you'd be surprised at how simple it really is, for example...
DefaultTableModel model = new DefaultTableModel(10, 10);
JTable table = new JTable(model);
JTableHeader header = table.getTableHeader();
header.setFont(header.getFont().deriveFont(30f));
You could...
Take advantage of Swing's inbuilt HTML support. This example sets up a HTML table with a defined cell height
DefaultTableModel model = new DefaultTableModel(10, 10);
JTable table = new JTable(model);
TableColumnModel columnModel = table.getColumnModel();
String prefix = "<html><body><table><tr><td height=100>";
String suffix = "</td></tr></table></body><html>";
for (int col = 0; col < columnModel.getColumnCount(); col++) {
TableColumn column = columnModel.getColumn(col);
String text = prefix + Character.toString((char)('A' + col)) + suffix;
System.out.println(text);
column.setHeaderValue(text);
}
You could...
Just supply your own TableCellRenderer as the default cell renderer for the table header. This is a little tricky, as it's difficult to mimic the default renderer used by the current look and feel and the UIManager doesn't help. Instead, you need to consider using a "proxy" approach, where by you apply the changes you need to the existing header renderer instead.
DefaultTableModel model = new DefaultTableModel(10, 10);
JTable table = new JTable(model);
JTableHeader header = table.getTableHeader();
TableCellRenderer proxy = header.getDefaultRenderer();
header.setDefaultRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component comp = proxy.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (comp instanceof JLabel) {
JLabel label = (JLabel) comp;
label.setBorder(new CompoundBorder(label.getBorder(), new EmptyBorder(50, 0, 50, 0)));
}
return comp;
}
});
As far as solutions go, this is probably my preferred, as it takes into account more of the variables involved in determine the preferred size of the column header itself
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.Arrays;
import javax.swing.*;
import javax.swing.table.*;
public class TableHeaderHeightTest {
private static int HEADER_HEIGHT = 32;
private JTable makeTable() {
JTable table = new JTable(new DefaultTableModel(2, 20));
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
return table;
}
public JComponent makeUI() {
JPanel p = new JPanel(new GridLayout(2,1));
JTable table1 = makeTable();
//Bad: >>>>
JTableHeader header = table1.getTableHeader();
//Dimension d = header.getPreferredSize();
//d.height = HEADER_HEIGHT;
//header.setPreferredSize(d); //addColumn case test
header.setPreferredSize(new Dimension(100, HEADER_HEIGHT));
p.add(makeTitledPanel("Bad: JTableHeader#setPreferredSize(...)", new JScrollPane(table1)));
//<<<<
JTable table2 = makeTable();
JScrollPane scroll = new JScrollPane(table2);
scroll.setColumnHeader(new JViewport() {
#Override public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
d.height = HEADER_HEIGHT;
return d;
}
});
// //or
// table2.setTableHeader(new JTableHeader(table2.getColumnModel()) {
// #Override public Dimension getPreferredSize() {
// Dimension d = super.getPreferredSize();
// d.height = HEADER_HEIGHT;
// return d;
// }
// });
p.add(makeTitledPanel("Override getPreferredSize()", scroll));
final List<JTable> list = Arrays.asList(table1, table2);
JPanel panel = new JPanel(new BorderLayout());
panel.add(p);
panel.add(new JButton(new AbstractAction("addColumn") {
#Override public void actionPerformed(ActionEvent e) {
for(JTable t: list) {
t.getColumnModel().addColumn(new TableColumn());
JTableHeader h = t.getTableHeader();
Dimension d = h.getPreferredSize();
System.out.println(d);
}
}
}), BorderLayout.SOUTH);
panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
return panel;
}
private static JComponent makeTitledPanel(String title, JComponent c) {
JPanel p = new JPanel(new BorderLayout());
p.add(c);
p.setBorder(BorderFactory.createTitledBorder(title));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TableHeaderHeightTest().makeUI());
f.setSize(320, 320);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
Try this
My goal is to make a basic pixel art application in Java Swing (I know this is far from ideal, we have to do something with Swing for a class and I thought this sounded kind of fun).
The idea is that the color of any selected cell in the JTable is changed to the color selected in the JComboBox.
Here is what it looks like currently after a click at the highlighted cell (9,7):
And after a click elsewhere (such as at (0,6) shown), it tends to fill in the space in between the two spaces, as well as the remainder of the rows as well.
This of course is not ideal - I want only one cell to change color per click. I am new to custom JTable rendering so I have attached the necessary code in the hopes that someone can help me spot my error. The area of interest is toward the bottom when I create the JTable the CustomModel class.
//Lots of importing
public class PixelArtistGUI extends JFrame {
String colors[] = { "Red", "Orange", "Yellow", "Green", "Blue", "Magenta", "Black", "White" };
JComboBox colorList = new JComboBox(colors);
public PixelArtistGUI() {
setTitle("PixelArtist");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
this.setPreferredSize(new Dimension(400, 450));
// Content Pane
JPanel contentPane = new JPanel();
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[] { 125, 125, 125 };
gbl_contentPane.rowHeights = new int[] {360, 15};
contentPane.setLayout(gbl_contentPane);
JLabel colorSelect = new JLabel("Select Color:");
colorSelect.setFont(new Font("Tahoma", Font.PLAIN, 18));
colorSelect.setHorizontalAlignment(SwingConstants.CENTER);
GridBagConstraints gbc_colorSelect = new GridBagConstraints();
gbc_colorSelect.insets = new Insets(5, 0, 0, 0);
gbc_colorSelect.gridx = 0;
gbc_colorSelect.anchor = GridBagConstraints.SOUTH;
gbc_colorSelect.fill = GridBagConstraints.BOTH;
gbc_colorSelect.gridy = 1;
contentPane.add(colorSelect, gbc_colorSelect);
GridBagConstraints gbc_colorList = new GridBagConstraints();
gbc_colorList.anchor = GridBagConstraints.SOUTH;
gbc_colorList.fill = GridBagConstraints.BOTH;
gbc_colorList.insets = new Insets(5, 0, 0, 0);
gbc_colorList.gridx = 1;
gbc_colorList.gridy = 1;
contentPane.add(colorList, gbc_colorList);
JButton screenshotButton = new JButton("Save Screenshot");
GridBagConstraints gbc_screenshotButton = new GridBagConstraints();
gbc_screenshotButton.anchor = GridBagConstraints.SOUTH;
gbc_screenshotButton.fill = GridBagConstraints.BOTH;
gbc_screenshotButton.insets = new Insets(5, 0, 0, 0);
gbc_screenshotButton.gridx = 2;
gbc_screenshotButton.gridy = 1;
contentPane.add(screenshotButton, gbc_screenshotButton);
String[] colHeadings = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" };
int numRows = 16;
PixelModel model = new PixelModel(numRows, colHeadings.length);
model.setColumnIdentifiers(colHeadings);
JTable table_1 = new JTable(model);
table_1.setBorder(new LineBorder(new Color(0, 0, 0)));
table_1.setRowSelectionAllowed(false);
table_1.setDefaultRenderer(Object.class, new CustomModel());
GridBagConstraints gbc_table_1 = new GridBagConstraints();
gbc_table_1.gridwidth = 3;
gbc_table_1.fill = GridBagConstraints.BOTH;
gbc_table_1.gridx = 0;
gbc_table_1.gridy = 0;
contentPane.add(table_1, gbc_table_1);
table_1.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
table_1.setCellSelectionEnabled(true);
table_1.setRowHeight(23);
this.pack();
}
// Custom table renderer to change cell colors
public class CustomModel extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
column);
Color c;
try {
String cString = colorList.getSelectedItem().toString().toLowerCase();
Field field = Class.forName("java.awt.Color").getField(cString);
c = (Color) field.get(null);
} catch (Exception e) {
c = null;
}
if (isSelected)
label.setBackground(c);
return label;
}
}
// Custom table model to make the cells selectable but not editable
public class PixelModel extends DefaultTableModel {
PixelModel(int numRows, int numColumns) {
super(numRows, numColumns);
}
public boolean isCellEditable(int row, int column) {
return false;
}
}
I appreciate any tips, I am stuck on how to fix this.
Take a look at Concepts: Editors and Renderers, Writing a Custom Cell Renderer and Using Other Editors for more details about how renderers and editors actually work.
Each time getTableCellRendererComponent is called, you are expected to completely configure the renderer based on the value and state of the cell. So basically, what you're doing, is simply setting the background color once and never change it for any other condition, meaning when any other cell is painted (for whatever reason), it's still using the same background color.
Instead, you should be using the value stored in the TableModel to make decisions about what the cell should be painting. To accomplish this, you'll probably need a simple CellEditor which can simply return the currently selected color
Maybe something like...
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.lang.reflect.Field;
import java.util.EventObject;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
public class PixelArtistGUI extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
PixelArtistGUI frame = new PixelArtistGUI();
frame.setVisible(true);
}
});
}
String colors[] = {"Red", "Orange", "Yellow", "Green", "Blue", "Magenta", "Black", "White"};
JComboBox colorList = new JComboBox(colors);
public PixelArtistGUI() {
setTitle("PixelArtist");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
this.setPreferredSize(new Dimension(400, 450));
// Content Pane
JPanel contentPane = new JPanel();
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[]{125, 125, 125};
gbl_contentPane.rowHeights = new int[]{360, 15};
contentPane.setLayout(gbl_contentPane);
JLabel colorSelect = new JLabel("Select Color:");
colorSelect.setFont(new Font("Tahoma", Font.PLAIN, 18));
colorSelect.setHorizontalAlignment(SwingConstants.CENTER);
GridBagConstraints gbc_colorSelect = new GridBagConstraints();
gbc_colorSelect.insets = new Insets(5, 0, 0, 0);
gbc_colorSelect.gridx = 0;
gbc_colorSelect.anchor = GridBagConstraints.SOUTH;
gbc_colorSelect.fill = GridBagConstraints.BOTH;
gbc_colorSelect.gridy = 1;
contentPane.add(colorSelect, gbc_colorSelect);
GridBagConstraints gbc_colorList = new GridBagConstraints();
gbc_colorList.anchor = GridBagConstraints.SOUTH;
gbc_colorList.fill = GridBagConstraints.BOTH;
gbc_colorList.insets = new Insets(5, 0, 0, 0);
gbc_colorList.gridx = 1;
gbc_colorList.gridy = 1;
contentPane.add(colorList, gbc_colorList);
JButton screenshotButton = new JButton("Save Screenshot");
GridBagConstraints gbc_screenshotButton = new GridBagConstraints();
gbc_screenshotButton.anchor = GridBagConstraints.SOUTH;
gbc_screenshotButton.fill = GridBagConstraints.BOTH;
gbc_screenshotButton.insets = new Insets(5, 0, 0, 0);
gbc_screenshotButton.gridx = 2;
gbc_screenshotButton.gridy = 1;
contentPane.add(screenshotButton, gbc_screenshotButton);
String[] colHeadings = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
int numRows = 16;
PixelModel model = new PixelModel(numRows, colHeadings.length);
model.setColumnIdentifiers(colHeadings);
JTable table_1 = new JTable(model);
table_1.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
TableCellEditor editor = table_1.getCellEditor();
if (editor != null) {
if (editor.stopCellEditing()) {
editor.cancelCellEditing();
}
}
}
});
table_1.setBorder(new LineBorder(new Color(0, 0, 0)));
table_1.setRowSelectionAllowed(false);
table_1.setDefaultRenderer(Object.class, new CustomRenderer());
table_1.setDefaultEditor(Object.class, new CustomEditor());
GridBagConstraints gbc_table_1 = new GridBagConstraints();
gbc_table_1.gridwidth = 3;
gbc_table_1.fill = GridBagConstraints.BOTH;
gbc_table_1.gridx = 0;
gbc_table_1.gridy = 0;
contentPane.add(table_1, gbc_table_1);
table_1.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
table_1.setCellSelectionEnabled(true);
table_1.setRowHeight(23);
this.pack();
}
public class CustomRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
super.getTableCellRendererComponent(table, null, false, hasFocus, row, column);
if (value != null && value instanceof Color) {
setBackground((Color) value);
} else {
setBackground(null);
}
return this;
}
}
public class CustomEditor extends AbstractCellEditor implements TableCellEditor {
private JPanel panel;
public CustomEditor() {
this.panel = new JPanel();
}
#Override
public Object getCellEditorValue() {
Color c = null;
try {
String cString = colorList.getSelectedItem().toString().toLowerCase();
Field field = Class.forName("java.awt.Color").getField(cString);
c = (Color) field.get(null);
} catch (Exception e) {
c = null;
}
return c;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
panel.setBackground((Color) getCellEditorValue());
return panel;
}
#Override
public boolean isCellEditable(EventObject e) {
return true;
}
}
// Custom table model to make the cells selectable but not editable
public class PixelModel extends DefaultTableModel {
PixelModel(int numRows, int numColumns) {
super(numRows, numColumns);
}
#Override
public boolean isCellEditable(int row, int column) {
return true;
}
}
}
Now, before anyone jumps on me. I would fill the JComboBox with Colors and use a custom ListCellRenderer to display it.
I would like to make multiple cells bold, I have arraylist with the cell names that should be bold but doesn't seem to work. My Arraylist with the cells that I want to bold is called bibNumbers, so far tried converting the arralist into array and putting the if statement into a loop and loop results into bolding variable
//edit
added example, so now id want all the 0's and 1's in the column 2 to be bold.
import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class as extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTable table;
private ArrayList<String> ShadowBibNumber;
/**
* Launch the application.
*/
public static void main(String[] args) {
as frame = new as();
frame.setVisible(true);
}
/**
* Create the frame.
*/
public as() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
ShadowBibNumber = new ArrayList<String>();
ShadowBibNumber.add("0");
ShadowBibNumber.add("1");
JLabel lblNewLabel = new JLabel("New label");
contentPane.add(lblNewLabel, BorderLayout.NORTH);
DefaultTableModel tableModel = new DefaultTableModel();
tableModel.addColumn("column 0");
tableModel.addColumn("column 1");
tableModel.addColumn("column 2");
tableModel.addColumn("column 3");
tableModel.addColumn("column 4");
new JScrollPane(table);
table = new JTable(tableModel);
table.setEnabled(false);
table.setPreferredScrollableViewportSize(new Dimension(200, 100));
JScrollPane scrollPaneForTable = new JScrollPane(table);
contentPane.add(scrollPaneForTable, BorderLayout.CENTER);
for (int i = 0; i < 20; ++i) {
tableModel
.addRow(new Object[] { i, i, i, i, i });
}
table.getColumn("column 2").setCellRenderer(new boldRenderer());
}
class boldRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
Component cellComponent = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
for (Object x: ShadowBibNumber) {
if (table.getValueAt(row, 2).equals(x)) {
cellComponent.setFont(cellComponent.getFont().deriveFont(
Font.BOLD));
} else {
cellComponent.setFont(cellComponent.getFont().deriveFont(
Font.PLAIN));
}
}
return cellComponent;
}
} }
I'm currently writing a custom ListCellRenderer for a JComboBox. To do this, I'm using a system to fetch a new renderer whenever the L&F changes, and delegate the method to this. This works nicely in all L&Fs. However, when I place this component in a panel (so I can add some more components), it works nicely in the Metal and Windows L&Fs, but the JComboBox text disappears in Motif. See screenshot and code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TextDemo extends JPanel implements ActionListener {
private static JFrame frame;
public TextDemo() {
super(new GridBagLayout());
JComboBox correct = new JComboBox(new String[]{"One", "Two", "Three"});
JComboBox alsoCorrect = new JComboBox(new String[]{"One", "Two", "Three"});
alsoCorrect.setRenderer(new MyRenderer());
JComboBox incorrect = new JComboBox(new String[]{"One", "Two", "Three"});
incorrect.setRenderer(new NotWorkingRenderer());
JButton button = new JButton("Change LnF");
button.addActionListener(this);
add(correct, getConstraints(0));
add(alsoCorrect, getConstraints(1));
add(incorrect, getConstraints(2));
add(button, getConstraints(3));
}
private GridBagConstraints getConstraints(int y) {
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0; c.gridy = y;
c.insets = new Insets(4,8,4,8);
c.weightx = 1.0; c.weighty = 1.0;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.FIRST_LINE_START;
return c;
}
#Override
public void actionPerformed(ActionEvent ev) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
SwingUtilities.updateComponentTreeUI(frame);
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static void createAndShowGUI() {
frame = new JFrame("TextDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TextDemo());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
class MyRenderer implements ListCellRenderer {
protected static ListCellRenderer delegate;
static {
refreshRenderers();
UIManager.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("lookAndFeel")) {
refreshRenderers();
}
}
});
}
protected static void refreshRenderers() {
delegate = new JComboBox().getRenderer();
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
return delegate.getListCellRendererComponent(list, value,
index, isSelected, cellHasFocus);
}
}
class NotWorkingRenderer extends MyRenderer {
private JPanel panel = new JPanel();
public NotWorkingRenderer() {
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
c.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
panel.removeAll();
panel.add(c);
return panel;
}
}
Any help on understanding why this happens would be greatly appreciated!
not an answer,
but see whats happens, with JPanel as renderers JComponents for JComboBox
are you sure that JPanel with String value is proper way, please whats goal,
is there the same effect with default JLabel, (J)Component instead of JPanel
from code
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class TextDemo extends JPanel implements ActionListener {
private static JFrame frame;
public TextDemo() {
super(new GridBagLayout());
JComboBox correct = new JComboBox(new String[]{"One", "Two", "Three"});
JComboBox alsoCorrect = new JComboBox(new String[]{"One", "Two", "Three"});
alsoCorrect.setRenderer(new MyRenderer());
JComboBox incorrect = new JComboBox(new String[]{"One", "Two", "Three"});
incorrect.setRenderer(new NotWorkingRenderer());
JButton button = new JButton("Change LnF");
button.addActionListener(this);
add(incorrect, getConstraints(0));
add(correct, getConstraints(1));
add(alsoCorrect, getConstraints(2));
add(button, getConstraints(3));
}
private GridBagConstraints getConstraints(int y) {
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = y;
c.insets = new Insets(4, 8, 4, 8);
c.weightx = 1.0;
c.weighty = 1.0;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.FIRST_LINE_START;
return c;
}
#Override
public void actionPerformed(ActionEvent ev) {
try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
SwingUtilities.updateComponentTreeUI(frame);
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static void createAndShowGUI() {
frame = new JFrame("TextDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TextDemo());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
//SwingUtilities.updateComponentTreeUI(frame);
} catch (Exception ex) {
ex.printStackTrace();
}
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
class MyRenderer implements ListCellRenderer {
protected static ListCellRenderer delegate;
static {
refreshRenderers();
UIManager.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("lookAndFeel")) {
refreshRenderers();
}
}
});
}
protected static void refreshRenderers() {
delegate = new JComboBox().getRenderer();
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
return delegate.getListCellRendererComponent(list, value,
index, isSelected, cellHasFocus);
}
}
class NotWorkingRenderer extends MyRenderer {
private JPanel panel = new JPanel();
public NotWorkingRenderer() {
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
c.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
panel.add(c);
return panel;
}
}
EDIT_1st.
all Standard L&F excluding ModifL&F showing that properly
one step forward ???, code line incorrect.setEditable(true); generating
I'm don't know proper way for ModifL&F and non_editable JComboBox
EDIT_2nd.
I'm blind class NotWorkingRenderer extends MyRenderer {, pip... pip... pip...
phaaa I'm participated on never ever to add / remove / modify a JComponent in Xxx(Xxx)Renderer, but is about if is possible or not,
class NotWorkingRenderer extends BasicComboBoxRenderer {
private JPanel panel = new JPanel();
public NotWorkingRenderer() {
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
//panel.setOpaque(false);
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JLabel c = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
c.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
panel.removeAll();
panel.add(c);
panel.revalidate();
panel.repaint();
return panel;
}
}
You are returning the panel instead of c
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
c.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
panel.removeAll();
panel.add(c);
return c;
This is my code:-
public class MyRender extends JPanel implements ListCellRenderer {
ImageIcon on_img;
JLabel name = new JLabel();
JLabel icn = new JLabel();
JLabel img = new JLabel();
public MyRender(Atalk) {
setOpaque(true);
setBackground(Color.WHITE);
setForeground(Color.black);
on_img = new ImageIcon(MyCls.class.getClassLoader().getResource("imgPath"));
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if (value != null) {
removeAll();
setLayout(new BorderLayout());
User user = (User) value;
String pres = user.getPresence().toLowerCase();
img.setIcon(default_img);
if (pres.contains("unavailable"))
icn.setIcon(off_img);
else
icn.setIcon(on_img);
name.setText(user.getName());
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
add(img, BorderLayout.EAST);
add(icn, BorderLayout.WEST);
panel.add(st, BorderLayout.CENTER);
panel.add(name, BorderLayout.NORTH);
add(panel, BorderLayout.CENTER);
JLabel lbl = new JLabel(" ");
lbl.setSize(100, 5);
add(lbl, BorderLayout.AFTER_LAST_LINE);
if (isSelected) {
setBackground(Color.lightGray);
panel.setBackground(Color.lightGray);
} else {
setBackground(Color.white);
panel.setBackground(Color.white);
}
return this;
}
return null;
}
}
As you can see I have called removeAll() method. If I remove that line the data is not displayed properly. All data overlaps each other. And If I add removeAll() all works fine. Why this happens? Is it necessary to call removeAll()?
You have to restructure your class so that all children of MyRender are created and added at construction time.
getListCellRendererComponent() should be used ONLY to change values or visual attributes (e.g. background) of existing components.
Don't forget that getListCellRendererComponent() should be as fast as possible (it can be called quite frequently), hence it should not create components but only modify existing ones.
Typically, here is how your getListCellRendererComponent() method should look like:
#Override
public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value != null) {
User user = (User) value;
String pres = user.getPresence().toLowerCase();
img.setIcon(default_img);
if (pres.contains("unavailable"))
icn.setIcon(off_img);
else
icn.setIcon(on_img);
name.setText(user.getName());
if (isSelected) {
setBackground(Color.lightGray);
panel.setBackground(Color.lightGray);
} else {
setBackground(Color.white);
panel.setBackground(Color.white);
}
}
return this;
}
No, you shouldn't have to call removeAll(). I think that your problem is that you're creating a new JPanel inside of the getListCellRendererComponent method each time the method is called here:
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
If you made this JPanel a class field, you would likely not have to call removeAll.
edit: answered better by jfpoilpret. 1+ to him.
also use revalidate() on panel