Disposing of GUI Elements - java

I have several GUI elements added to a JPanel. The JPanel is added to a JScrollPane. The JScrollPane is added to a JFrame (CENTER section of a BorderLayout).
At times I need to remove the JScrollPane and make the space available for other elements. I've provided a method for that. Want to make sure that this method disposes of all resources used by the old JScrollPane and makes them available for Garbage Collection. Please see code below. Is my clearCenter() method sufficient for this task? Is there a better way to do it?
Thanks.
import java.awt.*;
import javax.swing.*;
public class MyGui extends JFrame {
private JScrollPane scroll;
private JPanel panel;
private JButton button1;
private JButton button2;
private JButton button3;
private JButton button4;
// Constructor
public MyGui() {
super("Playback");
setSize(250, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BorderLayout layout = new BorderLayout();
setLayout(layout);
panel = new JPanel();
GridLayout grid = new GridLayout(0, 1, 30, 30);
panel.setLayout(grid);
button1 = new JButton("Button1");
button2 = new JButton("Button2");
button3 = new JButton("Button3");
button4 = new JButton("Button4");
panel.add(button1);
panel.add(button2);
panel.add(button3);
panel.add(button4);
scroll = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
add(scroll, BorderLayout.CENTER);
add(new JLabel("South", JLabel.CENTER),BorderLayout.SOUTH);
add(new JLabel("North", JLabel.CENTER),BorderLayout.NORTH);
add(new JLabel("East", JLabel.CENTER),BorderLayout.EAST);
add(new JLabel("West", JLabel.CENTER),BorderLayout.WEST);
setVisible(true);
}
public void clearCenter() {
button1 = null;
button2 = null;
button3 = null;
button4 = null;
panel = null;
remove(scroll);
scroll = null;
}
}

At times I need to remove the JScrollPane and make the space available for other elements.
Use a CardLayout as shown in this answer. And I would not worry too much about disposing of a scroll pane, keep it in memory. When it is next needed, update the scroll pane contents then flip back to that card in the layout.
Resetting the content of the scroll-pane can be done like below. Activate the first button to see the button panel replaced by the yellow panel as the view of the scroll-pane. Note that this code is a 'ready to run' MCVE (with a main(String[]) to show it onscreen). Please post MCVE code in future.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MyGui extends JFrame {
private JScrollPane scroll;
private JPanel panel;
private JPanel brightPanel;
private JButton button1;
private JButton button2;
private JButton button3;
private JButton button4;
// Constructor
public MyGui() {
super("Playback");
setSize(250, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BorderLayout layout = new BorderLayout();
setLayout(layout);
// create the panel, but don't add it yet.
brightPanel = new JPanel();
brightPanel.setBackground(Color.YELLOW);
panel = new JPanel();
GridLayout grid = new GridLayout(0, 1, 30, 30);
panel.setLayout(grid);
button1 = new JButton("Button1");
button2 = new JButton("Button2");
button3 = new JButton("Button3");
button4 = new JButton("Button4");
panel.add(button1);
panel.add(button2);
panel.add(button3);
panel.add(button4);
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
changeViews();
}
};
button1.addActionListener(listener);
scroll = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
add(scroll, BorderLayout.CENTER);
add(new JLabel("South", JLabel.CENTER), BorderLayout.SOUTH);
add(new JLabel("North", JLabel.CENTER), BorderLayout.NORTH);
add(new JLabel("East", JLabel.CENTER), BorderLayout.EAST);
add(new JLabel("West", JLabel.CENTER), BorderLayout.WEST);
setVisible(true);
}
public void changeViews() {
scroll.setViewportView(brightPanel);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new MyGui();
}
};
SwingUtilities.invokeLater(r);
}
}

Related

JScrollPane not showing in my JTextArea

