Java Swing: Trying to get a button to center - java

I'm trying to make a login page for an idea I'm working on and am trying to center two buttons. When I get the screen dimensions and divide them by 2 it is not centered. Here's my code:
import javax.swing.*;
import java.awt.*;
public class ChatWindow extends JFrame {
public ChatWindow() {
JFrame frame = new JFrame("EasyChat");
JButton login = new JButton("Login");
JButton signup = new JButton("Don't have an account? Sign Up");
JPanel mainPanel = new JPanel();
Dimension ss = Toolkit.getDefaultToolkit().getScreenSize();
frame.setVisible(true);
frame.setLayout(null);
frame.setSize(800,450);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.getContentPane().add(login);
frame.getContentPane().add(signup);
login.setPreferredSize(new Dimension(25,60));
login.setFont(new Font("HelveticaNeue", Font.BOLD, 20));
signup.setBounds(ss.width / 2, ss.height / 2 + 125, 200, 100);
login.setBounds(ss.width / 2, ss.height / 2, 200, 100);
mainPanel.setLayout(new BorderLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
}
}
I also want to know how to make the buttons stayed centered if the user exits fullscreen mode.
Thank you.

Make use of the available layout managers. See Laying Out Components Within a Container for more details
For simplicity, I've just use GridBagLayout as this will centre the components within the container by default
And you get resisability for free
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
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() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBorder(new EmptyBorder(16, 16, 16, 16));
setLayout(new GridBagLayout());
add(new JButton("Login"));
add(new JButton("Sign Up"));
}
}
}
Now, if you want the buttons to be the same, you might be able to get it to work using something like GridLayout,
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
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() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
JPanel buttonPane = new JPanel(new GridLayout(1, -1));
buttonPane.add(new JButton("This is a long button"));
buttonPane.add(new JButton("Sign Up"));
add(buttonPane);
}
}
}
Or you could use a custom layout manager, for example...
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.LayoutManager2;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
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() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new ButtonLayoutManager());
add(new JButton("This is a long button"));
add(new JButton("Sign Up"));
}
}
public class ButtonLayoutManager implements LayoutManager2 {
private int horizontalPadding = 0;
#Override
public void addLayoutComponent(Component comp, Object constraints) {
}
#Override
public void addLayoutComponent(String name, Component comp) {
}
#Override
public void removeLayoutComponent(Component comp) {
}
#Override
public void invalidateLayout(Container target) {
}
#Override
public Dimension maximumLayoutSize(Container target) {
return preferredLayoutSize(target);
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
int height = 0;
int width = 0;
for (Component comp : parent.getComponents()) {
height = Math.max(comp.getPreferredSize().height, height);
width = Math.max(comp.getPreferredSize().width, width);
}
width = (width * parent.getComponentCount()) + (horizontalPadding * parent.getComponentCount() - 1);
Insets insets = parent.getInsets();
width += insets.left + insets.right;
height += insets.top + insets.bottom;
return new Dimension(width, height);
}
#Override
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
#Override
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
#Override
public void layoutContainer(Container parent) {
int width = parent.getWidth();
int height = parent.getHeight();
Insets insets = parent.getInsets();
int maxWidth = 0;
int maxHeight = 0;
for (Component comp : parent.getComponents()) {
maxWidth = Math.max(comp.getPreferredSize().width, maxWidth);
maxHeight = Math.max(comp.getPreferredSize().height, maxHeight);
}
int padding = (horizontalPadding * parent.getComponentCount() - 1);
int totalWidth = padding + (maxWidth * parent.getComponentCount());
int yOffset = (height - maxHeight) / 2;
int xOffset = (width - totalWidth) / 2;
for (Component comp : parent.getComponents()) {
comp.setBounds(xOffset, yOffset, maxWidth, maxHeight);
xOffset += horizontalPadding + maxWidth;
}
}
}
}
nb: I've not done extensive testing on this and is only meant for demonstration purposes

