Related
I am aware of the NORTH, CENTER and SOUTH field details for setting a component (e.g. BorderLayout) to either the top, middle or bottom respectively, however, I was wondering if it's possible to have more than three components and if so, how would I go about doing this with additional field details.
Currently, I have the following.
North - BorderLayout
Center - GridLayout
South - GridBagLayout
I am wanting to add an additional GridBagLayout to the bottom of the program (either below or above existing GridBagLayout). How would I go about adding an additional layout so that it does not interfere with and merge with the current SOUTH area?
Code:
public class boggleView extends JFrame {
public boggleView(){
super("Boggle");
setResizable(false);
setLocationRelativeTo(null);
setMinimumSize(new Dimension(400, 400));
JPanel northPanel = new JPanel();
JPanel middlePanel = new JPanel();
JPanel southPanel = new JPanel();
JPanel southPanelBottom = new JPanel();
// North Panel
getContentPane().add(northPanel, BorderLayout.NORTH);
northPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
JLabel gameBoardTitle = new JLabel("<html><font size = 5>Game Board</font></html>");
northPanel.add(gameBoardTitle);
// Middle Panel
getContentPane().add(middlePanel, BorderLayout.CENTER);
middlePanel.setLayout(new GridLayout(4,4));
for(int button=0 ; button<16 ; button++){
JButton diceButton = new JButton(String.valueOf("<html><font size = 10>E</font></html>"));
diceButton.setBackground(Color.WHITE);
diceButton.setBorder(new LineBorder(Color.BLACK));
diceButton.setPreferredSize(new Dimension(100, 100));
middlePanel.add(diceButton);
}
// South Panel
southPanel.setLayout (new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(10,10,0,10);
c.fill = GridBagConstraints.HORIZONTAL;
Border wordBorder = BorderFactory.createLineBorder(Color.BLACK, 1);
Border textFieldBorder = BorderFactory.createLineBorder(Color.BLACK, 2);
JButton button;
JLabel textField = new JLabel("");
textField.setBorder(textFieldBorder);
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 8;
textField.setPreferredSize(new Dimension(0,35));
southPanel.add(textField, c);
button = new JButton("Submit");
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 1;
button.setBackground(Color.GREEN);
button.setPreferredSize(new Dimension(80, 35));
southPanel.add(button, c);
button = new JButton("Cancel");
c.gridx = 2;
c.gridy = 1;
c.gridwidth = 1;
button.setBackground(Color.RED);
button.setPreferredSize(new Dimension(80, 35));
southPanel.add(button, c);
button = new JButton("Restart");
c.gridx = 4;
c.gridy = 1;
c.gridwidth = 1;
button.setBackground(Color.CYAN);
button.setPreferredSize(new Dimension(80, 35));
southPanel.add(button, c);
button = new JButton("Info");
c.gridx = 6;
c.gridy = 1;
c.gridwidth = 1;
button.setBackground(Color.CYAN);
button.setPreferredSize(new Dimension(80, 35));
southPanel.add(button, c);
JLabel wordListTitle = new JLabel("<html><font size = 5>Recent Words</font></html>");
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 3;
c.insets = new Insets(0,5,0,0);
southPanel.add(wordListTitle, c);
// Bottom South Panel
southPanelBottom.setLayout (new GridBagLayout());
GridBagConstraints d = new GridBagConstraints();
d.fill = GridBagConstraints.HORIZONTAL;
d.insets = new Insets(0,0,0,0);
JLabel word = new JLabel("<html><font size = 5>HAT</font></html>");
word.setBorder(wordBorder);
d.gridx = 0;
d.gridy = 3;
d.gridwidth = 2;
southPanelBottom.add(word, d);
JLabel word2 = new JLabel("<html><font size = 5>1</font></html>");
word2.setBorder(wordBorder);
d.gridx = 2;
d.gridy = 3;
d.gridwidth = 1;
southPanelBottom.add(word2, d);
getContentPane().add(southPanel, BorderLayout.SOUTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
}
use a new helper Panel with layout Borderlayout.
put your new GridBagLayout panel to this new helper Panel's South and put the existing GridBagLayout panel (currently at SOUTH) this panel's North.
then put this new helper Panel to SOUTH replacing old GridBagLayout panel.
JPanel southHelperPanel = new JPanel(new BorderLayout());
southHelperPanel.add(southPanel, BorderLayout.NORTH);
southHelperPanel.add(southPanelBottom, BorderLayout.SOUTH);
getContentPane().add(southHelperPanel, BorderLayout.SOUTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
You can just combine layouts as you need them. Please have a look at the below example.. In this example, the main panel has a BorderLayout. In the different directions of this panel I'm adding new panels with other layouts.
public class Test extends JFrame {
public static void main(String[] args) {
Test test = new Test();
test.setVisible(true);
}
public Test() {
JPanel main = new JPanel(new BorderLayout());
JPanel top = new JPanel(new FlowLayout());
JPanel center = new JPanel(new GridBagLayout());
JPanel bottom = new JPanel(new BorderLayout());
main.add(top, BorderLayout.PAGE_START);
main.add(center, BorderLayout.CENTER);
main.add(bottom, BorderLayout.PAGE_END);
this.getContentPane().add(main);
this.setSize(800, 500);
}
}
You could also give your main panel a different layout (like GridBagLayout) if you need more "directions" in the beginning.
BorderLayout cannot itself do this; it can only lay out 3 things vertically. Switch the container (window.getContentPane(), presumably) to a different layout.
Something similar-ish to BorderLayout is to use BoxLayout; I'd need to know a little more about exactly what's in those subcomponents to be sure if it's the right replacement here.
So I recently started learning object-oriented programming, did most basic stuff in Java and now I want to change from console writing to actual GUI.
But I have problem understanding how it works, I read everything in oracle documentation but their examples are not so clear and easy to understand, also googled it but couldn't manage to find any good explanation. This is my last resort.
Here is my idea of how my program GUI should look:
![like this][1]
I couldn't draw very nice but all check boxes should be aligned.
If someone can provide me explanation with code that would be great, if not just some good explanation would help me a lot, my problem is that when I align 1 thing other gets messed up.
My current code:
public class Zadatak2 extends JFrame{
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
new Zadatak2();
}
public Zadatak2(){
JPanel panel1 = new JPanel();
setSize(500, 250);
setLocationRelativeTo(null);
add(panel1);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
BorderLayout border1 = new BorderLayout();
panel1.setLayout(border1);
JPanel panel2 = new JPanel();
GridLayout grid1 = new GridLayout(3,2);
panel2.setLayout(grid1);
panel2.add(new JCheckBox("Bold"));
panel2.add(new JCheckBox("Italic"));
panel2.add(new JCheckBox("Underline"));
panel1.add(panel2,BorderLayout.WEST);
JPanel panel3 = new JPanel();
GridLayout grid2 = new GridLayout(4,1);
panel3.setLayout(grid2);
panel3.add(new JCheckBox("Strikerthrough"));
panel3.add(new JCheckBox("Teletype"));
panel3.add(new JCheckBox("Emphasis"));
panel3.add(new JCheckBox("Strong"));
panel1.add(panel3,BorderLayout.CENTER);
JPanel panel4 = new JPanel();
BorderLayout border2 = new BorderLayout();
panel4.setLayout(border2);
panel4.add(new JButton("Apply"), BorderLayout.EAST);
panel4.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 70));
panel1.add(panel4,BorderLayout.SOUTH);
JPanel panel5 = new JPanel();
GridLayout grid3 = new GridLayout(2,1);
panel5.setLayout(grid3);
panel5.add(new JLabel("Sample text"));
JTextArea ta = new JTextArea("Sample text");
panel5.setBorder(BorderFactory.createEmptyBorder(5, 0, 10, 30));
ta.setSize(200, 200);
panel5.add(ta);
panel1.add(panel5,BorderLayout.EAST);
setVisible(true);
}
}
Thanks for help from everyone, finally made the gui right, now I understand thins much better.
To position the check boxes in the GridLayout, you should not define a panel for each column. Just define and place them like this:
JPanel panel2 = new JPanel();
GridLayout grid1 = new GridLayout(4, 2);
panel2.setLayout(grid1);
panel2.add(new JCheckBox("Bold"));
panel2.add(new JCheckBox("Strikerthrough"));
panel2.add(new JCheckBox("Italic"));
panel2.add(new JCheckBox("Teletype"));
panel2.add(new JCheckBox("Underline"));
panel2.add(new JCheckBox("Emphasis"));
panel2.add(new JLabel("")); // fill the empty cell with an empty label
panel2.add(new JCheckBox("Strong"));
However, since you have a TextArea that should be aligned with the check boxes and span several rows, I would recomment using a GridBagLayout instead. It's more code to write, but much more flexible than the GridLayout.
An example:
public Zadatak2() {
JPanel panel1 = new JPanel();
setSize(500, 250);
setLocationRelativeTo(null);
add(panel1);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
BorderLayout border1 = new BorderLayout();
panel1.setLayout(border1);
JPanel panel2 = new JPanel();
GridBagLayout grid1 = new GridBagLayout();
panel2.setLayout(grid1);
panel2.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
Insets insets = new Insets(2, 2, 2, 2);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.insets = insets;
c.anchor = GridBagConstraints.WEST;
panel2.add(new JCheckBox("Bold"), c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 0;
c.insets = insets;
c.anchor = GridBagConstraints.WEST;
panel2.add(new JCheckBox("Strikerthrough"), c);
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.insets = insets;
c.anchor = GridBagConstraints.WEST;
panel2.add(new JCheckBox("Italic"), c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 1;
c.insets = insets;
c.anchor = GridBagConstraints.WEST;
panel2.add(new JCheckBox("Teletype"), c);
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 2;
c.insets = insets;
c.anchor = GridBagConstraints.WEST;
panel2.add(new JCheckBox("Underline"), c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 2;
c.insets = insets;
c.anchor = GridBagConstraints.WEST;
panel2.add(new JCheckBox("Emphasis"), c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 3;
c.insets = insets;
c.anchor = GridBagConstraints.WEST;
panel2.add(new JCheckBox("Strong"), c);
insets = new Insets(2, 40, 2, 2);
c = new GridBagConstraints();
c.gridx = 2;
c.gridy = 0;
c.insets = insets;
c.anchor = GridBagConstraints.WEST;
panel2.add(new JLabel("Sample text"), c);
c = new GridBagConstraints();
c.gridx = 2;
c.gridy = 1;
c.insets = insets;
c.weightx = .5;
c.fill = GridBagConstraints.BOTH;
c.gridheight = 3;
JTextArea ta = new JTextArea("Sample text", 4, 4);
JScrollPane sp = new JScrollPane(ta);
panel2.add(sp, c);
c = new GridBagConstraints();
c.gridx = 2;
c.gridy = 5;
c.insets = new Insets(40, 40, 2,2);
c.anchor = GridBagConstraints.WEST;
panel2.add(new JButton("Apply"), c);
panel1.add(panel2, BorderLayout.CENTER);
pack();
setVisible(true);
}
The result:
Please see the GridBagLayout Tutorial and the JavaDoc to learn about all the options of this layout.
Remember to nest JPanels each using its own layout. For instance your imaged GUI could be made one of many ways. The overall JPanel could use BoxLayout oriented to the line, and on the left have a GridLayout using JPanel on the right a BorderLayout using JPanel. For example:
Other issues:
The JTextArea should be placed into a JScrollPane, and the scrollpane then added to the GUI.
NEVER set the sizes or preferred sizes of text components, especially JTextAreas as that will prevent them from working correctly, especially if within a scrollpane.
Instead set the JTextArea's column and row properties.
Avoid setting sizes in general. Let the GUI components and layouts set their own sizes by calling pack() on the JFrame after adding everything and before setting it visible.
For example, with slight modification:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.*;
#SuppressWarnings("serial")
public class SimpleGui extends JPanel {
private static final String[] CHK_BOX_TEXTS = {"Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "Sunday"};
private String title = "My Title";
private JTextArea textArea = new JTextArea(10, 30);
private JButton applyButton = new JButton("Apply");
public SimpleGui() {
// gridlayout with 2 columns, variable rows
JPanel checkBoxPanel = new JPanel(new GridLayout(0, 2, 4, 4));
for (String chkBoxText : CHK_BOX_TEXTS) {
checkBoxPanel.add(new JCheckBox(chkBoxText));
}
JPanel leftPanel = new JPanel();
leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));
leftPanel.add(Box.createVerticalStrut(20));
leftPanel.add(checkBoxPanel);
leftPanel.add(Box.createGlue());
JLabel titleLabel = new JLabel(title, SwingConstants.CENTER);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 20));
JScrollPane scrollPane = new JScrollPane(textArea);
JPanel btnPanel = new JPanel();
btnPanel.add(applyButton);
JPanel rightPanel = new JPanel(new BorderLayout(5, 5));
rightPanel.add(titleLabel, BorderLayout.PAGE_START);
rightPanel.add(scrollPane, BorderLayout.CENTER);
rightPanel.add(btnPanel, BorderLayout.PAGE_END);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
add(leftPanel);
add(rightPanel);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SimpleGui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SimpleGui());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Which displays as:
I have created a simple for-loop that changes the amount of JTextFields and JLabels based on the value of a JSpinner, as seen in the following code:
public static ArrayList<ArrayList<JTextField>> ChangeQuestionAnswerFields(int numberOfQuestions){
ArrayList<ArrayList<JTextField>> txtFieldArray = new ArrayList<ArrayList<JTextField>>();
JPanel scrollPanel = new JPanel(new GridBagLayout());
//JScrollPane scrollPane = new JScrollPane(scrollPanel);
frame.add(scrollPanel, BorderLayout.CENTER);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
for(int i = 0; i != numberOfQuestions; i++){
JTextField tempQuestion = new JTextField(10);
JTextField tempAnswer = new JTextField(10);
JLabel tempQuestionHeader = new JLabel("Question " + (i + 1)+ " ");
JLabel tempQuestionLbl = new JLabel("Question: ");
JLabel tempAnswerLbl = new JLabel("Answer: ");
ArrayList<JTextField> tempArrayList = new ArrayList<>();
tempArrayList.add(tempQuestion);
tempArrayList.add(tempAnswer);
txtFieldArray.add(tempArrayList);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempQuestionHeader, c);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempQuestionLbl, c);
c.gridx = 1;
c.gridwidth = 3;
scrollPanel.add(tempQuestion, c);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempAnswerLbl, c);
c.gridx = 1;
c.gridwidth = 3;
scrollPanel.add(tempAnswer, c);
}
return txtFieldArray;
}
}
The value of the Spinner is passed into the method, and the method is called using a change listener (where noQuestions is the value of the JSpinner):
noQuestions.addChangeListener(e -> {
ChangeQuestionAnswerFields((int) noQuestions.getValue());
frame.revalidate();
frame.repaint();
});
This method is first called in the code when the screen first appears, and works properly. However, whenever the value of the spinner changes the original labels and fields stay on the screen and more text fields simply appear, or disappear on top.
http://i.imgur.com/GBY8L3u.png - JSpinner has a value of 2
http://i.imgur.com/pSQsA3G.png - JSpinner has a value of 3
Is there any way to fix this? Any help is much appreciated.
Thanks,
Tom
Minimal Runnable Example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
public class MainGUI {
static JFrame frame = new JFrame("Math Reviser");
public static void main(String[] args) {
frame.setSize(400, 600);
frame.setVisible(true);
createScreen();
frame.revalidate();
frame.repaint();
public static void createScreen(){
frame.getContentPane().removeAll();
JSpinner noQuestions = new JSpinner(new SpinnerNumberModel(1, 1, 10, 1));
frame.add(noQuestions, BorderLayout.NORTH);
);
changeQuestionAnswerFields(1);
frame.revalidate();
frame.repaint();
noQuestions.addChangeListener(e -> {
changeQuestionAnswerFields((int) noQuestions.getValue());
frame.revalidate();
frame.repaint();
});
}
public static ArrayList<ArrayList<JTextField>> changeQuestionAnswerFields(int numberOfQuestions){
ArrayList<ArrayList<JTextField>> txtFieldArray = new ArrayList<ArrayList<JTextField>>();
JPanel scrollPanel = new JPanel(new GridBagLayout());
frame.add(scrollPanel, BorderLayout.CENTER);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
for(int i = 0; i != numberOfQuestions; i++){
JTextField tempQuestion = new JTextField(10);
JTextField tempAnswer = new JTextField(10);
JLabel tempQuestionHeader = new JLabel("Question " + (i + 1)+ " ");
JLabel tempQuestionLbl = new JLabel("Question: ");
JLabel tempAnswerLbl = new JLabel("Answer: ");
ArrayList<JTextField> tempArrayList = new ArrayList<>();
tempArrayList.add(tempQuestion);
tempArrayList.add(tempAnswer);
txtFieldArray.add(tempArrayList);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempQuestionHeader, c);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempQuestionLbl, c);
c.gridx = 1;
c.gridwidth = 3;
scrollPanel.add(tempQuestion, c);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempAnswerLbl, c);
c.gridx = 1;
c.gridwidth = 3;
scrollPanel.add(tempAnswer, c);
}
return txtFieldArray;
}
}
Using static variables and methods is an indication of a poorly designed application. There is no need for the static variables or methods. I suggest you read the section from the Swing tutorial on How to Use Labels. The LabelDemo.java code will show you how to create a panel containing all the components. This panel will then be added to the frame. This panel will also contain all the instance variables you need for your program.
Not only that the example will show you how to create the GUI components on the EDT which is something you should always do to prevent random errors since Swing was designed to be single threaded.
However, the main problem with your existing code is that you continue to create and add new panels to the content pane of the frame. Try changing the spinner to 2 and then resize the frame. Then try changing the spinner to 3 and resize the frame. After the resizing the first panel is displayed. This is because Swing will paint the last component added first so the first panel added will be painted on top of the last panel you created.
You can change this in your existing code by removing the old panel before adding the new panel:
static JFrame frame = new JFrame("Math Reviser");
static JPanel scrollPanel = new JPanel();
...
frame.remove(scrollPanel);
//JPanel scrollPanel = new JPanel(new GridBagLayout());
scrollPanel = new JPanel(new GridBagLayout());
However, I do not recommend this approach. As I initially suggestion you need to redesign the entire class. When you do the redesign I would use a BorderLayout on your panel and then you can add your spinner to the PAGE_START and then add a JScrollPane to the CENTER of the panel.
Then when you want to create a new panel you add the panel to the scrollpane using code like:
scrollPane.setViewportView( scrollPanel );
The scrollpane will refresh itself and you don't need to worry about revalidate() or repaint() or anything else.
The UI I am working on displays a panel which lets a user select a movie and play. There are controls to play, pause, etc.
The layout seems to look the way I want. The panel uses a GridBagLayout. Row 2 displays a text area for status messages and row 3 displays a panel with buttons and a progress bar.
The problem I am running into is that when I have too many lines of text in the text area, the buttons in row 3 wrap around. This is irrespective of the height of the outer frame.
The height in row 2 is affecting the width in row 3. I don't understand this behavior. I am wondering if someone can tell me what is it that I am doing wrong and how I can fix it? I have attached the code.
On a slightly different topic, if you are looking at the code, can you also suggest a way to leave a margin between the bottom-most component and the outermost panel?
Thank you in advance for your help.
Regards,
Peter
private static JButton CreateImageButton(String fileName) {
JButton retVal = new JButton("xxx");
return retVal;
}
public MoviePanel() {
this.setLayout(new GridBagLayout());
this.setBackground(Color.WHITE);
JButton btnRefresh = CreateImageButton("refresh.png");
GridBagConstraints c = new GridBagConstraints();
c.gridx=0;
c.gridy=0;
c.fill = GridBagConstraints.NORTH;
c.insets.left = 10; c.insets.right = 10; c.insets.top = 10;
this.add(btnRefresh, c);
JComboBox cbMovieList = new JComboBox();
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 0;
c.fill = GridBagConstraints.HORIZONTAL;
c.insets.right = 10; c.insets.top = 10;
c.weightx = 1.0;
this.add(cbMovieList, c);
JButton btnAuthorize = new JButton("Get Info");
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 1;
c.anchor = GridBagConstraints.WEST;
c.insets.top = 10;
this.add(btnAuthorize, c);
JTextArea txtInfo = new JTextArea();
txtInfo.setFont( new Font("SansSerif", Font.BOLD, 12));
txtInfo.setBackground(Color.cyan);
// txtInfo.setText("abc\ndef");
txtInfo.setText("abc\ndef\nghi\njkl\nmno\npqr\nstu\nvwx\nyz");
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 2;
c.anchor = GridBagConstraints.NORTHWEST;
c.weighty = 1.0;
c.insets.top = 10;
this.add(txtInfo, c);
JPanel controllerOuter = new JPanel();
controllerOuter.setLayout(new BoxLayout(controllerOuter, BoxLayout.Y_AXIS));
controllerOuter.setBorder(BorderFactory.createRaisedBevelBorder());
FlowLayout controllerLayout = new FlowLayout(FlowLayout.CENTER);
controllerLayout.setHgap(0);
JPanel controller = new JPanel(controllerLayout);
controller.setBorder(new EmptyBorder(10, 10, 10, 10));
Dimension dim = new Dimension(60, 40);
JButton btnPlay = CreateImageButton("play.png");
btnPlay.setPreferredSize(dim);
controller.add(btnPlay);
JButton btnPause = CreateImageButton("pause.png");
btnPause.setPreferredSize(dim);
controller.add(btnPause);
JButton btnStop = CreateImageButton("stop.png");
btnStop.setPreferredSize(dim);
controller.add(btnStop);
JButton btnForward = CreateImageButton("forward.png");
btnForward.setPreferredSize(dim);
controller.add(btnForward);
JComboBox cbAspectRatio = new JComboBox();
cbAspectRatio.setPreferredSize(new Dimension(100, 40));
cbAspectRatio.setBorder(new EmptyBorder(0, 10, 0, 0));
controller.add(cbAspectRatio);
controllerOuter.add(controller);
JProgressBar pbProgress = new JProgressBar(0, 100);
pbProgress.setPreferredSize(new Dimension(350, 40));
pbProgress.setBorder(new EmptyBorder(0, 10, 10, 10));
pbProgress.setValue(50);
pbProgress.setString("50/100");
pbProgress.setStringPainted(true);
pbProgress.setForeground(Color.BLUE);
pbProgress.setBorderPainted(true);
controllerOuter.add(pbProgress);
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 3;
c.gridwidth = 2;
c.weightx = 1.0;
this.add(controllerOuter, c);
}
I see several things in your code:
You force the preferredSize of the JButton's. If possible, I would remove that because this will often get you more problems than solutions. If you want to force the preferredSize, you should also pay attention to set the minimum and maximum sizes as well, otherwise you get weird behaviour like the one you are observing
You use a BoxLayout to display the controls. While this is perfectly acceptable, BoxLayout also relies on min/max size to perform the layout, which you did not set.
You use imbricated layouts. This is fine too, but why not use only the GridBagLayout of your MoviePanel?
Usually TextAreas are wrapped in JScrollPane, in case the text is too big. You can also setLineWrap(true) on the TextArea, so that it does not go too far on the right. By setting rows/columns on the TextArea, you will define its preferreSize (to prevent it from depending of the text it contains).
On your GridBagConstraints, the fill property can only be: NONE, VERTICAL, HORIZONTAL or BOTH (You used VERTICAL for one of them). Also, it is not needed to recreate a new instance, you can reuse the same GridBagConstraint over and over, it is automatically cloned by the LayoutManager when you set the constraint for the component.
Now for the solutions, I found several:
When you add the contollerOuter, also specify c.fill = GridBagConstraints.HORIZONTAL; (This is the easiest way to solve your issues)
When you set the preferredSize of the JButtons, also force their minimumSize to the same value.
Use only the GridBagLayout to layout all components. (This would be my favorite)
Replace the FlowLayout by a BoxLayout with a X_AXIS.
Rember that GridBagConstraints properties :
gridx, gridy: specifies the location
gridwidth, gridheight: specifies the colspan/rowspan
weightx, weighty: specifies who gets the extra horizontal/vertical space and in what proportion
anchor: specifies the alignement of the component withing its "cell", if the "cell" is bigger than the component
fill: specifies if the component should stretch to the cell width/height
Just adding one JPanel each for Center and Bottom will do the trick for you, so till your JTextArea your GridBagLayout will server the purpose and after that the BorderLayout of the MAIN JPanel will do. Moreover, adding JScrollPane also to the whole thing reduces the effort needed at other areas. Have a look at the code and output :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class JTextPaneExample extends JPanel
{
private Icon info = UIManager.getIcon("OptionPane.informationIcon");
private Icon error = UIManager.getIcon("OptionPane.errorIcon");
private static JButton CreateImageButton(String fileName) {
JButton retVal = new JButton("xxx");
return retVal;
}
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("JTextPane Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
this.setBackground(Color.WHITE);
JPanel centerPanel = new JPanel();
centerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
centerPanel.setLayout(new GridBagLayout());
centerPanel.setBackground(Color.WHITE);
JButton btnRefresh = CreateImageButton("refresh.png");
GridBagConstraints c = new GridBagConstraints();
c.gridx=0;
c.gridy=0;
c.fill = GridBagConstraints.NORTH;
c.insets.left = 10; c.insets.right = 10; c.insets.top = 10;
centerPanel.add(btnRefresh, c);
JComboBox cbMovieList = new JComboBox();
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 0;
c.fill = GridBagConstraints.HORIZONTAL;
c.insets.right = 10; c.insets.top = 10;
c.weightx = 1.0;
centerPanel.add(cbMovieList, c);
JButton btnAuthorize = new JButton("Get Info");
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 1;
c.anchor = GridBagConstraints.WEST;
c.insets.top = 10;
centerPanel.add(btnAuthorize, c);
JTextArea txtInfo = new JTextArea();
txtInfo.setFont( new Font("SansSerif", Font.BOLD, 12));
txtInfo.setBackground(Color.cyan);
// txtInfo.setText("abc\ndef");
txtInfo.setText("abc\ndef\nghi\njkl\nmno\npqr\nstu\nvwx\nyz");
JScrollPane scroller = new JScrollPane();
scroller.setViewportView(txtInfo);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 2;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.HORIZONTAL;
c.weighty = 1.0;
c.insets.top = 10;
centerPanel.add(scroller, c);
JPanel controllerOuter = new JPanel();
controllerOuter.setLayout(new BoxLayout(controllerOuter, BoxLayout.Y_AXIS));
controllerOuter.setBorder(BorderFactory.createRaisedBevelBorder());
FlowLayout controllerLayout = new FlowLayout(FlowLayout.CENTER);
controllerLayout.setHgap(0);
JPanel controller = new JPanel(controllerLayout);
controller.setBorder(new EmptyBorder(10, 10, 10, 10));
Dimension dim = new Dimension(60, 40);
JButton btnPlay = CreateImageButton("play.png");
btnPlay.setPreferredSize(dim);
controller.add(btnPlay);
JButton btnPause = CreateImageButton("pause.png");
btnPause.setPreferredSize(dim);
controller.add(btnPause);
JButton btnStop = CreateImageButton("stop.png");
btnStop.setPreferredSize(dim);
controller.add(btnStop);
JButton btnForward = CreateImageButton("forward.png");
btnForward.setPreferredSize(dim);
controller.add(btnForward);
JComboBox cbAspectRatio = new JComboBox();
cbAspectRatio.setPreferredSize(new Dimension(100, 40));
cbAspectRatio.setBorder(new EmptyBorder(0, 10, 0, 0));
controller.add(cbAspectRatio);
controllerOuter.add(controller);
JProgressBar pbProgress = new JProgressBar(0, 100);
pbProgress.setPreferredSize(new Dimension(350, 40));
pbProgress.setBorder(new EmptyBorder(0, 10, 10, 10));
pbProgress.setValue(50);
pbProgress.setString("50/100");
pbProgress.setStringPainted(true);
pbProgress.setForeground(Color.BLUE);
pbProgress.setBorderPainted(true);
controllerOuter.add(pbProgress);
add(centerPanel, BorderLayout.CENTER);
add(controllerOuter, BorderLayout.PAGE_END);
frame.getContentPane().add(this);
frame.pack();
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new JTextPaneExample().createAndDisplayGUI();
}
});
}
}
Here is the output as you add more lines :
Im having a hard time identifying what layout to be used. help any suggestions.
JPanel mainpanel = new JPanel();
public void addPanel(JPanel panel){
mainpanel.add(panel);
}
addPanel(A);
addPanel(B);
addPanel(C);
addPanel(D);
addPanel(E);
....
Panels A,B,C,D... are not of fixed sized.
How can I make this possible?
Seems like by using GridBagLayout, you can achieve this. Hopefully you can change the JPanel with MAGENTA colour as per your liking :-)
Here is the output :
And here is the code :
import java.awt.*;
import javax.swing.*; //swing package
public class GridBagLayoutTest
{
//defining the constructor
public GridBagLayoutTest()
{
JFrame maFrame = new JFrame("The main screen"); //creating main Jframe
maFrame.setLocationByPlatform(true); //centering frame
JPanel headPanel = new JPanel(); //creating the header panel
Container container = maFrame.getContentPane();
container.setLayout(new GridBagLayout()); //setting layout of main frame
GridBagConstraints cns = new GridBagConstraints(); //creating constraint
cns.gridx = 0;
cns.gridy = 0;
//cns.gridwidth = 3;
//cns.gridheight = 4;
cns.weightx = 0.5;
cns.weighty = 0.2;
cns.anchor = GridBagConstraints.FIRST_LINE_START;
cns.fill = GridBagConstraints.BOTH;
headPanel.setBackground(Color.BLUE);
container.add(headPanel, cns);
JPanel panel = new JPanel();
panel.setBackground(Color.CYAN);
cns = new GridBagConstraints();
cns.gridx = 1;
cns.gridy = 0;
//cns.gridwidth = 7;
//cns.gridheight = 4;
cns.weightx = 0.5;
cns.weighty = 0.2;
cns.anchor = GridBagConstraints.FIRST_LINE_END;
cns.fill = GridBagConstraints.BOTH;
container.add(panel, cns);
JPanel panel1 = new JPanel();
panel1.setBackground(Color.RED);
cns = new GridBagConstraints();
cns.gridx = 0;
cns.gridy = 1;
//cns.gridwidth = 2;
cns.gridheight = 2;
cns.weightx = 0.5;
cns.weighty = 0.3;
cns.anchor = GridBagConstraints.LINE_START;
cns.fill = GridBagConstraints.BOTH;
container.add(panel1, cns);
JPanel panel2 = new JPanel();
panel2.setBackground(Color.PINK);
cns = new GridBagConstraints();
cns.gridx = 1;
cns.gridy = 1;
//cns.gridwidth = 2;
//cns.gridheight = 2;
cns.weightx = 0.5;
cns.weighty = 0.2;
cns.anchor = GridBagConstraints.LINE_END;
cns.fill = GridBagConstraints.BOTH;
container.add(panel2, cns);
JPanel panel4 = new JPanel();
panel4.setBackground(Color.ORANGE);
cns = new GridBagConstraints();
cns.gridx = 1;
cns.gridy = 2;
//cns.gridwidth = 2;
//cns.gridheight = 2;
cns.weightx = 0.5;
cns.weighty = 0.2;
cns.anchor = GridBagConstraints.LINE_END;
cns.fill = GridBagConstraints.BOTH;
container.add(panel4, cns);
JPanel mainPanel = new JPanel();
mainPanel.setBackground(Color.WHITE);
mainPanel.setLayout(new GridBagLayout());
cns = new GridBagConstraints();
cns.gridx = 0;
cns.gridy = 4;
cns.gridwidth = 2;
cns.gridheight = 2;
cns.weightx = 1.0;
cns.weighty = 0.3;
cns.anchor = GridBagConstraints.LAST_LINE_START;
cns.fill = GridBagConstraints.BOTH;
container.add(mainPanel, cns);
JPanel panel3 = new JPanel();
panel3.setBackground(Color.MAGENTA);
cns = new GridBagConstraints();
cns.gridx = 0;
cns.gridy = 0;
//cns.gridwidth = 2;
//cns.gridheight = 2;
cns.weightx = 0.5;
cns.weighty = 0.2;
cns.anchor = GridBagConstraints.FIRST_LINE_START;
cns.fill = GridBagConstraints.BOTH;
mainPanel.add(panel3, cns);
JPanel bottomPanel = new JPanel();
bottomPanel.setBackground(Color.WHITE);
cns = new GridBagConstraints();
cns.gridx = 0;
cns.gridy = 1;
//cns.gridwidth = 2;
//cns.gridheight = 2;
cns.weightx = 1.0;
cns.weighty = 0.2;
cns.anchor = GridBagConstraints.LAST_LINE_START;
cns.fill = GridBagConstraints.BOTH;
mainPanel.add(bottomPanel, cns);
//JButton button = new JButton("BUTTON");
//headPanel.add(button);
maFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //setting the default close operation of JFrame
maFrame.pack();
maFrame.setVisible(true); //making the frame visible
}
//defining the main method
public static void main(String[] args)
{
Runnable runnable = new Runnable()
{
public void run()
{
new GridBagLayoutTest(); //instantiating the class
}
};
SwingUtilities.invokeLater(runnable);
}
}
Consider using JGoodies Forms layout. it is highly flexible and easy to use. Any sort of layouting of widgets are possible, vertical stacking , horizontal stacking etc.
http://www.jgoodies.com/freeware/forms/index.html
/* B1 Space B2 Space B3 Space B4 */
String col1 = "10dlu, 3dlu, 10dlu, 3dlu 10dlu, 3dlu, 10ldu";
/*Width of button */
String row1 = "5dlu";
FormLayout layout = new FormLayout( col1, row1);
JPanel panel = new JPanel(layout);
panel.setBorder(Borders.DIALOG_BORDER);
CellConstraints cc = new CellConstraints();
/* X - stands for column position :: Y - stand for row */
panel.add(new JButton("B1"), cc.xy(1, 1));
panel.add(new JButton("B2"), cc.xy(2, 1));
.
.
.
there is one more cc.xyh(1,1,2) where 'h' stands for vertical span or width.
Yes, you read more about JGoodies forms layout, 'DLU' means dialog units, rather than me explaining all these, kindly visit JGoodies site, download the library and documentation. Trust be, this layout manager is much better, in terms of usability , maintainability and readability.
I would say, create a temporary panel for ACF, then BDE, then create one to combine ACF and BDE, then add the last temp panel and your main panel onto the frame with BorderLayout NORTH and SOUTH
Grid layout might be fit into this shape. Just look to the java swing documentation.
Depends on what the behaviour should be when the window is resized. But you won't avoid building a tree structure with JPanels.
The top component can have BorderLayout, with one panel in the North and main panel in Center.
The North panel will have X-axis BoxLayout and contain two panels.
Both these panels should have Y-axis BoxLayout and the first one will contain A, C, F and the second one B, D, E.
You should also set preferred sizes for A B C D E and F so that they render with appropriate size.
EDIT:
Here, I created an example:
public class GladysPanel extends JPanel
{
public GladysPanel(JComponent A, JComponent B, JComponent C, JComponent D, JComponent E, JComponent F, JComponent main){
super(new BorderLayout());
JPanel abcdef = new JPanel(new BorderLayout());
Box ab = new Box(BoxLayout.X_AXIS);
ab.add(A);
ab.add(B);
abcdef.add(ab, BorderLayout.NORTH);
Box cdef = new Box(BoxLayout.X_AXIS);
Box cf = new Box(BoxLayout.Y_AXIS);
cf.add(C);
cf.add(F);
cf.add(Box.createVerticalGlue());
Box de = new Box(BoxLayout.Y_AXIS);
de.add(D);
de.add(E);
de.add(Box.createVerticalGlue());
cdef.add(cf, BorderLayout.WEST);
cdef.add(de, BorderLayout.EAST);
abcdef.add(cdef);
add(abcdef, BorderLayout.NORTH);
add(main);
}
public static void main(String[] args){
JPanel A = new JPanel();
A.setOpaque(true);
A.setBackground(Color.BLUE);
A.add(new JLabel("A"));
JPanel B = new JPanel();
B.setOpaque(true);
B.setBackground(Color.LIGHT_GRAY);
B.add(new JLabel("B"));
JPanel C = new JPanel();
C.setPreferredSize(new Dimension(0, 100));
C.setOpaque(true);
C.setBackground(Color.RED);
C.add(new JLabel("C"));
JPanel D = new JPanel();
D.setOpaque(true);
D.setBackground(Color.PINK);
D.add(new JLabel("D"));
JPanel E = new JPanel();
E.setOpaque(true);
E.setBackground(Color.YELLOW);
E.add(new JLabel("E"));
E.setPreferredSize(new Dimension(0, 60));
JPanel F = new JPanel();
F.setOpaque(true);
F.setBackground(Color.MAGENTA);
F.add(new JLabel("F"));
JPanel main = new JPanel();
main.setOpaque(true);
main.setBackground(Color.WHITE);
main.add(new JLabel("main"));
GladysPanel panel = new GladysPanel(A, B, C, D, E, F, main);
JFrame example = new JFrame("Gladys example");
example.setContentPane(panel);
example.setSize(300, 300);
example.setVisible(true);
}
}
you can omit the setPreferredSize(), I added it only to demonstate behaviour. You can also try to resize the window. The code is much much shorter that when using GridBagLayout.