I have a JTextArea named as txtChat which is used as the chatting area in my chatbot. I have created a JScrollPane scroll = new JScrollPane(txtChat) and added my txtChat inside the JScrollPane. My JTextArea is being put inside a Panel which has BorderLayout, so I have added my scroll to the panel which contains my JTextArea chatPanel.add(scroll, BorderLayout.East). BUT IT IS NOT WORKING! Like when my conversation go longer, the scroll does not appear!
Sorry the code is quite long, so I just pasted the essential parts here.
public class GUI_V3 extends JFrame {
//mainPanel into Frame
private JPanel mainPanel = new JPanel();
//clock component
private JTextField timeF = new JTextField(8);
//Button component
private Box btnBox = Box.createHorizontalBox();
private JButton button1 = new JButton("Add Keywords");
private JButton button2 = new JButton("Help");
//Top menu bar
private JPanel topPanel = new JPanel();
//Typing Area
private JTextField txtEnter = new JTextField();
//Typing Panel
private JPanel typingPanel = new JPanel();
//Chat Area
private JTextArea txtChat = new JTextArea();
private JPanel chatPanel = new JPanel();
//Scroll
private JScrollPane scroll = new JScrollPane(txtChat);
private String name;
private Conversation_V3 convo = new Conversation_V3();
public GUI_V3(){
//Frame attributes
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(1000,1000);
this.setVisible(true);
//this.setResizable(false);
this.setLocationRelativeTo(null);
this.setTitle("Welcome to Haidilao");
//clock attributes
timeF.setEditable(false);
timeF.setFont(new Font("Arial",Font.BOLD,48));
timeF.setBackground(new Color(228,224,199));
timeF.setHorizontalAlignment(SwingConstants.RIGHT);
//button attributes
button1.setFont(new Font("Arial",Font.PLAIN,38));
button2.setFont(new Font("Arial",Font.PLAIN,38));
btnBox.add(button1);
btnBox.add(Box.createRigidArea(new Dimension(10,70)));
btnBox.add(button2);
//Add ActionListener to buttons
Button1Handler handlerB1 = new Button1Handler();
button1.addActionListener(handlerB1);
Button2Handler handlerB2 = new Button2Handler();
button2.addActionListener(handlerB2);
//Top menu bar
topPanel.setLayout(new BorderLayout());
topPanel.add(btnBox, BorderLayout.WEST);
topPanel.add(timeF, BorderLayout.EAST);
topPanel.setBackground(new Color(228,224,199));
//Typing Area Attribute
txtEnter.setFont(new Font("DejaVu Sans",Font.PLAIN,30));
typingPanel.setBorder(BorderFactory.createEmptyBorder(10,20,10,20));
typingPanel.setLayout(new BorderLayout());
typingPanel.setBackground(new Color(228,224,199));
typingPanel.add(txtEnter);
//Add action listener for typing area
TypingHandler handlerT = new TypingHandler();
txtEnter.addActionListener(handlerT);
//Chat Area Attribute
txtChat.setEditable(false);
txtChat.setFont(new Font("DejaVu Sans",Font.PLAIN,30));
txtChat.setLineWrap(true);
txtChat.setWrapStyleWord(true);
chatPanel.setBorder(BorderFactory.createEmptyBorder(5,20,10,20));
chatPanel.setLayout(new BorderLayout());
chatPanel.setBackground(new Color(228,224,199));
chatPanel.add(txtChat, BorderLayout.CENTER);
chatPanel.add(scroll, BorderLayout.EAST);
scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
//mainPanel Layout
mainPanel.setLayout(new BorderLayout());
mainPanel.add(topPanel, BorderLayout.NORTH);
mainPanel.add(typingPanel, BorderLayout.SOUTH);
mainPanel.add(chatPanel, BorderLayout.CENTER);
//Add components to the JFrame
this.add(mainPanel);
//Add actionListener to clock
ClockHandler handlerC = new ClockHandler();
Timer t = new Timer(500, handlerC);
t.start();
//display greetings and ask for name
name = greetings();
addText(botSays("Welcome! " + name + ", you can ask me anything about the menu by providing keywords."));
}
//Action handler for txtEnter
private class TypingHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
//grab input
String input = txtEnter.getText();
//add to chat area
txtChat.append(name + ": " + input + "\n");
//set input field to empty
txtEnter.setText("");
SoundEffect.music();
convo.setInput(input);
addText(botSays(convo.getReply()));
//set the chat area to bottom of scroll
txtChat.setCaretPosition(txtChat.getDocument().getLength());
}
}
Please find a working solution and tweak this as per your requirements.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class TestFrame extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestFrame frame = new TestFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TestFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
JTextArea textArea = new JTextArea();
scrollPane.setViewportView(textArea);
}
}
Hope this will be helpful. :-)