This answer seems to use the (first) approach detailed by MadProgrammer, but since I have it ready.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class CenteredButtons {
public CenteredButtons() {
JFrame f = new JFrame("Centered Buttons");
// A FlowLayout might also be used here
// Doing so would allow each button to be its natural size
JPanel buttonPanel = new JPanel(new GridLayout(1,0,20,20));
buttonPanel.add(new JButton("Yes"));
buttonPanel.add(new JButton("No"));
buttonPanel.setBorder(new EmptyBorder(30,75,30,75));
// a component (e.g. buttonPanel) added with no constraints will be centered
JPanel centerPanel = new JPanel(new GridBagLayout());
centerPanel.add(buttonPanel);
f.setContentPane(centerPanel);
f.pack(); // validates the layout and sets a size for the frame
f.setLocationRelativeTo(null); // centers the window on the screen
f.setExtendedState(JFrame.MAXIMIZED_BOTH); // maximizes the window
f.setVisible(true);
}
public static void main(String[] args) {
Runnable r = () -> new CenteredButtons();
SwingUtilities.invokeLater(r);
}
}

You need to subtract half the width and half the height of each of the buttons from the screen dimensions to center the two widgets.
Change the code where you set the bounds on the buttons to the following:
signup.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 + 125 - 100 / 2, 200, 100);
login.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 - 100 / 2, 200, 100);
To be notified when the user exits full screen mode, add a WindowStateListener to the frame and reset the bounds on the buttons.
Here's the complete code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
public class ChatWindow extends JFrame implements WindowStateListener{
Dimension ss;
JButton login;
JButton signup;
JFrame frame;
public ChatWindow() {
frame = new JFrame("EasyChat");
frame.addWindowStateListener(this);
login = new JButton("Login");
signup = new JButton("Don't have an account? Sign Up");
JPanel mainPanel = new JPanel();
ss = Toolkit.getDefaultToolkit().getScreenSize();
frame.setVisible(true);
frame.setLayout(null);
frame.setSize(800,450);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.getContentPane().add(login);
frame.getContentPane().add(signup);
login.setPreferredSize(new Dimension(25,60));
login.setFont(new Font("HelveticaNeue", Font.BOLD, 20));
signup.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 + 125 - 100 / 2, 200, 100);
login.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 - 100 / 2, 200, 100);
mainPanel.setLayout(new BorderLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
}
public static void main(String[] args) {
new ChatWindow();
}
#Override
public void windowStateChanged(WindowEvent e) {
Dimension ss = frame.getSize();
signup.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 + 125 - 100 / 2, 200, 100);
login.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 - 100 / 2, 200, 100);
}
}

Related

How to indeed center object in a JFrame?

I have a class which extends a Jframe, and i have it centered using setLocationRelativeTo(null);. The layouManager is null aswell.
My JFrame:
mport com.sxf.protocol.chat.util.window.AbstractField;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
public class Field extends AbstractField {
private Container cp;
public Field() {
super("Test");
buildWindow();
}
private void buildWindow() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setPreferredSize(new Dimension(frameWidth, frameHeight));
setResizable(false);
cp = getContentPane();
cp.setLayout(null);
initComponents();
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void initComponents() {
JLabel label = new JLabel("Test", SwingConstants.CENTER);
JLabel border = new JLabel("");
label.setSize(200, 30);
label.setLocation((frameWidth - label.getWidth()) / 2, (frameHeight - label.getHeight()) / 2);
border.setBounds(frameWidth / 2, 0, frameWidth / 2, frameHeight);
label.setBorder(new LineBorder(new Color(0, 0, 0)));
border.setBorder(new LineBorder(new Color(255, 0, 0)));
cp.add(label);
cp.add(border);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Field();
}
});
}
}
I added to border to see if its centered correctly or not.
The AbstractField (only some calculations in it):
public abstract class AbstractField extends JFrame {
private final static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private static final Dimension frameSize = new Dimension(screenSize.width / 4, screenSize.height / 4);
protected static final int frameWidth;
protected static final int frameHeight;
protected static final int x;
protected static final int y;
static {
frameWidth = frameSize.width;
frameHeight = frameSize.height;
x = (screenSize.width - frameWidth) / 2;
y = (screenSize.height - frameHeight) / 2;
}
public AbstractField(String title) {
super(title);
}
}
But when i try to center my components, e.g. the JLabel, doing
(frame.getWidth - component.getWidth) / 2, and the same for the height, it is not actually centered but a little bit to the right.
Is that due to a native moved beginning of the jframe and can i calculate that?
How to indeed center object in a JFrame?
Indeed add it as the only component added to a JPanel with a GridBagLayout. Use that panel as the content pane.
Example:
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class CenteredLabel {
private JComponent ui = null;
CenteredLabel() {
initUI();
}
public final void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridBagLayout());
ui.setBorder(new EmptyBorder(4,4,4,4));
JLabel centeredLabel = new JLabel("Test");
centeredLabel.setBorder(new LineBorder(Color.RED));
ui.add(centeredLabel);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
CenteredLabel o = new CenteredLabel();
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);
}
}

