How can I center align a Component with SpringLayout - java

I am trying to create a Form in Java with Swing and I'm having difficulty with managing my layouts.
I want to have a few text fields with labels in the center of a dialog and have "save" and "close" buttons in the lower right.
Adding the buttons to the lower right of the dialog is simple, but I am not sure how to center align the text fields. I figured that, if there wasn't a center component method, then I might be able to align the field by calculating the center of the dialog window and then updating the position when the dialog is re-sized. But I am new to swing and I'm not sure how to do either (or if that is even a good idea).
How can I center align my components using the Spring Layout Manager?
public class Main {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame myFrame = new MyFrame();
myFrame.setVisible(true);
}
});
}
}
Here's how the frame looks:
public class MyFrame extends JFrame {
JLabel label1;
JTextField field1;
JLabel label2;
JTextField field2;
JButton saveButton;
JButton closeButton;
public MyFrame() {
initLookAndFeel();
initFrameProperties();
initContent();
initLayout();
}
private initContent() {
label1= new JLabel("Label 1");
field1= new JTextField();
label1.setLabelFor(field1);
label2= new JLabel("Label 2");
field2= new JTextField();
label2.setLabelFor(field2);
saveButton = new JButton("Save");
closeButton = new JButton("Close");
closeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
});
this.add(label1);
this.add(field1);
this.add(lebel2);
this.add(field2);
this.add(saveButton);
this.add(closeButton);
}
private void initLayout() {
SpringLayout layout = new SpringLayout();
this.setLayout(layout);
}

You can center align components by adding a constraint that sets the Horizontal Center of your component to be the same as the Horizontal Center of the content pane. This will automatically update the components position when the window is re-sized.
SpringLayout layout = new SpringLayout();
// For Horizontal Alignment
layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, component, 0, SpringLayout.HORIZONTAL_CENTER, contentPane);
// For Vertical Alignment
layout.putConstraint(SpringLayout.VERTICAL_CENTER, component, 0, SpringLayout.VERTICAL_CENTER, contentPane);
setLayout(layout);

SpringLayout.NORTH specifies the top edge of a component's bounding rectangle.
SpringLayout.SOUTH specifies the bottom edge of a component's bounding rectangle.
SpringLayout.EAST specifies the right edge of a component's bounding rectangle.
SpringLayout.WEST specifies the left edge of a component's bounding rectangle.
SpringLayout.BASELINE specifies the baseline of a component.
SpringLayout.HORIZONTAL_CENTER specifies the horizontal center of a component's bounding rectangle.
SpringLayout.VERTICAL_CENTER specifies the vertical center of a component's bounding rectangle.
(How to Use SpringLayout)
Use the same springLayout.putConstraint() for placing at center, as you do in the corner.

Related

How to add scrolling feature to a JComponent on a JFrame?

