I have a JFrame with a BorderLayout. I added a JPanel to the NORTH side of the JFrame. In this panel I want to add components to it in an absolute positioning. In the Center side of the JFrame I added another JPanel which should take a huge space. However when I run the application I see nothing from the North JPanel as the Center JPanel occupied all the space of the JFrame! How can I give vertical space to the North JPanel?
I really need to used absolute positioning for the north JPanel.
Here's my code:
public class AAAA extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AAAA frame = new AAAA();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public AAAA() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 1136, 520);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.NORTH);
panel.setLayout(null);
JButton btnNewButton = new JButton("New button");
btnNewButton.setBounds(0, 0, 117, 29);
panel.add(btnNewButton);
JPanel panel_1 = new JPanel();
contentPane.add(panel_1, BorderLayout.CENTER);
}
}
Update 1
I see you have already selected an answer (prematurely, I think). Here is the first iteration of what I believe you are trying to achieve. Without need for setting bounds or preferred sizes..
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class AAAA extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AAAA frame = new AAAA();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public AAAA() {
super("Laid Out");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// OMG! If you can make a GUI break at 1336 px wide, it should be
// possible to make it break at ..much smaller!
//setBounds(100, 100, 1136, 520);
setBackground(Color.YELLOW);
contentPane = new JPanel();
contentPane.setBackground(Color.BLUE);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
// make it a FlowLayout as FlowLayout.LEADING with no spacing to
// make the button snug up against the top left
JPanel panel = new JPanel(
new FlowLayout(FlowLayout.LEADING, 0, 0));
panel.setBackground(Color.GREEN);
contentPane.add(panel, BorderLayout.NORTH);
//panel.setPreferredSize(new Dimension(1024,400));
JButton btnNewButton = new JButton("New button");
// we change the margin to make the button bigger than natural size.
btnNewButton.setMargin(new Insets(6, 22, 6, 22));
panel.add(btnNewButton);
JPanel panel_1 = new JPanel();
// create a solic color image to both pad the GUI and
// provide visual indication of where it is.
BufferedImage bi = new BufferedImage(
400,200,BufferedImage.TYPE_INT_RGB);
JLabel padder = new JLabel(new ImageIcon(bi));
panel_1.add(padder);
panel_1.setBackground(Color.RED);
contentPane.add(panel_1, BorderLayout.CENTER);
pack();
setMinimumSize(getSize());
}
}
I really need to used absolute positioning for the north JPanel.
Why? If we know why you think you need to do this we can probably offer a better approach.
Don't use a null layout. Swing was designed to be used with layout managers.
The BorderLayout will respect the preferred height of the component added to the NORTH. The preferred height is zero so nothing is displayed.
Note: I am not suggesting that you set the preferred height of the panel, that is the job of the layout manager and that is why you should always use a layout manager. Layout managers do more than just set the size/location of a component.
Related
This question is very similiar to this: JScrollPane doesn't top align when there is more than enough space to show the content I tried this solution, but it does not work.
When I add a jlabel to jscrollpane, when the jlabel is small, the label becomes centered. It works normally when the scrollbar shows. Setting boxlayout does not change anything. I feel like this isn't working properly because I'm setting a perferred size to the panel? But if I remove the line panel.setPreferredSize(new Dimension((int)(screenSize.width*0.7 - 50), screenSize.height-150)); The label becomes small when there is no text, and grows to accomdate text, which I don't want. If I add the panel instead of the label, it makes the screen scrollable even though there isn't text?
This is my code:
public class Test {
// JFrame
static JFrame frame = new JFrame("Test");
//panel 1
static JPanel panel = new JPanel(new BorderLayout());
// label to display text
static JLabel label = new JLabel();
//scroll panel in main method
public static void main(String[] args) throws Exception {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
label.setBorder(new EmptyBorder(5, 5, 5, 20));
label.setText("any text makes it centered beyond 40 lines");
//create panel
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(label, BorderLayout.NORTH);
panel.add(Box.createVerticalGlue());
panel.setPreferredSize(new Dimension((int)(screenSize.width*0.7 - 50), screenSize.height-150));
panel.setBorder(new EmptyBorder(5, 5, 5, 10));
JScrollPane jspanel = new JScrollPane(label, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//jspanel.add(label, BorderLayout.CENTER);
jspanel.setPreferredSize(new Dimension((int)(screenSize.width*0.7 - 70), screenSize.height-180));
jspanel.getVerticalScrollBar().setUnitIncrement(20);
jspanel.setBorder(BorderFactory.createEmptyBorder());
jspanel.setAlignmentX(JScrollPane.LEFT_ALIGNMENT);
jspanel.setAlignmentY(JScrollPane.TOP_ALIGNMENT);
//panel.setPreferredSize(new Dimension(640, 480));
//frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(jspanel);
frame.setSize((int)(screenSize.width*0.7), screenSize.height - 50);
frame.revalidate();
frame.pack();
frame.setVisible(true);
}
}
jspanel.setAlignmentX(JScrollPane.LEFT_ALIGNMENT);
jspanel.setAlignmentY(JScrollPane.TOP_ALIGNMENT);
That will align the scrollpane in its parent container, depending on the layout manager being used. It does not affect the alignment of any component added to the scrollpane. It is not needed.
the label becomes centered
The label is sized to fill the entire space available, so you need to customize how the text of the label is painted.
If you don't want it centered then you can place it at the top using:
label.setVerticalAlignment( SwingConstants.TOP );
After reworking your code, I came up with the following GUI.
I added a call to the SwingUtilities invokeLater method. This method ensures that all Swing components are created and executed on the Event Dispatch Thread.
I eliminated all static references, except for the main method.
I reworked your code into methods so I could focus on one part of the GUI at a time.
Here's the complete runnable example. This is a minimal reproducible example.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class JScrollPaneTestGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new JScrollPaneTestGUI());
}
#Override
public void run() {
JFrame frame = new JFrame("JScrollPane Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane jspanel = createJScrollPane();
frame.add(jspanel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private JScrollPane createJScrollPane() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBackground(Color.YELLOW);
panel.setPreferredSize(new Dimension(400, 300));
JLabel label = new JLabel();
label.setBorder(new EmptyBorder(5, 5, 5, 20));
label.setText("any text makes it centered beyond 40 lines");
//create panel
panel.add(label, BorderLayout.NORTH);
JScrollPane jspanel = new JScrollPane(panel);
return jspanel;
}
}
I'm trying to create a canvas for my oval shape, and I want it to be different from the main JFrame color. So far, using setSize upon the panel doesn't work, it ended up creating a small box that I couldn't draw in. Here is the panel design that I intended it to be, with the white-colored part as the main frame.
PanelDesign
As I've said, using all three Layout modes (Border, Flow, and Grid) only creates a yellow small box in the upper middle part of the frame. This is the code that I use.
How can I create the panel design similar to the image posted above?
setTitle("Oval Shape Mover");
setSize(500, 200);
setLayout(new BorderLayout());
JPanel mainpanel, panel1, panel2;
mainpanel = new JPanel();
panel1 = new JPanel();
panel2 = new JPanel();
panel1.setBackground(Color.YELLOW);
mainpanel.add(panel1, BorderLayout.CENTER);
mainpanel.add(panel2);
add(mainpanel);
setVisible(true);
The layouts used to make Java Swing GUIs will more often honor the preferred size than the size. Having said that, a custom rendered component should override (rather than set) getPreferredSize().
This example suggests a preferred size by using a JLabel to display the icon, and empty borders to pad the GUI out.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.net.*;
public class RedDotLayout {
private JComponent ui = null;
String urlToRedCircle = "https://i.stack.imgur.com/wCF8S.png";
RedDotLayout() {
try {
initUI();
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
public final void initUI() throws MalformedURLException {
ui = new JPanel(new BorderLayout());
ui.setBackground(Color.YELLOW);
ui.setBorder(new LineBorder(Color.BLACK, 2));
JLabel label = new JLabel(new ImageIcon(new URL(urlToRedCircle)));
label.setBorder(new CompoundBorder(
new LineBorder(Color.GREEN.darker(), 2),
new EmptyBorder(20, 200, 20, 200)));
ui.add(label, BorderLayout.CENTER);
JPanel bottomPanel = new JPanel();
bottomPanel.setBackground(Color.WHITE);
bottomPanel.setBorder(new EmptyBorder(30, 50, 30, 50));
ui.add(bottomPanel, BorderLayout.PAGE_END);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
RedDotLayout o = new RedDotLayout();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
I am designing a Java app with Swing, and I have trouble designing the GUI without a layout.
My purpose is to design a GUI with one JPanel and four JButtons. I've done the math to set buttons and panel on the right place and coded like the following:
import java.awt.*;
import javax.swing.*;
public class MainFrame extends JFrame {
public MainFrame() {
this.setTitle("Example Frame");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
JPanel randomPanel = new JPanel();
randomPanel.setOpaque(true);
randomPanel.setBackground(Color.RED);
randomPanel.setBounds(10, 10, 430, 530);
JButton addButton = new JButton("Add");
addButton.setBounds(10, 550, 100, 40);
addButton.setBackground(Color.GRAY);
JButton deleteButton = new JButton("Delete");
deleteButton.setBounds(120, 550, 100, 40);
deleteButton.setBackground(Color.GRAY);
JButton refreshButton = new JButton("Refresh");
refreshButton.setBounds(230, 550, 100, 40);
refreshButton.setBackground(Color.GRAY);
JButton devButton = new JButton("Developer");
devButton.setBounds(340, 550, 100, 40);
devButton.setBackground(Color.GRAY);
this.add(randomPanel);
this.add(addButton);
this.add(deleteButton);
this.add(refreshButton);
this.add(devButton);
this.setSize(900, 600);
this.setResizable(false);
this.setVisible(true);
}
public static void main(String[] args) {
new MainFrame();
}
}
Following to the code, the components are expected to be placed as following:
However, the actual form was displayed as following:
The components exceed the form, which does not match with the expected look.
What is the problem of this and what should be done for an accurate placement of components?
There are two main problems...
setLayout(null)
setSize
What you've not taken into account is the fact that the amount of space available to the content of the window, is the size of the window MINUS the frame decorations.
Pixel perfect layouts are an illusion in modern UI development and are best avoided.
You could have a look at:
What's wrong with the Null Layout in Java?
Why is it frowned upon to use a null layout in Swing?
Why null layout and absolute positions are bad practice in Java Swing?
for more details.
A better solution is to make use one or more available layout managers. The example below simply makes use of BorderLayout and GridLayout with the help of EmptyBorder to provide some padding
See Laying Out Components Within a Container for more details
Benefits
Adaptable layout:
The example uses pack to "pack" the window around the content, automatically, without you having to adapt your code to the currently running OS (or frame decorations provided by different look and feels)
The user can change the size of the window and the content will resize automatically - bonus to the user.
The layout will adapt to the user's system settings, so if they are using a font larger then you've designed for, it won't completely blow up in your face
Want to add more buttons? No worries, knock yourself out, just add more buttons, the layout will adapt automatically, no need to "pixel push" ever component on the screen
Runnable example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
setBorder(new EmptyBorder(10, 10, 10, 10));
add(new SizablePane(430, 530));
JPanel buttonPane = new JPanel(new GridLayout(1, 3, 20, 0));
buttonPane.setBorder(new EmptyBorder(10, 0, 0, 0));
buttonPane.add(new JButton("Add"));
buttonPane.add(new JButton("Delete"));
buttonPane.add(new JButton("Refresh"));
buttonPane.add(new JButton("Developer"));
add(buttonPane, BorderLayout.SOUTH);
}
}
public class SizablePane extends JPanel {
private Dimension size;
public SizablePane(int width, int height) {
size = new Dimension(width, height);
setBackground(Color.RED);
}
#Override
public Dimension getPreferredSize() {
return size;
}
}
}
Need to add more buttons? Easy...
JPanel buttonPane = new JPanel(new GridLayout(1, 0, 20, 0));
buttonPane.setBorder(new EmptyBorder(10, 0, 0, 0));
buttonPane.add(new JButton("Add"));
buttonPane.add(new JButton("Delete"));
buttonPane.add(new JButton("Refresh"));
buttonPane.add(new JButton("Developer"));
buttonPane.add(new JButton("Some"));
buttonPane.add(new JButton("More"));
buttonPane.add(new JButton("Buttons"));
I'm quite late, I don't think this will be helpful to OP anymore... But to anyone else in the same situation.
As others mentioned, when you setSize on a JFrame, that includes the title bar and borders. There's a way to get the size values for those, but... If you want to lay things out manually in your content pane, why not prepare a content pane first, then add it to the JFrame?
class MainPanel extends JPanel {
public MainPanel() {
setLayout(null);
setPreferredSize(new Dimension(900, 600));
// JFrame will have some layouting going on,
// it won't listen to setSize
JPanel randomPanel = new JPanel();
randomPanel.setOpaque(true);
randomPanel.setBackground(Color.RED);
randomPanel.setBounds(10, 10, 430, 530);
JButton addButton = new JButton("Add");
addButton.setBounds(10, 550, 100, 40);
addButton.setBackground(Color.GRAY);
JButton deleteButton = new JButton("Delete");
deleteButton.setBounds(120, 550, 100, 40);
deleteButton.setBackground(Color.GRAY);
JButton refreshButton = new JButton("Refresh");
refreshButton.setBounds(230, 550, 100, 40);
refreshButton.setBackground(Color.GRAY);
JButton devButton = new JButton("Developer");
devButton.setBounds(340, 550, 100, 40);
devButton.setBackground(Color.GRAY);
this.add(randomPanel);
this.add(addButton);
this.add(deleteButton);
this.add(refreshButton);
this.add(devButton);
}
public static void main(String[] args) {
JFrame mainFrame = new JFrame();
mainFrame.setTitle("Example Frame");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setContentPane(new MainPanel());
mainFrame.pack();
mainFrame.setResizable(false);
mainFrame.setVisible(true);
}
}
If you mess with JFrame directly you're sort of bypassing the component system. Whereas this way, you're doing components just fine! Now, you have a JFrame fit to a single child panel, which has some things laid out manually.
This is how I normally do things, in such a situation.
P.S. "Don't lay things out manually, just use layout managers" is not something you can apply everywhere. You may need custom components sometimes, especially for something like a video game, where you have a game screen that you're custom rendering. Inside the game screen, you would be doing manual layout. They can coexist just fine, as long as you know which is which.
You need to override the getInsets() method of the underlying JFrame.
#Override
public Insets getInsets() {
return new Insets(0, 0, 0, 0);
}
Take a look at this question for more information.
On Eclipse, using JFrames, I'm using a mainFrame as the main user interface and in that frame i got a contentPanel (JPanel) containing a small panel (JPanel as well), under that panel there's a buttong, and i have another class which i named 'clients' (another frame) containting a contentPanel too (JPanel) with other compenents, i want to get the the second class contentPanel to show in the first's panel (the small panel i mentionned).
here's what i did, but it's not working!! any help?
MainF.java
public class mainF extends JFrame {
private JPanel contentPane;
public JPanel panel;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
mainF frame = new mainF();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public mainF() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 404);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
panel = new JPanel();
panel.setBounds(10, 11, 414, 256);
contentPane.add(panel);
panel.setLayout(null);
JLabel Panel = new JLabel("Main Panel");
Panel.setHorizontalAlignment(SwingConstants.CENTER);
Panel.setBounds(10, 11, 69, 33);
panel.add(Panel);
JButton btnClients = new JButton("Clients");
btnClients.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel = new Clients().getContentPane();
panel.setVisible(true);
}
});
btnClients.setBounds(162, 296, 89, 23);
contentPane.add(btnClients);
}
}
Clients
public class Clients extends JFrame {
private JPanel contentPane;
public JPanel getContentPane() {
return contentPane;
}
public Clients() {
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblClients = new JLabel("Clients");
lblClients.setHorizontalAlignment(SwingConstants.CENTER);
lblClients.setFont(new Font("Times New Roman", Font.BOLD, 18));
lblClients.setBounds(10, 11, 85, 37);
contentPane.add(lblClients);
}
}
Thanks Everyone!!
here's an image to explain the situation:
See the image here
You are using one JPanel reference panel, and using it to create 2 different panel objects. So first remove the panel from contentPane then add it back with new initialization.
public void actionPerformed(ActionEvent e) {
contentPane.remove(panel);
panel = new Clients().getContentPane();
panel.setVisible(true);
contentPane.add(panel);
contentPane.repaint();
contentPane.revalidate();
}
});
Also you require contentpane to revalidate() and repaint()
I have the following structure in a frame:
Frame->contentPane panel->topPanel panel->table
This is the code:
private JPanel contentPane;
private JTable table;
private JPanel topPanel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ShowList frame = new ShowList();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public ShowList() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 675, 433);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
topPanel = new JPanel();
topPanel.setBounds(76, 76, 491, 245);
contentPane.add(topPanel);
topPanel.setLayout(null);
table = new JTable();
table.setBounds(0, 0, 491, 245);
topPanel.add(table);
}
What I want to achieve is that when I resize the frame making the window bigger, the topPanel and the table that it is contained by this one resize also and do not stay the same size as they were before resizing the frame. I have read about Layouts but I can not make it work. Any suggestion?
Use a LayoutManager to control the size and position of the components inside of your frame. Avoid setting the layout manager of your panels as null.
I recommend you to take a look at this link: "A Visual Guide to Layout Managers" to learn more about the different kinds of layouts you can use.
In your code, for example, I would use a BorderLayout:
contentPane.setLayout(new BorderLayout());
...
contentPane.add(topPanel, BorderLayout.CENTER);
topPanel.setLayout(new BorderLayout());
...
topPanel.add(table, BorderLayout.Center);
By the way, I suppose your class ShowList extends JFrame because methods like setDefaultCloseOperation gives you an error if not, right?
I hope it helps.