Java CardLayout JPanel moves up, when second JPanel added - java

I am new to Java and mostly CardLayout. I want to simply switch "windows" represented by JPanels. I read somewhere that job for CardLayout. But my problem is, when add chatPanel to mainPanel (this is the CardLayout one), it shifts the content of connectPanel several pixels to the top, away from its centered position. Is I skip in my code createChatPanel(), its where it should be.
I have this code:
package App;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import Validators.*;
public class GUI {
private JFrame mainFrame = null;
private JPanel mainPanel = null;
private CardLayout cl = new CardLayout();
public GUI(){
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (UnsupportedLookAndFeelException e) {
}
catch (ClassNotFoundException e) {
}
catch (InstantiationException e) {
}
catch (IllegalAccessException e) {
}
mainFrame = new JFrame("MainChat");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(640,480);
mainFrame.setLocationRelativeTo(null);
mainFrame.setResizable(false);
mainFrame.setLayout(new GridBagLayout());
JMenuBar menuBar = new JMenuBar();
JMenu menuFile = new JMenu("Soubor");
JMenu menuHelp = new JMenu("Nápověda");
menuBar.add(menuFile);
menuBar.add(menuHelp);
menuFile.add(new JMenuItem("Nové Připojení"));
menuFile.add(new JSeparator());
menuFile.add(new JMenuItem("Konec"));
menuHelp.add(new JMenuItem("O programu"));
mainFrame.setJMenuBar(menuBar);
createMainPanel();
createConnectPanel();
createChatPanel();
mainFrame.setVisible(true);
}
public void createMainPanel() {
mainPanel = new JPanel(cl);
mainFrame.add(mainPanel);
}
public void createConnectPanel() {
JPanel connectPanel = new JPanel();
mainPanel.add(connectPanel,"connectPanel");
JTextField ip = new JTextField();
ip.setDocument(new JTextFieldLimit(15));
ip.setColumns(11);
JLabel iplabel = new JLabel("IP:");
connectPanel.add(iplabel);
connectPanel.add(ip);
JButton connect = new JButton("Connect");
connect.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(mainPanel,"chatPanel");
}
});
connectPanel.add(connect);
}
public void createChatPanel(){
JPanel chatPanel = new JPanel();
mainPanel.add(chatPanel,"chatPanel");
JTextArea chatbox = new JTextArea();
chatbox.setPreferredSize(new Dimension(200,200));
chatPanel.add(chatbox);
}
}
Please, what I messed up? Thanks.

Since you are adding two JPanels to your main JPanel,
these two panels both need to fit within the main panel.
If one of the inner panels is much larger than the other one,
the main panel will adjust to fit the larger one.
E.g. commenting this line:
chatbox.setPreferredSize(new Dimension(200,200));
would cause your text field to stay put. This is because the
chatbox would not cause the container to resize.
Also note that the main panel is not initially the same size as your
main frame, since you have not set the size of the main panel.
If you would set the size of the connectPanel to the same size
as your main frame, the connectPanel would not
be automatically resized when adding the chatPanel (as a
consequence of the mainPanel being resized)
So what you could do is add the middle line in:
JPanel connectPanel = new JPanel();
connectPanel.setSize(640, 480);
mainPanel.add(connectPanel, "connectPanel");
, which probably would solve your problem.
Although this would work, I definitely recommend using
MIG Layout for
all your GUI designing. It will save you plenty of time if
you take an hour to learn it. It will also save you from
having to set sizes manually (and thereby saving you from
having to rewrite half your GUI code with every design change).