My GUI consists of a Diagram class which extends JFrame. I've created a different class called DrawingTool which extends JComponent. The DrawingTool class is like a canvas area for users to drop and drag shapes. I've also added a button panel at the bottom of the JFrame for the users to click various buttons to choose their desired shape and control actions. I've added the button panel and an instance of the DrawingTool class to the Diagram class. How do I make the canvas area (DrawingTool) scrollable? The way I have attempted it is not working, I know I am missing something.
Here is the Diagram class:
public class Diagram extends JFrame {
JButton serverButton, vipButton, arrowButton, undoButton, dragButton, loadButton, submitButton;
JButton applicationButton;
int currentAction = 1;
Graphics2D graphSettings;
Color strokeColor = Color.BLUE, fillColor = Color.BLACK;
/**
* Constructor to generate new diagram with empty drawing board and button
* panel.
*/
public Diagram() {
// Define the defaults for the JFrame
this.setSize(1000, 1000);
this.setTitle("Diagram Tool");
//this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel buttonPanel = new JPanel();
// Swing box that will hold all the buttons
Box theBox = Box.createHorizontalBox();
// Make all the buttons in makeButtons by calling helper function
serverButton = makeButtons("Server", 2);
vipButton = makeButtons("VIPs", 3);
arrowButton = makeButtons("Arrow", 4);
undoButton = makeButtons("Undo", 5);
dragButton = makeButtons("Drag", 6);
loadButton = makeButtons("Load", 11);
applicationButton = makeButtons("Application", 8);
submitButton = makeButtons("Submit", 12);
// Add the buttons to the box
theBox.add(serverButton);
theBox.add(vipButton);
theBox.add(applicationButton);
theBox.add(arrowButton);
theBox.add(undoButton);
theBox.add(dragButton);
theBox.add(loadButton);
theBox.add(submitButton);
// Add the box of buttons to the panel
buttonPanel.add(theBox);
// Position the buttons in the bottom of the frame
JPanel container=new JPanel();
container.add(new DrawingBoard(),BorderLayout.CENTER);
JScrollPane jsp=new JScrollPane(container);
this.add(buttonPanel, BorderLayout.SOUTH);
this.add(jsp);
// Make the drawing area take up the rest of the frame
// Show the frame
this.setVisible(true);
}
Here is the DrawingBoard class:
private class DrawingBoard extends JComponent implements MouseListener, MouseMotionListener {
//declare variables
/**
* Constructor to initialize the drawing board
*/
public DrawingBoard() {
addMouseListener(this);
addMouseMotionListener(this);
// initializeCanvas();
}
//Rest of the code for DrawingBoard
}
This is how it looks now. I'd like to make the gray canvas area scrollable.
Diagram Image
What MadProgrammer said in the comments is just about right. You need to set some informations so your ScrollPanel knows how to behave. What is it's own size, the size of the components inside it, etc.
So normally you'll have a ContentPane, and inside of it panes with your content. To do a scrollable pane you only need to put the ScrollPane inside of your ContentPane and then set a viewport for your ScrollPane. A little code I used fully functional:
contentPane = new JPanel();
setContentPane(contentPane);
contentPane.setLayout(null);
JScrollPane scrollPane = new JScrollPane();
//Vertical and Horizontal scroll bar policy is set to choose when the scroll will be visible scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBounds(0, 217, 414, 505);
scrollPane.setPreferredSize(new Dimension(414, 414));
JPanel viewport = new JPanel();
viewport.setLayout(null);
viewport.setBounds(0, 0, 414, 505);
//Create your components here, then:
//viewport.add(component)
viewport.setPreferredSize(new Dimension(414, 150));
scrollPane.setViewportView(viewport);
contentPane.add(scrollPane);
Anything you put inside of your ViewPort
will be automaticaly scrolable, if it's size is bigger than the PreferredSize.
Note that all the dimensions I've put is only for example.

Java basic GUI blank

When I run this program it appears as an empty window until you fullscreen, then it can be resized as you like, why is it doing this/how do I stop it?
the program is very basic just a menubar and two panels split.
public class SplitPane {
public static void main(String[] args) {
window view = new window();
}
private static class window extends JFrame {
public window() {
this.setSize(1000, 750);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//menubar is here, must lower code quantity for stack
//panels
//graph half
JPanel graphRep = new JPanel();
//Background colour - graphRep.setBackground(Color.RED);
graphRep.setVisible(true);
String graphTitle = "Textual Representation.";
Border graphBorder = BorderFactory.createTitledBorder(graphTitle);
graphRep.setBorder(graphBorder);
//text half
JPanel textRep = new JPanel();
textRep.setVisible(true);
String textTitle = "Graphical Representation.";
Border textBorder = BorderFactory.createTitledBorder(textTitle);
textRep.setBorder(textBorder);
//splitpane
JSplitPane splitPane = new JSplitPane();
splitPane.setSize(600, 750);
splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setOneTouchExpandable(true);
splitPane.setDividerSize(10);
splitPane.setDividerLocation(250);
splitPane.setLeftComponent(graphRep);
splitPane.setRightComponent(textRep);
this.add(splitPane);
}
}
this.setVisible(true);
You are making the frame visible BEFORE you add components to the frame. The layout manager is never invoked so the size of all the components remains (0, 0) so there is nothing to paint.
The frame should be made visible AFTER all the components have been added to the frame.
And the code should be:
frame.pack();
frame.setVisible();
So each component is displayed at its proper size. Don't hardcode the size() because you don't know what the size of a users screen might be.

Why does the first panel added to a frame disappear?

Below is an example of adding two panels to a frame. Only one panel (the 2nd, red panel) appears.
Why does the first panel disappear?
import java.awt.Color;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class DisappearingPanelInFrame {
DisappearingPanelInFrame() {
JFrame f = new JFrame(this.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.add(getColoredPanel(Color.GREEN));
f.add(getColoredPanel(Color.RED));
f.pack();
f.setVisible(true);
}
private JPanel getColoredPanel(Color color) {
JPanel p = new JPanel();
p.setBackground(color);
p.setBorder(new EmptyBorder(20, 150, 20, 150));
return p;
}
public static void main(String[] args) {
Runnable r = DisappearingPanelInFrame::new;
SwingUtilities.invokeLater(r);
}
}
The default layout of a JFrame (or more specifically in this case, the content pane of the frame) is a BorderLayout.
When adding a component to a BordeLayout with no constraint, the Swing API will put the component in the CENTER.
A BorderLayout can contain exactly one component in each of the 5 layout constraints.
When a second component is added to the same (in this case CENTER) constraint of a BorderLayout, this implementation of Java will display the last component added.
As to what would be a better approach depends on the specific needs of the user interface.
When a second component is added to the same (in this case CENTER) constraint of a BorderLayout, this implementation of Java will display the last component added.
Not strictly true.
The BorderLayout will only reset the bounds (ie size and location) of the last component added to a specific constraint location. This is different from other layout managers in that they will reset the bounds of all components in the container.
In the example code the red panel was the "active" panel at the time the frame was validated by using the pack() method and therefore only its bound were set and therefore only it was painted.
For a demonstration of this process run the example below using the following steps:
Click on the "Add Panel in Center" button, nothing appears to happen even though the blue panel was added to the center.
Move the mouse over the red panel and the buttons will appear because the mouse rollover logic will cause the buttons to be repainted.
Now increase the frame width and the blue panel will appear under the red panel.
The code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class DisappearingPanelInFrame {
DisappearingPanelInFrame()
{
JButton button = new JButton ("Add Panel In Center");
button.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
JPanel blue = new JPanel();
blue.setBackground( Color.BLUE );
blue.add( new JButton("Button 1") );
blue.add( new JButton("Button 2") );
Component c = (Component)e.getSource();
Window window = SwingUtilities.windowForComponent(c);
window.add(blue );
window.revalidate();
window.repaint();
}
});
JFrame f = new JFrame(this.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.add(new ColoredPanel(Color.GREEN));
//f.pack();
f.add(new ColoredPanel(Color.RED));
f.add(button, BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new DisappearingPanelInFrame();
}
};
SwingUtilities.invokeLater(r);
}
}
class ColoredPanel extends JPanel {
ColoredPanel(Color color) {
setBackground(color);
setBorder(new EmptyBorder(20, 150, 20, 150));
}
}
When the blue panel is added to the BorderLayout and when the revalidate() is invoked the bounds of the blue panel are set.
However, because of the way Swing does ZOrder painting the blue panel is painted first and then the red panel is painted on top of the blue panel. The green panel still has a size of (0, 0) since it was never the "active" panel in the BorderLayout.CENTER when the frame was initially validated with the pack() method.
When the frame is resized, the blue panel being the "active" panel in the BorderLayout.CENTER, has its bounds adjusted, so it will now fill the extra space in the frame.
Now for another test:
pack() the frame after adding the green panel to the frame.
run the code and increase the width of the frame and the red and green frame will appear
then click the button and increase the width and now all 3 panels will appear
Bottom line is still the same:
Don't try to add multiple panels to the same constraint of a BorderLayout. If you do, then make sure you remove the previous panel or you have the potential for unexpected results.

