Reputation: 183
So I'm writing a GUI for a complicated program I'm developing, and I get tired of trying to get components to scale correctly when the window is resized.
At first I was using several layouts inside the jframe, and each jpanel to try and place the components correctly and scale them appropriately. Naturally, I got fed up with them, and I started trying to scale and set the x,y positions of the components dynamically (it's so much easier :D).
Basically I'm trying to divide the screen into three sections left margin (JSplitPane), center (JTabbedPane), and right margin (JSplitPane). I don't think the internal components matter at this point. The main problem is the right JSplitPane scales over the whole window despite my using setBounds() to place the x,y over on the right and set the size to 21% of the total width. It seems to interact weird with the other panels.
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.Dimension;
@SuppressWarnings("deprecation")
public class test extends JFrame implements WindowListener {
/* Constants =========================================================================*/
private final double LEFT_SIZE = .21;
private final double CENTER_SIZE = .58;
private final double RIGHT_SIZE = .21;
private final int TOP_PADDING = 50;
private final int LEFT_PADDING = 4;
private final int RIGHT_PADDING = 4;
private final int BOTTOM_PADDING = 4;
private final int MIN_WIDTH = 640;
private final int MIN_HEIGHT = 480;
public static final String INIT_TITLE = "TestFrame v0.01";
/* End Constants =====================================================================*/
/* Instance Variables ================================================================*/
private int contentWidth;
private int contentHeight;
/* End Instance Variables ============================================================*/
/* Objects ===========================================================================*/
public static test window;
/* Begin Frame Design =========================================================== */
private JSplitPane left;
private JButton button1; private JButton button2;
private JTabbedPane center;
private JPanel panel1; private JPanel panel2;
private JSplitPane right;
private JButton button3; private JButton button4;
/* End Frame Design ============================================================= */
/* End Objects ====================================================================== */
/** Initializes and Places all GUI elements **/
public test ( String windowName ) {
super(windowName); //call parent constructor
this.addWindowListener(this); //adds window event functionality such as close
this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH); //Starts program maximized
this.setMinimumSize(new Dimension(MIN_WIDTH,MIN_HEIGHT));
this.setVisible(true);
this.setMaximumSize(this.getSize());
/* Begin Init JFrame this ------------------------------------------------------------ */
button1 = new JButton("button1");
button2 = new JButton("button2");
left = new JSplitPane(JSplitPane.VERTICAL_SPLIT, button1, button2);
left.setResizeWeight(1);
button3 = new JButton("button3");
button4 = new JButton("button4");
right = new JSplitPane(JSplitPane.VERTICAL_SPLIT, button3, button4);
right.setResizeWeight(.25);
panel1 = new JPanel();
panel2 = new JPanel();
center = new JTabbedPane();
center.addTab("Panel1", panel1);
center.addTab("Panel2", panel2);
this.add(left);
this.add(center);
this.add(right);
this.addComponentListener(new ComponentListener() {
@Override
public void componentResized (ComponentEvent e) {
window.contentWidth = window.getWidth() - window.LEFT_PADDING - window.RIGHT_PADDING;
window.contentHeight = window.getHeight() - window.TOP_PADDING - window.BOTTOM_PADDING;
window.left.setBounds ( 0, 0, (int)(window.contentWidth * window.LEFT_SIZE), window.contentHeight);
window.center.setBounds ( window.left.getWidth(), 0, (int)(window.contentWidth * window.CENTER_SIZE), window.contentHeight);
window.panel1.setBounds ( 0, 0, (int)(window.contentWidth * window.CENTER_SIZE), window.contentHeight);
window.panel2.setBounds ( 0, 0, (int)(window.contentWidth * window.CENTER_SIZE), window.contentHeight);
window.right.setBounds ( window.left.getWidth() + window.center.getWidth(), 0, (int)(window.contentWidth * window.RIGHT_SIZE), window.contentHeight);
}
public void componentHidden (ComponentEvent e) {}
public void componentMoved (ComponentEvent e) {}
public void componentShown (ComponentEvent e) {}
});
/* End Init JFrame this -------------------------------------------------------------- */
}
// window event abstracts
@Override
public void windowClosing (WindowEvent event) { window.dispose(); System.exit(0); }
public void windowClosed (WindowEvent event) {}
public void windowDeiconified (WindowEvent event) {}
public void windowIconified (WindowEvent event) {}
public void windowActivated (WindowEvent event) {}
public void windowDeactivated (WindowEvent event) {}
public void windowOpened (WindowEvent event) {}
public static void main(String[] args){
window = new test(INIT_TITLE);
window.setVisible(true);
}
}
Upvotes: 4
Views: 8213
Reputation: 205775
I don't think the internal components matter at this point.
As discussed in Should I avoid the use of set[Preferred|Maximum|Minimum]Size methods in Java Swing?, nothing could be further from the truth. Correct use of layouts relies on a component's preferred size. That size is carefully calculated based on the contents. Second guessing, as shown in your example, is doomed to fail.
Instead, add components and pack()
the frame. In the example below, the center panel returns an arbitrary result to show how pack()
does its work.
Addendum: Two additional points helpfully adduced by @mKorbel:
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
See also this example that shows how to use setDividerLocation()
in invokeLater()
.
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import java.awt.Dimension;
import java.awt.EventQueue;
public class Test extends JFrame {
public static final String INIT_TITLE = "TestFrame v0.02";
public static Test window;
private JSplitPane left;
private JTabbedPane center;
private JSplitPane right;
public Test(String windowName) {
super(windowName);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
left = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
new JButton("button1"), new JButton("button2"));
left.setResizeWeight(0.5);
right = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
new JButton("button3"), new JButton("button4"));
right.setResizeWeight(0.5);
center = new JTabbedPane();
center.addTab("Panel1", new MyPanel());
center.addTab("Panel2", new MyPanel());
this.add(left, BorderLayout.WEST);
this.add(center, BorderLayout.CENTER);
this.add(right, BorderLayout.EAST);
this.pack();
this.setLocationByPlatform(true);
this.setVisible(true);
}
private static class MyPanel extends JPanel {
private Dimension d = new Dimension(320, 240);
@Override
public Dimension getPreferredSize() {
return d;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
window = new Test(INIT_TITLE);
window.setVisible(true);
}
});
}
}
Upvotes: 3