I need guidance with GUI Layouts
To narrow it down to main points:
I have three main JPanels (info section, operations and data
structure)
I cannot populate these without the JLabels being shifted
I need a sub-panel for operations with a grid layout (cannot get this
to work and it's really annoying me now)
I need it to look like the picture below
Red separator lines are optional to make it a bit more neater
My next step is to implement a stack but I want to first make it look normal.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class StackPanel extends JPanel {
JPanel west, westSub1, east, south, southSub1;
JTextArea infoText, popText, pushText, peekText, resultText;
JLabel aTitle, bTitle, cTitle, Result;
JButton push, pop, peek, test;
public StackPanel() {
// Creating JPanels
setLayout(new BorderLayout());
west = new JPanel();
westSub1 = new JPanel(new GridLayout(3,2));
east = new JPanel();
south = new JPanel();
west.add(westSub1);
// Creating JLabels / JTextArea
aTitle = new JLabel("Operations");
bTitle = new JLabel("Data Structure Contents");
cTitle = new JLabel("Information");
infoText = new JTextArea("This is where commands will be displayed.");
pushText = new JTextArea("pushtxt");
popText = new JTextArea("poptxt");
peekText = new JTextArea("g");
resultText = new JTextArea("");
west.add(aTitle);
westSub1.add(pushText);
westSub1.add(popText);
westSub1.add(peekText);
westSub1.add(resultText);
east.add(bTitle);
south.add(cTitle);
south.add(infoText);
// Creating & Adding JButtons
push = new JButton("PUSH");
pop = new JButton("POP") ;
peek = new JButton("PEEK");
test = new JButton("TEST");
westSub1.add(push);
westSub1.add(pop);
westSub1.add(peek);
westSub1.add(test);
// Setting the placements of GUI objects
add(west, BorderLayout.WEST);
add(east, BorderLayout.CENTER);
add(south, BorderLayout.SOUTH);
// Declaring JPanel sizes // Width|Height
west.setPreferredSize(new Dimension(200,200));
east.setPreferredSize(new Dimension(400,100));
south.setPreferredSize(new Dimension(100,150));
// Setting black borders for JPanels
west.setBorder(BorderFactory.createLineBorder(Color.black));
east.setBorder(BorderFactory.createLineBorder(Color.black));
south.setBorder(BorderFactory.createLineBorder(Color.black));
// Setting JPanel background colours
west.setBackground(new Color(234,237,242));
east.setBackground(new Color(255,255,255));
south.setBackground(new Color(240,240,240));
}
}
Maybe instead of using labels at the top of each of the west/east/south panels you can use a TitledBorder. This will put a rectangular line around the panel with a title at the top.
Read the section from the Swing tutorial on How to Use Borders for more information and working examples.
If you don't want to do this then you will probably need to change the default FlowLayout or each of the panels to another layout. For example you could use a BorderLayout. Then add the label to the PAGE_START and the other components to the CENTER. The main point is you can nest panels with different layout to achieve your desired layout.
Here is something to get you started. Please read comments and don't hesitate to ask for clarifications as needed.
I did not do all needed layout changes: I did just about to demonstrate waht should be done, so you get the idea.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
public class StackPanel extends JPanel {
JPanel west, westSub1, east, south, southSub1;
JTextArea infoText, popText, pushText, peekText, resultText;
JLabel aTitle, bTitle, cTitle, Result;
JButton push, pop, peek, test;
public StackPanel() {
// Creating JPanels
setLayout(new BorderLayout());
// Creating JLabels / JTextArea
aTitle = new JLabel("Operations");
bTitle = new JLabel("Data Structure Contents");
west = new JPanel();
//you need to set layout manager to the panel, to lay out its components
west.setLayout(new BorderLayout());
west.setPreferredSize(new Dimension(200,200));
west.setBorder(BorderFactory.createLineBorder(Color.black));
west.setBackground(new Color(234,237,242));
add(west, BorderLayout.WEST);
west.add(aTitle, BorderLayout.NORTH);//use panel's layout manager
//you have 4 rows so GridLayout(3,2) is wrong
westSub1 = new JPanel(new GridLayout(4,2));
//for a grid layout: add components in the right order
push = new JButton("PUSH");
westSub1.add(push);
pushText = new JTextArea("pushtxt");
westSub1.add(pushText);
pop = new JButton("POP") ;
westSub1.add(pop);
popText = new JTextArea("poptxt");
westSub1.add(popText);
peek = new JButton("PEEK");
westSub1.add(peek);
peekText = new JTextArea("g");
westSub1.add(peekText);
test = new JButton("TEST");
westSub1.add(test);
resultText = new JTextArea("");
westSub1.add(resultText);
west.add(westSub1, BorderLayout.CENTER);//use panel's layout manager
east = new JPanel();
east.setPreferredSize(new Dimension(400,100));
east.setBorder(BorderFactory.createLineBorder(Color.black));
east.setBackground(new Color(255,255,255));
east.add(bTitle);
add(east, BorderLayout.CENTER);
south = new JPanel();
//you need to set layout manager to the panel, to lay out its components
south.setLayout(new BorderLayout());
south.setPreferredSize(new Dimension(100,150));
south.setBorder(BorderFactory.createLineBorder(Color.black));
south.setBackground(new Color(240,240,240));
add(south, BorderLayout.SOUTH);
cTitle = new JLabel("Information");
south.add(cTitle, BorderLayout.NORTH); //use panel's layout manager
infoText = new JTextArea("This is where commands will be displayed.");
south.add(infoText, BorderLayout.CENTER);
}
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new StackPanel());
frame.pack();
frame.setVisible(true);
}
}
The code has all the imports it needs, as wall as a main to run it.
For more information about how a code should be posted, please read :
https://stackoverflow.com/help/mcve
It's a long time ago that I worked with Swing. But I had the same troubles with the default layouts of Swing. My tip is to change to the TableLayout. It's really easy to use and you can get exact results.
Please check the tutorial: http://www.clearthought.info/sun/products/jfc/tsc/articles/tablelayout/Simple.html
Not perfect but I would chance your code like this
public class StackPanel extends JPanel {
JPanel west, east, south, southSub1;
JTextArea infoText, popText, pushText, peekText, resultText;
JLabel aTitle, bTitle, cTitle, Result;
JButton push, pop, peek, test;
public StackPanel() {
// Creating JPanels
double size[][] = {{0.3, 0.7}, {TableLayout.FILL, 70}};
setLayout(new TableLayout(size));
double sizeWest[][] = {{0.5, 0.5}, {20, 20, 20, 20, 20, 20}};
setLayout(new TableLayout(size));
west = new JPanel(new TableLayout(sizeWest));
east = new JPanel();
south = new JPanel();
// Creating JLabels / JTextArea
aTitle = new JLabel("Operations");
bTitle = new JLabel("Data Structure Contents");
cTitle = new JLabel("Information");
infoText = new JTextArea("This is where commands will be displayed.");
pushText = new JTextArea("pushtxt");
popText = new JTextArea("poptxt");
peekText = new JTextArea("g");
resultText = new JTextArea("");
west.add(aTitle, "0,0,1,0");
west.add(pushText, "0,1");
west.add(popText, "0,2");
west.add(peekText, "0,3");
west.add(resultText, "0,4");
east.add(bTitle);
south.add(cTitle);
south.add(infoText);
// Creating & Adding JButtons
push = new JButton("PUSH");
pop = new JButton("POP") ;
peek = new JButton("PEEK");
test = new JButton("TEST");
west.add(push, "1,1");
west.add(pop,"1,2");
west.add(peek,"1,3");
west.add(test, "1,4");
// Setting the placements of GUI objects
add(west, "0,0");
add(east, "1,0");
add(south, "0,1, 1,1");
// Declaring JPanel sizes // Width|Height
west.setPreferredSize(new Dimension(200,200));
east.setPreferredSize(new Dimension(400,100));
south.setPreferredSize(new Dimension(100,150));
// Setting black borders for JPanels
west.setBorder(BorderFactory.createLineBorder(Color.black));
east.setBorder(BorderFactory.createLineBorder(Color.black));
south.setBorder(BorderFactory.createLineBorder(Color.black));
// Setting JPanel background colours
west.setBackground(new Color(234,237,242));
east.setBackground(new Color(255,255,255));
south.setBackground(new Color(240,240,240));
}}
Hope this works for you!
The basic Swing layout managers are either very rudimentary or very complicated to use.
Therefore maybe FormLayout or MigLayout may be an option to use, which are sophisticated, but not too complicated to use.
Related
I wanted components deployment like this picture:
I wrote a code that makes two JPanel in a JFrame and puts components JPanel on left side. I set Frame Layout to BorderLayout and Each panel's Layout to FlowLayout. However, result was not what I wanted. Even List is not appear.
Result picture:
Can you tell me what to do?
There is a code below.
package com.java.APISearch;
import java.awt.*;
import javax.swing.*;
import javax.swing.JPanel;
public class MainFrame extends JFrame {
JPanel search;
JPanel result;
JLabel ksLb;
JTextField ksTf;
JButton ksOK;
JCheckBox choicePackage;
JCheckBox choiceClass;
JCheckBox choiceFunc;
JTextField dsTf;
JButton dsOK;
JLabel rcLb;
JList<String> rcList;
JTextField resultTf;
Container contentPane;
public MainFrame(String title) {
super(title);
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension screenSize = tk.getScreenSize();
setLocation(screenSize.width/2 - 300, screenSize.height/2 - 200);
setSize(new Dimension(600, 400));
setResizable(false);
setLayout(new BorderLayout());
search = new JPanel();
result = new JPanel();
search.setLayout(new FlowLayout(FlowLayout.LEFT));
search.setSize(new Dimension(300,400));
result.setLayout(new FlowLayout());
result.setSize(new Dimension(300,400));
contentPane = getContentPane();
contentPane.add(search, BorderLayout.WEST);
contentPane.add(result, BorderLayout.EAST);
ksLb = new JLabel("키워드 검색");
ksTf = new JTextField(20);
ksOK = new JButton("검색");
search.add(ksLb);
search.add(ksTf);
search.add(ksOK);
choicePackage = new JCheckBox("package");
choiceClass = new JCheckBox("class");
choiceFunc = new JCheckBox("function");
dsTf = new JTextField(20);
dsOK = new JButton("검색");
search.add(choicePackage);
search.add(choiceClass);
search.add(choiceFunc);
search.add(dsTf);
search.add(dsOK);
rcLb = new JLabel("recent search");
rcList = new JList<String>();
search.add(rcLb);
search.add(rcList);
}
}
The common strategy to solve complex computing tasks, is to break them into small, well defined manageable tasks. Divide and conquer.
This also applies to gui: break the design into small, easy to layout containers.In this case, for example start by dividing the design into two areas:
Serach panel added to JFrame's NORTH, and a main panel added to JFrame's CENTER. The main panel is a container for all other gui components. See more info in the code.
Here is a skeleton to demonstrate the strategy. Note the comments :
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class MainFrame extends JFrame {
public MainFrame(String title) {
super(title);
setSize(new Dimension(600, 400));
setResizable(false);
//setLayout(new BorderLayout());// no need. its the default for JFrame
JPanel search = new JPanel();
search.setLayout(new FlowLayout(FlowLayout.LEFT));
//search.setSize(new Dimension(300,400)); //let layout manager set size
//set preferred size if needed
JLabel ksLb = new JLabel("Search:");
JTextField ksTf = new JTextField(20);
JButton ksOK = new JButton("Click Me");
search.add(ksLb);
search.add(ksTf);
search.add(ksOK);
add(search, BorderLayout.NORTH); //add search to content pane
//construct a container to hold all the rest
//set border layout to it
JPanel mainPanel = new JPanel(new BorderLayout());
//add content to mainPanel:
//add result to NORTH
//add a JPanel to hold list and label to CENTER
add(mainPanel, BorderLayout.CENTER);//main to content pane
setVisible(true);
}
}
More examples of applying this strategy: 1 2 and 3
To make thing like this, use NetBeans (or some other tool that will help you create layout).
In NetBeans, getting something like you want takes ~5 minutes. It's really easier comparing to writing code for yourself.
In my personal opinion, GridBagLayout is the best thing when it comes to most of Swing based components. You can easily take control over each and every cell (whether it should grow or not, how anchors should behave, whether components should fill cell or not, etc.).
Take a look here: https://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
If you don't know which layout would suit you best, you can always take a look here:
https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
For NetBeans tutorial, take a look here: https://netbeans.org/kb/docs/java/quickstart-gui.html
So I am a computer science student and I've finished my first year. I wanted to create a simple program and I realized that I am so tired of using no layout;
this.setLayout(null);
It is so tiresome to add bounds to every single component. Well, I have been using JPanel components and GridLayout a lot, which have made my work a bit easier. But I am tired of it.
I care very much about the look of the GUI I make and use almost half the time programming to make the GUI look good before I start adding the functionality of the code. By not using a layout and adding bounds I am forced to setResizable(false) because it looks bad if I change the size of the JFrame.
I've been searching a bit, and I know of BorderLayout, and FlowLayout, but I don't like them. Is there any Layout that keeps the relative size of the components with respect to the size of the window?
For example I want to make a simple program that looks like this: (Quick sketch in Photoshop)
I can easily make this with 3 panels, but as I said, if I change the size of the frame everything stays in place instead of being relative to the window-size.
Can you guys help me?
This design looks for me to fit the BorderLayout, where in the NORTH you have the values that changes the CENTER you have the main part, and the SOUTH you have the buttons.
Link to the Oracle Border Layout
You can apply this BorderLayout to the JFrame, then create 3 JPanels for each of the NORTH,CENTER and SOUTH sections. If you want to use responsive design for the components and panels, take a look at GridBagLayout which is much more flexible than the GridLayout
Layout management is a very complex problem, I don't think people really appreciate just how complex it really is.
No one layout is ever going to achieve everything your want, in most cases, you will need to resort to two or more layouts, especially as your requirements become more complex.
For example, the following is simply a BorderLayout at the base and the buttons on a JPanel using a FlowLayout
Which is achieved by using
JList listOfThings = new JList(...);
JTextField tf = new JTextField();
JButton add = new JButton("Add");
JButton delete = new JButton("Delete");
JButton go = new JButton("Go...");
JPanel buttons = new JPanel();
buttons.add(add);
buttons.add(delete);
buttons.add(go);
add(new BorderLayout());
add(tf, BorderLayout.NORTH);
add(new JScrollPane(listOfThings));
add(buttons, BorderLayout.SOUTH);
For more complex layouts, I would consider using something like GridBagLayout. You may also want to consider MigLayout as an alternative
Take a look at Laying Out Components Within a Container for more details about using layout managers
I'd like to use the combination of BorderLayout and BoxLayout. BorderLayout let me put the component based on their relative location's relation and BoxLayout let me manage the subtle distance ( create some white space). You can use component.setBorder(BorderFactory.createEmptyBorder(top, left, bottom, right)); to achieve this goal too.
Here is a demo and hope it can help you.
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class LayoutTest{
private JTextField jTextField;
public void createUI(){
JFrame frame = new JFrame("Layout Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
JPanel mainPanel = new JPanel();
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
mainPanel.add(new TextFieldPanel());
mainPanel.add(Box.createVerticalStrut(8));
mainPanel.add(new ListPanel());
mainPanel.add(Box.createVerticalStrut(8));
mainPanel.add(new ButtonPanel());
frame.add(mainPanel,BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
LayoutTest layoutTest = new LayoutTest();
layoutTest.createUI();
}
#SuppressWarnings("serial")
class TextFieldPanel extends JPanel{
public TextFieldPanel(){
setLayout(new BorderLayout());
jTextField = new JTextField();
jTextField.setEditable(false);
add(jTextField,BorderLayout.CENTER);
}
}
#SuppressWarnings("serial")
class ListPanel extends JPanel implements ListSelectionListener{
private JList<String> list;
public ListPanel(){
setLayout(new BorderLayout());
String stringArr[] = new String[30];
for (int i = 0; i < 30; i++) {
stringArr[i] = "JList :This line is item" + i;
}
list = new JList<String>(stringArr);
JScrollPane scrollPane = new JScrollPane(list);
add(scrollPane,BorderLayout.CENTER);
setBackground(new Color(211,211,211));
list.addListSelectionListener(this);
}
#Override
public void valueChanged(ListSelectionEvent e) {
// TODO Auto-generated method stub
jTextField.setText(list.getSelectedValue());
}
}
#SuppressWarnings("serial")
class ButtonPanel extends JPanel{
public ButtonPanel(){
JButton button1 = new JButton("Button1");
JButton button2 = new JButton("Button2");
JButton button3 = new JButton("Button3");
setLayout(new BorderLayout());
add(button1,BorderLayout.WEST);
add(button2,BorderLayout.CENTER);
add(button3,BorderLayout.EAST);
}
}
}
Here is the effect:
You can use BoxLayout for ButtonPanel if you don't want to let the button's size change.
#SuppressWarnings("serial")
class ButtonPanel extends JPanel{
public ButtonPanel(){
JButton button1 = new JButton("Button1");
JButton button2 = new JButton("Button2");
JButton button3 = new JButton("Button3");
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(button1);
add(Box.createHorizontalStrut(8));
add(button2);
add(Box.createHorizontalStrut(8));
add(button3);
}
}
And the effect is like this:
For more infomation about using BoxLayout to generate whitespace, you can refer to https://stackoverflow.com/a/22525005/3378204
Try GridBagLayout.
Your sketch is actually quite close to the one of the examples in the official tutorial.
HVLayout keeps the relative size of the components with respect to the size of the window, that is, if you configure components to have a relative size (e.g. buttons usually do not grow or shrink - they stick to their preferred size). This SO question was one of the motivations for me to push HVLayout to a release and a screenshot is included (showing big window size, smalll size and preferred "default" size):
Source code for the window is in RelativeToWindowSize.java
A number of helper-classes from HVLayout are used to build the window, so I don't think it will be of much use here, but to get an impression, the "build window" part shown below:
public RelativeToWindowSize build() {
CSize cs = new CSize();
CForm form = new CForm(new VBox(new Insets(2, 4, 2, 4)), cs);
addTitledBorder(form.get(), "Vertical box", Color.BLACK);
form.add(new JScrollPane(
tfield = new JTextArea("Value that changes with value choosen from list.\nhttp://stackoverflow.com/questions/24462297/layout-relative-to-screensize/")
)).csize().setAreaSize(1.0f, 2.5f).fixedMinHeight().setMaxHeight(4.0f);
// tfield shows mono-spaced font by default.
tfield.setFont(SwingUtils.getUIFont());
form.add(new JScrollPane(vlist = new JList<String>(getListValues())))
.csize().setAreaSize(1.0f, 5.0f);
form.addChild(new HBox());
addTitledBorder(form.get(), "Horizontal box", Color.RED);
form.addChild(new HBox(SwingConstants.CENTER));
addTitledBorder(form.get(), "Centered box.", Color.BLUE);
form.add(createButton(cs, "Add"));
form.add(createButton(cs, "Modify"));
form.up();
form.addChild(new HBox(SwingConstants.TRAILING));
addTitledBorder(form.get(), "Trailing box", Color.GREEN);
form.add(createButton(cs, "Delete"));
setContentPane(form.getRoot());
pack();
setLocationByPlatform(true);
//applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
vlist.addListSelectionListener(this);
log.debug(getClass().getName() + " build.");
return this;
}
private Component createButton(CSize cs, String text) {
// For purpose of demo, let button shrink in width.
return cs.set(new TButton(text)).setFixed().shrinkWidth(0.33f).get();
}
The useless Layout Manager guy is back again, I just can't seem to get my head around these darn layouts and make them work the way I want.
Anyway, I want to have a JFrame which has one large panel at the top (I call it a header) which runs from the left to right side of the frame at the north part of the frame, then four panels below it, two just below the header and two below those, and finally a "footer" panel, basically the same as the header panel, only at the south part of the frame.
Like this:
I had code which had the four middle panels working fine, but the header panel just messed everything up, and I have since been testing with the demo layout manager code for GridBagLayout, GridLayout again and BoxLayout. I can't getting any to work as I want.
For the aware of you here, you will probably notice I've already had a question related to this, and if having two similar questions are not allowed, please make me aware and I will move this to my previous question and this can be closed.
public Shop() {
shopUI = new JFrame("Shop Menu");
shopUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
shopUI.setBounds(100, 100, 700, 500);
shopUI.setResizable(false);
allPanels = new JPanel();
headerPanel = new JPanel();
headerPanel.setLayout(new BorderLayout());
headerPanel.setBackground(Color.cyan);
mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout(2,2));
topLeft = new JPanel();
topLeft.setBackground(Color.pink);
topRight = new JPanel();
topRight.setBackground(Color.black);
bottomLeft = new JPanel();
bottomLeft.setBackground(Color.green);
bottomRight = new JPanel();
bottomRight.setBackground(Color.blue);
footerPanel = new JPanel();
footerPanel.setLayout(new BorderLayout());
footerPanel.setBackground(Color.magenta);
mainPanel.add(topLeft);
mainPanel.add(topRight);
mainPanel.add(bottomLeft);
mainPanel.add(bottomRight);
allPanels.add(headerPanel, BorderLayout.NORTH);
allPanels.add(footerPanel, BorderLayout.SOUTH);
allPanels.add(mainPanel);
shopUI.add(allPanels);
shopUI.setVisible(true);
}
I suggest learning about border layout.
for what you want, put the header in the NORTH of the border panel, and the footer in the SOUTH. How you do your other panels depends a bit on what you want them to do; if you always want them to be the same size as each other, you can use a gridlayout for them; if not, you can use boxlayout to lay either the two pairs horizontally or the two pairs vertically, again depending on what you want them to do when the frame resizes.
I think using layout managers is simplified by deciding what you want to happen in the first place, including what happens when the frame is resized. That's a large part of what layouts are all about, anyway -- what stretches, what lines up, etc.
Anyway. what you have there looks like classic BorderLayout to me. Let us know if you need further help. Incidentally, BorderLayout is default for JFrame...
edit...
this will get more interesting when you put something in the panels...
package simpleborderlayout;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main
{
public static void main(String[] args)
{
Main main = new Main(args);
main.go();
}
public Main(String ... args)
{}
public void go()
{
JPanel headerPanel = getPanel(Color.RED);
JPanel footerPanel = getPanel(Color.BLUE);
JPanel p1 = getPanel(Color.GRAY);
JPanel p2 = getPanel(Color.GRAY);
JPanel p3 = getPanel(Color.GRAY);
JPanel p4 = getPanel(Color.GRAY);
GridLayout gridLayout = new GridLayout(2,2);
JPanel middlePanel = new JPanel(gridLayout);
middlePanel.add(p1);
middlePanel.add(p2);
middlePanel.add(p3);
middlePanel.add(p4);
JFrame mainFrame = new JFrame();
mainFrame.add(headerPanel, BorderLayout.NORTH);
mainFrame.add(middlePanel, BorderLayout.CENTER);
mainFrame.add(footerPanel, BorderLayout.SOUTH);
mainFrame.pack();
mainFrame.setVisible(true);
}
private JPanel getPanel(Color c)
{
JPanel result = new JPanel();
result.setBorder(BorderFactory.createLineBorder(c));
return result;
}
}
I have a Java program where i would prefer if i could get a very specific layout.
This is what I get:
JLabel JToggleButon JLabel JToggleButon
This is what I want:
JLabel JToggleButon
JLabel JToggleButon
This is the code:
package Main;
import javax.swing.*;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
public class SystemWindow {
static JFrame window = new JFrame("System statistics");
static JToggleButton button = new JToggleButton("Push me");
static JLabel status = new JLabel("Status: ");
static JLabel status2 = new JLabel("Status: ");
static JToggleButton button2 = new JToggleButton("Push me");
static FlowLayout layout = new FlowLayout();
public static void openWindow(){
window.setLayout(new GridBagLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(status);
window.add(button);
window.add(status2);
window.add(button2);
window.setSize(100, 100);
window.pack();
window.setSize(200,70);
window.setVisible(true);
while(true){
status.setText("Status: "+button.isSelected());
status2.setText("Status: "+button2.isSelected());
}
}
}
p.s: Wrote the code in eclipse.
you can use GridLayout where you can specify rows, columns and spacings
i.e. add a jpanel with gridlayout and add these elements inside this panel
new JPanel(new GridLayout(2,2,5,5));
first parameter is the rows, second the columns and the others are the horizontal and vertical spacing between controls
I guess this works
JPanel panel = new JPanel(new GridLayout(2,2,5,5));
window.add(panel);
panel.add(status);
panel.add(button);
panel.add(status2);
panel.add(button2);
The behaviour you are getting is the default behaviour for FlowLayout. Read more about it here. Read morea bout layouts here and choose what you prefer.
As you are using GridBayLayout you have to provide some position constraints when adding controls to container. Here you have complete guide. 3rd party layout manager as MigLayout should suit your needs too.
while(true){
status.setText("Status: "+button.isSelected());
status2.setText("Status: "+button2.isSelected());
}
your computer is going to explode thanks to that code :)
I can't get my JFrame from main class to display JPanel from another class. Everything compiles without errors.
JFrameTest.java:
package jframetest;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class JFrameTest extends JFrame {
public JFrameTest() {
FlowLayout mainLayout = new FlowLayout();
setSize(320, 480);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(mainLayout);
JPanel panelMain = new JPanel(mainLayout);
JButton testButton = new JButton("Test12");
panelMain.add(testButton);
JPanelOne panel = new JPanelOne();
panelMain.add(panel);
panel.setVisible(true);
add(panelMain);
}
public static void main(String[] arguments) {
JFrameTest frame = new JFrameTest();
frame.setVisible(true);
}
}
JPanelOne.java:
package jframetest;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
public class JPanelOne extends JPanel {
public JPanelOne() {
FlowLayout layoutPanel = new FlowLayout();
JPanel panel = new JPanel(layoutPanel);
JButton button = new JButton("test");
panel.add(button);
panel.setVisible(true);
}
}
Is it good practice to keep diffrent JPanels in their own classes? (Example: Wanting to have JFrame contain few same size JPanels, which will be switched by setting setVisible() to true/false)
EDIT
Thank you for all your answers. Noted. Now back to my question:
Now that I know how to add single GUI elements created in other classes I want to know if it is possible to organize elements with layout manager in one of the classes (maybe in some other container than JPanel), so I can add them as a group organized in a layout (thats why I was asking about creating whole JPanel in other class). As on the picture:
JPanel (that 2nd class) code for this example would be:
package jframetest;
import java.awt.*;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import net.miginfocom.swing.MigLayout;
public class JPanelOne extends JPanel {
private JPanel panelSettingsMain;
private JLabel labelChooseLanguage, labelWordsCollection;
private JButton buttonSelectLanguage, buttonSelectCollection,
buttonStatistics, buttonPrintingOptions, buttonAddNewWordCollection,
buttonInterfaceCustomization;
private JSeparator separatorSettingsOne, separatorSettingsTwo,
separatorSettingsThree, separatorSettingsFour,
separatorSettingsFive;
private Color greenRegular, separatorGreenLight, separatorGreenDark;
public JPanelOne() {
// creating settings main panel
// setting up layout managers
MigLayout layoutSettingsMain = new MigLayout(
"insets 3 0 0 0");
// setting up colors
greenRegular = new Color(30, 165, 145);
separatorGreenLight = new Color(190, 240, 220);
separatorGreenDark = new Color(130, 205, 180);
panelSettingsMain = new JPanel(layoutSettingsMain);
panelSettingsMain.setBackground(Color.WHITE);
// setting up choose language label
labelChooseLanguage = new JLabel("Choose language:");
panelSettingsMain.add(labelChooseLanguage,
"gapleft 10, gaptop 15, width 200");
// setting up select language button
buttonSelectLanguage = new JButton("language");
buttonSelectLanguage.setForeground(greenRegular);
buttonSelectLanguage.setFocusPainted(false);
buttonSelectLanguage.setBorder(null);
buttonSelectLanguage.setContentAreaFilled(false);
buttonSelectLanguage.setCursor(new java.awt.Cursor(
java.awt.Cursor.HAND_CURSOR));
panelSettingsMain.add(buttonSelectLanguage, "gapbottom 15px, wrap");
// setting up light separator
separatorSettingsOne = new JSeparator();
separatorSettingsOne.setForeground(separatorGreenLight);
panelSettingsMain.add(separatorSettingsOne,
"span 2, width 320, gapbottom 15, wrap");
// setting up words collection label
labelWordsCollection = new JLabel("Words collection:");
panelSettingsMain.add(labelWordsCollection, "gapleft 10");
// setting up selectcollection button
buttonSelectCollection = new JButton("collection");
buttonSelectCollection.setForeground(greenRegular);
buttonSelectCollection.setFocusPainted(false);
buttonSelectCollection.setBorder(null);
buttonSelectCollection.setContentAreaFilled(false);
buttonSelectCollection.setCursor(new java.awt.Cursor(
java.awt.Cursor.HAND_CURSOR));
panelSettingsMain.add(buttonSelectCollection,
"gapbottom 15px, wrap");
// setting up dark separator
separatorSettingsTwo = new JSeparator();
separatorSettingsTwo.setForeground(separatorGreenDark);
panelSettingsMain.add(separatorSettingsTwo,
"span 2, width 320, gapbottom 15px, wrap");
// setting up show statistics button
buttonStatistics = new JButton("Show statistics");
buttonStatistics.setForeground(greenRegular);
buttonStatistics.setFocusPainted(false);
buttonStatistics.setBorder(null);
buttonStatistics.setContentAreaFilled(false);
buttonStatistics.setCursor(new java.awt.Cursor(
java.awt.Cursor.HAND_CURSOR));
panelSettingsMain.add(buttonStatistics,
"gapleft 10, gapbottom 15px, , wrap");
// setting up dark separator
separatorSettingsThree = new JSeparator();
separatorSettingsThree.setForeground(separatorGreenDark);
panelSettingsMain.add(separatorSettingsThree,
"span 2, width 320, gapbottom 15px, wrap");
// setting up printing options button
buttonPrintingOptions = new JButton("Printing options");
buttonPrintingOptions.setForeground(greenRegular);
buttonPrintingOptions.setFocusPainted(false);
buttonPrintingOptions.setBorder(null);
buttonPrintingOptions.setContentAreaFilled(false);
buttonPrintingOptions.setCursor(new java.awt.Cursor(
java.awt.Cursor.HAND_CURSOR));
panelSettingsMain.add(buttonPrintingOptions,
"gapleft 10, gapbottom 15px, wrap");
// setting up dark separator
separatorSettingsFour = new JSeparator();
separatorSettingsFour.setForeground(separatorGreenDark);
panelSettingsMain.add(separatorSettingsFour,
"span 2, width 320, gapbottom 15px, wrap");
// setting up add new word collection button
buttonAddNewWordCollection = new JButton("Add new word collection");
buttonAddNewWordCollection.setForeground(greenRegular);
buttonAddNewWordCollection.setFocusPainted(false);
buttonAddNewWordCollection.setBorder(null);
buttonAddNewWordCollection.setContentAreaFilled(false);
buttonAddNewWordCollection.setCursor(new java.awt.Cursor(
java.awt.Cursor.HAND_CURSOR));
panelSettingsMain.add(buttonAddNewWordCollection,
"gapleft 10, gapbottom 15px, , wrap");
// setting up dark separator
separatorSettingsFive = new JSeparator();
separatorSettingsFive.setForeground(separatorGreenDark);
panelSettingsMain.add(separatorSettingsFive,
"span 2, width 320, gapbottom 10px, wrap");
// setting up interface customization button
buttonInterfaceCustomization = new JButton(
"Interface customization");
buttonInterfaceCustomization.setForeground(greenRegular);
buttonInterfaceCustomization.setFocusPainted(false);
buttonInterfaceCustomization.setBorder(null);
buttonInterfaceCustomization.setContentAreaFilled(false);
buttonInterfaceCustomization.setCursor(new java.awt.Cursor(
java.awt.Cursor.HAND_CURSOR));
panelSettingsMain.add(buttonInterfaceCustomization,
"gapleft 10, gapbottom 15px, wrap");
}
}
I was thinking about navigating through the program GUI by setting JPanels (ones like in the example) to visible or not visible.
Is it good way to do it?
Should I split my GUI into few classes, or I should keep everything in one? I am asking, because now with only half of the GUI in the code its about 400 lines long (and it cant do anything than just "look" at this point). As I had said before - I am beginner and its one of the longest application I have written so far (which I am sure it is not that long anyway!).
EDIT
Maybe I am overthinking it, so in the end is it ok to have big GUI classes and to control visibility of different GUI areas by setting them visible or not?
EDIT
I've looked into the CardLayout tutorial at Oracle and it looks like it is good for my task (excluding the creating JPanels from the external classes, but it is ok). I misunderstood it at first and was thinking about CardLayout only in terms of tabbed pane (which I didn't want to implement in my project).
The problem comes from the JPanelOne class. It inherits JPanel but in the constructor, you create a new JPanel and then you add a button to it. If you do this instead:
public class JPanelOne extends JPanel {
public JPanelOne() {
JButton button = new JButton("test");
add(button);
}
}
it should work as you expect it.
First to answer your question, you need to add an instance of your panel to the frame with something like this in your JFrameTest constructor:
add(new JPanelOne());
You also need to add your button directly to JPanelOne itself:
public class JPanelOne extends JPanel {
public JPanelOne() {
JButton button = new JButton("test");
add(button);
}
}
Second, I believe there is a problem with these lines of code:
FlowLayout mainLayout = new FlowLayout();
// snip...
setLayout(mainLayout);
JPanel panelMain = new JPanel(mainLayout);
Each container should have its own instance of a layout manager. Otherwise your GUI will do strange things:
setLayout(new FlowLayout());
JPanel panelMain = new JPanel(mainLayout);
With some more help (user "Hilek" from some other site) I menaged to get the JPanel from another class to be displeyed in main class. Here is the code:
JFrameTest.java:
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class JFrameTest extends JFrame {
private JButton testButton;
private JPanel panelMain;
private JPanelOne panel;
public JFrameTest() {
// setting up JFrame
setLayout(null);
setPreferredSize(new Dimension(420, 90));
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// creating main JPanel (white)
panelMain = new JPanel();
panelMain.setBackground(Color.WHITE);
panelMain.setBounds(0, 0, 420, 90);
panelMain.setPreferredSize(new Dimension(200, 40));
add(panelMain);
// creating JButton in the main JPanel (white)
testButton = new JButton("Button from main class");
panelMain.add(testButton);
// creating new JPanelOne object from JPanelOne class containing black JPanel
panel = new JPanelOne();
// adding black JPanel to main JPanel (white)
panelMain.add(panel);
pack();
}
public static void main(String[] arguments) {
// creating JFrame object and setting it visible
JFrameTest frame = new JFrameTest();
frame.setVisible(true);
}
}
JPanelOne.java:
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class JPanelOne extends JPanel
{
public JPanelOne()
{
// setting up black JPanel
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(220, 40));
panel.setBackground(Color.BLACK);
// creating button on external JPanel
JButton button = new JButton("Button (+JPanel) from external class");
// adding button to the black JPanel
panel.add(button);
// adding blackJPanel
add(panel);
}
}
Print screen of working example:
http://i.stack.imgur.com/qKeBp.jpg
Maybe someone will find it helpful in their problem.
Don't call setSize() on your JFrame. Instead let the layouts set the proper sizes of their components and the GUI. After adding all components to your GUI, call pack() on the JFrame, then call setVisble(true). Note that most layouts respect a component's preferredSize more so than its size.
Also, your calling setVisible(true)on your individual components is unnecessary (unless you are changing their visibility after the GUI is up and running for some reason). You'll also want to read up more on using layout managers and will probably use FlowLayout less once you've studied them.
Edit
Regarding your recent Edit:
Maybe I am overthinking it, so in the end is it ok to have big GUI classes and to control visiblity of diffrent GUI areas by setting them visible or not?
I will answer that sometimes this is helpful, for instance if you want to change a standard calculator into a scientific calculator, sometimes it's good to simply show an already created JPanel filled with the advance calculation buttons by using setVisible(true). If on the other hand you want to swap "views" of your GUI to reflect a substantial change in its state, for instance a word processor changing from edit mode to print mode, you could swap JPanels easily to do this using a CardLayout.