If you want a JPanel centered in another, place your connectPanel in another JPanel that acts as a dumb container, and have this container use GridBagLayout. Then if you add the connectPanel to the container without any GridBagConstraints, it will be added to the default position for GridBagLayout which is centered. You can then add this container JPanel to your mainPanel using the same constant that you would have used for your connectPanel.
I would tend to let the layouts determine the size of components and avoid using setSize and even setPreferredSize, and would definitely call pack() on my JFrame prior to setting it visible. You definitely don't want to set the size or preferredSize of your JTextField, but rather set its columns and rows and place it in a JScrollPane, and then add that JScrollPane to the view.
Edit:
Here's an example that shows placement of something like your connect panel at the top, middle and bottom of a small gui. Just press the "Next" button to see what I mean:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class GUI2 extends JPanel {
public static final String CONNECT_NORTH = "connect north";
public static final String CONNECT_CENTER = "connect center";
private static final String CONNECT_SOUTH = "connect south";
private static final String CHAT_PANEL = "chat panel";
private CardLayout cardlayout = new CardLayout();
public GUI2() {
setLayout(cardlayout);
add(createConnectPanel(BorderLayout.NORTH), CONNECT_NORTH);
add(createConnectPanel(BorderLayout.CENTER), CONNECT_CENTER);
add(createConnectPanel(BorderLayout.SOUTH), CONNECT_SOUTH);
add(createChatPanel(), CHAT_PANEL);
}
public void nextPanel() {
cardlayout.next(this);
}
private JPanel createConnectPanel(String borderlayoutLocation) {
JPanel innerPanel = new JPanel();
innerPanel.add(new JLabel("IP:"));
innerPanel.add(Box.createHorizontalStrut(5));
innerPanel.add(new JTextField(11));
innerPanel.add(Box.createHorizontalStrut(5));
innerPanel.add(new JButton(new AbstractAction("Next") {
#Override
public void actionPerformed(ActionEvent arg0) {
GUI2.this.nextPanel();
}
}));
JPanel innerPanel2 = new JPanel(new GridBagLayout());
innerPanel2.add(innerPanel);
JPanel connectPanel = new JPanel(new BorderLayout());
connectPanel.add(innerPanel2, borderlayoutLocation);
return connectPanel;
}
private JPanel createChatPanel() {
JPanel chatPanel = new JPanel(new BorderLayout(5, 5));
chatPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
chatPanel.add(new JScrollPane(new JTextArea(15, 30)), BorderLayout.CENTER);
chatPanel.add(new JTextField(), BorderLayout.SOUTH);
return chatPanel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGui();
}
});
}
private static void createGui() {
JFrame frame = new JFrame("App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new GUI2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

Related

Adding JScrollPane to a JFrame

I want to add JPanel containers to a JScrollPane and add this scroll pane to a JFrame. But when I add multiple panels to the scroll pane this happens. The gap between the scroll pane and the top bar increases. I use BoxLayout as layout manager for all the components that I use.
Here is my take on laying out this GUI. Some notes:
Rather than use a BoxLayout in the JScrollPane it puts a GridLayout in the PAGE_START of a BorderLayout. This is fine for when it's OK to stretch the elements in the scroll pane to the full width of the GUI. Stick to a BoxLayout (which I rarely use) or a GridBagLayout if it's necessary to keep the elements at their preferred size.
This strategy of layout is basically 'divide and conquer' in that it starts with the smallest sub-divisions of the GUI (e.g. the FlowLayout for the buttons) and then adds those containers to larger containers with different layouts and constraints (e.g. adding that button panel to the LINE_END of a BorderLayout - to push I to the right of the GUI) as needed for the overall effect.
I'd also consider using a JList (using a panel for the renderer) in the scroll pane. It depends on the use as to whether that makes sense.
Note that this code is an MRE. An MRE should have everything that's needed (including imports, a class structure and the main method) for another person to compile and run the code.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.ActionEvent;
// ref: https://stackoverflow.com/a/70934802/418556
public class ScrollPaneTestGUI {
int elementCount = 1;
JPanel elementsPanel = new JPanel(new GridLayout(0,1,2,2));
public ScrollPaneTestGUI() {
initGUI();
}
private void initGUI() {
// this will become the content pane of the frame
JPanel gui = new JPanel(new BorderLayout(4,4));
gui.setBorder(new EmptyBorder(4,4,4,4));
JPanel pageStartPanel = new JPanel(new BorderLayout(2,2));
gui.add(pageStartPanel, BorderLayout.PAGE_START);
pageStartPanel.add(new JLabel("LINE START label"), BorderLayout.LINE_START);
// default flow layout is good for this one
JPanel buttonPanel = new JPanel();
pageStartPanel.add(buttonPanel, BorderLayout.LINE_END);
buttonPanel.add(new JButton("Does Nothing"));
Action addToScrollAction = new AbstractAction("Add to scrollPane") {
#Override
public void actionPerformed(ActionEvent e) {
elementsPanel.add(getPanelForScroll());
elementsPanel.revalidate();
}
};
JButton addToScrollButton = new JButton(addToScrollAction);
buttonPanel.add(addToScrollButton);
JPanel scrollPanel = new JPanel(new BorderLayout());
scrollPanel.add(elementsPanel, BorderLayout.PAGE_START);
gui.add(new JScrollPane(scrollPanel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
);
for (int ii=0; ii<2; ii++) {
elementsPanel.add(getPanelForScroll());
}
JFrame frame = new JFrame("ScrollPane GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setContentPane(gui);
frame.pack(); // sets the GUI to the exact size needed
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
}
private JPanel getPanelForScroll() {
JPanel p = new JPanel();
p.add(new JLabel("Panel " + elementCount++));
p.setBorder(new EmptyBorder(10,200,10,200));
p.setBackground(Color.GREEN);
return p;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new ScrollPaneTestGUI();
}
};
SwingUtilities.invokeLater(r);
}
}

Background JSwing Image Loading Oddly

I can't seem to figure out how I would add in a background WITH all of my panels showing.
I tried to set the JFrame content pane as a label with an imageicon and the frame does show, it just doesn't show the image like above.
This is the code that I've used.
frame.setContentPane(new JLabel(new ImageIcon("res/Wallpaper.png")));
The second attempt I've used is to ADD (not set) an image into the content pane of the frame. This did not work as shown in the second picture above and it only shows the panels but no background. The code is on the bottom.
frame.getContentPane().add(new JLabel(new ImageIcon("res/Wallpaper.png")));
The third attempt I've tried is to create a subclass of JComponent and Override the paintComponents method then setan object of it as the contentpane. This does not work and instead turns my screen blank.
Here is the code I've used and the class code is in the 1st answer of this link Setting background images in JFrame. The result is the 3rd image of this post.
File img = new File("res/Wallpaper.png");
BufferedImage myImage;
try {
myImage = ImageIO.read(img);
frame.setContentPane(new ImagePanel(myImage));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The 4th attempt I've tried is adding the picture into the main panel that fills up the screen. This does not work at all and instead breaks the image in half so half of the screen has the image half doesn't.
Here is the code I've used for my 4th attempt. The result is the 4th last image on the top.
BufferedImage myPicture;
try {
myPicture = ImageIO.read(new File("res/Wallpaper.png"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
pMain.add(picLabel);
} catch (IOException e) {
e.printStackTrace();
}
I'm not sure why the JPanels aren't showing up.
I know that in the 1st example when you set the frame as a JLabel it gives it a null layout but that was the only way I could find to DISPLAY the image.
I would like to somehow add the panels ontop of the frame with that background but after reading numerous threads I could not find out how.
If anyone does find out, please post the code and explain if you can. I also have the class get the system class theme that sets it into the theme of what the computer is using. Ex. I am using a windows operating system so it shows it kind of like my operating system.
This thread is not a duplicate. In other threads they only have a frame but in my thread I have several panels that aren't showing for some particular reason.
EDIT: I don't know what's up, I tried to use this thread Setting background images in JFrame but I had no luck.
The 1st method it gave me I tried and then instead of showing anything it showed nothing at all, no picture no components nothing at all. In case if you need more information I have: 4 JPanels on the bottom of the screen, I also have a border surrounding my window but doesn't show up in the 1st window. I also have borders surrounding my panels too.
So the 1st method I've tried setting it on the content pane, image loads but all of the components are gone.
2nd method I've tried adding it into the content pane but yet again with no luck and I get a panel with no background.
3rd method I've tried is creating a separate class and overriding the paintComponent method and adding an image to the constructor of it then placing this object of the class into the setcontentPane() parameter of the frame. Does not work at all, all I get is a blank frame.
Code I am using for my frame:
public class LoginScreen {
JCheckBox remember_User;
JButton login, create_Account, forums, faqs;
Border whiteLine;
JTextField userField;
JFormattedTextField passField;
private void createView() {
// Created essential details for the frame
JFrame frame = new JFrame();
frame.setTitle("Name of the game");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Defining panels and a constraint on the bottomPanel.
// More info - Total amt of panels: 5
// pLogin and pInfo are in the bottomCompPanel and bottomCompPanel is in
// bottomPanel
// bottom panel is in pMain
// Giving panels some attributes like backgrounds and borders
JPanel pMain = new JPanel(new BorderLayout());
pMain.setBorder(BorderFactory.createMatteBorder(3, 3, 6, 3,
Color.DARK_GRAY));
frame.getContentPane().add(pMain);
whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400, 250));
pLogin.setBorder(whiteLine);
JPanel pInfo = new JPanel(new GridBagLayout());
pInfo.setBackground(Color.green);
pInfo.setPreferredSize(new Dimension(200, 100));
pInfo.setBorder(whiteLine);
JPanel bottomCompPanel = new JPanel(new GridBagLayout());
GridBagConstraints bGBC = new GridBagConstraints();
bGBC.gridx = 0;
bGBC.gridy = 0;
bGBC.insets = new Insets(0, 20, 0, 0);
bGBC.anchor = GridBagConstraints.PAGE_END;
bottomCompPanel.add(pLogin, bGBC);
bGBC.gridx++;
bottomCompPanel.add(pInfo, bGBC);
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
bottomPanel.add(bottomCompPanel);
pMain.add(bottomPanel, BorderLayout.SOUTH);
frame.setVisible(true);
}
public static void main(String[] args) {
LoginScreen login = new LoginScreen();
login.createView();
}
}
POST UPDATE 2: Here is the code that I've used using #peeskillet's 1st method. It works sort of but it gives me the same results as the 3rd photo, a cut off picture. P.S I add the panels down at the bottom to my JLabel at the end.
private void createView() {
//Created essential details for the frame
JFrame frame = new JFrame();
frame.setTitle("Name of the game");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
JLabel background = new JLabel(new ImageIcon("res/Wallpaper.png"));
background.setLayout(new BorderLayout());
frame.setContentPane(background);
//Defining panels and a constraint on the bottomPanel.
//More info - Total amt of panels: 5
//pLogin and pInfo are in the bottomCompPanel and bottomCompPanel is in bottomPanel
//bottom panel is in pMain
//Giving panels some attributes like backgrounds and borders
whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400,250));
pLogin.setBorder(whiteLine);
JPanel pInfo = new JPanel(new GridBagLayout());
pInfo.setBackground(Color.green);
pInfo.setPreferredSize(new Dimension(200,100));
pInfo.setBorder(whiteLine);
JPanel bottomCompPanel = new JPanel(new GridBagLayout());
GridBagConstraints bGBC = new GridBagConstraints();
bGBC.gridx = 0;
bGBC.gridy = 0;
bGBC.insets = new Insets(0,20,0,0);
bGBC.anchor = GridBagConstraints.PAGE_END;
bottomCompPanel.add(pLogin, bGBC);
bGBC.gridx++;
bottomCompPanel.add(pInfo, bGBC);
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
bottomPanel.add(bottomCompPanel);
background.add(bottomPanel, BorderLayout.SOUTH);
"I tried to set the JFrame content pane as a label with an imageicon"
You need to set the layout on the JLabel. It will be null be default.
import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;
public class BackgroundImage {
private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";
private void init() throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel background = new JLabel(new ImageIcon(new URL(IMG)));
background.setLayout(new GridBagLayout());
background.add(loginPanel());
f.setContentPane(background);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel loginPanel() {
Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400, 250));
pLogin.setBorder(whiteLine);
return pLogin;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
new BackgroundImage().init();
} catch (Exception ex) {}
});
}
}
"I've tried is to create a subclass of JComponent and Override the paintComponents method then setan object of it as the contentpane"
Should be paintComponent (no "s"), but just like with JLabel, you need to set the layout. JComponent layout is null be default. You also need to give it a preferred size when painting.
import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;
public class BackgroundImage {
private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";
private void init() throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent background = new BackgroundComponent(new ImageIcon(new URL(IMG)));
background.setLayout(new GridBagLayout());
background.add(loginPanel());
f.setContentPane(background);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel loginPanel() {
Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400, 250));
pLogin.setBorder(whiteLine);
return pLogin;
}
class BackgroundComponent extends JComponent {
public ImageIcon background;
public BackgroundComponent(ImageIcon background) {
this.background = background;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(background.getIconWidth(), background.getIconHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background.getImage(),
0, 0,
background.getIconWidth(),
background.getIconHeight(), this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
new BackgroundImage().init();
} catch (Exception ex) {}
});
}
}
Using (extending) JPanel instead of JComponent would be similar except JPanel does have a default layout which is FlowLayout.
UPDATE
To get your desired layout, you need to play around with the different layout managers. The combination I used is
Outer (main panel) -- BorderLayout
Bottom (bottom panel) -- BoxLayout inside (south) of outer layout
For the BorderLayout, you need to make sure the panel opaque property is set to false, as BorderLayout will stretch the panel and cover the background.
For the BoxLayout, you need to make sure to set the maximum size and the preferred size
import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;
public class BackgroundImage {
private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";
private final Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
private void init() throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent background = new BackgroundComponent(new ImageIcon(new URL(IMG)));
background.setLayout(new BorderLayout());
background.add(bottomPanel(), BorderLayout.SOUTH);
f.setContentPane(background);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel bottomPanel() {
JPanel bottomPanel = new JPanel();
bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
BoxLayout layout = new BoxLayout(bottomPanel, BoxLayout.X_AXIS);
bottomPanel.setLayout(layout);
bottomPanel.setOpaque(false);
bottomPanel.add(Box.createHorizontalGlue());
bottomPanel.add(loginPanel());
bottomPanel.add(Box.createRigidArea(new Dimension(10, 0)));
bottomPanel.add(infoPanel());
return bottomPanel;
}
private JPanel infoPanel() {
JPanel pInfo = new JPanel(new GridBagLayout());
pInfo.setAlignmentY(Component.BOTTOM_ALIGNMENT);
pInfo.setBackground(Color.green);
pInfo.setMaximumSize(new Dimension(200, 100));
pInfo.setPreferredSize(new Dimension(200, 100));
pInfo.setBorder(whiteLine);
return pInfo;
}
private JPanel loginPanel() {
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setAlignmentY(Component.BOTTOM_ALIGNMENT);
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400, 250));
pLogin.setMaximumSize(new Dimension(400, 250));
pLogin.setBorder(whiteLine);
return pLogin;
}
class BackgroundComponent extends JComponent {
public ImageIcon background;
public BackgroundComponent(ImageIcon background) {
this.background = background;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(background.getIconWidth(), background.getIconHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background.getImage(),
0, 0,
background.getIconWidth(),
background.getIconHeight(), this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
new BackgroundImage().init();
} catch (Exception ex) {
}
});
}
}
For more information about using the different layout managers, see
Laying Out Components Within a Container
You can try JLayeredPane and setOpaque(boolean) method.
Code:
public class BackgroundImageTest{
private JFrame frame;
public BackgroundImageTest() {
frame = new JFrame("Background Image Frame");
// set frame properties
JPanel panel = new JPanel(new FlowLayout());
panel.setOpaque(false);
JButton btn = new JButton("Change Background");
panel.add(btn);
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae) {
setBackgroundImage(getImage(new File("Wallpaper2.png")));
}
});
JPanel main = (JPanel) frame.getContentPane();
main.setLayout(new FlowLayout());
main.add(panel);
main.setOpaque(false);
setBackgroundImage(getImage(new File("Wallpaper.png")));
frame.setVisible(true);
}
private Image getImage(File imageFile) {
BufferedImage image = null;
try {
image = ImageIO.read(imageFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return image;
}
private void setBackgroundImage(Image img) {
if(img == null) return;
ImageIcon ii = new ImageIcon(img);
JLabel lblBG = new JLabel(ii);
lblBG.setName("BackgroundImageLabel");
JLayeredPane layeredPane = frame.getLayeredPane();
Component[] comps = layeredPane.getComponentsInLayer(new Integer(Integer.MIN_VALUE));
for (int i = 0; i < comps.length; i++) {
System.out.println(comps[i].getName());
if (comps[i] instanceof JLabel && comps[i].getName().equals("BackgroundImageLabel")){
layeredPane.remove(comps[i]);
break;
}
}
layeredPane.add(lblBG, new Integer(Integer.MIN_VALUE));
lblBG.setBounds(0,0,ii.getIconWidth(), ii.getIconHeight());
}
}

Swing: JscrollPane with autonomous content size

I have a panel with layout (for example, BorderLayout) and a JScrollPane on its center. JScrollPane has content inside it (a JPanel)
The thing is, that when this JScrollPane resizes, I do not want its content to resize. For example, if layout increases the JScrollPane, I want its content to be as small it was (and occupy only part of the pane), but it resizes to fit pane.
I also need an opportunity to reduce content inside the pane and increase it manually (there is no problems with increasing, they are in reducing).
So, how can I achieve content size independency? Of course, I need to save scrolling features, if content will be bigger than JScrollPane.
Here is a simple example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestScroll extends JFrame {
public TestScroll() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(500, 500);
init();
}
private void init() {
setLayout(new BorderLayout());
// Inner panel
final JPanel innerPanel = new JPanel();
innerPanel.setOpaque(true);
innerPanel.setBackground(Color.BLUE);
innerPanel.setPreferredSize(new Dimension(200, 200));
// Scroll
final JScrollPane scrollPane = new JScrollPane(innerPanel);
add(scrollPane, BorderLayout.CENTER);
// Buttons
JPanel buttonPanel = new JPanel();
JButton extendButton = new JButton("Extend inner panel");
extendButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
innerPanel.setPreferredSize(new Dimension(innerPanel.getWidth() * 2,
innerPanel.getHeight() * 2));
innerPanel.revalidate();
}
});
buttonPanel.add(extendButton);
JButton reduceButton = new JButton("Reduce inner panel");
reduceButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
innerPanel.setPreferredSize(new Dimension(innerPanel.getWidth() / 2,
innerPanel.getHeight() / 2));
innerPanel.revalidate();
}
});
buttonPanel.add(reduceButton);
add(buttonPanel, BorderLayout.NORTH);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new TestScroll();
}
});
}
}
So, problem statement:
I do not want inner panel to stretch to the pane (but pane can be resized by outer layout, so the panel must just keep its size).
I want to be able to reduce inner panel manually so it can occupy only a part of the scroll pane.
And, of course, I want to save scrolling functionality when inner panel is larger than scroll pane.
Did you follow Andrew's link about using layout managers to achieve your goal?
Here is another simple example:
//final JScrollPane scrollPane = new JScrollPane(innerPanel);
JPanel outer = new JPanel();
outer.add( innerPanel );
final JScrollPane scrollPane = new JScrollPane(outer);

