Unexpected jtable custom renderer behavior - java

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.

Related

Changing JTable header height

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

JTable column labels not printing

I have a JTable that I am using to display data from my database as a print preview. I can get it to print how I want except that the column headers wont print no matter what I try. I add my JTable to a JScrollPane, I have even gone so far as to add my JScrollPane to another JPanel which gets added to another JPanel with everything .setVisible(true).
After extensively traversing the Google-verse, the only solution I have found was here but I am already doing what they said. Here is my code so far:
public class PrintPreview extends JDialog implements ActionListener
{
private JTable infoTable;
private boolean printed;
private int windowWidth;
private int windowHeight;
JPanel scrollerPanel;
JPanel dataPanel;
private int[] idList;
private Connection conn;
private JScrollPane scroller;
private JButton printButton;
public PrintPreview(int[] tIds, Connection tConn)
{
printed = false;
idList = tIds;
conn = tConn;
setupFrame();
setupScroller();
setupButtons();
this.pack();
this.setVisible (true);
}
//returns true if printed, false otherwise
public boolean getCloseValue()
{
return printed;
}
private void setupFrame()
{
this.setTitle("Edit Data");
this.setSize (800, 700); //Width, Height
this.setLocationRelativeTo(null); //Centers the JFrame on the screen
this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
this.setResizable(false);
this.setModalityType(APPLICATION_MODAL);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
//Gets the size of the contentPanel of the frame
Insets inset = this.getInsets();
windowWidth = this.getSize().width - (inset.left + inset.right);
windowHeight = this.getSize().height - (inset.top + inset.bottom);
}
private void setupScroller()
{
scrollerPanel = new JPanel();
scroller = new JScrollPane (setupTable(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
infoTable.setFillsViewportHeight(true);
scroller.setSize(windowWidth, windowHeight - 120);
scroller.setMinimumSize(new Dimension (windowWidth, windowHeight - 120));
scroller.setMaximumSize(new Dimension (windowWidth, windowHeight - 120));
scroller.setPreferredSize(new Dimension (windowWidth, windowHeight - 120));
scroller.setVisible(true);//*********************************************************
scroller.add (setupTable());
this.add (scroller);
}
private void setupButtons()
{
JPanel spacer1 = new JPanel();
spacer1.setSize(100, 20);
spacer1.setMaximumSize(new Dimension (100, 20));
spacer1.setMinimumSize(new Dimension (100, 20));
spacer1.setPreferredSize(new Dimension (100, 20));
JPanel spacer2 = new JPanel();
spacer2.setSize(100, 20);
spacer2.setMaximumSize(new Dimension (100, 20));
spacer2.setMinimumSize(new Dimension (100, 20));
spacer2.setPreferredSize(new Dimension (100, 20));
printButton = new JButton ("Print");
printButton.setFont((new Font("", Font.BOLD, 14)));
printButton.setSize(new Dimension (130, 35));
printButton.setMaximumSize(new Dimension (130, 35));
printButton.setMinimumSize(new Dimension (130, 35));
printButton.setPreferredSize(new Dimension (130, 35));
printButton.addActionListener(this);
spacer1.setAlignmentX(Component.CENTER_ALIGNMENT);
printButton.setAlignmentX(Component.CENTER_ALIGNMENT);
this.add (spacer1);
this.add (printButton);
this.add (spacer2);
}
private JTable setupTable()
{
infoTable = new JTable();
DefaultTableModel dm = new DefaultTableModel(0, 0);
String header[] = new String[] {"Case #", "Date", "Officer #", "Offence",
"Description", "Report"};
dm.setColumnIdentifiers(header);
infoTable.setModel(dm);
infoTable.setRowHeight(26);
infoTable.setFocusable(false);//display only
//Adds everything to the table
int idSize = idList.length;
for (int x = 0; x < idSize; x++)
{
try
{
String[] values = getInfo(idList[x]);
values[4] = values[4].trim();
values[4] = values[4].replaceAll("<html>", "");
dm.addRow(values);
}
catch (SQLException e)
{
System.out.println ("Error: " + e);
System.out.println ("Event-addObjects(): Problem with getting event info");
}
infoTable.setFont(new Font("Serif", Font.PLAIN, 10));
}
//Centers the values on the smaller columns
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
centerRenderer.setHorizontalAlignment(JLabel.CENTER);
infoTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer);
infoTable.getColumnModel().getColumn(1).setCellRenderer(centerRenderer);
infoTable.getColumnModel().getColumn(2).setCellRenderer(centerRenderer);
infoTable.getColumnModel().getColumn(3).setCellRenderer(centerRenderer);
infoTable.getColumnModel().getColumn(5).setCellRenderer(centerRenderer);
//Sets the sizes of the columns
infoTable.getColumnModel().getColumn(0).setMinWidth(40);
infoTable.getColumnModel().getColumn(1).setMinWidth(65);
infoTable.getColumnModel().getColumn(2).setMinWidth(40);
infoTable.getColumnModel().getColumn(3).setMinWidth(80);
infoTable.getColumnModel().getColumn(4).setMinWidth(250);
infoTable.getColumnModel().getColumn(5).setMinWidth(50);
//Makes the Description column cells JTextFields
infoTable.getColumnModel().getColumn(4).setCellRenderer(new VariableRowHeightRenderer());
//Looks at the size each JTextField would like to be and changes the rows to accomidate
int column = 4;
for (int row = 0; row < infoTable.getRowCount(); row++)
{
int rowHeight = 26;
Component comp = infoTable.prepareRenderer(infoTable.getCellRenderer(row, column), row, column);
rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
if(rowHeight != infoTable.getRowHeight(row))
{
infoTable.setRowHeight(row, rowHeight);
}
}
infoTable.setVisible(true);//***********************************************************************
return infoTable;
}
private String[] getInfo(int id) throws SQLException
{
String result[];
ResultSet rs;
String command = "SELECT * FROM Logs_Table where id = " + id;
Statement stmt = conn.createStatement();
rs = stmt.executeQuery(command);
result = new String[] {rs.getString("Case_Num"), rs.getString("Event_Date"),
rs.getString("Officer_Num"), rs.getString("Offence"),
("<html>" + rs.getString("Description") + "<html>"),
rs.getString("Report")};
return result;
}
#Override
public void actionPerformed(ActionEvent e)
{
String cmd = e.getActionCommand();
switch (cmd)
{
case "Print":
printed = true;
try
{
infoTable.setSize(infoTable.getPreferredSize());
//Makes the margins smaller
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add (new MediaPrintableArea((float)8.25, (float)10.0, (float)8.5, (float)11.0, MediaPrintableArea.INCH));
MessageFormat empty = new MessageFormat ("");
MessageFormat footerFormat = new MessageFormat("- {0} -");
infoTable.print (PrintMode.FIT_WIDTH, empty, footerFormat, true, aset, false);
}
catch (PrinterException ex)
{
System.out.println ("Error: " + ex);
System.out.println ("Built in table print didnt work");
}
//this.dispose();
break;
default:
break;
}
}
private class VariableRowHeightRenderer extends JTextArea implements TableCellRenderer
{
public VariableRowHeightRenderer()
{
super();
this.setEditable(false);
this.setLineWrap(true);
this.setWrapStyleWord(true);
this.setWrapStyleWord(true);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column)
{
this.setBackground(Color.WHITE);
this.setText((String) (value));
this.setSize(table.getColumnModel().getColumn(column).getWidth(),
Short.MAX_VALUE);
return this;
}
}
}
Can someone please tell me what I am doing wrong?
Okay, after much screwing around, I got "something" to work. The "core" problems seem to come down to
Creating multiple instance of the JTable
"add" the JTable to the JScrollPane (scroller.add(setupTable());), as apposed to setting it as the screen pane's viewport's view
Addition, unnecessary UI elements which just made it more difficult to understand the code then was required
This example just dumps the output to a file, but it should work just fine for printing.
import java.awt.Color;
import java.awt.Component;
import static java.awt.Dialog.ModalityType.APPLICATION_MODAL;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.text.MessageFormat;
import javax.imageio.ImageIO;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
public class PrintPreview extends JDialog implements ActionListener {
public static void main(String[] args) {
new PrintPreview(new int[]{1, 2, 3, 4}, null);
}
private JTable infoTable;
private boolean printed;
private int windowWidth;
private int windowHeight;
JPanel container;
// JPanel scrollerPanel;
JPanel dataPanel;
private int[] idList;
private Connection conn;
private JScrollPane scroller;
private JButton printButton;
JTable printable;
public PrintPreview(int[] tIds, Connection tConn) {
container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
printed = false;
idList = tIds;
conn = tConn;
setupFrame();
setupScroller();
setupButtons();
this.setContentPane(container);
this.pack();
this.setVisible(true);
}
//returns true if printed, false otherwise
public boolean getCloseValue() {
return printed;
}
private void setupFrame() {
this.setTitle("Edit Data");
this.setSize(800, 700); //Width, Height
this.setLocationRelativeTo(null); //Centers the JFrame on the screen
this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
// this.setResizable(false);
this.setModalityType(APPLICATION_MODAL);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
//Gets the size of the contentPanel of the frame
Insets inset = this.getInsets();
windowWidth = this.getSize().width - (inset.left + inset.right);
windowHeight = this.getSize().height - (inset.top + inset.bottom);
}
private void setupScroller() {
// scrollerPanel = new JPanel();
scroller = new JScrollPane(setupTable());
// scroller = new JScrollPane(setupTable(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
// JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// infoTable.setFillsViewportHeight(true);
// scroller.setSize(windowWidth, windowHeight - 120);
// scroller.setMinimumSize(new Dimension(windowWidth, windowHeight - 120));
// scroller.setMaximumSize(new Dimension(windowWidth, windowHeight - 120));
// scroller.setPreferredSize(new Dimension(windowWidth, windowHeight - 120));
// scroller.setVisible(true);//*********************************************************
// scroller.add(setupTable());
// scrollerPanel.add(scroller);
// scrollerPanel.setVisible(true);//******************************************************
// scrollerPanel.setOpaque(true);//*************************************************************
container.add(scroller);
}
private void setupButtons() {
JPanel spacer1 = new JPanel();
spacer1.setSize(100, 20);
spacer1.setMaximumSize(new Dimension(100, 20));
spacer1.setMinimumSize(new Dimension(100, 20));
spacer1.setPreferredSize(new Dimension(100, 20));
JPanel spacer2 = new JPanel();
spacer2.setSize(100, 20);
spacer2.setMaximumSize(new Dimension(100, 20));
spacer2.setMinimumSize(new Dimension(100, 20));
spacer2.setPreferredSize(new Dimension(100, 20));
printButton = new JButton("Print");
printButton.setFont((new Font("", Font.BOLD, 14)));
printButton.setSize(new Dimension(130, 35));
printButton.setMaximumSize(new Dimension(130, 35));
printButton.setMinimumSize(new Dimension(130, 35));
printButton.setPreferredSize(new Dimension(130, 35));
printButton.addActionListener(this);
spacer1.setAlignmentX(Component.CENTER_ALIGNMENT);
printButton.setAlignmentX(Component.CENTER_ALIGNMENT);
container.add(spacer1);
container.add(printButton);
container.add(spacer2);
}
private JTable setupTable() {
infoTable = new JTable();
DefaultTableModel dm = new DefaultTableModel(0, 0);
String header[] = new String[]{"Case #", "Date", "Officer #", "Offence",
"Description", "Report"};
dm.setColumnIdentifiers(header);
infoTable.setModel(dm);
infoTable.setRowHeight(26);
infoTable.setFocusable(false);//display only
//Adds everything to the table
int idSize = idList.length;
for (int row = 0; row < 10; row++) {
String value = Integer.toString(row);
String[] values = new String[]{value, value, value, value, value, value};
dm.addRow(values);
}
// for (int x = 0; x < idSize; x++) {
// try {
// String[] values = getInfo(idList[x]);
// values[4] = values[4].trim();
// values[4] = values[4].replaceAll("<html>", "");
//
// dm.addRow(values);
// } catch (SQLException e) {
// System.out.println("Error: " + e);
// System.out.println("Event-addObjects(): Problem with getting event info");
// }
//
// infoTable.setFont(new Font("Serif", Font.PLAIN, 10));
// }
//Centers the values on the smaller columns
// DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
// centerRenderer.setHorizontalAlignment(JLabel.CENTER);
// infoTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer);
// infoTable.getColumnModel().getColumn(1).setCellRenderer(centerRenderer);
// infoTable.getColumnModel().getColumn(2).setCellRenderer(centerRenderer);
// infoTable.getColumnModel().getColumn(3).setCellRenderer(centerRenderer);
// infoTable.getColumnModel().getColumn(5).setCellRenderer(centerRenderer);
//
// //Sets the sizes of the columns
// infoTable.getColumnModel().getColumn(0).setMinWidth(40);
// infoTable.getColumnModel().getColumn(1).setMinWidth(65);
// infoTable.getColumnModel().getColumn(2).setMinWidth(40);
// infoTable.getColumnModel().getColumn(3).setMinWidth(80);
// infoTable.getColumnModel().getColumn(4).setMinWidth(250);
// infoTable.getColumnModel().getColumn(5).setMinWidth(50);
//Makes the Description column cells JTextFields
// infoTable.getColumnModel().getColumn(4).setCellRenderer(new VariableRowHeightRenderer());
//Looks at the size each JTextField would like to be and changes the rows to accomidate
// int column = 4;
// for (int row = 0; row < infoTable.getRowCount(); row++) {
// int rowHeight = 26;
//
// Component comp = infoTable.prepareRenderer(infoTable.getCellRenderer(row, column), row, column);
// rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
//
// if (rowHeight != infoTable.getRowHeight(row)) {
// infoTable.setRowHeight(row, rowHeight);
// }
// }
// infoTable.setVisible(true);//***********************************************************************
return infoTable;
}
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
switch (cmd) {
case "Print":
printed = true;
//Makes the margins smaller
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(new MediaPrintableArea((float) 8.25, (float) 10.0, (float) 8.5, (float) 11.0, MediaPrintableArea.INCH));
MessageFormat empty = new MessageFormat("");
MessageFormat footerFormat = new MessageFormat("- {0} -");
// printable.print(PrintMode.FIT_WIDTH, empty, footerFormat, true, aset, false);
Paper paper = new Paper();
paper.setImageableArea(0, 0, 700, 890);
paper.setSize(700, 890);
PageFormat format = new PageFormat();
format.setPaper(paper);
format.setOrientation(PageFormat.PORTRAIT);
// printjob.setPrintable(printable, format);
BufferedImage img = new BufferedImage(700, 890, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(0, 0, 890, 700));
Printable printable = infoTable.getPrintable(JTable.PrintMode.FIT_WIDTH, null, null);
try {
printable.print(g2d, format, 0);
} catch (Exception exp) {
exp.printStackTrace();
}
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Print.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
//this.dispose();
break;
default:
break;
}
}
}