JButtons are not resizing to match their preferred size

I am trying to make a menu screen for a game. I've added two buttons, play and exit, and am currently trying to figure out how to resize them. When I run my code the buttons are almost the exact same size (different I imagine because of the text). I'm using BoxLayout for my buttons, and I just read here Why will BoxLayout not allow me to change the width of a JButton but let me change the height? why it would only resize the width or height, but it's not resizing either right now. In my code I use BoxLayout.PAGE_AXIS, I don't know if that makes a difference, but it didn't resize vertically either with BoxLayout.Y_AXIS.
Here's my code:
public class Stage extends JFrame {
/* PRIVATE */
private JButton play, exit;
// Setup the Menu screen.
private void createMenuScreen() {
Container window = getContentPane();
// window.setBackground(Color.BLACK);
JPanel menuScreen = new JPanel();
menuScreen.setLayout(new BoxLayout(menuScreen, BoxLayout.PAGE_AXIS));
window.add(menuScreen, "Center");
play = new JButton("Play");
play.setPreferredSize(new Dimension(20, 20));
play.setAlignmentX(Component.CENTER_ALIGNMENT);
exit = new JButton("Exit");
exit.setPreferredSize(new Dimension(100, 100));
exit.setAlignmentX(Component.CENTER_ALIGNMENT);
menuScreen.add(play);
menuScreen.add(exit);
}
/* PUBLIC */
public Stage() {
// Setup the frame.
setSize(224, 288);
setLocationRelativeTo(null); // Centers the window.
setUndecorated(true); // Removes the Windows border.
setVisible(true);
createMenuScreen();
}
}
Try to use setMaximumSize() method
exit.setMaximumSize(new Dimension(100,100));
Or try to use BorderLayout instead of BoxLayout

