I'm looking for a way to fill JTable from bottom to top, for example:
1 row:
[clean space]
row1
after adding 2nd row:
[clean space]
row2
row1
Looked at ComponentOrientation - seems it allows only right-to-left but not bottom-to-up
Also don't see any ways by using LookAndFill
Any ideas?
I found a solution, thank you guys!
It's pretty simple by extracting table header to BorderLayout.NORTH and adding table entries to BorderLayout.SOUTH. This allows to make table growing from bottom to top.
Table entries can further be reversed by entries decorator by this way.
Code snippet below:
final MyTableModel model = new ReverseOrderModelDecorator(new MyTableModel());
final JTable table = new JTable(model);
JTableHeader header = table.getTableHeader();
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(header, BorderLayout.NORTH);
mainPanel.add(table, BorderLayout.SOUTH);
thank you guys!
I hope this is the behaviour you are looking for:
import java.awt.ScrollPane;
import java.util.Collections;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
/**
*
* #author Skynet
*/
public class JTableReverseFill {
public static void main(String[] args) {
Runnable r = new Runnable(){
#Override
public void run() {
JFrame frame = new JFrame("jtable-reverse");
frame.setSize(200,200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTable jt = new JTable();
MyReversedTableModel mtm = new MyReversedTableModel();
mtm.addColumn("col1");
mtm.addColumn("col2");
for(Integer i = 0; i < 1000; i++)
{
mtm.addRow(new Object[]{"cell" + i.toString(), "cell" + i.toString() + i.toString()});
}
jt.setModel(mtm);
ScrollPane sp = new ScrollPane();
sp.add(jt);
frame.add(sp);
frame.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
public static class MyReversedTableModel extends DefaultTableModel
{
public void reverse()
{
Collections.reverse(getDataVector());
}
#Override
public void addRow(Object[] rowData) {
reverse();
super.addRow(rowData);
reverse();
}
}
}
You can also call reverse() outside of the model to save some cpu time.
Related
My plan is to get a 2-dimensional array into a JTable into a JScrollPanel. The Table already shows the 2-dimensional array's data. The problem is that the table won't show when I add it to a jscrollpanel (The scrollpanel is visible though but empty. It does work when I put the table in the JPanel (not jscrollpanel). but not when using a jscrollpanel.
Does any one have any idea?
package arraytablestable;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class ArrayTablesTable extends JFrame {
public static JFrame frame;
public static void main(String[] args) {
frame = new JFrame();
frame.setSize(1280,720);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Array Table 7 in Tables");
frame.setContentPane(new Paneel());
frame.setVisible(true);
}
private static class Paneel extends JPanel {
// Declareren
public static JTable Table;
public JTableHeader tblHeader;
public TableModel tblModel;
public Object[] columnNames;
public static Object[][] Data;
public int Resultaat, a ,i ;
public JScrollPane jScrollPane;
public Paneel() {
this.setLayout(new GridLayout(1,1));
// Initialiseren
Data = new Object[200][1];
columnNames = new Object[]{"Product","Resultaat"};
// Model maken & importen
tblModel = new DefaultTableModel(columnNames,0);
Table = new JTable(tblModel);
// Table Eigenschaooen
// tblHeader = Table.getTableHeader();
// tblHeader.setBackground(Color.decode("#a181a1"));
// tblHeader.setForeground(Color.decode("#1b1b1b"));
// Table.setFocusable(false);
// Table.setRowSelectionAllowed(false);
Data[0] = new String[100];
Data[1] = new Integer[100];
// For Loop
for(i = 0; i < 100; i++){
Data[0][i]= "7 x " + i;
Resultaat = 7 * i;
Data[1][i]= Resultaat;
TabelVullen(new Object[]{Data[0][i],Data[1][i]});
}
System.out.println("object: " + Data[0][4]);
this.add(jScrollPane);
}
public void TabelVullen(Object[] data){
((DefaultTableModel)Table.getModel()).addRow(data);
// Components -> Panel
jScrollPane = new JScrollPane(Table);
jScrollPane.add(Table);
}
}
}
jScrollPane = new JScrollPane(Table);
The above line is correct. It creates the scrollpane and adds the table to the "viewport" of the scrollpane.
//jScrollPane.add(Table);
The above line is incorrect. It removes the table from the viewport of the scrollpane. Never use the add(...) method of a scrollpane. All components must be added to the viewport.
Learn of follow Java naming conventions. Variable names should NOT start with an upper case character. "Table" should be "table". All you other names follow this standard. Be consistent!!!
Also, method names should NOT start with an upper case character (TabelVullen).
Why is there an A on the top of the table?
I placed a JTable inside a JScrollPane to make it scrollable.
Are there methods that I need to place?
I did not place a letter A though so I cant track.
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.BoxLayout;
import javax.swing.JTable;
import javax.swing.border.LineBorder;
import java.awt.Color;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
public class Rawr {
private JFrame frame;
private JScrollPane scrollPane;
private JTable table;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Rawr window = new Rawr();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Rawr() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
scrollPane = new JScrollPane();
scrollPane.setToolTipText("");
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
panel.add(scrollPane);
table = new JTable(100, 1);
table.setBorder(new LineBorder(new Color(0, 0, 0)));
scrollPane.setViewportView(table);
}
}
How do I remove it? Thanks!
Set the column name explicitly using:
String[] colNames = new String[]{"Your Column Name"};
DefaultTableModel defaultTableModel = new DefaultTableModel(colNames, 100);
table = new JTable(defaultTableModel);
If you create a table using new JTable(100, 1) you will see the A, B and so on column headers because the constructor javadoc says:
Constructs a JTable with numRows and numColumns of empty cells using DefaultTableModel.
Since the JTable constructor does not have any information about the column headers. It can only create a DefaultTableModel that does not know any column header names.
The DefaultTableModel extends AbstractTableModel and the javadoc of AbstractTableModel.getColumnName() says
Returns a default name for the column using spreadsheet conventions: A, B, C, ... Z, AA, AB, etc. If column cannot be found, returns an empty string.
Add the following code after the creation of your table.
String[] columns = new String[]{"Column Name"};
((DefaultTableModel)table.getModel()).setColumnIdentifiers(columns);
How do I remove it?
A JTable is designed to display data with a header to describe the data in the column.
Since you only have a single column of data, if you don't want the header then don't use a JTable. Instead you can use a JList.
Read the section from the Swing tutorial on How to Use Lists for more information and examples.
I have noticed that when I have a JTable with a TableRowSorter contained by a JScrollPane, the vertical scrollbar does not appear until after I have created SortKeys for the sorter (which is done by calling toggleSortOrder() for one of the columns).
My question is really why? What do SortKeys have to do with a vertical scrollbar?
Update: Added SSCCE that opens a JFrame with a JTable inside a JScrollPane, that sits in a Container along with a "Populate" button. When the table is initially painted, there is no data and hence no need for a scroll bar. After I populate it with 20 rows, there is a need for a scroll bar, but none appears.
There are two ways to make the scroll bar appear:
Click on either of the header cells to cause a sort to occur.
Remove the commented call toggleSortOrder() in the Container's refresh() method.
// table.getRowSorter().toggleSortOrder(0);
toggleSortOrder() calls setSortKeys() calls sort() calls fireRowSorterChanged() and eventually something catches the event and adds the scroll bar.
package test;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.WindowConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
#SuppressWarnings("serial")
public class TestFrame extends JFrame
{
class MyTableModel extends AbstractTableModel
{
public List<String> names = new ArrayList<String>();
public int getRowCount ()
{
return names.size();
}
public int getColumnCount ()
{
return 2;
}
public String getColumnName (int columnIndex)
{
return columnIndex > 0 ? "Name" : "Number";
}
public Class<?> getColumnClass (int columnIndex)
{
return String.class;
}
public Object getValueAt (int row, int col)
{
return row < names.size() ? col == 0 ? Integer.toString(row) : names.get(row) : "";
}
public void refresh (List<String> names)
{
this.names = names;
}
}
class MyContainer extends java.awt.Container implements ActionListener
{
JTable table;
MyTableModel model = new MyTableModel();
private TableRowSorter<MyTableModel> sorter;
public MyContainer()
{
}
public void init ()
{
sorter = new TableRowSorter<MyTableModel>(model);
table = new JTable(model);
table.setBorder(BorderFactory.createEmptyBorder());
table.setRowHeight(35);
table.getTableHeader().setPreferredSize(new Dimension(200, 35));
table.setRowSorter(sorter);
table.setPreferredScrollableViewportSize(new Dimension(200, 70));
table.setFillsViewportHeight(true);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setBounds(10, 10, 200, 210);
//Add the scroll pane to this panel.
add(scrollPane);
JButton btn = new JButton("Populate");
btn.setActionCommand("populate");
btn.addActionListener(this);
btn.setBounds(10, 220, 200, 35);
add(btn);
}
public void refresh (List<String> rows)
{
model.refresh(rows);
try
{
// Notify sorter that model data (possibly number of rows) has changed.
// Without this call, the sorter assumes the number of rows is the same.
table.getRowSorter().allRowsChanged();
// Do we really want to toggle the sort order every time we refresh?
// User can toggle the sort order himself by clicking on the
// appropriate header cell.
List<?> keys = table.getRowSorter().getSortKeys();
if (null == keys || keys.isEmpty())
{
// table.getRowSorter().toggleSortOrder(0);
}
} catch (Exception e)
{
e.printStackTrace();
}
table.repaint();
}
public void actionPerformed(ActionEvent e)
{
if ("populate".equals(e.getActionCommand()))
{
List<String> rows = new ArrayList<String>();
for (int ii = 0; ii < 20; ii++)
{
rows.add(String.format("%02d", new Integer(ii)));
}
refresh(rows);
}
}
MyTableModel getModel ()
{
return model;
}
}
public static void main (String args[])
{
new TestFrame();
}
MyContainer myContainer = new MyContainer();
TestFrame()
{
myContainer.init();
myContainer.table.getSelectionModel().clearSelection();
add(myContainer);
this.setSize(240, 310);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//pack();
setVisible(true);
}
}
Well, that is not really a SSCCE because you are using a custom TableModel. If you would have created a proper SSCCE you would be using the DefaultTableModel so that you are testing your code with standard JDK classes. If you did this then you would have noticed that the code would work.
So then your next step would be to try the code with your custom TableModel and you would notice that the code did not work.
So then your question on the forum would be why doesn't the code work with my custom TableModel? The point of the SSCCE is to do basic debugging to isolate where the error is happening so we have information to work with. In your original question we had no idea you where using custom classes.
Anyway, the problem is that your custom TableModel is not notifying the table when a change to the data is made. In your refresh(...) method you need to add the following after you reset the List containing the data:
fireTableRowsInserted(0, names.size()-1);
There is no need for table.repaint() in any of your code.
My aim is to create a JTable, and render the far left column cells only, with the aim of creating row headers for the table.
All row table examples I have come across online seem convoluted or do not fit my purposes, so I am wondering is there a simple way of creating JTable row headers through rendering the left column cells only?
Below I have code of a simple table with 2 columns and two rows. Is it possible someone could modify this, or explain in simple terms, how I could go about rendering the far left column for row header purposes.
Thank you.
import javax.swing.*;
import java.awt.*;
import javax.imageio.*;
import java.io.*;
import java.awt.image.BufferedImage;
import java.util.*;
public class GUITable extends JFrame{public GUITable(){
init();
}
public final void init(){
String[] columnNames = {"", "Gross Weight"};
Object[][] data = {
{"", new Integer(100)},};
final JTable table = new JTable(data, columnNames);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
GUITable ex = new GUITable();
ex.setVisible(true);
}
});
}
}
Yes - by using a custom TableCellRenderer, you can modify the way the first column (and first column only) displays.
Essentially you can use this to set the TableCellRenderer on the first column only:
table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer());
And you can extend the DefaultTableCellRenderer to take care of any special rendering you want to do:
//Custom Renderer - does the default rendering except if told the row should be a different color
public static class CustomRenderer extends DefaultTableCellRenderer{
public CustomRenderer(){
super();
//Customize the rendering however you want
setBackground(UIManager.getColor("TableHeader.background"));
}
}
To put it all together in your example:
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
public class TestTable extends JFrame{
public TestTable(){
init();
}
public final void init(){
String[] columnNames = {"", "Gross Weight"};
Object[][] data = {{"", new Integer(100)},};
final JTable table = new JTable(data, columnNames);
// Add Renderer to first column only
table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setPreferredSize(new Dimension(300, 200));
add(scrollPane);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
TestTable ex = new TestTable();
ex.pack();
ex.setVisible(true);
}
});
}
//Custom Renderer - does the default rendering except if told the row should be a different color
public static class CustomRenderer extends DefaultTableCellRenderer{
public CustomRenderer(){
super();
//Customize the rendering however you want
setBackground(UIManager.getColor("TableHeader.background"));
}
}
}
your code example could be
import javax.swing.*;
import java.awt.*;
public class GUITable extends JFrame {
public GUITable() {
init();
}
public final void init() {
String[] columnNames = {"", "Gross Weight"};
Object[][] data = {{"", new Integer(100)},};
final JTable table = new JTable(data, columnNames);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");//Java6
//UIManager.setLookAndFeel(
//"javax.swing.plaf.nimbus.NimbusLookAndFeel");//Java7
} catch (Exception fail) {
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUITable ex = new GUITable();
ex.setVisible(true);
}
});
}
}
not sure from your descriptions, are you meaning Row Number Table by #camickr, or another half_sized attempt
For the following code, I am not able to set the column size to a custom size. Why is it so?Also the first column is not being displayed.
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
public class Trial extends JFrame{
public void create(){
JPanel jp = new JPanel();
String[] string = {" ", "A"};
Object[][] data = {{"A", "0"},{"B", "3"},{"C","5"},{"D","-"}};
JTable table = new JTable(data, string);
jp.setLayout(new GridLayout(2,0));
jp.add(table);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn column = null;
for (int i = 0; i < 2; i++) {
column = table.getColumnModel().getColumn(i);
column.setPreferredWidth(20); //custom size
}
setLayout(new BorderLayout());
add(jp);
}
public static void main(String [] a){
Trial trial = new Trial();
trial.setSize(300,300);
trial.setVisible(true);
trial.setDefaultCloseOperation(Trial.EXIT_ON_CLOSE);
trial.create();
}
}
You've got a couple of issues here. First and foremost, Always initialize your JFrame from the Swing EDT as such:
public static void main(String[] a) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Trial trial = new Trial();
trial.setSize(300, 300);
trial.setDefaultCloseOperation(Trial.EXIT_ON_CLOSE);
trial.create();
}
});
}
Failure to do so will lead to subtle errors. Second: JTables like to exist within JScrollPanes. That's why you don't see the column headers:
JScrollPane pane = new JScrollPane();
pane.setViewportView(table);
jp.add(pane);
With the above done, I see your tiny little columns, each 20 pixels wide.
When autoresize mode is set to off the column widths will not be adjusted at all when the table is layed out. From JTable's doLayout() documentation:
AUTO_RESIZE_OFF: Don't automatically
adjust the column's widths at all. Use
a horizontal scrollbar to accomodate
the columns when their sum exceeds the
width of the Viewport. If the JTable
is not enclosed in a JScrollPane this
may leave parts of the table
invisible.
Try adding the JTable to a JScrollPane and then adding that to the panel.