How can I resize my JTextFields in my Jpanel

being new to programming, i'm having a slight issue resizing the text fields I've added to the JPanel. While I could go the route of creating individual panels with their own text field, I though it would be better to add all the components into one panel. Part of my overall idea is to have my add button reference the panel, containing the text fields, to add more text fields on the tracker for users to fill out, and while I can get the fields to display when I implement the setBounds method on my panel object, i'm having tough time figuring out how resize them in the panel itself. And if you have any other advice on my overall structure, I welcome it.
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class UI {
JFrame frame;
JLabel Title,Name, CheckOut, CheckIn, Email;
JTextField NameField,CheckOutField, CheckInField, EmailField;
JButton Add, Delete;
JPanel buttons, textfields, primary;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UI window = new UI();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public UI(){
design();
}
private void design(){
frame = new JFrame("Form 48 Tracker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(100, 100, 750, 400);
frame.getContentPane().setLayout(null);
Title = new JLabel();
Title.setText("Form 48 Tracker");
Title.setFont(new Font("Calibri", Font.PLAIN, 28));
Title.setBounds(233, 11, 200, 75);
frame.getContentPane().add(Title);
Title.setForeground(Color.BLACK);
Name = new JLabel();
Name.setText("Name");
Name.setFont(new Font("Calibri", Font.PLAIN, 15));
Name.setBounds(50, 80, 128, 20);
frame.getContentPane().add(Name);
Name.setForeground(Color.BLACK);
CheckOut = new JLabel();
CheckOut.setText("Check Out Date");
CheckOut.setFont(new Font("Calibri", Font.PLAIN, 15));
CheckOut.setBounds(200, 80, 128, 20);
frame.getContentPane().add(CheckOut);
CheckOut.setForeground(Color.BLACK);
CheckIn = new JLabel();
CheckIn.setText("Check In Date");
CheckIn.setFont(new Font("Calibri", Font.PLAIN, 15));
CheckIn.setBounds(350, 80, 128, 20);
frame.getContentPane().add(CheckIn);
CheckIn.setForeground(Color.BLACK);
Email = new JLabel();
Email.setText("Email");
Email.setFont(new Font("Calibri", Font.PLAIN, 15));
Email.setBounds(500, 80, 128, 20);
frame.getContentPane().add(Email);
Email.setForeground(Color.BLACK);
Add = new JButton("Add");
buttons = new JPanel();
buttons.add(Add);
buttons.setBounds(200, 270, 157, 50); //x , y , width , height//
frame.getContentPane().add(buttons);
Add.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
}
});
Delete = new JButton("Delete");
buttons = new JPanel();
buttons.add(Delete);
buttons.setBounds(605, 101, 128, 50);
frame.getContentPane().add(buttons);
primary = new JPanel();
NameField = new JTextField();
CheckOutField = new JTextField();
CheckInField = new JTextField();
EmailField = new JTextField();
primary.add(NameField);
primary.add(CheckOutField);
primary.add(CheckInField);
primary.add(EmailField);
primary.setBounds(50, 110, 128, 20);
frame.getContentPane().add(primary);
}
}
Let's concentrate on the code that's causing the problem, and only that code. I've created a minimal example program, one that has enough code to compile and run, and that demonstrates the problem, but that has no unnecessary code:
import javax.swing.*;
public class UiFoo {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null); // **** no!! ****
JPanel primary = new JPanel();
JTextField NameField = new JTextField();
JTextField CheckOutField = new JTextField();
JTextField CheckInField = new JTextField();
JTextField EmailField = new JTextField();
primary.add(NameField);
primary.add(CheckOutField);
primary.add(CheckInField);
primary.add(EmailField);
primary.setBounds(50, 110, 128, 20);
frame.getContentPane().add(primary);
frame.setSize(600, 250);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
So, if you run this code, you'll see 4 very small JTextFields. Why are they so small? Because you've not set the columns property for the JTextFields, and so they default to columns size 0 and show up like so:
So it's better if you can give the JTextField a columns property so that they have some width, e.g., make this change:
JPanel primary = new JPanel();
int columns = 8;
JTextField NameField = new JTextField(columns);
JTextField CheckOutField = new JTextField(columns);
JTextField CheckInField = new JTextField(columns);
JTextField EmailField = new JTextField();
But this just shows one JTextField, and cuts off the bottom as well:
Why? Because you're artificially constraining the size of the containing JPanel, primary via:
primary.setBounds(50, 110, 128, 20);
This containing JPanel is only 128 pixels wide by 20 pixels high, meaning that it won't even display one JTextField well.
One solution is to use a mix of layout managers and JPanels as well as a JScrollPane to allow for a grid of JPanels to be added, something like so (try it out!):
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
#SuppressWarnings("serial")
public class UiFoo2 extends JPanel {
JPanel singleColumnPanel = new JPanel(new GridLayout(0, 1, 2, 2));
public UiFoo2() {
JButton addButton = new JButton("Add");
addButton.addActionListener(e -> {
JPanel rowPanel = new JPanel(new GridLayout(1, 4, 2, 2));
for (int i = 0; i < 4; i++) {
rowPanel.add(new JTextField(8));
}
singleColumnPanel.add(rowPanel);
singleColumnPanel.revalidate();
singleColumnPanel.repaint();
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(addButton);
JPanel labelPanel = new JPanel(new GridLayout(1, 4, 2, 2));
labelPanel.add(new JLabel("Name", SwingConstants.CENTER));
labelPanel.add(new JLabel("Check Out Date", SwingConstants.CENTER));
labelPanel.add(new JLabel("Check In Date", SwingConstants.CENTER));
labelPanel.add(new JLabel("Email", SwingConstants.CENTER));
singleColumnPanel.add(labelPanel);
JPanel containerPanel = new JPanel(new BorderLayout(5, 5));
containerPanel.add(singleColumnPanel, BorderLayout.PAGE_START);
JScrollPane scrollPane = new JScrollPane(containerPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setPreferredSize(new Dimension(650, 400));
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
UiFoo2 mainPanel = new UiFoo2();
JFrame frame = new JFrame("UiFoo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
This will create a row JPanel that holds four JTextFields that get added to the JScrollPane when the add JButton is pressed, and looks like so:
but we still can do better. Why not instead create a class to hold a row of data, something like so:
import java.util.Date;
public class Form48Customer {
private String name;
private Date checkIn;
private Date checkOut;
private String Email;
public Form48Customer(String name, Date checkIn, Date checkOut, String email) {
this.name = name;
this.checkIn = checkIn;
this.checkOut = checkOut;
Email = email;
}
public Date getCheckIn() {
return checkIn;
}
public void setCheckIn(Date checkIn) {
this.checkIn = checkIn;
}
public Date getCheckOut() {
return checkOut;
}
public void setCheckOut(Date checkOut) {
this.checkOut = checkOut;
}
public String getName() {
return name;
}
public String getEmail() {
return Email;
}
// should override hashCode and equals here
}
and then create a JTable complete with custom model to display objects of this type, and then display them in the GUI. This is much cleaner, more flexible, and extendable. Something like so:
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.*;
import java.util.Date;
import javax.swing.*;
import javax.swing.JFormattedTextField.AbstractFormatter;
import javax.swing.table.*;
#SuppressWarnings("serial")
public class Form48TrackerPanel extends JPanel {
public static final String TITLE = "Form 48 Tracker";
private static final String DATE_FORMAT_TXT = "MM/dd/yyyy";
private Form48TableModel model = new Form48TableModel();
private JTable table = new JTable(model);
private JButton addButton = new JButton("Add");
private JButton deleteButton = new JButton("Delete");
private JButton exitButton = new JButton("Exit");
public Form48TrackerPanel() {
final SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_TXT);
TableCellRenderer dateRenderer = new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if( value instanceof Date) {
value = dateFormat.format(value);
}
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
};
table.getColumnModel().getColumn(1).setCellRenderer(dateRenderer);
table.getColumnModel().getColumn(2).setCellRenderer(dateRenderer);
JLabel titleLabel = new JLabel(TITLE, SwingConstants.CENTER);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 28f));
addButton.addActionListener(new AddListener());
addButton.setMnemonic(KeyEvent.VK_A);
deleteButton.addActionListener(new DeleteListener());
deleteButton.setMnemonic(KeyEvent.VK_D);
exitButton.addActionListener(new ExitListener());
exitButton.setMnemonic(KeyEvent.VK_X);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
buttonPanel.add(addButton);
buttonPanel.add(deleteButton);
buttonPanel.add(exitButton);
setPreferredSize(new Dimension(800, 500));
int ebGap = 8;
setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
setLayout(new BorderLayout(ebGap, ebGap));
add(titleLabel, BorderLayout.PAGE_START);
add(new JScrollPane(table), BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
model.addRow(new Form48Customer("John Smith", new Date(), new Date(), "JSmith#Yahoo.com"));
model.addRow(new Form48Customer("Fred Flinstone", new Date(), new Date(), "FFlinstone#GMail.com"));
}
private class AddListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
AddForm48Panel addFormPanel = new AddForm48Panel();
int result = JOptionPane.showConfirmDialog(Form48TrackerPanel.this,
addFormPanel, "Add Customer", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
Form48Customer customer = addFormPanel.getForm48Customer();
model.addRow(customer);
}
}
}
private class DeleteListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO *** finish this code ***
}
}
private class ExitListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
Window win = SwingUtilities.getWindowAncestor(Form48TrackerPanel.this);
win.dispose();
}
}
private static void createAndShowGui() {
Form48TrackerPanel mainPanel = new Form48TrackerPanel();
JFrame frame = new JFrame(TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class AddForm48Panel extends JPanel {
private static final int TFIELD_COLS = 10;
private static final String DATE_FORMAT_TXT = "MM/dd/yyyy";
private static final Format DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_TXT);
private static final Insets INSETS = new Insets(5, 5, 5, 5);
private JTextField nameField = new JTextField(TFIELD_COLS);
private JFormattedTextField checkOutDateField = new JFormattedTextField(DATE_FORMAT);
private JFormattedTextField checkInDateField = new JFormattedTextField(DATE_FORMAT);
private JTextField emailField = new JTextField(TFIELD_COLS);
private JComponent[] fields = {nameField, checkOutDateField, checkInDateField, emailField};
private String[] labels = {"Name", "Check Out Date", "Check In Date", "Email"};
public AddForm48Panel() {
InputVerifier verifier = new DateFieldVerifier();
checkInDateField.setInputVerifier(verifier);
checkOutDateField.setInputVerifier(verifier);
setLayout(new GridBagLayout());
for (int i = 0; i < fields.length; i++) {
add(new JLabel(labels[i] + ":"), createGbc(0, i));
add(fields[i], createGbc(1, i));
}
}
public String getName() {
return nameField.getText();
}
public String getEmail() {
return emailField.getText();
}
public Date getCheckOut() {
return (Date) checkOutDateField.getValue();
}
public Date getCheckIn() {
return (Date) checkInDateField.getValue();
}
public Form48Customer getForm48Customer() {
String name = getName();
Date checkOut = getCheckOut();
Date checkIn = getCheckIn();
String email = getEmail();
return new Form48Customer(name, checkIn, checkOut, email);
}
private GridBagConstraints createGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.insets = INSETS;
gbc.anchor = x == 0 ? GridBagConstraints.WEST :GridBagConstraints.EAST;
gbc.fill = GridBagConstraints.HORIZONTAL;
return gbc;
}
private class DateFieldVerifier extends InputVerifier {
#Override
public boolean verify(JComponent input) {
if (input instanceof JFormattedTextField) {
JFormattedTextField ftf = (JFormattedTextField)input;
AbstractFormatter formatter = ftf.getFormatter();
if (formatter != null) {
String text = ftf.getText();
try {
formatter.stringToValue(text);
return true;
} catch (ParseException pe) {
return false;
}
}
}
return true;
}
#Override
public boolean shouldYieldFocus(JComponent input) {
boolean verify = verify(input);
if (!verify) {
String message = "Enter a valid date, e.g.: 01/05/2017";
String title = "Invalid Date Format";
int type = JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(input, message, title, type);
}
return verify;
}
}
}
#SuppressWarnings("serial")
class Form48TableModel extends DefaultTableModel {
private static final String[] COL_NAMES = {"Name", "Check Out Date", "Check In Date", "Email"};
public Form48TableModel() {
super(COL_NAMES, 0);
}
public void addRow(Form48Customer customer) {
Object[] rowData = {
customer.getName(),
customer.getCheckOut(),
customer.getCheckIn(),
customer.getEmail()
};
addRow(rowData);
}
public Form48Customer getRow(int row) {
String name = (String) getValueAt(row, 0);
Date checkIn = (Date) getValueAt(row, 1);
Date checkOut = (Date) getValueAt(row, 2);
String email = (String) getValueAt(row, 3);
return new Form48Customer(name, checkIn, checkOut, email);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 1:
return Date.class;
case 2:
return Date.class;
default:
break;
}
return super.getColumnClass(columnIndex);
}
}
Which would look like:

