My question is about layout in Java Swing.
I want to make a screen like shown below. I saw this video on youtube and made a gif of the part I want.
I want 2 panels and a button like this:
When i clicked the button the JPanel will be hidden and JTable's width will be 100% like html/css like this; (And when button clicked again JPanel will be shown etc..)
How can I do this? Which layout should I use?
There is more than one way to do it, but here's an example that uses BorderLayout as the main layout, and places the button in a left aligning FlowLayout:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class LayoutDemo {
private LayoutDemo() {
JFrame frame = new JFrame("Demo");
frame.setLocationByPlatform(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel buttonHolder = new JPanel(new FlowLayout(FlowLayout.LEADING));
frame.add(buttonHolder, BorderLayout.NORTH);
JButton button = new JButton("Toggle visibility");
buttonHolder.add(button);
final JPanel left = new JPanel();
left.setPreferredSize(new Dimension(100, 200));
left.setBackground(Color.BLUE);
frame.add(left, BorderLayout.LINE_START);
JLabel table = new JLabel("This pretends to be a table", SwingConstants.CENTER);
table.setPreferredSize(new Dimension(400, 200));
frame.add(table);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
left.setVisible(!left.isVisible());
}
});
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new LayoutDemo();
}
});
}
}
I used setPreferredSize() to give the components some reasonable default size, but usually it should be automatically calculated by the layout manager from the sizes of the child components, or in case of a custom component, you should override getPreferredSize() return what is appropriate for the component.
The result looks like:
Related
I want to add a JPanel to a JLayeredPane when the user clicks enter, but the JPanel is not showing up.
If i add the JPanel to the JLayeredPane in the JFrame's constructor, everything is working correctly.
What do i have to do, that the JPanel is showing up, when the user clicks 'enter'?
Here's the code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Test extends javax.swing.JFrame {
public static void main(String[] args) {
Test test = new Test();
test.setSize(800, 500);
test.setVisible(true);
}
public Test() {
setLayout(new BorderLayout());
//LayeredPane on JFrame
JLayeredPane jlp = new JLayeredPane();
jlp.setLayout(new BorderLayout());
this.add(jlp, BorderLayout.CENTER);
//Adds a JPanel to the North
JPanel jPNorth = new JPanel();
jPNorth.setBackground(Color.RED);
jlp.add(jPNorth, BorderLayout.NORTH, JLayeredPane.DEFAULT_LAYER);
//Adds Enter Keybinding
InputMap key_input_map = jlp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap key_action_map = jlp.getActionMap();
key_input_map.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "add_jpanel");
key_action_map.put("add_jpanel", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
JPanel jPSouth = new JPanel();
jPSouth.setBackground(Color.YELLOW);
jlp.add(jPSouth, BorderLayout.SOUTH, JLayeredPane.DEFAULT_LAYER);
System.out.println("enter");
}
});
}
}
Thanks,
Jumagoro
You did everything correct, the solution is very simple. When you dynamically add swing Components to each other, you must to use component.repaint(); and component.revalidate(); to redraw the elements. Add the two commands after everything is added. So your actionPerformed method should be changed to the following:
public void actionPerformed(ActionEvent e) {
JPanel jPSouth = new JPanel();
jPSouth.setBackground(Color.YELLOW);
jlp.add(jPSouth, BorderLayout.SOUTH, JLayeredPane.DEFAULT_LAYER);
//Need these to here!
jlp.repaint();
jlp.revalidate();
System.out.println("enter");
}
I'm creating a login system and when I made my login button, it took up the entire frame. I tried the .setBounds(); but it did not work. Not sure what I did wrong, please help.
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Main extends JFrame{
public Main(){
JTextField name = new JTextField("Username");
JTextField pass = new JTextField("Password");
JButton login = new JButton("Login");
name.setBounds(230, 110, 100, 25);
pass.setBounds(230, 145, 100, 25);
login.setBounds(230, 165, 100, 25);
add(name);
add(pass);
add(login);
}
public static void main(String [] args) {
Main a = new Main();
a.setDefaultCloseOperation(EXIT_ON_CLOSE);
a.setSize(500, 300);
a.setLocationRelativeTo(null);
a.setVisible(true);
a.setTitle("Login System");
a.setResizable(false);
a.setLayout(new FlowLayout());
}
}
in your constructor, try setLayout(new FlowLayout());.
This will likely not lead to what you want, but from there on you can investigate further. i recommend you read about layouts here:
https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
By default, Frame has a BorderLayout installed. When the items are added they are all added to "centre" because constraints are not passed. And the centre component occupies all free space in the BorderLayout. You can either change the layout manager or provide constraints while adding components.
FlowLayout or BoxLayout are good candidates for this.
Problem is by default the layout manager for JFrame is BorderLayout. Once you add components with method add() it gets added to the center region. So the last component added is shown. In your case its the login button. Also setBounds() don't work with the said layout manager.
You have to work a lot on your coding style. What you did is first created the frame and added components to it and later in the main() you have set the size, made it visible and then you set the layout manager to FlowLayout.
Ideally, you must construct the frame, set layout, add components to frame, use pack() to set frame size, set frame's location and finally make frame visible.
Using BorderLayout:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Main implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Main());
}
#Override
public void run() {
JFrame frame = new JFrame("BorderLayout");
frame.getContentPane().add(new JTextField(15), BorderLayout.WEST);
frame.getContentPane().add(new JPasswordField(15), BorderLayout.CENTER);
frame.getContentPane().add(new JButton("Login"), BorderLayout.EAST);
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
Using FlowLayout:
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Main implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Main());
}
#Override
public void run() {
JFrame frame = new JFrame("FlowLayout");
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new JTextField(15));
frame.getContentPane().add(new JPasswordField(15));
frame.getContentPane().add(new JButton("Login"));
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
P.S. If you still want to use absolute positions, I would recommend you using SpringLayout or GroupLayout.
Accordion can be downloaded here - http://www.javaswingcomponents.com/product/accordion
Here is a sample output of an accordion. I want to remove the numbers on the right side of the tab. How can I do it? Thanks!
Here is the code of the sample:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.javaswingcomponents.accordion.JSCAccordion;
import com.javaswingcomponents.accordion.TabOrientation;
public class SampleAccordion extends JPanel {
static JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SampleAccordion codeExample = new SampleAccordion();
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container panel = frame.getContentPane();
panel.setLayout(new BorderLayout());
panel.add(codeExample, BorderLayout.CENTER);
frame.pack();
frame.setSize(500, 300);
frame.setVisible(true);
}
});
}
public SampleAccordion() {
JSCAccordion accordion = new JSCAccordion();
JPanel transparentPanel = new JPanel();
transparentPanel.setOpaque(false);
transparentPanel.setBackground(Color.GRAY);
JPanel opaquePanel = new JPanel();
opaquePanel.setOpaque(true);
opaquePanel.setBackground(Color.GRAY);
accordion.addTab("Tab 1", new JLabel("help me remove 1"));
accordion.addTab("Tab 2", new JLabel("help me remove 2"));
accordion.setTabOrientation(TabOrientation.VERTICAL);
setLayout(new GridLayout(1, 1, 30, 30));
add(accordion);
}
}
You can specify whether you want to see the tab index:
accordion.setTabOrientation(TabOrientation.VERTICAL);
((FormattedTabRenderer) accordion.getTabRenderer()).setShowIndex(false);
(The first line is already in the sample code and is only included as a reference.)
It looks like the accordion supports three pluggable look & feels: basic, steel, and dark steel. I'm not sure whether the tab renderer can be cast to the FormattedTabRenderer abstract class for all PLAFs, but it seems to work fine for steel.
I am trying to add a JPanel to a JFrame with FlowLayout, but continue to get this exception: "Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: illegal component position". I would like to be able to implement a JPanel with a few buttons in the near future, so please let me know what I can do to allow that.
package textadv;
import java.awt.FlowLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Label;
import java.awt.event.KeyEvent;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TextAdv {
private JFrame frame = new JFrame("Text Adventure");
private JPanel mainPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
private JButton b1 = new JButton("Left");
public TextAdv() {
mainPanel.setBackground(Color.RED);
int FRAME_WIDTH = 400;
int FRAME_HEIGHT = 400;
b1.setEnabled(true);
b1.setVisible(true);
b1.setPreferredSize(new Dimension(40, 40));
mainPanel.setVisible(true);
mainPanel.setPreferredSize(new Dimension (50, 50));
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setVisible(true);
mainPanel.add(b1, FlowLayout.CENTER);
frame.add(mainPanel);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TextAdv fS = new TextAdv();
}
});
}
You cant specify FlowLayout options to the add method of Container. This resolves to the add() overload which accepts Component, and an int, index. Other layouts let you use the add(Component, Object) overload, like the GridBagLayout and its GridBagConstraints. For the FlowLayout you specify the options to the constructor of the layout only.
Replace this
mainPanel.add(b1, FlowLayout.CENTER);
with this
mainPanel.add(b1);
Consider revisiting the tutorial here: http://docs.oracle.com/javase/tutorial/uiswing/layout/flow.html
See Container here : http://docs.oracle.com/javase/7/docs/api/java/awt/Container.html#add%28java.awt.Component,%20int%29
I'm working on a program in which I'd used a JTextArea, JButton, JLabel and JPanel.
The logic I'd to implement is: user types a text in the given textArea and then click on the button. On button click I'd to retrieve the text from the textArea and create a label with the written text(as in textArea) and show it on the panel.
Everything I'd done previously is correct but the problem is with the label and panel. The label is not visible on the panel.
The code snippets is:
import java.awt.BorderLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.BevelBorder;
/**
*
* #author mohammadfaisal
* http://ermohammadfaisal.blogspot.com
* http://facebook.com/m.faisal6621
*
*/
public class CodeMagnets extends JFrame{
private JTextArea area4Label;
private JLabel codeLabel;
private JButton createButton;
private JPanel magnet;
public CodeMagnets(String title) throws HeadlessException {
super(title);
magnet=new JPanel(null);
JScrollPane magnetScroller=new JScrollPane(magnet);
magnetScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
magnetScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
add(BorderLayout.CENTER, magnetScroller);
JPanel inputPanel=new JPanel();
area4Label=new JTextArea(5, 30);
area4Label.setTabSize(4);
JScrollPane textScroller=new JScrollPane(area4Label);
inputPanel.add(textScroller);
createButton=new JButton("Create code magnet");
createButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//codeLabel=new JLabel(area4Label.getText());
codeLabel=new MyLabel(area4Label.getText());//this is for my new question
codeLabel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
codeLabel.setLocation(50, 20);
codeLabel.setVisible(true);
magnet.add(codeLabel);
area4Label.setText("");
//pack();
}
});
inputPanel.add(createButton);
add(BorderLayout.SOUTH, inputPanel);
//pack();
setSize(640, 480);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new CodeMagnets("Code Magnets");
}
}
You need to repaint()/validate() your panle after adding new components in it dynamically. So after this:
magnet.add(codeLabel);
add this:
magnet.validate();
or
magnet.repaint();
Also one thing you are using null layout for magnet panel. So must have to setBounds() of jLable before adding it to magnet panel. So it becomes
public void actionPerformed(ActionEvent e) {
codeLabel=new JLabel(area4Label.getText());
codeLabel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
codeLabel.setBounds(50, 20, 100, 100);
magnet.add(codeLabel);
magnet.repaint();
area4Label.setText("");
}
It is not recommended to use null as layout, you should use proper layout like BorderLayout or GridLayout or even simpler FlowLayout based on your requirement.
As said by #Andrew use something like:
codeLabel.setSize(codeLabel.getPreferredSize());
codeLabel.setLocation(50, 20);
instead of
codeLabel.setBounds(50, 20, 100, 100);
This will solve the size issue of jLabel.
public void actionPerformed(ActionEvent e) {
codeLabel=new JLabel(area4Label.getText());
codeLabel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
codeLabel.setBounds(50, 20, 100, 100);
codeLabel.setOpaque(True);
magnet.add(codeLabel);
magnet.repaint();
area4Label.setText("");
}