How to make JLabel consume space when not visible?

I have a program which creates 2 Panels and then places a label and two buttons in them. The label is set to invisible setVisible(false) and then the two buttons are added and the frame is packed. When i click the first button, the label is shown, setVisible(true), and the seccond one hides it again, setVisible(false). When i click each button, they move to fill the space of the label as it hides, and move again to get out of the way of the label as it is shown. I want to stop this from happening and have the buttons stay in the same place even when the label is hidden.
Here is the code:
public class MainFrame extends JFrame{
public JLabel statusLabel;
public JButton show;
public JButton hide;
public MainFrame(){
super("MagicLabel");
JPanel topPanel = new JPanel(); //Create Top Panel
statusLabel = new JLabel(""); //Init label
statusLabel.setVisible(false); //Hide label at startup
topPanel.setSize(400, 150); //Set the size of the panel, Doesn't work
topPanel.add(statusLabel); //Add label to panel
JPanel middlePanel = new JPanel(); //Create Middle Panel
show= new JButton("Show"); //Create show button
hide= new JButton("Hide"); //Create hide button
middlePanel.setSize(400, 50); //Set the size of the panel, Doesn't work
middlePanel.add(show); //Add show button
middlePanel.add(hide); //Add hide button
this.add(topPanel, "North"); //Add Top Panel to North
this.add(middlePanel, "Center"); //Add Middle Panel to Center
addActionListeners(); //void:adds action listeners to buttons
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(100, 100, 512, 400);
this.setPreferredSize(new Dimension(400,200)); //Set size of frame, Does work
this.pack();
this.setVisible(true);
}
public void animateInstall(boolean var0){ //Void to show and hide label from action listeners
statusLabel.setVisible(var0);
sendWorkingMessage("Boo!");
}
public void sendWorkingMessage(String message){ //Void to set text of label
this.statusLabel.setForeground(new Color(225, 225, 0));
this.statusLabel.setText(message);
}
void addActionListeners(){
show.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
animateInstall(true);
}
});
hide.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
animateInstall(false);
}
});
}
this.setPreferredSize(new Dimension(400,200));
this.setMinimumSize(new Dimension(400,200));
So pack() cannot interfere.
Use CardLayout. Add the JLabel and empty JPanel. Instead of seting it visible/invisible swap the cards showing the JLabel or the JPanel when necesary.
Extending JFrame is not advisable, better extend JPanel put all your components inside and then add it to a JFrame
You need to learn how to use SwingUtilities.invokeLater(): See example how your should look like
You need to learn about Layout: Tutorial
Very dumb and easy approach in your code would be:
this.statusLabel.setForeground(bgColor); //background color
this.statusLabel.setText(" "); //some number of characters
By default for you frame you are using BorderLayout. You can try to have like:
this.add(topPanel, BorderLayout.NORTH); //Add Top Panel to North
this.add(middlePanel, BorderLayout.SOUTH); //Add Middle Panel to South
rather than at center.
Or you can create an intermediate container panel for these 2 panels, or consider other layout managers like BoxLayout, etc

Categories