How centrate JLabel in a GridLayout [duplicate]

I'm making a score-keeping program, but I'm running into a problem. What I've tried to do is have a JPanel at the top that contains two JPanels, which, in turn, contains two team names. I'm confused as to why the two JLabels at the top of the program aren't centered inside of the JPanels they're contained in.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ScoreFrame extends JFrame {
private static final Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize();
private static final int WIDTH = SCREEN_SIZE.width;
private static final int HEIGHT = SCREEN_SIZE.height;
private final JTextField[] nameField = new JTextField[] { new JTextField(), new JTextField() };
private final JLabel[] nameLabel = new JLabel[] { new JLabel("Team 1"), new JLabel("Team 2") };
private final GridBagLayout gridBag = new GridBagLayout();
private final GridBagConstraints constraints = new GridBagConstraints();
private final JPanel topPanel = new JPanel();
public ScoreFrame() {
super();
setResizable(false);
setSize(SCREEN_SIZE);
setLayout(gridBag);
setUndecorated(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addKeyListener(new EscapeListener());
addComponents();
}
private void addComponents() {
addToTopPanel();
constraints.insets = new Insets(0, 0, (int) (HEIGHT * (double) 4 / 5), 0);
gridBag.setConstraints(topPanel, constraints);
add(topPanel);
}
private void addToTopPanel() {
final JPanel[] teamPanel = new JPanel[] { new JPanel(), new JPanel() };
topPanel.setLayout(gridBag);
topPanel.setSize(new Dimension(WIDTH, HEIGHT / 5));
Dimension teamPanelSize = new Dimension(WIDTH / 2, HEIGHT / 5);
teamPanel[0].setSize(teamPanelSize);
teamPanel[1].setSize(teamPanelSize);
Font nameFont = new Font("Times New Roman", Font.PLAIN, 50);
nameLabel[0].setFont(nameFont);
nameLabel[1].setFont(nameFont);
teamPanel[0].add(nameLabel[0]);
teamPanel[1].add(nameLabel[1]);
gridBag.setConstraints(teamPanel[0], constraints);
constraints.gridx = 1;
gridBag.setConstraints(teamPanel[1], constraints);
topPanel.add(teamPanel[0]);
topPanel.add(teamPanel[1]);
}
public void paint(Graphics g) {
super.paint(g);
int strokeSize = ((WIDTH + HEIGHT) / 2) / 300;
if (strokeSize < 1) {
strokeSize = 1;
}
final int fontSize = (int) (strokeSize * 12.5);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(strokeSize));
g.drawLine(WIDTH / 2, 0, WIDTH / 2, HEIGHT / 5);
g.drawLine(WIDTH / 2, (int) (HEIGHT * (double) 105 / 400), WIDTH / 2, HEIGHT);
g.drawLine(0, HEIGHT / 5, WIDTH, HEIGHT / 5);
g.drawRect((int) (WIDTH * (double) 45 / 100), HEIGHT / 5, WIDTH / 10, (int) (HEIGHT * (double) 3 / 20));
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setFont(new Font("Times New Roman", Font.PLAIN, fontSize));
g.drawString("Errors", (int) (WIDTH * (double) 101 / 220), HEIGHT / 4);
}
private JFrame getFrame() {
return this;
}
public static void main(final String args[]) {
new ScoreFrame().setVisible(true);
}
public class EscapeListener implements KeyListener {
public void keyPressed(final KeyEvent event) {
if (event.getKeyCode() == 27) {
final int choice = JOptionPane.showConfirmDialog(getFrame(), "Do you want to exit the program?");
if (choice == 0) {
System.exit(0);
}
}
}
public void keyReleased(final KeyEvent event) {
}
public void keyTyped(final KeyEvent event) {
}
}
}
Invoking pack() is a critical step in using layouts. This example uses JLabel.CENTER and GridLayout to center the labels equally as the frame is resized. For simplicity, the center panel is simply a placeholder. This somewhat more complex example uses a similar approach along with java.text.MessageFormat.
Addendum: But how would I apply pack() to my code?
Simply invoke pack() as shown in the examples cited. I don't see an easy way to salvage your current approach of setting sizes extrinsically. Instead, override getPreferredSize() in a JPanel for your main content. No matter the screen size, your implementation of paintComponent() should adapt to the current size, for example.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/** #see https://stackoverflow.com/a/14422016/230513 */
public class Scores {
private final JLabel[] nameLabel = new JLabel[]{
new JLabel("Team 1", JLabel.CENTER),
new JLabel("Team 2", JLabel.CENTER)};
private void display() {
JFrame f = new JFrame("Scores");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel teamPanel = new JPanel(new GridLayout(1, 0));
teamPanel.add(nameLabel[0]);
teamPanel.add(nameLabel[1]);
f.add(teamPanel, BorderLayout.NORTH);
f.add(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
}, BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Scores().display();
}
});
}
}

