Moving Jtable in Java, Swing, Flowlayout - java

I have this code so far:
public class Table extends JFrame {
JTable table;
public Table()
{
setLayout (new FlowLayout()); //Default layout
String[] columnNames = {"Fly model", "Fly kode",
"Destination", "Tidspunkt"};
Object[][] data = {
{"Boeing 737", "Ab79SO", "Oslo", "22:00"},
{"MD125", "Tb682O", "Stockholm", "15:21"},
{"Boeing 737", "HJ72SR", "Reikjavic", "08:13"},
};
table = new JTable(data, columnNames);
table.setPreferredScrollableViewportSize(new Dimension(500, 50));
table.setFillsViewportHeight(true);
setVisible(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public JTable returnJTable()
{
setVisible(false);
return table;
}
}
I am not used to use FlowLayout, and I therefore don't know how to move this object around in the JFrame that I am using. I know that when you use a null (absolute) layout, you can use setBounds() to tell the JFrame where to position the elements. But how do I do that in FlowLayout?

You can't do that with FlowLayout. You can add new components horizontally or vertically one by another, but you can't to add component to specific position. You can try to use some tricks with blank panels or labels for spaces before/after your JTable, but better to use another layout.
Try to use BorderLayout, it's simple and with help of that, you can positioning your JTable in different places. Read tutorial for that.
Or you can use another LayoutManager, read about them and choose.

With FlowLayout you can't move the object around. All objects are placed in one line.
Try to use the BorderLayout or GridBagLayout.
Here's a visual guide to Layout Managers.
Panel myTable = new Panel(new GridBagLayout());
GridBagConstraints c1 = new GridBagConstraints();
c1.fill = GridBagConstraints.HORIZONTAL; //area
c1.ipadx = 0; //spacing
c1.ipady = 0; //spacing
c1.weightx = 1.0; //horizontal
c1.weighty = 1.0; //vertical
c1.anchor = GridBagConstraints.CENTER; //orientation
c1.insets = new Insets(10,10,10,10); //padding
c1.gridx = 0; //column
c1.gridy = 0; //line
c1.gridheight = 1; //number of lines
c1.gridwidth = 1; //number of columns
myTable.add(new JScrollPane(table),c1);
You can move your table if you change the orientation.

Related

GridBagLayout: how to fill vertically using preferred width horizontally

I have an issue trying to fill vertically a JScrollPane (which contains a JTable) inside a JPanel: the panel should not be filled horizontally, instead, the JScrollPane should take only the "necessary" space.
I'm using some code found on SO to set the table preferred width according to its content (i'm also overrding JTable's getPreferredScrollableViewportSize method).
This is a screenshot of what i want to achieve:
The JPanel is wider because in my application it will be part of a CardLayout, so the other cards width and height will determine this panel size (in the code below i'm overriding getPreferredSize method for convenience, but i don't want to use it).
This result can be achieved using the below code, you only need to change this line of code:
Object [][] data = new Object [100][1];
to:
Object [][] data = new Object [10][1];
The problem is when the JTable has more rows, in this case the vertical scrollbar will appear, but the scroll pane will "shrink":
This is the code i'm using:
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;
public class TableTest
{
public static void main (String [] a) {
SwingUtilities.invokeLater (new Runnable () {
#Override public void run () {
createAndShowGUI ();
}
});
}
private static void createAndShowGUI () {
JFrame frame = new JFrame ("Table Test");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setContentPane (new MainPanel ());
frame.pack ();
frame.setLocationRelativeTo (null);
frame.setVisible (true);
}
}
class MainPanel extends JPanel
{
private static int MAX_HEIGHT = 600;
private static int MAX_WIDTH = 600;
private JTable table;
protected MainPanel () {
super (new GridBagLayout ());
Object [][] data = new Object [100][1];
for (int i = 0; i < 10; i ++) data [i] = new String [] {"Some data ..."};
table = new JTable (data, new String [] {""}) {
#Override public Dimension getPreferredScrollableViewportSize () {
int width = 0;
for (int column = 0; column < getColumnCount (); column ++) width += columnModel.getColumn (column).getPreferredWidth ();
return new Dimension (Math.min (MAX_WIDTH, width), Math.min (MAX_HEIGHT, getRowHeight () * getRowCount ()));
}
};
table.setAutoResizeMode (JTable.AUTO_RESIZE_OFF);
table.setShowGrid (false);
table.setTableHeader (null);
resizeColumns ();
JScrollPane scrollPane = new JScrollPane (table);
scrollPane.setBackground (table.getBackground ());
scrollPane.getViewport ().setBackground (table.getBackground ());
// --- Adding components ---
GridBagConstraints c = new GridBagConstraints ();
c.fill = GridBagConstraints.VERTICAL;
c.weightx = 0.0;
c.weighty = 1.0;
add (scrollPane, c);
}
#Override public Dimension getPreferredSize () {
return new Dimension (500, 400);
}
protected void resizeColumns () {
for (int column = 0; column < table.getColumnCount (); column ++) {
TableColumn tableColumn = table.getColumnModel ().getColumn (column);
int width = 0;
for (int row = 0; row < table.getRowCount (); row ++) {
width = Math.max (table.prepareRenderer (table.getCellRenderer (row, column), row, column).getPreferredSize ().width, width);
}
tableColumn.setPreferredWidth (width + table.getIntercellSpacing ().width);
}
}
}
If i set c.fill to GridBagConstraints.BOTH and c.weightx to any positive value, the JScrollPane will fill the parent panel both horizontally and vertically.
How can i let the table's preferred width to be used without manually setting the JScrollPane size?
EDIT
My code is very minimal, since i saw that my problem was not related to the number of table columns. But my real program has to deal with more columns, and a huge number of rows (a million or more in many cases).
A JList was my first try, since i liked the way i could use a prototype value, but it was too slow to load the data (which can also be updated at runtime), all the GUI freezed with more than 200 000 rows, also due to the fact that i'm using a custom renderer.
Also, i already tried to use a BorderLayout, but i really want the scrollpane height to fill my panel, i have tried different solutions, but still i can't solve it.
EDIT2
As #camickr suggests, i could use a BorderLayout for my panel, adding the scrollpane at BorderLayout.WEST to fill the panel vertically wihout taking all the horizontal space. This is the best solution for now, but this will cause the horizontal center alignment to be lost. Any ideas?
(in the code below i'm overriding getPreferredSize method for convenience, but i don't want to use it
I agree. Get rid of the override.
The painting problem when you decrease the height of the frame is because the GridBagLayout will paint the component at its minimum size when there is not enough space.
So, although in general I don't like using any of the set??? methods to hardcode a size the following seems to work:
scrollPane.setMinimumSize(scrollPane.getPreferredSize());
This will keep the scrollpane width from decreasing.
If you don't like playing with hardcoded sizes you could use the Relative Layout. This will easily allow you to center a component.
Then basic code would be:
RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS);
rl.setFill( true );
setLayout(rl);
...
add(Box.createHorizontalGlue(), new Float(1));
add(scrollPane);
add(Box.createHorizontalGlue(), new Float(1));
Your layout problem is caused by your GridBagConstraints (especially fill and weightx)
which prevented the scrollPane from using the available horizontal space.
Instead of
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.VERTICAL;
c.weightx = 0.0;
c.weighty = 1.0;
add (scrollPane, c);
you should use
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH; // !!
c.weightx = 1.0; // !!
c.weighty = 1.0;
add (scrollPane, c);
Then it will look like this:

GridBagLayout - Trouble placing components without anchor

I'm making an assignment planner program. For the containers (the assignments), I want to place certain components into certain places. However. I can only seem to move components around by using anchor. It seems as if my gridx and gridy do nothing. Could anyone point out my problem and possibly offer some suggestions. My code and a picture of the intended final result are provided below.
Code:
import javax.swing.*;
import java.awt.*;
import static java.awt.GridBagConstraints.*;
//import java.util.ArrayList;
public class MyWindow
{
private final JFrame frame = new JFrame();
private final int WINDOW_WIDTH = 500, WINDOW_DEPTH = 500;
private JPanel panel;
private JPanel toDoList, completed;
private int scrollPaneValue = 110;
//ArrayList<JFrame> frame = new ArrayList<>();
public MyWindow()
{
frame.setTitle("Assignment Planner");
this.contents();
}
private void contents()//make a border above each panel stating "TO-DO" or "COMPLETED"
{//use an arraylist to create containers ArrayList<JPanel> container = new ArrayList<>();
frame.setSize(WINDOW_WIDTH, WINDOW_DEPTH);
panel = new JPanel(new GridLayout(2, 1));
toDoList = new JPanel();
toDoList.setLayout(new /*GridLayout(0,1,5,5)*/BoxLayout(toDoList, BoxLayout.PAGE_AXIS));
toDoList.setPreferredSize(new Dimension(250, 110));
panel.add(toDoList);
completed = new JPanel();
//panelCompleted.setLayout(new GridLayout(0, 1)); //fix like one above
panel.add(completed);
JScrollPane scroll = new JScrollPane(toDoList);
panel.add(scroll); //scroll panes for both panels
JScrollPane scroll2 = new JScrollPane(completed);
panel.add(scroll2);
toDoList.add(Box.createRigidArea(new Dimension(0,1)));
toDoList.add(assignment());
scrollPaneValue += 110; //add these 2 lines of code, beginning after the first two containers to increase jscrollpane
toDoList.setPreferredSize(new Dimension(250, scrollPaneValue));
//toDoList.revalidate(); may not even need
frame.getContentPane().add(panel, BorderLayout.CENTER);//add the panel in the JFrame's content pane in the center
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
JPanel assignment()
{
JPanel container = new JPanel(new GridBagLayout());
container.setMaximumSize(new Dimension(500,100));
GridBagConstraints cDefault = new GridBagConstraints();
cDefault.weightx = 0.5;
cDefault.insets = new Insets(5,5,5,5);
JCheckBox cb;
JLabel dueDate, description;
JButton edit;
cb = new JCheckBox();
GridBagConstraints cCb = new GridBagConstraints();
cCb.weightx = 0.5;
cCb.weighty = 1;
cCb.fill = GridBagConstraints.NONE;//originally none
cCb.gridx = 0;
cCb.gridy = 0;
//cCb.gridwidth = 1;
//cCb.gridheight = 1;
cCb.anchor = FIRST_LINE_START;//may not need, plus needs static import
cCb.insets = cDefault.insets;
cb.setBackground(Color.RED);
container.add(cb, cCb);
dueDate = new JLabel("Due Date");
GridBagConstraints cDueDate = new GridBagConstraints();
cDueDate.gridx = 1;
cDueDate.gridy = 0;
cDueDate.gridwidth = 2;
//cDueDate.fill = GridBagConstraints.HORIZONTAL;
cDueDate.anchor = PAGE_START;
dueDate.setBackground(Color.BLUE);
//cDueDate.anchor = FIRST_LINE_START;
container.add(dueDate, cDueDate);
edit = new JButton("Edit");
GridBagConstraints e = new GridBagConstraints();
e.gridx = 4;
e.gridy = 0;
e.anchor = GridBagConstraints.FIRST_LINE_END;
e.insets = cDefault.insets;
edit.setBackground(Color.GREEN);
container.add(edit, e);
description = new JLabel("Description...");
GridBagConstraints d = new GridBagConstraints();
d.gridx = 1;
d.gridy = 3;
d.gridwidth = 3;
d.fill = GridBagConstraints.HORIZONTAL;
description.setBackground(Color.YELLOW);
container.add(description, d);
container.setBackground(Color.LIGHT_GRAY);//does no fill area behind checkbox
return container;
}
}
What I want the container to look like:
This just concerns my lack of knowledge with GridBagLayout.
Start with the section from the Swing tutorial on How to Use GridBagLayout for working examples and an explanation of all the constraints.
A few things about the code:
//container.setMaximumSize(new Dimension(500,100));
Don't set a maximum size. The layout manager will determine the size of the panel.
//cCb.weightx = 0.5;
//cCb.weighty = 1;
The above code assigns all the extra space of the panel to the check box, since it is the only component with a weightx/y constraint. I doubt you want that. Try commenting out those statements to see what happens.
dueDate.setOpaque(true);
dueDate.setBackground(Color.BLUE);
Yes, that is a good idea to set a background to see the actual size of the component. Problem is a JLabel is transparent by default so the background is never painted. You need need to make your labels opaque if you want to see the background. Another approach to help with debugging is to add LineBorder to the label, then you don't need to worry about transparency.
//e.gridx = 4;
e.gridx = 3;
Be careful with the grid value. You can't just use an value. The first component has a width of 1 and the second a width of 2, so the this component should start at 3.
I can only seem to move components around by using anchor
Actually, I don't this the anchor is doing anything. As I understand it, the anchor only has meaning when the component size is smaller than the grid size. In your original code, only the check box used weightx/y values, so that is the only component where this is true.
The GridBagLayout is one of the most complicated (and flexible) layout manager to use, so yes it takes practice to learn how to use it. Reread the tutorial and play with the constraints.

JTable larger than JFrame

EDIT: Sorry for many edits. I forgot what I wrote by myself.
I use JPanel that has BoxLayout as root Panel for JFrame. I'm adding to this root Panel two other Panels: buttonPanel with FlowLayou and tabbedPane. Each tabbed Pane is created dynamically by pressing second button at the top. In tabbedPane there is a templatePanel with BoxLayout that contains three other general JPanels: Checkboxes Panel with FlowLayout, tablePanel with BorderLayout and another one with BoxLayout.
I'm adding a JTable to tablePanel with BoderLayout.CENTER and after running program JTable is way too big vertically and I need to resize frame. I need to add rows dynamically so I create an empty JTable with my custom DefaultTableModel (I overloaded isCellEditable method, nothing more) and then by checking checkboxes I fill it with data.
JTable is also way too big than maximum rows number it is designed to hold.
What I mean:
How can I shrink it?
I create templatePanel with class's constructor (extends JPanel) by just add.(templatePanel)
code:
public TemplatePanel()
{
model = new DefaultTableModel(new Object[][] {}, new String[]
{"<html>...</html>", "<html>...</html>",
"...", "...", "<html>...</html>",
"<html>...</html>", "...", "...",
"<html>...</html>"})
{
#Override
public boolean isCellEditable(int row, int column)
{
return column == 1 || column == 3;
}
};
templatePanel = new JPanel();
tablePanel = new JPanel();
templatePanel.setLayout(new BoxLayout(templatePanel, BoxLayout.PAGE_AXIS));
tablePanel.setLayout(new BorderLayout());
checkBoxPanel = new JPanel();
checkBoxPanel.setLayout(new FlowLayout());
1 = new JCheckBox("...");
2 = new JCheckBox("...");
3 = new JCheckBox("...");
4 = new JCheckBox("...");
5 = new JCheckBox("...");
6 = new JCheckBox("...");
checkBoxPanel.add(1);
checkBoxPanel.add(2);
checkBoxPanel.add(3);
checkBoxPanel.add(4);
checkBoxPanel.add(5);
checkBoxPanel.add(6);
1.addItemListener(this);
2.addItemListener(this);
3.addItemListener(this);
4.addItemListener(this);
5.addItemListener(this);
6.addItemListener(this);
table = new JTable(model);
scrollPane = new JScrollPane(table);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setTableHeader(new JTableHeader(table.getColumnModel())
{
#Override
public Dimension getPreferredSize()
{
Dimension d = super.getPreferredSize();
d.height = 50;
return d;
}
});
TableColumn firstColumn = table.getColumnModel().getColumn(0);
TableColumn secondColumn = table.getColumnModel().getColumn(1);
TableColumn thirdColumn = table.getColumnModel().getColumn(2);
TableColumn ninthColumn = table.getColumnModel().getColumn(8);
firstColumn.setPreferredWidth(170);
secondColumn.setPreferredWidth(50);
thirdColumn.setPreferredWidth(30);
ninthColumn.setPreferredWidth(100);
table.setRowHeight(30);
tablePanel.add(scrollPane, BorderLayout.NORTH);
templatePanel.add(checkBoxPanel);
templatePanel.add(tablePanel);
add(templatePanel);
}
The basic logic should be:
JTable table = new JTable(model);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
This will get rid of the extra vertical space.
If I understand correctly, you want the frame of the table to be smaller? Is that correct? If you're using BorderLayout, center will cover the entire frame unless you add something in the cardinal directions. Create a box and add it SOUTH to create a cushion between the bottom and the table.
Again, If I'm not understanding this properly I apologize.
Edit:
Have you tried using setPreferredSize(new Dimension(800, 500)) on the scrollpane?

JScrollPane can resize smaller, but JTextArea does not

I have a window containing a JScrollArea, which contains a JPanel which contains a JTextArea. When I resize the window to make it larger, the layout updates perfectly, but if I make the window smaller, the JPanel does not shrink its contents. I attempted to add a ComponentListener on the JScrollArea to resize the JPanel based on the new size of the viewport, but this seems to defeat the purpose of the vertical scroll bar.
UPDATE: The idea here is that the JScrollArea will contain a JPanel (since it can only contain one component for its viewport), and within that JPanel I will be adding multiple JPanels containing components that describe processes that are running to the user. Since there could be any number of these processes running, I need to have some kind of scroll bar functionality available. Hence the component hierarchy I'm using below.
The desired behavior here is that the window can be resized larger or smaller and the text area will wrap its contents accordingly, and a vertical scroll bar will appear if the contents of the JPanel are larger vertically than the window. Any suggestions?
public class TestWindow extends JFrame {
JPanel scrollContentPanel;
JScrollPane scrollPane;
public TestWindow() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel mainPanel = new JPanel();
this.setContentPane(mainPanel);
GridBagLayout mainPanelLayout = new GridBagLayout();
mainPanel.setLayout(mainPanelLayout);
scrollContentPanel = new JPanel();
scrollPane = new JScrollPane();
scrollPane.setViewportView(scrollContentPanel);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
GridBagLayout scrollContentLayout = new GridBagLayout();
scrollContentPanel.setLayout(scrollContentLayout);
JPanel contentEntry = new JPanel();
GridBagConstraints contentEntryConstraints = new GridBagConstraints();
contentEntryConstraints.weightx = 1.0;
contentEntryConstraints.insets = new Insets(3, 3, 5, 3);
contentEntryConstraints.fill = GridBagConstraints.BOTH;
contentEntryConstraints.gridx = 0;
contentEntryConstraints.gridy = 1;
scrollContentPanel.add(contentEntry, contentEntryConstraints);
GridBagLayout contentEntryLayout = new GridBagLayout();
contentEntry.setLayout(contentEntryLayout);
JTextArea descTextArea = new JTextArea();
descTextArea.setEditable(false);
descTextArea.setFont(new Font("Dialog", Font.PLAIN, 11));
descTextArea.setText("This is a description of an arbitrary unspecified length that may easily span multiple lines without any breaks in-between. Therefore it is necessary that the description automatically wrap as appropriate.");
descTextArea.setLineWrap(true);
descTextArea.setWrapStyleWord(true);
GridBagConstraints descTextAreaConstraints = new GridBagConstraints();
descTextAreaConstraints.weightx = 1.0;
descTextAreaConstraints.weighty = 1.0;
descTextAreaConstraints.insets = new Insets(0, 0, 3, 0);
descTextAreaConstraints.fill = GridBagConstraints.BOTH;
descTextAreaConstraints.gridx = 0;
descTextAreaConstraints.gridy = 1;
descTextAreaConstraints.gridwidth = 2;
contentEntry.add(descTextArea, descTextAreaConstraints);
GridBagConstraints scrollPaneConstraints = new GridBagConstraints();
scrollPaneConstraints.insets = new Insets(0, 0, 5, 0);
scrollPaneConstraints.weightx = 1.0;
scrollPaneConstraints.weighty = 1.0;
scrollPaneConstraints.fill = GridBagConstraints.BOTH;
scrollPaneConstraints.gridx = 0;
scrollPaneConstraints.gridy = 0;
mainPanel.add(scrollPane, scrollPaneConstraints);
scrollPane.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent evt) {
super.componentResized(evt);
scrollContentPanel.setPreferredSize(scrollPane.getViewportBorderBounds().getSize());
scrollContentPanel.validate();
}
});
pack();
}
public static void main(String[] args) {
TestWindow wnd = new TestWindow();
wnd.setVisible(true);
}
}
JTextArea should be placed directly into the JScrollPane, as long as that is the component your are trying to scroll. If there are other items you want to scroll with it (and hence the intermediate JPanel), then you might want to consider making that JPanel implement Scrollable so that the JScrollPane knows what to do with it. JTextArea implements Scrollable, which is why it works with JScrollPane out of the box.
no idea about your goal without detailed description, explanation
JTextArea should be placed in JScrollPane
set intial setPreferredSize for JTextArea, e.g. JTextArea(5, 10)
you are put three JPanels (is there reason ??? for this components hierarchy) one to JScrollPane, JTextArea is placed directly into JPanel instead of to the JScrollPane
then usage of ComponentListener is useless and contraproductive