JScrollPane inside JPanel inside a JTabbedPane is not scrolling

I have this JPanel called CatalogPane, which is of size 800 by 600, which is inside a JTabbedPane inside a JFrame called BookFrame. So inside the CatalogPane, I created a JPanel called bookDisplay which displays a list of books and their details. I want it to be of size 780 by 900, leaving 20px for the scrollbar and taller than the frame so that it can scroll. Then I created a panel of size 800 by 400 because I need to leave some extra space at the bottom for other fields. I tried creating a JScrollPane for bookDisplay and then put it inside the other panel, but somehow the scrollbar appears but can't be used to scroll. I've experimented changing the sizes and scrollpane but I still can't get it to work.
What it looks like: http://prntscr.com/12j0d9
The scrollbar is there but can't work. I'm trying to get the scrollbar to work before I format the layout properly.
CatalogPane:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
public class CatalogPane extends JPanel{
//private Order currOrder = new Order();
//ArrayList<Book> bookCatalog = new ArrayList();
GridBagConstraints gbc = new GridBagConstraints();
GridBagLayout gbl = new GridBagLayout();
JPanel bookDisplay = new JPanel();
public CatalogPane()
{
//loadBookCatalog();
this.setPreferredSize(new Dimension(800, 600));
bookDisplay.setPreferredSize(new Dimension(780, 900));
bookDisplay.setLayout(new GridLayout(6, 5));
//bookDisplay.setLayout(gbl);
//gbc.fill = GridBagConstraints.NONE;
//gbc.weightx = 1;
//gbc.weighty = 1;
JLabel bookL = new JLabel("Books");
JLabel hardL = new JLabel("Hardcopy");
JLabel hardQuantL = new JLabel("Quantity");
JLabel eL = new JLabel("EBook");
JLabel eQuantL = new JLabel("Quantity");
bookDisplay.add(bookL);
bookDisplay.add(hardL);
bookDisplay.add(hardQuantL);
bookDisplay.add(eL);
bookDisplay.add(eQuantL);
/*
addComponent(bookL, 0, 0, 1, 1);
addComponent(hardL, 0, 1, 1, 1);
addComponent(hardQuantL, 0, 2, 1, 1);
addComponent(eL, 0, 3, 1, 1);
addComponent(eQuantL, 0, 4, 1, 1);
*/
Iterator<Book> bci = bookCatalog.iterator();
int row = 1;
/*
while(bci.hasNext())
{
Book temp = bci.next();
ImageIcon book1 = new ImageIcon(temp.getImage());
JLabel image = new JLabel(temp.getTitle(), book1, JLabel.CENTER);
image.setVerticalTextPosition(JLabel.TOP);
image.setHorizontalTextPosition(JLabel.CENTER);
String[] quant = {"1", "2", "3", "4", "5"};
JLabel hardP = new JLabel("$" + temp.getHardPrice());
JLabel eP = new JLabel("$" + temp.getEPrice());
JComboBox jbc1 = new JComboBox(quant);
JComboBox jbc2 = new JComboBox(quant);
jbc1.setSelectedIndex(0);
jbc2.setSelectedIndex(0);
/*
addComponent(b1temp, row, 0, 1, 1);
addComponent(hardP, row, 1, 1, 1);
addComponent(jbc1, row, 2, 1, 1);
addComponent(eP, row, 3, 1, 1);
addComponent(jbc2, row, 4, 1, 1);
row++;
bookDisplay.add(image);
bookDisplay.add(new JLabel("$" + temp.getHardPrice()));
bookDisplay.add(jbc1);
bookDisplay.add(new JLabel("$" + temp.getEPrice()));
bookDisplay.add(jbc2);
*/
for(int i=0;i<5;i++)
{
String[] quant = {"1", "2", "3", "4", "5"};
JComboBox jbc1 = new JComboBox(quant);
JComboBox jbc2 = new JComboBox(quant);
jbc1.setSelectedIndex(0);
jbc2.setSelectedIndex(0);
JLabel image = new JLabel("image");
bookDisplay.add(image);
bookDisplay.add(new JLabel("$" + 20));
bookDisplay.add(jbc1);
bookDisplay.add(new JLabel("$" + 15));
bookDisplay.add(jbc2);
}
JScrollPane vertical = new JScrollPane(bookDisplay);
//JPanel testP = new JPanel();
//testP.setPreferredSize(new Dimension(800, 400));
//JScrollPane vertical = new JScrollPane(testP);
//testP.add(bookDisplay);
vertical.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel testP = new JPanel();
testP.setPreferredSize(new Dimension(800, 400));
testP.add(vertical);
add(testP);
}
public void addComponent(Component c, int row, int col, int hei, int wid)
{
gbc.gridx = col;
gbc.gridy = row;
gbc.gridwidth = wid;
gbc.gridheight = hei;
gbl.setConstraints(c, gbc);
bookDisplay.add(c);
}
public Order getCurrOrder()
{
return currOrder;
}
private void loadBookCatalog()
{
try
{
String[] str = new String[8];
Scanner sc = new Scanner(new File("bookcat.txt"));
double temp1, temp2;
while(sc.hasNextLine())
{
str = sc.nextLine().split(";");
temp1 = Double.parseDouble(str[3]);
temp2 = Double.parseDouble(str[4]);
Book temp = new Book(temp1, temp2, str[0], str[1], str[2], str[5]);
bookCatalog.add(temp);
}
}
catch(IOException e)
{
System.out.println("File not found!");
}
}
}
BookFrame:
public class BookFrame extends JFrame{
JButton closeButton;
CatalogPane cp;
//IntroPane ip;
public BookFrame(String name)
{
super(name);
this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
this.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(new IntroPane()),
"Thank you for visiting Groovy Book Company.", "Message",
JOptionPane.INFORMATION_MESSAGE, new ImageIcon("coffee.jpg"));
System.exit(0);
}
});
//ip = new IntroPane();
cp = new CatalogPane();
JTabbedPane jtp = new JTabbedPane();
jtp.setPreferredSize(new Dimension(800, 600));
//jtp.addTab("Intro", ip);
jtp.addTab("Catalog", cp);
add(jtp);
pack();
setVisible(true);
}
}
I'd look at JTable, which handles scrolling and rendering as shown here and below. This example shows how to render images and currency. Start by adding a third column for quantity of type Integer. This related example illustrates using a JComboBox editor.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.text.NumberFormat;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
/**
* #see https://stackoverflow.com/a/16264880/230513
*/
public class Test {
public static final Icon ICON = UIManager.getIcon("html.pendingImage");
private JPanel createPanel() {
JPanel panel = new JPanel();
DefaultTableModel model = new DefaultTableModel() {
#Override
public Class<?> getColumnClass(int col) {
if (col == 0) {
return Icon.class;
} else {
return Double.class;
}
}
};
model.setColumnIdentifiers(new Object[]{"Book", "Cost"});
for (int i = 0; i < 42; i++) {
model.addRow(new Object[]{ICON, Double.valueOf(i)});
}
JTable table = new JTable(model);
table.setDefaultRenderer(Double.class, new DefaultTableCellRenderer() {
#Override
protected void setValue(Object value) {
NumberFormat format = NumberFormat.getCurrencyInstance();
setText((value == null) ? "" : format.format(value));
}
});
table.setRowHeight(ICON.getIconHeight());
panel.add(new JScrollPane(table) {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
});
return panel;
}
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTabbedPane jtp = new JTabbedPane();
jtp.addTab("Test1", createPanel());
jtp.addTab("Test2", createPanel());
f.add(jtp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}

How to set size of swing components

I want to customize the height and width of the JTextField objects. I have tried with the setSize method, passing width and height as dimensions and as int as well. But none of them seems to work. Am I missing something, like some mandatory method call on the panel or something so that the size customization would be effective? Please help. Thanks in advance.
EDIT: Here is a bit of the code:
public class WestPanel extends JPanel{
private JLabel dateL;
private JTextField date;
public WestPanel(){
setBackground(Color.white);
setLayout(new GridLayout(1,2,0,0));
dateL=new JLabel("Date: ");
date=new JTextField("dd/mm/yyyy");
date.setSize(60,10);
add(dateL);
add(date);
//....remaining code....//
Let the layout manager take care of the dimensions of your Swing components, but if you absolutely must, use setPreferredSize in combination with a layout manager that respects that property.
I'm not sure this answers the original poster's questions, but hopefully it will be helpful to other Swing developers.
Most people want the labels and components to line up, like in the following dialog I created.
I use the Swing layout manager GridBagLayout to create this type of layout. Rather than lots of explanation, here's the code that created this dialog.
package com.ggl.business.planner.view;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import com.ggl.business.planner.model.BusinessPlannerModel;
import com.ggl.business.planner.view.extended.EscapeDialog;
import com.ggl.business.planner.view.extended.JFontChooser;
public class OptionsDialog {
protected static final Insets entryInsets = new Insets(0, 10, 4, 10);
protected static final Insets spaceInsets = new Insets(10, 10, 4, 10);
protected static final Insets noInsets = new Insets(0, 0, 0, 0);
protected static final Insets iconInsets = new Insets(0, 4, 0, 0);
protected BusinessPlannerFrame frame;
protected BusinessPlannerModel model;
protected EscapeDialog dialog;
protected JButton activityTextFontButton;
protected JButton connectorTextFontButton;
protected JSpinner borderSizeSpinner;
protected SpinnerNumberModel spinnerNumberModel;
protected boolean okPressed;
public OptionsDialog(BusinessPlannerModel model, BusinessPlannerFrame frame) {
this.model = model;
this.frame = frame;
createPartControl();
}
protected void createPartControl() {
dialog = new EscapeDialog();
dialog.setTitle("Business Planner Options");
dialog.setLayout(new GridBagLayout());
int gridy = 0;
gridy = createBorderFields(gridy);
gridy = createFontFields(gridy);
gridy = createButtonFields(gridy);
dialog.pack();
dialog.setBounds(dialogBounds());
dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
dialog.setVisible(true);
}
protected int createBorderFields(int gridy) {
JLabel borderSizeLabel = new JLabel("Border size:");
borderSizeLabel.setHorizontalAlignment(SwingConstants.LEFT);
addComponent(dialog, borderSizeLabel, 0, gridy, 1, 1, spaceInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
spinnerNumberModel = new SpinnerNumberModel(model.getActivityBorder(), 1, 5, 1);
borderSizeSpinner = new JSpinner(spinnerNumberModel);
addComponent(dialog, borderSizeSpinner, 1, gridy++, 4, 1, spaceInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
return gridy;
}
protected int createFontFields(int gridy) {
JLabel boxtextFontLabel = new JLabel("Activity text font:");
boxtextFontLabel.setHorizontalAlignment(SwingConstants.LEFT);
addComponent(dialog, boxtextFontLabel, 0, gridy, 1, 1, spaceInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
Font font = model.getActivityFont();
activityTextFontButton = new JButton(getFontText(font));
activityTextFontButton.setFont(font);
activityTextFontButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
JFontChooser fontChooser = new JFontChooser();
fontChooser.setSelectedFont(model.getActivityFont());
int result = fontChooser.showDialog(dialog);
if (result == JFontChooser.OK_OPTION) {
Font font = fontChooser.getSelectedFont();
String text = getFontText(font);
model.setActivityFont(font);
activityTextFontButton.setText(text);
activityTextFontButton.setFont(font);
JButton dummy = new JButton(text);
setButtonSizes(activityTextFontButton,
connectorTextFontButton, dummy);
dialog.validate();
dialog.pack();
}
}
});
addComponent(dialog, activityTextFontButton, 1, gridy++, 4, 1, spaceInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
JLabel connectortextFontLabel = new JLabel("Connector text font:");
connectortextFontLabel.setHorizontalAlignment(SwingConstants.LEFT);
addComponent(dialog, connectortextFontLabel, 0, gridy, 1, 1, spaceInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
font = model.getConnectorFont();
connectorTextFontButton = new JButton(getFontText(font));
connectorTextFontButton.setFont(font);
connectorTextFontButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
JFontChooser fontChooser = new JFontChooser();
fontChooser.setSelectedFont(model.getConnectorFont());
int result = fontChooser.showDialog(dialog);
if (result == JFontChooser.OK_OPTION) {
Font font = fontChooser.getSelectedFont();
String text = getFontText(font);
model.setConnectorFont(font);
connectorTextFontButton.setText(text);
connectorTextFontButton.setFont(font);
JButton dummy = new JButton(text);
setButtonSizes(activityTextFontButton,
connectorTextFontButton, dummy);
dialog.validate();
dialog.pack();
}
}
});
addComponent(dialog, connectorTextFontButton, 1, gridy++, 4, 1, spaceInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
setButtonSizes(activityTextFontButton, connectorTextFontButton);
return gridy;
}
protected String getFontText(Font font) {
StringBuilder builder = new StringBuilder();
builder.append(font.getName());
builder.append(", ");
builder.append(font.getSize());
builder.append(" points, ");
if (font.isPlain()) {
builder.append("plain");
} else if (font.isBold()) {
builder.append("bold ");
} else if (font.isItalic()) {
builder.append("italic");
}
return builder.toString();
}
protected int createButtonFields(int gridy) {
JPanel buttondrawingPanel = new JPanel();
buttondrawingPanel.setLayout(new FlowLayout());
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
//TODO Add edits to make sure fields are filled correctly
setModel();
okPressed = true;
dialog.setVisible(false);
}
});
dialog.setOkButton(okButton);
buttondrawingPanel.add(okButton);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
okPressed = false;
dialog.setVisible(false);
}
});
buttondrawingPanel.add(cancelButton);
setButtonSizes(okButton, cancelButton);
addComponent(dialog, buttondrawingPanel, 0, gridy++, 5, 1, spaceInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
return gridy;
}
protected void addComponent(Container container, Component component,
int gridx, int gridy, int gridwidth, int gridheight,
Insets insets, int anchor, int fill) {
GridBagConstraints gbc = new GridBagConstraints(gridx, gridy,
gridwidth, gridheight, 1.0D, 1.0D, anchor, fill, insets, 0, 0);
container.add(component, gbc);
}
protected void setButtonSizes(JButton ... buttons) {
Dimension preferredSize = new Dimension();
for (JButton button : buttons) {
Dimension d = button.getPreferredSize();
preferredSize = setLarger(preferredSize, d);
}
for (JButton button : buttons) {
button.setPreferredSize(preferredSize);
}
}
protected Dimension setLarger(Dimension a, Dimension b) {
Dimension d = new Dimension();
d.height = Math.max(a.height, b.height);
d.width = Math.max(a.width, b.width);
return d;
}
protected void setModel() {
model.setActivityBorder(spinnerNumberModel.getNumber().intValue());
}
protected Rectangle dialogBounds() {
int margin = 200;
Rectangle bounds = dialog.getBounds();
Rectangle f = frame.getFrame().getBounds();
bounds.x = f.x + margin;
bounds.y = f.y + margin;
return bounds;
}
public boolean isOkPressed() {
return okPressed;
}
}
The EscapeDialog class I extend just lets me use the Esc key to close the dialog, as if I left clicked on the Cancel button.
There are two things I'll make note of. The first is the addComponent method, which simplifies adding components to a GridBagLayout.
The second is the setButtonSizes method, which makes all of the button sizes uniform. Even though they are JButton components, and not JTextField components, you can do something similar if you want to make JTextField components the same size.
The setSize() method only works when setting the layout manager to null.
As suggested in comments, use size hints in the text field constructor, and an appropriate layout manager.
import java.awt.*;
import javax.swing.*;
public class WestPanel extends JPanel {
private JLabel dateL;
private JTextField date;
public WestPanel(){
setBackground(Color.white);
setLayout(new FlowLayout());
dateL=new JLabel("Date: ");
date=new JTextField("dd/mm/yyyy",6);
add(dateL);
add(date);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JPanel gui = new JPanel(new BorderLayout());
gui.add(new WestPanel(), BorderLayout.LINE_START);
gui.setBackground(Color.ORANGE);
JOptionPane.showMessageDialog(null, gui);
}
};
SwingUtilities.invokeLater(r);
}
}
Size of your components in Swing will depend on the type of layout manager you are using. If you want full control of UI, you can use a Freeflow layout.
Read the full story here:
http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
JTextField can not be set size, infact, you should use a JTextArea instead.

Categories