JAVA JTextField doesnt show up

So Im trying to make a little program to calculate the area of a specific shape.
The user should be able to make a input via a textfield (Like the height and stuff of the shapes). The he should press a button and the price should get printed.
But it doesnt show up.
Code:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Rechner extends JFrame implements ActionListener{
private static JButton button1;
private static JButton button2;
private static JButton button3;
private static JButton button4;
private static JTextField numberField;
private JPanel jpanel;
public Rechner(String titel){
super(titel);
jpanel = new JPanel();
numberField = new JTextField(1500);
add(numberField, BorderLayout.CENTER);
button1 = new JButton("Rechteck");
button1.setBounds(10, 10, 150, 30);
button1.addActionListener(this);
add(button1);
button2 = new JButton("Dreieck");
button2.setBounds(170, 10, 150, 30);
button2.addActionListener(this);
add(button2);
button3 = new JButton("Trapez");
button3.setBounds(330, 10, 150, 30);
button3.addActionListener(this);
add(button3);
button4 = new JButton("Parallelogramm");
button4.setBounds(490, 10, 150, 30);
button4.addActionListener(this);
add(button4);
setResizable(false);
}
public static void main(String[] args) {
Rechner frame = new Rechner("Menu");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(660, 400);
frame.setLayout(null);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button1){
System.out.println("fff");
}
String numberStr = numberField.getText();
}
}
The default layout manager of a JFrame (well, of its content pane in fact) is BorderLayout.
Without specified constraints , the component is added to BorderLayout.CENTER, so
add(component);
is the same as
add(component, BorderLayout.CENTER);
and each component added this way will replace the last component added to the center.
Also note that setBounds will have no effect if there is a layout manager, and that you create a JPanel that you never use.
Finally, you may want to have a look at this guide : A Visual Guide to Layout Managers
This line is mainly the problem:
add(numberField, BorderLayout.CENTER);
Is causing the TextField to fill the entire space. Then, the next time you add a component to the JFrame with BorderLayout.CENTER, the JTextField gets replaced. To fix this:
super(titel);
jpanel = new JPanel();
add(jpanel, BorderLayout.NORTH); //adding the jpanel
button1 = new JButton("Rechteck");
jpanel.add(button1);
button1.setBounds(10, 10, 150, 30);
//adding the other buttons to the JPanel...
//...
//...
button4.addActionListener(this);
button3.addActionListener(this);
button2.addActionListener(this);
button1.addActionListener(this);
numberField = new JTextField(1500);
add(numberField);//this will cause it to fill the remaining space
setResizable(false);
Explanation:
The buttons should go into the JPanel you created, and the JPanel should go into the JFrame's NORTH. That way they don't cover the JFrame

BorderLayout not working JFrame