Creating Vertical Scrollable Pane for JPanels

I am trying to make a JScrollPane that contains JPanels that have charts from the JFreeChart API. GenerateChartPanel is a method that return the charts in a JPanel so I can quickly make a bunch of them. So far I have this in main:
public static void main (String[] args){
JFrame main = new JFrame();
main.setLayout(new BorderLayout());
main.setPreferredSize(new Dimension(500,500));
//Creates specFrame
JScrollPane specScrollPane = new JScrollPane();
JPanel container = new JPanel();
container.setLayout(new GridLayout());
container.add(generateSpecPanelFromSmiles("C"));
container.add(generateSpecPanelFromSmiles("CC"));
container.add(generateSpecPanelFromSmiles("CCC"));
container.setVisible(true);
specScrollPane.setVisible(true);
specScrollPane.add(container);
main.add(specScrollPane);
RefineryUtilities.centerFrameOnScreen(main);
main.setVisible(true);
When I run this, nothing shows up. Apparently you can't pack, setCloseOp, setLayout, or center these panes so I commented them out. What am I missing?
EDIT: Getting Dimensions
specPanel.addComponentListener(new java.awt.event.ComponentAdapter() {
#Override
public void componentResized(ComponentEvent event) {
specPanel.setSize(Math.min(specPanel.getPreferredSize().width, specPanel.getWidth()),
Math.min(specPanel.getPreferredSize().height, specPanel.getHeight()));
}
});
thanks
JScrollPane is designated to nest only one JComponent
you have to put another JPanel to JScrollPane, to this JPanel you can to add your three components
have to change default Layout Manager (FlowLayout) for parent JPanel (contains three components), which one to depends of those components, how they returns its PreferredSize, maybe to start with GridLayout(all childs has the same size on the screen)
EDIT
whatever the generateSpecPanelFromSmiles is it, to must returns PreferredSize to parentPanel, e.g. (playing with PreferredSize with GridLayout and BoxLayout - box accepting min, max and preferred size)
.
.
.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class JPanelsInsideJScrollPane {
private JFrame frame = new JFrame("JPanels Inside JScrollPane");
private JScrollPane scrollPane = new JScrollPane();
private JPanel parentPanel, childOne, childTwo, childThree;
private JButton button = new JButton("Change, Switch Layout Manager to BoxLayout");
public JPanelsInsideJScrollPane() {
parentPanel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(new Dimension(800, 600));
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
};
parentPanel.setLayout(new GridLayout(0, 1));
childOne = new JPanel() {
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 300);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(500, 300);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
};
childTwo = new JPanel() {
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(600, 400);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
};
childThree = new JPanel() {
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(800, 600);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.ORANGE);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
};
parentPanel.add(childOne);
parentPanel.add(childTwo);
parentPanel.add(childThree);
scrollPane.setViewportView(parentPanel);
scrollPane.getVerticalScrollBar().setUnitIncrement(30);
scrollPane.getHorizontalScrollBar().setUnitIncrement(30);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
LayoutManager manager = parentPanel.getLayout();
if ((manager != null) && (manager instanceof BoxLayout)) {
parentPanel.setLayout(new GridLayout(0, 1));
button.setText("Change, Switch Layout Manager to BoxLayout");
} else if ((manager != null) && (manager instanceof GridLayout)) {
parentPanel.setLayout(new BoxLayout(parentPanel, BoxLayout.PAGE_AXIS));
button.setText("Change, Switch Layout Manager to GridLayout");
}
parentPanel.revalidate();
parentPanel.repaint();
}
});
frame.add(scrollPane);
frame.add(button, BorderLayout.SOUTH);
frame.setSize(400, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JPanelsInsideJScrollPane();
}
});
}
}

