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?
Related
Image of my GUI.
I am trying to add components to two JPanel containers and then add those panels as cards. I want the checkboxes after labels in a vertical manner. The problem I am facing is that the components are coming in a grid of two columns:
public class MyFrame extends JFrame {
MyFrame(int width, int height, String title){
setTitle(title);
setSize(width, height);
JPanel internalJP1 = new JPanel(new GridLayout(5,1));
JLabel hobby = new JLabel("Enter your hobbies:");
JCheckBox cricket = new JCheckBox("Cricket");
JCheckBox music = new JCheckBox("Music");
JCheckBox drawing = new JCheckBox("Drawing");
JCheckBox dancing = new JCheckBox("Dancing");
JCheckBox other = new JCheckBox("Other");
internalJP1.add(hobby);
internalJP1.add(cricket);
internalJP1.add(music);
internalJP1.add(drawing);
internalJP1.add(dancing);
internalJP1.add(other);
JPanel internalJP2 = new JPanel(new GridLayout(4,1));
JLabel payment = new JLabel("Payment by:");
ButtonGroup buttonGroup = new ButtonGroup();
JRadioButton cheque = new JRadioButton("Cheque", false);
JRadioButton cash = new JRadioButton("Cash", false);
JRadioButton debitCard = new JRadioButton("Debit Card", false);
JRadioButton creditCard = new JRadioButton("Credit Card", false);
buttonGroup.add(cheque);
buttonGroup.add(cash);
buttonGroup.add(debitCard);
buttonGroup.add(creditCard);
internalJP2.add(payment);
internalJP2.add(cheque);
internalJP2.add(cash);
internalJP2.add(debitCard);
internalJP2.add(creditCard);
Container c = getContentPane();
CardLayout cl = new CardLayout();
c.setLayout(cl);
c.add(internalJP1,"crd1");
c.add(internalJP2,"crd2");
cl.show(c,"crd1");
}
}
public class Jtest {
public static void main(String[] args) {
MyFrame frame = new MyFrame(300,200,"FirstFrame");
frame.setVisible(true);
}
}
Just change this line of code (in constructor of class MyFrame)
JPanel internalJP1 = new JPanel(new GridLayout(5,1));
to this
JPanel internalJP1 = new JPanel(new GridLayout(0,1));
i.e. replace 5 with 0
I find GridLayout to not be intuitive. When the row parameter of GridLayout constructor is zero, then each row will contain exactly the number of columns indicated. Hence new GridLayout(0, 1) will ensure that each row (in the grid) will contain exactly one column and it will create as many rows as required in order to ensure this.
Note that GridLayout is not the only layout manager to use when you want to place GUI components in a single column. Swing also has BoxLayout, GridBagLayout, GroupLayout and SpringLayout.
There are also third party layout managers including JGoodies and MiG Layout.
The fact that you are using a CardLayout to view one panel or the other does not affect the layout of those panels. Your problem is entirely related to the layout of the 2 panels.
There are 2 easy ways to fix the panels to make them 1-column:
fix their number of rows so that it is >= the number of elements that you actually add. Now, you have JPanel internalJP1 = new JPanel(new GridLayout(5,1)); - but add 6 elements. If you change it to JPanel internalJP1 = new JPanel(new GridLayout(6,1));, you will solve the problem for your 1st panel. The same fix applies to your second panel. Even better, use 0 to make the layout use as many rows as it needs (see docs).
use a vertical BoxLayout and do not worry about the number of elements at all - just stack them vertically. This has the additional advantage that they look better, because even if you give the layout more size than it needs, they still stack together nicely: JPanel internalJP1 = new JPanel(); internalJP1.setLayout(new BoxLayout(internalJP1, BoxLayout.Y_AXIS));
I have the following code taken from GeeksforGeeks that displays the contents of a 2-d array in JTable using JScrollPane:
public class JTableExamples {
// frame
JFrame f;
// Table
JTable j;
// Constructor
JTableExamples()
{
// Frame initiallization
f = new JFrame();
// Frame Title
f.setTitle("JTable Example");
// Data to be displayed in the JTable
String[][] data = {
{ "Kundan Kumar Jha", "4031", "CSE" },
{ "Anand Jha", "6014", "IT" }
};
// Column Names
String[] columnNames = { "Name", "Roll Number", "Department" };
// Initializing the JTable
j = new JTable(data, columnNames);
j.setBounds(30, 40, 200, 300);
// adding it to JScrollPane
JScrollPane sp = new JScrollPane(j);
f.add(sp);
// Frame Size
f.setSize(500, 200);
// Frame Visible = true
f.setVisible(true);
}
What I am trying to do is add a simple Component (like JButton) underneath the table but it does not seem to work. I tried modifying the code by adding the JButton to JPanel and adding JPanel to the frame:
JButton button = new JButton("Back");
JPanel panel = new JPanel();
panel.add(button);
f.add(sp);
f.add(panel);
But this simply deletes the entire table and replaces it with a single button. I also tried adding the button to JPanel and adding that JPanel to JScrollPane:
JButton button = new JButton("Back");
JPanel panel = new JPanel();
panel.add(button);
sp.add(panel);
f.add(sp);
But this did not seem to change anything. I also tried to tinker with preferred and maximum size of JScrollPanel to no avail - it always occupies the entire screen and prevents JButton from appearing on the screen.
Not shooting for design here, just functionality: have a JButton appear underneath my JTable. Any suggestions will be greatly appreciated. Thank you in advance!
The default layout manager of a JFrame is the BorderLayout.
f.add(sp);
f.add(panel);
When you don't specify a constraint for the BorderLayout the CENTER is assumed. You can only have a single component added to the CENTER.
Instead your code should be:
f.add(sp, BorderLayout.CENTER);
f.add(panel, BorderLayout.PAGE_END);
Note the default layout manager for a JPanel is the FlowLayout. So the button will be horizontally centered in the panel.
Also, instead of using a JPanel, try adding the button directly to the PAGE_END of the frame to see the difference.
Read the section from the Swing tutorial on Using Layout Manager for more information and examples for using each of the different layout managers to understand the differences of the above suggestions.
Edit:
Is there a way to decrease the height of the table
If you know you have a small table then you can use:
table.setPreferredScrollableViewportSize(table.getPreferredSize());
This will make the scroll pane the size of the table.
Then you use:
//f.setSize(500, 200);
f.pack();
Now all components will be displayed at their preferred size.
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.
I'm trying to create a JTable with the column headers defined in colName using a DefaultTableModel, then adding the table to a JScrollPane then to a JPanel. However, when I add the panel to my JFrame, only the panel shows up, not the table. I am using similar code in another table, and that one shows up fine, only difference being the number of columns and variable names.
What am I missing?
My code :
//Column Names
final String[] colNames = {"Item", "Count"};
DefaultTableModel dtm = new DefaultTableModel(0, colNames.length);
//Panel to hold Table
JPanel j = new JPanel(new BorderLayout());
j.setBounds(9, 78, 267, 254);
//Colored to see if the panel has been added
j.setBackground(Color.RED);
//Set Column Headers
dtm.setColumnIdentifiers(colNames);
//Jtable with model
JTable t = new JTable(dtm);
t.setBackground(Color.GREEN);
t.getTableHeader().setReorderingAllowed(false);
t.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
t.getColumnModel().getColumn(0).setPreferredWidth(113);
t.doLayout();
j.add(new JScrollPane(t), BorderLayout.CENTER);
I would suggest that the column's are being overridden by those reported back by the table model. You could instead use...
String[] colNames = {"Item", "Count"};
DefaultTableModel dtm = new DefaultTableModel(colNames, 0);
JPanel j = new JPanel(new BorderLayout());
JTable t = new JTable(dtm);
t.setBackground(Color.GREEN);
t.getTableHeader().setReorderingAllowed(false);
t.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
t.getColumnModel().getColumn(0).setPreferredWidth(113);
j.add(new JScrollPane(t), BorderLayout.CENTER);
Instead...
Without seeing the code you're using to put the table on the frame, it's difficult to comment further, however...
Avoid using setBounds, it's pointless in this context any way.
The background color will actually be defined more by the view port then the table or panel until the table is either configured to fill the empty space or has enough rows to fill the empty space
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).