Moving JButtons

What would be the best way for me to move the buttons so they are under each other instead of beside each other (see image below)?
The code for this class is as follows. The Main method is in a different class.
package guiplay;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class MainGUI extends JFrame {
private JButton openReportSelection = new JButton("Open Report Viewer");
private JButton closeButton = new JButton("Close Program");
private JButton getCloseButton(){
return closeButton;
}
private JButton getOpenReportSelection(){
return openReportSelection;
}
public MainGUI(){
mainInterface();
}
private void mainInterface(){
setTitle("Program Information Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel centerPanel = new JPanel(new FlowLayout());
centerPanel.add(openReportSelection);
openReportSelection.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
JFrame reports = new JFrame();
new ReportGUI();
}
});
centerPanel.add(closeButton);
getCloseButton().addActionListener(new Listener());
add(centerPanel, BorderLayout.CENTER);
setSize(700,200);
setVisible(true);
}
}
You can use a BoxLayout as it aligns all elements either horizontally or vertically. Simply set BoxLayout's axis to BoxLayout.Y_AXIS.
Example:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.BoxLayout;
import javax.swing.JButton;
public class BoxLayoutExample extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
BoxLayoutExample frame = new BoxLayoutExample();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public BoxLayoutExample() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 180, 150);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
JButton btnOpenReportViewer = new JButton("Open Report Viewer");
contentPane.add(btnOpenReportViewer);
JButton btnCloseProgram = new JButton("Close Program");
contentPane.add(btnCloseProgram);
}
}
If you want to control the size so that they are similar to each other, you can use a grid layout by setting the JFrame's content pane to a GridLayout:
contentPane.setLayout(new GridLayout(0, 1, 0, 0)); // the value of 1 here means 1 column
Don't put the JButtons in a container that uses FlowLayout but rather one that uses another layout that allows stacking of components. A GridLayout comes to mind if the buttons are to be the same size, or if they need to be different sizes, a BoxLayout.
Check out the Layout Manager Tutorial.
You could try using a BoxLayout instead of a FlowLayout. In that case, you could have:
JPanel centerPanel = new JPanel(new BoxLayout());
centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); // Y_AXIS will cause the components to be added vertically
centerPanel.add(openReportSelection);
centerPanel.add(closeButton);
centerPanel.setMaximumSize(new Dimension(100, 60)); // Set the maximum horizontal and vertical distances used, as BoxLayouts expand to fill the provided area
Or as Hovercraft said, you could use a GridLayout, in which case you would specify it as follows:
JPanel centerPanel = new JPanel(new GridLayout(1,0); // The "0" parameter specifies as many rows as needed, but only one column
centerPanel.add(openReportSelection);
centerPanel.add(closeButton);
centerPanel.setMaximumSize(new Dimension(100, 60)); // GridLayouts will also expand to fill the entire area, so you'll probably want some size parameters.
You could also see this link for more on BoxLayouts, or this link for more on GridLayouts.

How can I align elements in JPanels / JFrames?

I'm completely new to using the GUI in java, so I'm having a bit of trouble figuring out how to align everything that I need to. I have to panels in my JFrame that I need to align (One to the left, one to the right) and a few buttons in one of the panels that I need to be centered in the panel. Here is my code.
package application;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.io.*;
import java.nio.*;
import java.util.*;
public class Main extends JPanel
{
public static void main(String[] args)
{
//set the ui to the native OS
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException e)
{
}
JFrame frame = new JFrame("Application Name");
Menu menu = new Menu();
JPanel iconPanel = new JPanel();
final JPanel grid = new JPanel(new FlowLayout());
JButton firewallButton = new JButton("Firewall");
JButton networkButton = new JButton("Network");
JButton printerButton = new JButton("Printer");
int iconPanelSizeX;
int iconPanelSizeY;
int gridSizeX;
int gridSizeY;
int gridPosition;
//frame setting
frame.setSize(800, 600);
frame.setMinimumSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//add grid and iconPanel JPanels to the frame
frame.add(iconPanel);
iconPanel.add(firewallButton);
iconPanel.add(networkButton);
iconPanel.add(printerButton);
frame.add(grid);
//iconPanel settings
iconPanel.setBorder(BorderFactory.createLoweredSoftBevelBorder());
iconPanel.setBackground(Color.gray);
iconPanel.setLayout(new FlowLayout());
iconPanel.setSize(new Dimension(100, 600));
iconPanel.setVisible(true);
//grid setting
grid.setBackground(Color.red);
grid.setSize(new Dimension(700, 600));
grid.setVisible(true);
//this is for resizing components when the user resizes the window
int counter = 0;
while(counter == 0)
{
firewallButton.setSize(new Dimension(iconPanel.getWidth(), 50));
networkButton.setSize(new Dimension(iconPanel.getWidth(), 50));
printerButton.setSize(new Dimension(iconPanel.getWidth(), 50));
iconPanelSizeX = frame.getWidth() / 10;
iconPanelSizeY = frame.getHeight();
gridSizeX = (frame.getWidth() / 10) * 9;
gridSizeY = frame.getHeight();
iconPanel.setSize(new Dimension(iconPanelSizeX, iconPanelSizeY));
grid.setSize(new Dimension(gridSizeX, gridSizeY));
}
}
}
As you can see, the second JPanel (grid) doesn't line up with the right side of the frame, and the buttons inside iconTray don't center either. I realize these are both probably simple layout fixes, but I have no clue where to start.
For simple splitting of JFrame you can use GridLayout with 1 row and 2 colums.
frame.setLayout(new GridLayout(1,2,3,3)); //3,3 are gaps
frame.add(grid);
frame.add(iconPanel);
For centering components in panels you can use FlowLayout which is by default set on JPanels:
Doing it manualy:
grid.setLayout(new FlowLayout()); //Centered components
grid.setLayout(new FlowLayout(FlowLayout.LEFT,3,3)); //Components aligned to left
grid.setLayout(new FlowLayout(FlowLayout.RIGHT,3,3)); //Components aligned to right
This is how it looks:
Also, few observations:
Never call setXXXSize() methods for your components;
Try to avoid calling setSize(); for JFrame, call pack(); instead;
Call setVisible(true); in the end of code;
All your huge code can be "stripped" to this:
import javax.swing.*;
import java.awt.*;
public class Main extends JPanel
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Application Name");
JPanel iconPanel = new JPanel();
JPanel grid = new JPanel(new FlowLayout());
JButton firewallButton = new JButton("Firewall");
JButton networkButton = new JButton("Network");
JButton printerButton = new JButton("Printer");
frame.add(iconPanel);
iconPanel.add(firewallButton);
iconPanel.add(networkButton);
iconPanel.add(printerButton);
grid.setBackground(Color.GREEN);
frame.setLayout(new GridLayout(1,2,3,3));
frame.add(grid);
frame.add(iconPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
how to align buttons vertically?
This example uses a vertical Box in the WEST area of the frame's default BorderLayout:
import java.awt.*;
import javax.swing.*;
/** #see http://stackoverflow.com/a/14927280/230513 */
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
display();
}
});
}
private static void display() throws HeadlessException {
JFrame frame = new JFrame("Application Name");
JButton firewallButton = new JButton("Firewall");
JButton networkButton = new JButton("Network");
JButton printerButton = new JButton("Printer");
//iconPanel settings
Box iconPanel = new Box(BoxLayout.Y_AXIS);
iconPanel.add(firewallButton);
iconPanel.add(networkButton);
iconPanel.add(printerButton);
iconPanel.setBackground(Color.gray);
iconPanel.setVisible(true);
frame.add(iconPanel, BorderLayout.WEST);
//grid setting
JPanel grid = new JPanel() {
#Override
// arbitrary placeholder size
public Dimension getPreferredSize() {
return new Dimension(320, 230);
}
};
grid.setBackground(Color.red);
frame.add(grid, BorderLayout.CENTER);
//frame setting
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I suggest you take some time going through A Visual Guide to Layout Managers. This will help you become familiar with the layout managers which are available with the Standard API. It takes some experience and hard work to figure out which of these is the right tool to get the exact look you want. Once you become comfortable with what is available from the Standard API, you should also look around for third-party Layout Manager APIs which provide other options.
I have to panels in my JFrame that I need to align (One to the left,
one to the right) and a few buttons in one of the panels that I need
to be centered in the panel. Here is my code.
I realize these are both probably simple layout fixes, but I have no
clue where to start.
Use more complex layout than simple FlowLayout which you actually using. I suggest to you use
GridBagLayout
BoxLayout
Check references here

Categories