Fit JTable to fill the JPanel

Hi here are my codes for my table settings:
String [] column = {"MacAddress","PcName","OperatingSystem","IpAddress","Port","Status"};
model = new DefaultTableModel(0,column.length);
model.setColumnIdentifiers(column);
mainTable = new JTable(model);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
for(int i=0;i<=column.length-1;i++){
mainTable.getColumnModel().getColumn(i).setPreferredWidth(300);
}
pane = new JScrollPane(mainTable);
pnlTabel = new JPanel();
pnlTabel.setBorder(BorderFactory.createTitledBorder(""));
pnlTabel.setPreferredSize(new Dimension(dim.width*70/100, dim.height*60/100));
pnlTabel.add(pane);
addMainPanel(pnlTabel);
Here is my addMainPanel() function:
public void addMainPanel(Component pnl){
mainPanel.add(pnl);
mainPanel.revalidate();
}
And here is my code for my mainPanel:
mainPanel = new JPanel();
mainPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
add(mainPanel,"Center");
and I'm using border layout for my frame:
setLayout(new BorderLayout(0,0));
My problem is that, even i use this set of code to set my JTable to fit but it seems to fail all the this, this code:
mainTable.setAutoResizeMode(JTa![enter image description here][1]ble.AUTO_RESIZE_OFF);
for(int i=0;i<=column.length-1;i++){
mainTable.getColumnModel().getColumn(i).setPreferredWidth(300);
}
When is use that code, my jtable does not resize but only add on a horizontal scroll bar at the bottom.
No offense meant but .. your code and consequently your question is a mess ;-) Plus you don't explain what exactly you want to achieve.
Trying to detangle, taking the nested layouts/resizing characteristics (as seen in the snippets, might not be complete):
frame // BorderLayout
mainPanel // FlowLayout
pnlTabel // FlowLayout, hard-coded prefSize
pane // scrollPane
mainTable // auto-resize-off
Aside: intentionally kept untelling names to demonstrate how mixing naming schemes tend to contribute to overall confusion :-) Doesn't really matter whether you decide for pre or postFixing some type-related marker, but if you do be consistent.
In that hierarchy, there are two levels of FlowLayout which basically will layout their children at their respective prefs and adjusting their own pref accordingly, lest the pref were hard-coded on the level of the pnlTable: however the table's pref will be changed (by changing the column prefs) it cannot bubble further up because ... hard-coding the pref leads not calculating its size (neither by layoutManager and nor uiDelegate, both never get a chance to do it)
Another issue - the more interesting one :-) - is that the JScrollPane is somewhat special in
calculating its own prefSize from its view's pref/scrollablePrefViewportSize depending on whether or not the view implements Scrollable (JTable does so, though in a crappy way)
being a validationRoot: invalidating the view (or any children) doesn't bubble further up the hierarchy
Assuming that you want the table's scrollPane to grow if the prefWidts of the columns change, there are two thingies to tweak:
implement table's getPreferredScrollableWidth to return a value calculated based on the prefWidth of the columns
revalidate a container higher up in the hierarchy
Some code to play with:
final JTable table = new JTable(50, 10) {
// properties to base a reasonable prefScrollable size
int visibleColumns = 3;
int visibleRows = 10;
// hard-coded default in super
Dimension dummySuper = new Dimension(450, 400);
#Override
public Dimension getPreferredScrollableViewportSize() {
Dimension dim = super.getPreferredScrollableViewportSize();
if (!dummySuper.equals(dim)) return dim;
dim = new Dimension();
for (int column = 0; column < Math.min(visibleColumns, getColumnCount()); column++) {
dim.width += getColumnModel().getColumn(column).getPreferredWidth();
}
dim.height = visibleRows * getRowHeight();
return dim;
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
for (int i = 0; i < table.getRowCount(); i++) {
table.setValueAt("row: " + i, i, 0);
}
JComponent tablePanel = new JPanel();
tablePanel.add(new JScrollPane(table));
Action sizeColumns = new AbstractAction("size columns") {
int prefWidth = 75;
#Override
public void actionPerformed(ActionEvent e) {
int newWidth = prefWidth + 15;
for (int i = 0; i < table.getColumnCount(); i++) {
if (table.getColumnModel().getColumn(i).getPreferredWidth() == prefWidth)
table.getColumnModel().getColumn(i).setPreferredWidth(newWidth);
}
prefWidth = newWidth;
// revalidate "higher up" than the table itself
frame.revalidate();
}
};
frame.add(new JButton(sizeColumns), BorderLayout.SOUTH);
If you want a JTable to fill the available space, you should put it inside a JPanel which has a BorderLayout layout manager. Also don't forget about the JScrollPane which ensures that if the table doesn't fit into the view (e.g. too many rows), scrollbars will appear:
JFrame frame = new JFrame();
// set up frame
JTable table = new JTable();
// Set up table, add data
// Frame has a content pane with BorderLayout by default
frame.getContentPane().add( new JScrollPane( table ), BorderLayout.CENTER );
If you have other content you wish to display besides the table, you can add those to the NORTH, SOUTH, EAST, WEST parts of the content panel (which can be wrapped into other panels if more components are to be placed there).

Categories

Resources