Is it possible to add buttons inside the JTable cell along with data?
What I am trying to do is to create a table with columns which display data(number) from the database, and two buttons to increase/decrease the number inside the same cell.
|ID | Quantity|
|06| 2 [+][-] |
it would be something like above with [+][-] being buttons. So when I press [+], the number will change to 3 and 1 if pressing [-].
Yes, it is possible, although It won't be easy.
You have to write your own custom cell renderer and your own cell editor.
This is a sample I made in 5 minutes:
It is far from perfect, but shows the concept.
Here's the source code:
import java.awt.Component;
import java.awt.Font;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.Dimension;
public class CustomCell {
public static void main( String [] args ) {
Object [] columnNames = new Object[]{ "Id", "Quantity" };
Object [][] data = new Object[][]{ {"06", 1}, {"08", 2} };
JTable table = new JTable( data, columnNames ) {
public TableCellRenderer getCellRenderer( int row, int column ) {
return new PlusMinusCellRenderer();
}
};
table.setRowHeight( 32 );
showFrame( table );
}
private static void showFrame( JTable table ) {
JFrame f = new JFrame("Custom Cell Renderer sample" );
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.add( new JScrollPane( table ) );
f.pack();
f.setVisible( true );
}
}
class PlusMinusCellRenderer extends JPanel implements TableCellRenderer {
public Component getTableCellRendererComponent(
final JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
this.add( new JTextField( value.toString() ) );
this.add( new JButton("+"));
this.add( new JButton("-"));
return this;
}
}
Here's a thread that may be interesting and here.
As discussed in the tutorial you'll need both a renderer to display your value and an editor to detect events from the cell being edited. In this example, the Component is a JCheckBox. Note that this requires a custom DataModel that extends AbstractTableModel to supply the correct Class for a given column. Joonas' suggestion to use JSpinner is a good one that works well.
I think you need to create a custom cell renderer if you want to show anything else than text (or numbers) in the cell. The cell renderer's job is to paint whatever you need to show in the cell.
See Table Renderer documentation.
So in this case you could create a small JPane which contains the text field and the tiny + and - buttons - or a just a JSpinner component, if does what you need. A bit tricky, for sure, but should be possible.
Related
I am trying to include a JTable in JOptionPane.showMessageDialog and adding some more text below the table. To do so, I have tried next code:
import javax.swing.JOptionPane;
import javax.swing.*;
public class TextInTable {
public static void main(String[] args) {
String[][] rowValues = {
{"1","2","3"}
};
String[] columnNames = {
"A","B", "C"
};
JTable table = new JTable(rowValues, columnNames);
JOptionPane.showMessageDialog(null, new JScrollPane(table) +"\n"+ "I need to add some text here \n" + "and here”);
}
}
However, the JTable does not show correctly if I put this code (+"\n"+ "I need to add some text here \n" + "and here”) after the table.
This is what I am trying to do:
Any idea about how to solve it? Thanks in advance.
You need to create your own JPanel the way you want it with the components you would like and then pass that panel to the JOptionPane. Below I provide a runnable demo of this. Read all the comments in code as they explain what is going on. You can delete them later if you like. Here is what it produces on Screen:
Here is the runnable code:
package joptionpanewithjtabledemo;
public class JOptionPaneWithJTableDemo {
public static void main(String[] args) {
// Application started this way to avoid the need for statics.
new JOptionPaneWithJTableDemo().startApp(args);
}
private void startApp(String[] args) {
/* Create a JDialog box to use as a parent for the JOptionPane
just in case the JOptionPane has no parent and needs to be
displyed on top of a window that has its own ON TOP property
set to true and the JOptionPane's parent property is set to
null. If this is the case then the message box will be hidden
behind it! If your JOptionPane will be displayed on an actual
parent window then use that window's variable name as parent.
You can then delete anything in code related to iDialog.
*/
javax.swing.JDialog iDialog = new javax.swing.JDialog();
iDialog.setAlwaysOnTop(true);
iDialog.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
iDialog.setLocationRelativeTo(null);
// Create a JPanel to display within the JOptionPane MessageBox //
javax.swing.JPanel panel = new javax.swing.JPanel();
// Size the Panel to what you want to hold the JTable and JLabel
panel.setPreferredSize(new java.awt.Dimension(400, 250));
panel.setLayout(new java.awt.BorderLayout()); // Set BorderLayout as the layout manager
// JTable Column Names
Object[] columnNames = {"A", "B", "C"};
// Some fictitious data for the JTable...
Object[][] data = {
{1000, 2000, 3000}, {1001, 2001, 3001}, {1002, 2002, 3002},
{1003, 2003, 3003}, {1004, 2004, 3004}, {1005, 2005, 3005},
{1006, 2006, 3006}, {1007, 2007, 3007}, {1008, 2008, 3008},
{1009, 2009, 3009}, {1010, 2010, 3010}, {1011, 2011, 3011},
};
// Declare a JTable and initialize with the table data and column names.
javax.swing.JTable table = new javax.swing.JTable(data, columnNames);
/* Align JTable Header Text to Center.
Alignment options are: Align_LEFT (2), Align_CENTER (0), Align_RIGHT (4),
Align_LEADING (10), or Align_TRAILING (11) */
int alignType = 0;
for (int i = 0; i < table.getColumnCount(); i++) {
table.getTableHeader().getColumnModel().getColumn(i)
.setHeaderRenderer(new HeaderRenderer(table, alignType));
}
// Declare a JScrollPane and place the JTable into it.
javax.swing.JScrollPane tableScrollPane = new javax.swing.JScrollPane(table);
// Ensure the ScrollPane size.
tableScrollPane.setPreferredSize(new java.awt.Dimension(400, 200));
panel.add(tableScrollPane, java.awt.BorderLayout.NORTH); // Add the scrollpane to top of panel.
/* Use basic HTML to create you message text. Gives you more
flexability towards how your message will look. */
String msg = "<html><font size='4'>I need to add some text "
+ "<font color=blue>here</font><center>and right "
+ "<font color=red>here</font>!</center></html>";
javax.swing.JLabel msgLabel = new javax.swing.JLabel(msg);
// Set the initial text alignment in the JLabel.
msgLabel.setHorizontalAlignment(javax.swing.JLabel.CENTER);
//msgLabel.setBorder(BorderFactory.createLineBorder(Color.blue, 1));
// Ensure label width and desired height.
msgLabel.setPreferredSize(new java.awt.Dimension(panel.getWidth(), 50));
panel.add(msgLabel, java.awt.BorderLayout.SOUTH); // add label to bottom of panel.
// Display The Message Box...
javax.swing.JOptionPane.showMessageDialog(iDialog, panel, "My Table Message Box",
javax.swing.JOptionPane.INFORMATION_MESSAGE);
iDialog.dispose();
}
// Inner class - A Header cell renderer class for header text alignment options.
class HeaderRenderer implements javax.swing.table.TableCellRenderer {
javax.swing.table.DefaultTableCellRenderer renderer;
int horAlignment;
HeaderRenderer(javax.swing.JTable table, int horizontalAlignment) {
horAlignment = horizontalAlignment;
renderer = (javax.swing.table.DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer();
}
#Override
public java.awt.Component getTableCellRendererComponent(javax.swing.JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
java.awt.Component c = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
javax.swing.JLabel label = (javax.swing.JLabel) c;
label.setHorizontalAlignment(horAlignment);
return label;
}
}
}
for this, I tried this method
table.setFont(new Font("Lucida Console", Font.PLAIN, 18));
but by using this I cannot find the appropriate Font at the time of Writing in the cell of the JTable.
I attach an image so you can find my question clearly .in this image u can see that at the time of writing font is small but after going to the next cell it becomes to change but I want that big font you can see that in image at the time of writing in the cell.
The problem is that table.setFont(new Font("Lucida Console", Font.PLAIN, 18)); will set the font of the cells when not being edited, it will not even set the font of the header. When editing, you have override the default setup by defining your own DefaultCellEditor. There are two ways to do so, the first (easier and cleaner) way is to create a JTextField and customize it the way you like and then pass it to the DefaultCellEditor constructor. The second (longer and not as clean) way is to override the getTableCellEditorComponent in the DefaultCellEditor and achieve the same result. I have included both solutions in a MCVE:
import java.awt.Color;
import java.awt.Font;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
public class Example extends JFrame {
private final JTable table;
private final String[] header = new String[]{"Column 0", "Column 1", "Column 2", "Column 3"};
private String[][] data = new String[][]{
{"(0,0)", "(1,0)", "(2,0)", "(3,0)"},
{"(0,1)", "(1,1)", "(2,1)", "(3,1)"},
{"(0,2)", "(1,2)", "(2,2)", "(3,2)"},
{"(0,3)", "(1,3)", "(2,3)", "(3,3)"}};
private final Font tableFont = new Font("Lucida Console", Font.PLAIN, 18);
public Example() {
table = new JTable(data, header);
table.getTableHeader().setFont(tableFont);//font of the header
table.setFont(tableFont);//set the font of the whole table
//Since each cell is editable, you could think about it as a JTextField. You can create a
//new JTextField and customize it. Then, you pass it as the new cell editor to the columns
//of the JTable.
JTextField textField = new JTextField();
textField.setFont(tableFont);//this is what you need.
//Extra changes, no boarder and selection colour is yellow... just to get the point across.
textField.setBorder(null);
textField.setSelectionColor(Color.YELLOW);
//Create DefaultCellEditor and pass the textfield to the constructor.
DefaultCellEditor customCellEditor = new DefaultCellEditor(textField);
//Loop through all the columns and set the cell editor as the customized one.
for (int i = 0; i < table.getColumnCount(); i++) {
table.getColumnModel().getColumn(i).setCellEditor(customCellEditor);
}
/*
OR, don't create a JTextField and use the following instead:
DefaultCellEditor customCellEditor2 = new DefaultCellEditor(new JTextField()) {
#Override
public java.awt.Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
JTextField result = (JTextField) super.getTableCellEditorComponent(table, value,
isSelected, row, column);
result.setFont(tableFont);//this is what you need.
result.setBorder(null);
result.setSelectionColor(Color.YELLOW);
return result;
}
};
//Loop through all the columns and set the cell editor as the customized one.
for (int i = 0; i < table.getColumnCount(); i++) {
table.getColumnModel().getColumn(i).setCellEditor(customCellEditor2);
}
*/
//probably, you should make the height of the cells larger.
for (int i = 0; i < table.getRowCount(); i++) {
table.setRowHeight(i, 25);
}
add(new JScrollPane(table));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
pack();
setVisible(true);
}
public static void main(String[] args) {
new Example();
}
Maybe you could check how many characters have been typed in and calculate approximately how big the font should be.
Calculation shouldn't be hard, is it? And then just change the size in this cell.
Is there a way to align all the column in jtable at the same time?
using this:
DefaultTableCellRenderer rightRenderer = new DefaultTableCellRenderer();
rightRenderer.setHorizontalAlignment( JLabel.RIGHT );
JTAB_TABLE.getColumnModel().getColumn(0).setCellRenderer( rightRenderer );
will let me align only one column but i need to align all.
Normally, a table contains different kinds of data, (Date, Number, Boolean, String) and it doesn't make sense to force all types of data to be right aligned.
If however you have a table with all the same type of data and you want to force the renderering of all columns to be the same, then you should probably use the same renderer. Assuming you are using the default renderer you can use:
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)table.getDefaultRenderer(Object.class);
renderer.setHorizontalAlignment( JLabel.RIGHT );
You can do so by overriding prepareRenderer(...) in JTable. This assumes that any custom renderers are JLabels (they're JLabels by default). You'd have to guard against it otherwise.
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableDemo implements Runnable
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new TableDemo());
}
public void run()
{
JTable table = new JTable(5, 5)
{
#Override
public Component prepareRenderer(TableCellRenderer renderer,
int row, int col)
{
Component comp = super.prepareRenderer(renderer, row, col);
((JLabel) comp).setHorizontalAlignment(JLabel.RIGHT);
return comp;
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
JFrame frame = new JFrame();
frame.getContentPane().add(scrollPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I have a Jtable allow editing and inserting.
When editing a column, lets say "ID", I want to have a check, if the inserted record or the record after editing have duplicat "ID" column value with the other records. it is not allowed.
actually, to be specific, if someone is editing the ID column, when he hit the "Enter" or move the focus to another cell, perform a check, if the ID is duplicate, then disallow the edition.
how can I do this?
if someone is editing the ID column, when he hit the "Enter" or move the focus to another cell, perform a check, if the ID is duplicate, then disallow the edition.
Create a custom editor to validate the id before it is saved to the model. Here is a simple example to get your started:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableEdit extends JFrame
{
TableEdit()
{
JTable table = new JTable(5,5);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollpane = new JScrollPane(table);
getContentPane().add(scrollpane);
// Use a custom editor
TableCellEditor fce = new FiveCharacterEditor();
table.setDefaultEditor(Object.class, fce);
}
class FiveCharacterEditor extends DefaultCellEditor
{
FiveCharacterEditor()
{
super( new JTextField() );
}
public boolean stopCellEditing()
{
try
{
String editingValue = (String)getCellEditorValue();
if(editingValue.length() != 5)
{
JTextField textField = (JTextField)getComponent();
textField.setBorder(new LineBorder(Color.red));
textField.selectAll();
textField.requestFocusInWindow();
JOptionPane.showMessageDialog(
null,
"Please enter string with 5 letters.",
"Alert!",JOptionPane.ERROR_MESSAGE);
return false;
}
}
catch(ClassCastException exception)
{
return false;
}
return super.stopCellEditing();
}
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
Component c = super.getTableCellEditorComponent(
table, value, isSelected, row, column);
((JComponent)c).setBorder(new LineBorder(Color.black));
return c;
}
}
public static void main(String [] args)
{
JFrame frame = new TableEdit();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
Extend DefaultTableModel and override the add and update methods checking for duplication and use this class for your JTable.
Extend AbstractTableModel and arrange for it to contain a Set, which precludes duplicate elements. As suggested by #camickr, you'll want a custom cell editor to communicate the results failed additions.
I have created a JList and I want to add it to the table and then add the table to the scroll pane so that both of them will be contained in the scroll pane.
import model.*;
import java.awt. *;
import java.text.*;
import javax.swing.*;
import javax.swing.table.TableColumn;
public class ScrollPanel extends JPanel implements View
{
private Prison prison;
private String[] cells = new String[20];
private JList list = new JList(cells);
public ScrollPanel(Prison prison)
{
this.prison = prison;
prison.attach(this);
setup();
build(prison);
}
public void setup()
{
}
public void build(Prison prison)
{
int rows = 20;
int columns = 2;
for (int i = 0; i < 20; i++)
{
cells[i] = prison.cells().get(i).id();
}
JTable table = new JTable(rows, columns);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn column = null;
column = table.getColumnModel().getColumn(0);
column.setPreferredWidth(91);
column = table.getColumnModel().getColumn(1);
column.setPreferredWidth(91);
table.add(list);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setPreferredSize(new Dimension(220, 150));
add(scrollPane);
}
public void update()
{ }
}
This is how my program looks when I did the code I pasted above, which is adding the list to the table.
alt text http://img21.imageshack.us/img21/3237/11834317.jpg
When I added the table to the list and then to the scroll pane, this is how it looked. How do I add them both to the scroll pane with both of them showing?
alt text http://img27.imageshack.us/img27/3678/94687555.jpg
This is what it should look like..
alt text http://img21.imageshack.us/img21/1343/90528093.jpg
What do you want to achieve by adding a JList to a table? It's a fundamentally wrong thing to do - JTables aren't intended to have components added to them at all. If you want the table to display the items in the list, you need an implementation of the TableModel interface, not a JList.
Edit:
If you want the JList and the JTable to be displayed next to each other, you have to addthem both to a JPanel before adding that to the ScrollPane. But this is a rather unusualy thing to do; normally, a table is in a ScrollPane of its own. You could have a separate ScrollPane each for the table and the list. Or you could simply put the list items in the first column of the table. Which is better depends on your requirements.
I'm not sure what you are trying to achieve, if you just want to have the first column in the table show values for a row id like 1.1,1.2,1.3, etc, you could just add those to the first column of the jtable, you could even style that column different w/ Renderers. If that will not work then you could try and set the JList on the rowHeader of the scrollpane, similiar to the below. You will need to adjust the row height to accomodate the list height, or vice-versa. But this will achieve what you want and allow the list to scroll w/ the table. Good Luck!
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class Scroll {
public static final void main(String[] args){
JFrame f = new JFrame();
f.setSize(new Dimension(400,400));
JList list = new JList(new Object[]{"1.1","1.2","1.3","1.4","1.5","1.6","1.7","1.8","1.9","1.10","1.11"});
JTable table = new JTable(11,10);
JScrollPane sp = new JScrollPane(table);
sp.setRowHeaderView(list);
f.getContentPane().add(sp);
f.setVisible(true);
}
}
Maybe you could add a "Details" button to each row of the table. If, so then the TableButtonColumn will help you out.