For some reason I can't get the BorderLayout to set the way it's supposed to. Just would like to know where I'm going wrong.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ColorFactory extends JFrame
{
final int width = 500;
final int height = 300;
private JPanel buttonPanel;
private JPanel radioButtonPanel;
private JLabel msgChangeColor;
public ColorFactory()
{
setTitle("Color Factory");
setSize(width, height);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
createTopPanel();
add(buttonPanel, BorderLayout.NORTH);
createBottomPanel();
add(radioButtonPanel, BorderLayout.SOUTH);
msgChangeColor = new JLabel("Top buttons change the panel color and bottom radio buttons change the text color.");
add(msgChangeColor, BorderLayout.CENTER);
pack();
}
private void createTopPanel()
{
buttonPanel = new JPanel();
setLayout(new FlowLayout());
JButton redButton = new JButton("Red");
redButton.setBackground(Color.RED);
redButton.addActionListener(new ButtonListener());
redButton.setActionCommand("R");
JButton orangeButton = new JButton("Orange");
orangeButton.setBackground(Color.ORANGE);
orangeButton.addActionListener(new ButtonListener());
orangeButton.setActionCommand("O");
JButton yellowButton = new JButton("Yellow");
yellowButton.setBackground(Color.YELLOW);
yellowButton.addActionListener(new ButtonListener());
yellowButton.setActionCommand("Y");
buttonPanel.add(redButton);
buttonPanel.add(orangeButton);
buttonPanel.add(yellowButton);
}
private void createBottomPanel()
{
radioButtonPanel = new JPanel();
setLayout(new FlowLayout());
JRadioButton greenRadioButton = new JRadioButton("Green");
greenRadioButton.setBackground(Color.GREEN);
greenRadioButton.addActionListener(new RadioButtonListener());
greenRadioButton.setActionCommand("G");
JButton blueRadioButton = new JButton("Blue");
blueRadioButton.setBackground(Color.BLUE);
blueRadioButton.addActionListener(new RadioButtonListener());
blueRadioButton.setActionCommand("B");
JButton cyanRadioButton = new JButton("Cyan");
cyanRadioButton.setBackground(Color.CYAN);
cyanRadioButton.addActionListener(new RadioButtonListener());
cyanRadioButton.setActionCommand("C");
radioButtonPanel.add(greenRadioButton);
radioButtonPanel.add(blueRadioButton);
radioButtonPanel.add(cyanRadioButton);
}
private class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String actionColor = e.getActionCommand();
if(actionColor.equals("R"))
{
buttonPanel.setBackground(Color.RED);
radioButtonPanel.setBackground(Color.RED);
}
if(actionColor.equals("O"))
{
buttonPanel.setBackground(Color.ORANGE);
radioButtonPanel.setBackground(Color.ORANGE);
}
if(actionColor.equals("Y"))
{
buttonPanel.setBackground(Color.YELLOW);
radioButtonPanel.setBackground(Color.YELLOW);
}
}
}
private class RadioButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String actionTextColor = e.getActionCommand();
if(actionTextColor.equals("G"))
{
msgChangeColor.setForeground(Color.GREEN);
}
if(actionTextColor.equals("B"))
{
msgChangeColor.setForeground(Color.BLUE);
}
if(actionTextColor.equals("C"))
{
msgChangeColor.setForeground(Color.CYAN);
}
}
}
public static void main(String[] args)
{
ColorFactory run = new ColorFactory();
run.setVisible(true);
}
}
The problem is you are changing the layout manager for the frame when you create your top and bottom panels...
private void createTopPanel() {
buttonPanel = new JPanel();
setLayout(new FlowLayout()); // <--- This is call setLayout on the frame
This is why it's dangerous to...
Extend from something like JFrame directly...
Dynamically build components
It's all to easy to lose context and start effecting components you didn't actually want to...
Another problem (besides the one posted by MadProgrammer) is that you add your components to the JFrame itself.
You should add content to the content pane of the frame which you can get by calling JFrame.getContentPane().
Example:
JFrame f = new JFrame("Test");
Container c = f.getContentPane();
c.add(new JButton("In Center"), BorderLayout.CENTER);
c.add(new JButton("At the Bottom"), BorderLayout.SOUTH);
c.add(new JButton("At the Top"), BorderLayout.NORTH);
c.add(new JButton("On the Left"), BorderLayout.WEST);
c.add(new JButton("On the Right"), BorderLayout.EAST);
You can set/change the content panel by calling JFrame.setContentPane(). The default content panel already has BorderLayout so you don't even need to change it nor to set a new panel.

Placing of JPanels on the JFrames is not correct

I wrote a program to compose a GUI using swing/awt framework for my assignment. So far, I am able to get the pieces working together, but when I put them all into a JFrame, they are not coming out as expected.
I have recently started working on Java GUI framework, and not sure what is missing in my code. How can I get this working properly?
I am also attaching the screen shots (see at the bottom) of the output I am getting.
public class MainFrame extends JFrame {
public MainFrame() {
addComponentsToPane(this.getContentPane());
}
private void addComponentsToPane(Container pane) {
// Set layout
GridBagConstraints gbc = new GridBagConstraints();
this.setTitle("Test tool");
this.setSize(600, 650);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new GridLayout(2, 1));
// Add video JComponent
mMainPanel = new MainPanel();
pane.add(mMainPanel, 0);
// Add conference screen panel
mFeedPanel = new FeedPanel();
pane.add(mFeedPanel, 1);
// Add a button panel
mButtonPanel = new ButtonPanel();
pane.add(mButtonPanel, 2);
this.setResizable(true);
this.setVisible(true);
this.pack();
}
}
// In actual output, there is 1 screen in this panel.
// mScreen1 is derived from JComponent object.
public class MainPanel() extends JPanel {
public MainPanel() {
addMainPanelComponents();
}
private void addMainPanelComponents() {
this.setSize(352, 240);
setBackground(Color.yellow);
setLayout(new GridLayout(1, 2));
add(mScreen);
setVisible(true);
}
}
// In actual output, there are 3 screens in this panel. I have shown code for 1 screen only
// mScreen1 is derived from JComponent object.
public class FeedPanel extends JPanel {
public FeedPanel() {
addFeedPanelComponents();
}
private void addFeedPanelComponents() {
String img1 = "images/screen1.png";
setSize(352, 150);
setBackground(Color.yellow);
setLayout(new GridLayout(1, 3));
Image image1 = ImageIO.read(new File(img1));
mScreen1.setImage(image1);
add(mScreen1);
setVisible(true);
}
}
public class ButtonPanel extends JPanel {
public ButtonPanel() {
addButtonPanelComponents();
}
private void addButtonPanelComponents() {
this.setSize(352, 150);
this.setBackground(Color.yellow);
this.setLayout(new GridLayout(1,
5));
// Add Button to panel
mStartButton = new JButton("Start");
this.add(mStartButton);
mStartButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
StartButtonActionListener(ae);
}
});
mStopButton = new JButton("Stop");
this.add(mStopButton);
mStopButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
StopButtonActionListener(ae);
}
});
setVisible(true);
}
}
This comes by default on running the code.
This comes after manually resizing the frame.
The combination of BorderLayout , GirdLayout and BoxLayout can do this for you(Actually it's not the only choice).
Here is the code:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GridLayoutTest {
public void createUI(){
JFrame frame = new JFrame();
JPanel topPanel = new TopPanel();
JPanel buttomPanel = new ButtomPanel();
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(topPanel,BorderLayout.CENTER);
mainPanel.add(buttomPanel,BorderLayout.SOUTH);
frame.add(mainPanel,BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
GridLayoutTest test = new GridLayoutTest();
test.createUI();
}
#SuppressWarnings("serial")
class TopPanel extends JPanel{
public TopPanel(){
setLayout(new GridLayout(2, 3));
ImageIcon icon = new ImageIcon("capture.png");
JLabel label1 = new JLabel(icon);
label1.setVisible(false);
JLabel label2 = new JLabel(icon);
JLabel label3 = new JLabel(icon);
label3.setVisible(false);
JLabel label4 = new JLabel(icon);
JLabel label5 = new JLabel(icon);
JLabel label6 = new JLabel(icon);
add(label1);
add(label2);
add(label3);
add(label4);
add(label5);
add(label6);
}
}
#SuppressWarnings("serial")
class ButtomPanel extends JPanel{
public ButtomPanel(){
JButton startButton = new JButton("start");
JButton stopButton = new JButton("stop");
JButton recordButton = new JButton("record");
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(Box.createHorizontalGlue());
add(startButton);
add(Box.createHorizontalStrut(10));
add(stopButton);
add(Box.createHorizontalStrut(10));
add(recordButton);
add(Box.createHorizontalGlue());
}
}
}
BoxLayout is so good too provide white space and help you to center the component.
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(Box.createHorizontalGlue());
add(startButton);
add(Box.createHorizontalStrut(10));
add(stopButton);
add(Box.createHorizontalStrut(10));
add(recordButton);
add(Box.createHorizontalGlue());
Add Glue before the first component and after the last component will help you too center the component and add strut can help you to provide white space you want. you can refer to https://stackoverflow.com/a/22525005/3378204 for more details.
Here is the effect:
The BoxLayout won't affect your component's size. Hope it can help you.
Try this :
public class Main{
private JFrame f;
private JLabel l1, l2, l3,l4;
private JPanel p1, p2, p3;
private JButton b1, b2, b3;
public Main(){
this.f = new JFrame();
this.f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.f.setLayout(new GridLayout(3,1));
this.p1 = new JPanel();
this.p1.setLayout(null)
this.p1.setSize(yoursize);
this.l1 = new JLabel();
this.l1.setBounds(x,y,xspan,yspan);
this.p1.add(l1);
this.p2 = new JPanel();
this.p2.setLayout(new GridLayout(1,3));
this.l2 = new JLabel();
this.l3 = new JLabel();
this.l4 = new JLabel();
this.p2.add(l2);
this.p2.add(l3);
this.p2.add(l4);
this.p3 = new JPanel();
this.p3.setLayout(new GridLayout(1,3));
this.b1 = new JButton();
this.b2 = new JButton();
this.b3 = new JButton();
this.p3.add(b1);
this.p3.add(b2);
this.p3.add(b3);
this.f.add(p1);
this.f.add(p2);
this.f.add(p3);
this.f.pack();
this.f.setResizeable(false)
}}
Add your video components instead of labels and you can change the color of the components as you wish.
Also if you want more control over the size and position of the components, use null layout and place them individually using setBounds() function as once shown in the program above. It is surely time consuming but makes the layout perfect.

How to set component size inside container with BoxLayout

I'm facing a problem with using BoxLayout.
In my example, I try to decrease the height of the text field and change the width of the buttons (as shown in green marker in the picture at the bottom). I know about the techniques setPreferredSize() and setMaximumSize(), but it did not work as it should. The line add(Box.createHorizontalGlue()) also did not help.
Thanks for any ideas.
public class Testy extends JPanel {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
constructGUI();
}
});
}
private static void constructGUI() {
JFrame frame = new JFrame("Testy");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel centerPanel = new JPanel();
centerPanel.setBackground(Color.DARK_GRAY);
centerPanel.setPreferredSize(new Dimension(100, 400));
frame.add(centerPanel, BorderLayout.CENTER);
Testy eastPanel = new Testy();
frame.add(eastPanel, BorderLayout.EAST);
frame.pack();
frame.setVisible(true);
}
public Testy() {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
JButton button = new JButton("Button ...... 1");
//button.setPreferredSize(...);
//button.setMaximumSize(...);
add(button);
button = new JButton("Button 2");
//button.setPreferredSize(...);
//button.setMaximumSize(...);
add(button);
button = new JButton("Button ........... 3");
//button.setPreferredSize(...);
//button.setMaximumSize(...);
add(button);
JLabel label = new JLabel("Label");
//label.setPreferredSize(...);
//label.setMaximumSize(...);
add(label);
JTextField textField = new JTextField();
//textField.setPreferredSize(...);
//textField.setMaximumSize(...);
add(textField);
button = new JButton("Button 4");
//button.setPreferredSize(...);
//button.setMaximumSize(...);
add(button);
//add(Box.createHorizontalGlue());
}
}
First you have to realize that component position and size in Java Swing depends on Layout manager (if layout manager is set) not on the component itself. The component requests the manager for size.
For this case I would use different layout - combination of GridLayout and BorderLayout is enough and very simple and straightforward. But if want use BoxLayout, then...
Documentation says:
BoxLayout pays attention
to a component's requested minimum, preferred, and maximum sizes.
While you are fine-tuning the layout, you might need to adjust these
sizes. ... For example, a button's maximum size is generally the
same as its preferred size. If you want the button to be drawn wider
when additional space is available, then you need to change its
maximum size.
Then set components maximum size: c.setMaximumSize(new Dimension(Integer.MAX_VALUE, c.getMinimumSize().height)); (c means button, label and textField in your example)
Edit 1:
Here is working source code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class Testy extends JPanel {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
constructGUI();
}
});
}
private static void constructGUI() {
JFrame frame = new JFrame("Testy");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel centerPanel = new JPanel();
centerPanel.setBackground(Color.DARK_GRAY);
centerPanel.setPreferredSize(new Dimension(100, 400));
frame.add(centerPanel, BorderLayout.CENTER);
Testy eastPanel = new Testy();
frame.add(eastPanel, BorderLayout.EAST);
frame.pack();
frame.setVisible(true);
}
public Testy() {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
JButton button = new JButton("Button ...... 1");
//button.setPreferredSize(...);
button.setMaximumSize(new Dimension(Integer.MAX_VALUE, button.getMinimumSize().height));
add(button);
button = new JButton("Button 2");
//button.setPreferredSize(...);
button.setMaximumSize(new Dimension(Integer.MAX_VALUE, button.getMinimumSize().height));
add(button);
button = new JButton("Button ........... 3");
//button.setPreferredSize(...);
button.setMaximumSize(new Dimension(Integer.MAX_VALUE, button.getMinimumSize().height));
add(button);
JLabel label = new JLabel("Label");
//label.setPreferredSize(...);
label.setMaximumSize(new Dimension(Integer.MAX_VALUE, label.getMinimumSize().height));
add(label);
JTextField textField = new JTextField();
//textField.setPreferredSize(...);
textField.setMaximumSize(new Dimension(Integer.MAX_VALUE, textField.getMinimumSize().height));
add(textField);
button = new JButton("Button 4");
//button.setPreferredSize(...);
button.setMaximumSize(new Dimension(Integer.MAX_VALUE, button.getMinimumSize().height));
add(button);
// add(Box.createVerticalGlue());
}
}
Edit 2:
If you want laid out Button 4 at the bottom of right column add this line add(Box.createVerticalGlue()); between add(textField); and button = new JButton("Button 4");.
As a quick remedy, you can use nested layouts, in the sense, that on the right side, create a JPanel with BorderLayout, put a JPanel(say compPanel) at the CENTER and a JPanel(say buttonPanel) at PAGE_END location. Now use a new JPanel(say panel) with GridLayout and put all the components on it, and place this compPanel inside centerPanel. Place JButton(button4) inside buttonPanel as is.
BoxLayout on the contrary, respects the preferred size of a given JComponent, which is usually calculated based on the content the JComponent holds or given explicity, hence components do not tend to align well with respect to other given components.
Here is the working example :
import java.awt.*;
import javax.swing.*;
public class Testy extends JPanel {
private JPanel panel;
private JPanel buttonPanel;
public Testy() {
setLayout(new BorderLayout(5, 5));
JPanel compPanel = new JPanel();
panel = new JPanel(new GridLayout(6, 1, 5, 5));
JButton button = new JButton("Button ...... 1");
//button.setPreferredSize(...);
//button.setMaximumSize(...);
panel.add(button);
button = new JButton("Button 2");
//button.setPreferredSize(...);
//button.setMaximumSize(...);
panel.add(button);
button = new JButton("Button ........... 3");
//button.setPreferredSize(...);
//button.setMaximumSize(...);
panel.add(button);
JLabel label = new JLabel("Label");
//label.setPreferredSize(...);
//label.setMaximumSize(...);
panel.add(label);
JTextField textField = new JTextField();
//textField.setPreferredSize(...);
//textField.setMaximumSize(...);
panel.add(textField);
compPanel.add(panel);
buttonPanel = new JPanel();
button = new JButton("Button 4");
buttonPanel.add(button);
add(compPanel, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
private void constructGUI() {
JFrame frame = new JFrame("Testy");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
JPanel centerPanel = new JPanel();
frame.getContentPane().setLayout(new BorderLayout(5, 5));
centerPanel.setBackground(Color.DARK_GRAY);
frame.add(centerPanel, BorderLayout.CENTER);
frame.add(this, BorderLayout.LINE_END);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Testy().constructGUI();
}
});
}
}
OUTPUT :
This should get close, based on your draw, just need to work on that component
below the JLabel (using setPreferredSize()):
JPanel main = new JPanel(new GridLayout(1, 2));
JPanel left = new JPanel();
//left.setPreferredSize(some size);
JPanel right = new JPanel(new GridLayout(6, 1));
//right.setPreferredSize(some size);
right.add(new JButton("Button 1"));
//...
right.add(new JButton("Button 4"));
main.add(left);
main.add(right);

Categories

Resources