JPanel Inside Of A JPanel

I am trying to get a JPanel to appear inside of another JPanel. Currently, the JPanel is in an external JFrame and loads with my other JFrame. I want the JPanel to be inside the other JPanel so the program does not open two different windows.
Here is a picture:
The small JPanel with the text logs I want inside of the main game frame. I've tried adding the panel to the panel, panel.add(othePanel). I've tried adding it the JFrame, frame.add(otherPanel). It just overwrites everything else and gives it a black background.
How can I add the panel, resize, and move it?
Edits:
That is where I want the chatbox to be.
Class code:
Left out top of class.
public static JPanel panel;
public static JTextArea textArea = new JTextArea(5, 30);
public static JTextField userInputField = new JTextField(30);
public static void write(String message) {
Chatbox.textArea.append("[Game]: " + message + "\n");
Chatbox.textArea.setCaretPosition(Chatbox.textArea.getDocument()
.getLength());
Chatbox.userInputField.setText("");
}
public Chatbox() {
panel = new JPanel();
panel.setPreferredSize(new Dimension(220, 40));
panel.setBackground(Color.BLACK);
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setPreferredSize(new Dimension(380, 100));
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
scrollPane
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
userInputField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
String fromUser = userInputField.getText();
if (fromUser != null) {
textArea.append(Frame.username + ":" + fromUser + "\n");
textArea.setCaretPosition(textArea.getDocument()
.getLength());
userInputField.setText("");
}
}
});
panel.add(userInputField, SwingConstants.CENTER);
panel.add(scrollPane, SwingConstants.CENTER);
//JFrame frame = new JFrame();
//frame.add(panel);
//frame.setSize(400, 170);
//frame.setVisible(true);
}
Main frame class:
public Frame() {
frame.getContentPane().remove(loginPanel);
frame.repaint();
String capName = capitalizeString(Frame.username);
name = new JLabel(capName);
new EnemyHealth("enemyhealth10.png");
new Health("health10.png");
new LoadRedCharacter("goingdown.gif");
new Spellbook();
new LoadMobs();
new LoadItems();
new Background();
new Inventory();
new ChatboxInterface();
frame.setBackground(Color.black);
Frame.redHealthLabel.setFont(new Font("Serif", Font.PLAIN, 20));
ticks.setFont(new Font("Serif", Font.PLAIN, 20));
ticks.setForeground(Color.yellow);
Frame.redHealthLabel.setForeground(Color.black);
// Inventory slots
panel.add(slot1);
panel.add(name);
name.setFont(new Font("Serif", Font.PLAIN, 20));
name.setForeground(Color.white);
panel.add(enemyHealthLabel);
panel.add(redHealthLabel);
panel.add(fireSpellBookLabel);
panel.add(iceSpellBookLabel);
panel.add(spiderLabel);
panel.add(appleLabel);
panel.add(fireMagicLabel);
panel.add(swordLabel);
// Character
panel.add(redCharacterLabel);
// Interface
panel.add(inventoryLabel);
panel.add(chatboxLabel);
// Background
panel.add(backgroundLabel);
frame.setContentPane(panel);
frame.getContentPane().invalidate();
frame.getContentPane().validate();
frame.getContentPane().repaint();
//I WOULD LIKE THE LOADING OF THE PANEL SOMEWHERE IN THIS CONSTRUCTOR.
new ResetEntities();
frame.repaint();
panel.setLayout(null);
Run.loadKeyListener();
Player.px = Connect.x;
Player.py = Connect.y;
new Mouse();
TextualMenu.rect = new Rectangle(Frame.inventoryLabel.getX() + 80,
Frame.inventoryLabel.getY() + 100,
Frame.inventoryLabel.getWidth(),
Frame.inventoryLabel.getHeight());
Player.startMessage();
}
Don't use static variables.
Don't use a null layout.
Use appropriate layout managers. Maybe the main panel uses a BorderLayout. Then you add your main component to the CENTER and a second panel to the EAST. The second panel can also use a BorderLayout. You can then add the two components to the NORTH, CENTER or SOUTH as you require.
For example, using a custom Border:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.RadialGradientPaint;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
#SuppressWarnings("serial")
public class FrameEg extends JPanel {
public static final String FRAME_URL_PATH = "http://th02.deviantart.net/"
+ "fs70/PRE/i/2010/199/1/0/Just_Frames_5_by_ScrapBee.png";
public static final int INSET_GAP = 120;
private BufferedImage frameImg;
private BufferedImage smlFrameImg;
public FrameEg() {
try {
URL frameUrl = new URL(FRAME_URL_PATH);
frameImg = ImageIO.read(frameUrl);
final int smlFrameWidth = frameImg.getWidth() / 2;
final int smlFrameHeight = frameImg.getHeight() / 2;
smlFrameImg = new BufferedImage(smlFrameWidth, smlFrameHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics g = smlFrameImg.getGraphics();
g.drawImage(frameImg, 0, 0, smlFrameWidth, smlFrameHeight, null);
g.dispose();
int top = INSET_GAP;
int left = top;
int bottom = top;
int right = left;
Insets insets = new Insets(top, left, bottom, right);
MyBorder myBorder = new MyBorder(frameImg, insets);
JTextArea textArea = new JTextArea(50, 60);
textArea.setWrapStyleWord(true);
textArea.setLineWrap(true);
for (int i = 0; i < 300; i++) {
textArea.append("Hello world! How is it going? ");
}
setLayout(new BorderLayout(1, 1));
setBackground(Color.black);
Dimension prefSize = new Dimension(frameImg.getWidth(),
frameImg.getHeight());
JPanel centerPanel = new MyPanel(prefSize);
centerPanel.setBorder(myBorder);
centerPanel.setLayout(new BorderLayout(1, 1));
centerPanel.add(new JScrollPane(textArea), BorderLayout.CENTER);
MyPanel rightUpperPanel = new MyPanel(new Dimension(smlFrameWidth,
smlFrameHeight));
MyPanel rightLowerPanel = new MyPanel(new Dimension(smlFrameWidth,
smlFrameHeight));
top = top / 2;
left = left / 2;
bottom = bottom / 2;
right = right / 2;
Insets smlInsets = new Insets(top, left, bottom, right);
rightUpperPanel.setBorder(new MyBorder(smlFrameImg, smlInsets));
rightUpperPanel.setLayout(new BorderLayout());
rightLowerPanel.setBorder(new MyBorder(smlFrameImg, smlInsets));
rightLowerPanel.setBackgroundImg(createBackgroundImg(rightLowerPanel
.getPreferredSize()));
JTextArea ruTextArea1 = new JTextArea(textArea.getDocument());
ruTextArea1.setWrapStyleWord(true);
ruTextArea1.setLineWrap(true);
rightUpperPanel.add(new JScrollPane(ruTextArea1), BorderLayout.CENTER);
JPanel rightPanel = new JPanel(new GridLayout(0, 1, 1, 1));
rightPanel.add(rightUpperPanel);
rightPanel.add(rightLowerPanel);
rightPanel.setOpaque(false);
add(centerPanel, BorderLayout.CENTER);
add(rightPanel, BorderLayout.EAST);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private BufferedImage createBackgroundImg(Dimension preferredSize) {
BufferedImage img = new BufferedImage(preferredSize.width,
preferredSize.height, BufferedImage.TYPE_INT_ARGB);
Point2D center = new Point2D.Float(img.getWidth()/2, img.getHeight()/2);
float radius = img.getWidth() / 2;
float[] dist = {0.0f, 1.0f};
Color centerColor = new Color(100, 100, 50);
Color outerColor = new Color(25, 25, 0);
Color[] colors = {centerColor , outerColor };
RadialGradientPaint paint = new RadialGradientPaint(center, radius, dist, colors);
Graphics2D g2 = img.createGraphics();
g2.setPaint(paint);
g2.fillRect(0, 0, img.getWidth(), img.getHeight());
g2.dispose();
return img;
}
private static void createAndShowGui() {
FrameEg mainPanel = new FrameEg();
JFrame frame = new JFrame("FrameEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyPanel extends JPanel {
private Dimension prefSize;
private BufferedImage backgroundImg;
public MyPanel(Dimension prefSize) {
this.prefSize = prefSize;
}
public void setBackgroundImg(BufferedImage background) {
this.backgroundImg = background;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return prefSize;
}
}
#SuppressWarnings("serial")
class MyBorder extends AbstractBorder {
private BufferedImage borderImg;
private Insets insets;
public MyBorder(BufferedImage borderImg, Insets insets) {
this.borderImg = borderImg;
this.insets = insets;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width,
int height) {
g.drawImage(borderImg, 0, 0, c);
}
#Override
public Insets getBorderInsets(Component c) {
return insets;
}
}
Which would look like:

Java stacking components

I am writing a program in Java which has a UI. I want to make a sort of health bar thing. I have to JLabels HealthBarUnder and HealthBarOver. I want to position them on top of each other so that I can decrease the width of HealthBarOver (thus making the appearance of a health bar). What is the best Layout to use. I am using BorderLayout, but it won't let me re-size the components.
Thank You
You "could" do something like this...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class SlidingLabels {
public static void main(String[] args) {
new SlidingLabels();
}
public SlidingLabels() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel lower = new JLabel();
private JLabel upper = new JLabel();
private float progress = 1f;
private boolean ignoreUpdates;
public TestPane() {
setLayout(new GridBagLayout());
lower.setOpaque(true);
lower.setBackground(Color.GRAY);
lower.setBorder(new LineBorder(Color.BLACK));
lower.setPreferredSize(new Dimension(200, 25));
upper.setOpaque(true);
upper.setBackground(Color.BLUE);
upper.setBorder(new LineBorder(Color.BLACK));
upper.setPreferredSize(new Dimension(200, 25));
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.NONE;
add(upper, gbc);
gbc.fill = GridBagConstraints.HORIZONTAL;
add(lower, gbc);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
progress -= 0.01;
if (progress <= 0.001) {
((Timer)e.getSource()).stop();
}
updateProgress();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void updateProgress() {
ignoreUpdates = true;
int width = (int) (getWidth() * progress);
upper.setPreferredSize(new Dimension(width, 25));
revalidate();
repaint();
ignoreUpdates = false;
}
#Override
public void invalidate() {
super.invalidate();
if (!ignoreUpdates) {
updateProgress();
}
}
}
}
But it uses a number of nasty hacks and will probably blow up in you face sooner rather then later....
You should use a JProgressBar
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class ProgressBar {
public static void main(String[] args) {
new ProgressBar();
}
public ProgressBar() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JProgressBar pb;
private float progress = 1f;
public TestPane() {
setLayout(new GridBagLayout());
pb = new JProgressBar();
pb.setBorderPainted(false);
pb.setStringPainted(true);
pb.setBorder(new LineBorder(Color.BLACK));
pb.setForeground(Color.BLUE);
pb.setBackground(Color.GRAY);
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(pb, gbc);
updateProgress();
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
progress -= 0.01;
if (progress <= 0.001) {
((Timer)e.getSource()).stop();
}
updateProgress();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void updateProgress() {
pb.setValue((int) (100 * progress));
}
}
}
But, if that doesn't meet your needs, you'd be better of writing your own progress component...
public class ProgressPane {
public static void main(String[] args) {
new ProgressPane();
}
public ProgressPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private float progress = 1f;
public TestPane() {
setOpaque(false);
setForeground(Color.BLUE);
setBackground(Color.GRAY);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
progress -= 0.01;
if (progress <= 0.001) {
((Timer)e.getSource()).stop();
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(200, fm.getHeight() + 4);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth() - 4;
int height = getHeight() - 4;
int x = 2;
int y = 2;
g.setColor(getBackground());
g.fillRect(x, y, width, height);
g.setColor(Color.BLACK);
g.drawRect(x, y, width, height);
g.setColor(getForeground());
g.fillRect(x, y, (int) (width * progress), height);
g.setColor(Color.BLACK);
g.drawRect(x, y, (int) (width * progress), height);
FontMetrics fm = g.getFontMetrics();
String value = NumberFormat.getPercentInstance().format(progress);
x = x + ((width - fm.stringWidth(value)) / 2);
y = y + ((height - fm.getHeight()) / 2);
g.setColor(Color.WHITE);
g.drawString(value, x, y + fm.getAscent());
}
}
}
I would HIGHLY recommend one of the two last examples, they are simpler to implement and maintain over time. The first WILL explode, very unpleasantly, in your face
ps- Kleo, please don't hurt me :(
I would use this little method as well to give a more manual approach:
private void addComponent(Container container, Component c, int x, int y,int width, int height) {
c.setBounds(x, y, width, height);
container.add(c);
}
And call it like this:
addComponent(container such as JPanel, component such as a JButton, x position, yposition, width, height);

Categories

Resources