I am making a java GUI in which I have some vertical boxes. Inside those boxes, there are some buttons and Labels. I am trying to put the buttons and labels in the center but doesn't work!
I am using this code to set the label in the center.
JLabel update = new JLabel("update");
update.setHorizontalTextPosition(CENTER);
where update is the last component of my vertical box.
The other problem is that I need the window to resize automatically depending on the changes in my GUI (since it is a dynamic one)!
How can I make this too?
I am trying to put the buttons and labels in the center but doesn't work! I am using this code to set the label in the center.
There are several ways to do this, but the easiest for me is to use a GridBagLayout.
If the boxes/container (which hopefully extend from JPanel or JComponent) uses a GridBagLayout, and you add components into the container with GridBagConstraints: gridX and gridY set, but with weightX and weightY set to default of 0, those added components will center in the container.
I can't show code since I have no knowledge of the code you're currently using or the images of your observed/desired GUI's. If you need more help, please edit your question and provide more pertinent information.
The other problem is that I need the window to resize automatically depending on the changes in my GUI (since it is a dynamic one)! How can I make this too?
This will all depend on the layout managers that your GUI is using, something that we have no knowledge of as yet. Again, if you're still stuck, please create and post your Minimal, Complete, and Verifiable Example Program.
For example the following resizable GUI with centered buttons and JLabel texts:
Is created by the following code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.*;
#SuppressWarnings("serial")
public class VertBoxes extends JPanel {
private static final String[] LABEL_TEXTS = { "A", "One", "Two", "Monday",
"Tuesday", "January", "Fourth of July",
"Four score and seven years ago" };
public static final int PREF_W = 260;
public static final int PREF_H = 80;
public VertBoxes() {
setLayout(new GridLayout(0, 1, 5, 5));
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
for (String labelTxt : LABEL_TEXTS) {
add(new InnerBox(labelTxt));
}
}
private class InnerBox extends JPanel {
public InnerBox(String labelTxt) {
setLayout(new GridBagLayout());
setBorder(BorderFactory.createLineBorder(Color.black, 4));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
add(new JButton("Button"), gbc);
gbc.gridy++;
add(new JLabel(labelTxt), gbc);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}
private static void createAndShowGui() {
VertBoxes mainPanel = new VertBoxes();
JFrame frame = new JFrame("Vertical Boxes");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
I'm having issues with my code regarding the fact that when I instantiate my City class as an object and add it to the right side of my JSplitPane (or even the left), the circle that is supposed to be drawn is not showing up. My cities class uses paintComponent and should draw a circle just by calling the constructor. I have also tried putting the repaint in its own drawIt() method but the result is still the same. The buttons and spinner show up on the left side of the divider, but the circle I am trying to draw does not show up at all.
Here is my City class.
import javax.swing.*;
import java.awt.*;
public class City extends JPanel{
int xPos, yPos;
City(int x, int y){
xPos = x;
yPos = y;
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(xPos, yPos, 10, 10);
}
}
And here is my main.
Here I try to instantiate my city and add it to the right side of the JSplitPane (under Add Components) and that is where I am having issues with, as the black circle will not be drawn on the JSplitPane.
import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
public class TSP{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TSP();
}
});
}
TSP(){
JLabel instructions = new JLabel("Enter the number of cities: ");
instructions.setBounds(30, 150, 300, 40);
SpinnerNumberModel numMod = new SpinnerNumberModel(2, 2, 10, 1);
JSpinner numOfCities = new JSpinner(numMod);
numOfCities.setBounds(185, 150, 80, 40);
JButton start = new JButton("Start Simulation");
start.setBounds(50, 400, 200, 40);
JFrame frame = new JFrame("Travelling Salesperson");
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
JPanel lp = new JPanel(null);
JPanel rp = new JPanel(null);
sp.setDividerLocation(300);
sp.setLeftComponent(lp);
sp.setRightComponent(rp);
sp.setEnabled(false);
frame.setDefaultCloseOperation(3);
frame.setSize(1100,600);
frame.setResizable(false);
////////////////Add Components//////////////////////////
lp.add(instructions);
lp.add(numOfCities);
lp.add(start);
City test = new City(301, 301);
rp.add(test);
frame.add(sp);
////////////////////////////////////////////////////////
frame.setVisible(true);
}
}
I feel like the circle is being drawn under the JSplitPane as if I add my cities object (test) to my frame instead of the JSplitPane(frame.add(test) instead of rp.add(test) under the Add Components section) the black circle will appear in the desired spot but the JSplitPane along with the buttons and spinners will disappear so I feel as if they are conflicting. Is there any fix to this or is there another way altogether to make the circle appear on the right side while the other components are on the left side.
I do not know why it is not drawing the circle on the JSplitPane, but any sort of help would be appreciated. Thanks!
Sorry if anything is unclear or there is any ambiguity in my code, or if I need to post more information as I am quite new to posting here. Let me know if there is anything else I need to add or if there are any questions regarding what I am asking!
EDIT:
It seems there is something blocking where I draw the circle, like another JPanel. Here is an image below. As you can see part of the circle looks as if it is being covered. The small box I drew is the only area that the dot is visible from (everywhere else the circle is covered up by white). Also, the coordinates for the circle in the image below is at (3, 0), i.e City test = new City(3, 0);
I am not quite sure why this is happening though.
the invisible JPanel?
Now that I've seen what you're trying to do, I can provide a more proper answer.
You have a control panel on the left and a drawing panel on the right. Usually, you don't use a JSplitPane to separate the panels. To create your layout, you would add the control panel to the LINE_START of the JFrame BorderLayout and the drawing panel to the CENTER.
The reason for this is that you don't want to constantly recalculate the size of the drawing panel.
So let me show you one way to get a solid start. Here's the GUI I created.
Here are the things I did.
All Swing GUI applications must start with a call to the SwingUtilities invokeLater method. This method ensures that Swing components are created and executed on the Event Dispatch Thread.
I separated the creation of the JFrame, the control panel, and the drawing panel. That way, I could focus on one part of the GUI at a time.
The JFrame methods must be called in a certain order. This is the order that I use for most of my Swing applications.
The JFrame is not sized. It is packed. The Swing layout managers will calculate the size of the components and the JPanels.
I used a FlowLayout and a GridBagLayout to create the control panel. Yes, this looks more complicated than absolute positioning, but in the long run, layout managers allow the GUI to be more flexible.
I used the setPreferredSize method in the drawing panel to set the preferred size of the drawing panel. Because I know the drawing panel size, I can put the first city in the center of the drawing panel.
And here's the code. You don't have to code exactly like this, but this code should give you a good basis to start your project. Take a look at the model / view / controller pattern and see how to further separate your code into smaller pieces that allow you to focus on one part of your application at a time.
I put all the classes in one file to make it easier to paste. You should separate these classes into separate files.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
public class CitySimulation implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CitySimulation());
}
private ControlPanel controlPanel;
private DrawingPanel drawingPanel;
private JFrame frame;
#Override
public void run() {
frame = new JFrame("Traveling Salesperson");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
controlPanel = new ControlPanel();
frame.add(controlPanel.getPanel(), BorderLayout.LINE_START);
drawingPanel = new DrawingPanel();
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class ControlPanel {
private JPanel panel;
public ControlPanel() {
panel = new JPanel(new FlowLayout());
JPanel mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(10, 10, 10, 10);
JLabel instructions = new JLabel("Enter the number " +
"of cities:");
mainPanel.add(instructions, gbc);
gbc.gridx++;
gbc.insets = new Insets(10, 0, 10, 10);
SpinnerNumberModel numMod =
new SpinnerNumberModel(2, 2, 10, 1);
JSpinner numOfCities = new JSpinner(numMod);
mainPanel.add(numOfCities, gbc);
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 2;
gbc.insets = new Insets(10, 10, 10, 10);
JButton start = new JButton("Start Simulation");
mainPanel.add(start, gbc);
panel.add(mainPanel);
}
public JPanel getPanel() {
return panel;
}
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(400, 400));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(195, 195, 10, 10);
}
}
}
I can't seem to find the correct layoutmanager, perhaps it doesn't exist, so I wanted to do it in miglayout, yet I can't seem to find my way to do this there either.
Most documentation, tutorials and examples I found don't adress the JPanel having contents at all 0.o
The problem I'm having is, I've got two JPanels(C 1&2) inside a JPanel(B) which in turn is inside a bigger resizeable JPanel(A).
Now both lowest level "C" JPanels contain 5 buttons, when the highest level "A" resizes and gets less width the buttons go from this:
to this:
As you can see the FlowLayout I'm using on the lowest level "C" JPanels is doing it's job!
c.setLayout(new FlowLayout(FlowLayout.LEFT,0,0))
But while the "B" JPanel that holds the C's does exactly what I want for the horizontal part
b.setLayout(new BoxLayout(b, BoxLayout.Y_AXIS));
I don't want it doing that on the height though!
So could anyone point me in the right direction like a tutorial or docs that cover such stuff? For miglayout or swing layout managers?
I have created a solution with a MigLayout manager. The panels keep their
height nicely when the window is resized and never shrink below the size
necessary to hold all the buttons.
package com.zetcode;
import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class MigLayoutSolution extends JFrame {
public MigLayoutSolution() {
initUI();
}
private void initUI() {
JPanel pnl = new JPanel(new MigLayout());
pnl.add(createPanel1("First"), "push, grow, wrap");
pnl.add(createPanel2("Second"), "push, grow");
add(pnl);
pack();
setTitle("MigLayout solution");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private JPanel createPanel1(String text) {
JPanel pnl = new JPanel(new MigLayout());
pnl.add(new JButton("A"));
pnl.add(new JButton("B"));
pnl.add(new JButton("C"));
pnl.add(new JButton("D"));
pnl.setBorder(BorderFactory.createTitledBorder(text));
return pnl;
}
private JPanel createPanel2(String text) {
JPanel pnl = new JPanel(new MigLayout());
pnl.add(new JButton("E"));
pnl.add(new JButton("F"));
pnl.add(new JButton("G"));
pnl.add(new JButton("H"));
pnl.setBorder(BorderFactory.createTitledBorder(text));
return pnl;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MigLayoutSolution ex = new MigLayoutSolution();
ex.setVisible(true);
}
});
}
}
The first picture shows two panels with plenty of empty space.
The second picture shows the panels in their minimal size.
I will place these buttons in the center of the frame and above each other, like this.
BUTTON
BUTTON
BUTTON
I've searched multiple topics on this forum but everything I tried didn't work for so far. I hope that somebody has the solution.
This is my code for so far:
package ípsen1;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Paneel extends JPanel implements ActionListener {
Image achtergrond;
private JButton spelHervatten;
private JButton spelOpslaan;
private JButton spelAfsluiten;
public Paneel(){
//buttons
spelHervatten = new JButton("Spel hervatten");
spelHervatten.setPreferredSize(new Dimension(380, 65));
spelOpslaan = new JButton("Spel opslaan");
spelOpslaan.setPreferredSize(new Dimension(380, 65));
spelAfsluiten = new JButton("Spel afsluiten");
spelAfsluiten.setPreferredSize(new Dimension(380, 65));
//object Paneel luistert naar button events
spelAfsluiten.addActionListener(this);
add (spelHervatten);
add (spelOpslaan);
add (spelAfsluiten);
}
public void paintComponent(Graphics g) {
//achtergrond afbeelding zetten
achtergrond = Toolkit.getDefaultToolkit().getImage("hout.jpg");
//screensize
g.drawImage(achtergrond, 0,0, 1024,768,this);
}
//actie na klik op button
public void actionPerformed(ActionEvent e) {
if(e.getSource() == spelAfsluiten){
System.out.println("Spel afsluiten");
System.exit(0);
}
}
}
You could use a GridBagLayout
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(new JButton("Button"), gbc);
add(new JButton("Button"), gbc);
add(new JButton("Button"), gbc);
add(new JButton("Button"), gbc);
See How to Use GridBagLayout for more details
A BoxLayout might be what you're after. You can specify that you want to add components along the y-axis in the constructor for that particular layout manager.
You could add this line to the constructor of your Paneel class.
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
As for center-aligning everything, I don't know if it's good practice but you can set the horizontal alignment for each of your buttons individually. Example:
spelHervatten.setAlignmentX(CENTER_ALIGNMENT);
Uses a GridLayout for a single column of buttons of equal width.
The buttons stretch as the window's size increases. To maintain the button size, put the GridLayout as a single component into a GridBagLayout with no constraint. It will be centered.
The size of the buttons is increased by setting a margin.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
/*
* Uses a GridLayout for a single column of buttons of equal width.
* The buttons stretch as the window's size increases. To maintain
* the button size, put the GridLayout as a single component into a
* GridBagLayout with no constraint. It will be centered.
*/
public class CenteredSingleColumnOfButtons {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
// the GUI as seen by the user (without frame)
JPanel gui = new JPanel(new GridLayout(0,1,10,10));
gui.setBorder(new EmptyBorder(20,30,20,30));
String[] buttonLabels = {
"Spel hervatten",
"Spel opslaan",
"Spel afsluiten"
};
Insets margin = new Insets(20,150,20,150);
JButton b = null;
for (String s : buttonLabels) {
b = new JButton(s);
b.setMargin(margin);
gui.add(b);
}
JFrame f = new JFrame("Centered Single Column of Buttons");
f.add(gui);
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
f.setMinimumSize(f.getSize());
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
System.out.println(b.getSize());
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
I thought there is no way to do that.
You should get size of Panel/Frame then calculate manually to find to center position for your button.
Rephrased some parts:
You might want to try to put the buttons in JFrame's "wind direction"-style BorderLayout:
http://www.leepoint.net/notes-java/GUI/layouts/20borderlayout.html
Just create a block in the CENTER with one EAST and WEST block with a certain size around it. Then insert the buttons inside of the center block. If you don't want them to be the full size, just add another EAST and WEST.
I almost have the repaint() Jcomponent working. I had it working and then tried to make an absolute positioning and now it doesn't work.
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
public class DDHGenericFrame {
private static final long serialVersionUID = 1L;
DDHGenericPanel d = new DDHGenericPanel();
//DDHCircleOne o = new DDHCircleOne();
public DDHGenericFrame() {
initUI();
}
public final void initUI() {
JFrame frame = new JFrame("AbsoluteLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Draw Circle");
frame.setBackground(Color.green);
frame.setLayout(null);
frame.setSize(300,425);
frame.add(d);
// frame.add(o);//didn't work neither
frame.setVisible(true);
}
public static void main(String[] args) {
DDHGenericFrame ex = new DDHGenericFrame();
}
}
Class 2: (This is the JComponent that I am trying to set)
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JComponent;
public class DDHTestDraw extends JComponent {
public DDHTestDraw () {
settPreferredSize();
}
public void settPreferredSize() {
Dimension d = new Dimension(25,25);
setPreferredSize(d);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("Text",20,20);
}
}
I added my component to the Container and then added the container to the JPanel and then the JPanel is added to the JFrame. I would think that this should work. I have a set preferred size. I had it working once and now it doesn't work.
I want to be able to make a component that is a circle. I want that circle to be able to be drawn any where on a Jframe, and then I want that circle to be able to move based on a a certain length of time. I am going to make a game that has circles dropping from the top and then falling to the bottom. When I had it working I did have the circle being written to the JPanel which is a complex piece of code. But I have had to go back to the old simple method of writing a single graphical word.
When you use null layout, you are completely responsible for making sure that components added have proper location and size (not preferredSize) set.
You should almost never use null layout.
Wouldn't this sort of thing work better by creating a logical class to represent the Circle, not a component? Then your drawing JPanel could hold a collection of logical circles, and the drawing JPanel could be responsible for drawing each Circle in its paintComponent method.
Edit
Your comments/my replies:
when you say never use an absolute layout, the company that I worked for always used a absolute layout only.
There are times when it is useful, but not for creating a typical component-filled GUI. Otherwise the GUI becomes very hard to modify and maintain.
When you mean a logical class you mean a class that just creates one circle.
Yes, and that holds all the necessary properties of that circle such as its Color, location, movement, etc..
Then the Jpanel would draw each circle.
Yes. I would imagine the drawing JPanel having an ArrayList<MyCircle> of them, and the paintComponent method iterating througgh this List.
when you say Size this is a property in JComponent.
I think that it is a property of Component, JComponent's parent. If you use null layout, then all components must have their size and location specified. Otherwise the component defaults to a location of [0, 0] and a size of [0, 0].
Edit 2
public Dimension Size(int a, int b) {
Dimension d = new Dimension();
d.width = a;
d.height = b;
return d;
}
This is the code that I used for the preferred size. I am at a lost why this doesn't work.
This code has no effect on either the size or the preferredSize properties of Component/JComponent. It doesn't surprise me that it will not help you. You would either have to override getSize() or getPreferredSize() or explicitly call setSize(...) or getPreferredSize(...) to change the state of the properties.
I am going to try it with a different layout manager and see but I would see the difference between one layout manager or another.
I'm not sure how to interpret this.
Edit 3
You state:
I worked at one company and we used absulute layouts all of the time. How would an absolute layout not work as good as, say BorderLayout(). To me the BorderLayout() are harder to implement. Or is it that you use a Jframe() with a BorderLayout, and then insert a Jpanel into an already existing position that is already also a BorderLayout(). I always have trouble getting my buttions and positions correct in a layout that is something different than a BorderLayout(). Can you post an example that would be easier to use than
I'm guessing you want an example of where use of layout managers is easier than using absolute positioning.
Let's take the example of a very simple calculator, one with buttons for numeric input and simple operations. Again this example is very basic, and is non-functional, but serves to illustrate the use of layouts. I could easily place my buttons in a GridLayout-using JPanel, and then place that button JPanel into a BorderLayout-using JPanel at the BorderLayout.CENTER position with the JTextField, display, placed in the same BorderLayout-using JPanel at the BorderLayout.PAGE_START position:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.*;
public class CalcEg {
private static final float BTN_FONT_SIZE = 20f;
private static final String[][] BTN_LABELS = {
{"7", "8", "9", "-"},
{"4", "5", "6", "+"},
{"1", "2", "3", "/"},
{"0", ".", " ", "="}
};
private static final int GAP = 4;
private JPanel mainPanel = new JPanel(new BorderLayout(GAP, GAP));
private JPanel buttonPanel = new JPanel();
private JTextField display = new JTextField();
public CalcEg() {
int rows = BTN_LABELS.length;
int cols = BTN_LABELS[0].length;
buttonPanel.setLayout(new GridLayout(rows, cols, GAP, GAP));
for (String[] btnLabelRow : BTN_LABELS) {
for (String btnLabel : btnLabelRow) {
if (btnLabel.trim().isEmpty()) {
buttonPanel.add(new JLabel());
} else {
JButton btn = createButton(btnLabel);
buttonPanel.add(btn);
}
}
}
display.setFont(display.getFont().deriveFont(BTN_FONT_SIZE));
display.setEditable(false);
display.setFocusable(false);
display.setBackground(Color.white);
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.add(buttonPanel, BorderLayout.CENTER);
mainPanel.add(display, BorderLayout.PAGE_START);
}
private JButton createButton(String btnLabel) {
JButton button = new JButton(btnLabel);
button.setFont(button.getFont().deriveFont(BTN_FONT_SIZE));
return button;
}
public JComponent getMainComponent() {
return mainPanel;
}
private static void createAndShowGui() {
CalcEg mainPanel = new CalcEg();
JFrame frame = new JFrame("CalcEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel.getMainComponent());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
This would result in a calculator that looks like so:
Now, sure you could say that you could produce this with null layout and setbounds(...), and that's all well and good, but now say that you're not satisfied with this calculator, and now desire that it has some scientific calculation functionality. Say you now want to add buttons for square, square root, exponential, and logarithm, but not only that, say you wish to add the buttons below the display and above the numeric and basic operations buttons. If you were to do this with null layout, you would have to reposition all the components below and to the right of any new components added, and you'd have to expand the size of the JTextField, all calculations that are tedious and prone to error.
If you used layout managers, you would instead only need to add one line of code, actually an additional row to an array:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.*;
public class CalcEg {
private static final float BTN_FONT_SIZE = 20f;
private static final String[][] BTN_LABELS = {
{"sqr", "sqrt", "exp", "log"}, // ******* Line Added Here *********
{"7", "8", "9", "-"},
{"4", "5", "6", "+"},
{"1", "2", "3", "/"},
{"0", ".", " ", "="}
};
private static final int GAP = 4;
private JPanel mainPanel = new JPanel(new BorderLayout(GAP, GAP));
private JPanel buttonPanel = new JPanel();
private JTextField display = new JTextField();
public CalcEg() {
int rows = BTN_LABELS.length;
int cols = BTN_LABELS[0].length;
buttonPanel.setLayout(new GridLayout(rows, cols, GAP, GAP));
for (String[] btnLabelRow : BTN_LABELS) {
for (String btnLabel : btnLabelRow) {
if (btnLabel.trim().isEmpty()) {
buttonPanel.add(new JLabel());
} else {
JButton btn = createButton(btnLabel);
buttonPanel.add(btn);
}
}
}
display.setFont(display.getFont().deriveFont(BTN_FONT_SIZE));
display.setEditable(false);
display.setFocusable(false);
display.setBackground(Color.white);
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.add(buttonPanel, BorderLayout.CENTER);
mainPanel.add(display, BorderLayout.PAGE_START);
}
private JButton createButton(String btnLabel) {
JButton button = new JButton(btnLabel);
button.setFont(button.getFont().deriveFont(BTN_FONT_SIZE));
return button;
}
public JComponent getMainComponent() {
return mainPanel;
}
private static void createAndShowGui() {
CalcEg mainPanel = new CalcEg();
JFrame frame = new JFrame("CalcEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel.getMainComponent());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
which would result in this GUI:
Again this is a very simplistic example, but the general principles apply to any GUI that holds components such as JButtons, JTextComponents, etc.
With Swing animation, the Timer class is an exceptional option.
//this class is a JPanel that implements ActionListener`
Timer t = new Timer(1000,this);//the first arg is how many times it repeats in milliseconds
//Then in the constructor...
t.start();
//the ActionPerformed function normally increments a variable then calls the repaint method.
rectangle_x++;
repaint(); //calls paintComponent
Another good idea is to cast g to a Graphics2D object- it's a lot safer and more capable.
Another way to use the Timer class:
Timer t = new Timer(510, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
rectangle_x++;
repaint();
}
})
...
t.start();
You still need to override actionPerformed() in your main class though.
I am creating a program which has three jpanels: one container, and inside the container is two jpanels, one that is going to hold buttons and one which will hold the content. Ive got them both showing so far and its looking good, the only problem i I was hoping to add some space or a border between or the two (or around the button menu if possible) however since both internal panels are set to null layouts and the external layout is set to a border layout I cannot seem to add a border between the two internal ones. Here is my code so far:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class internal_test extends JFrame {
int height = 480;
int width = 640;
public internal_test() {
initUI();
}
private void initUI() {
JPanel container = new JPanel();
container.setLayout(new BorderLayout());
container.setBackground(Color.black);
JPanel buttonMenu = new JPanel();
buttonMenu.setLayout(null);
buttonMenu.setBackground(Color.DARK_GRAY);
buttonMenu.setPreferredSize(new Dimension(150, height));
JPanel dragFrame = new JPanel();
dragFrame.setLayout(null);
dragFrame.setPreferredSize(new Dimension(200, 100));
dragFrame.setSize(new Dimension(490, height));
dragFrame.setBackground(Color.gray);
container.add(buttonMenu, BorderLayout.WEST);
container.add(dragFrame, BorderLayout.CENTER);
// container.setBorder(new EmptyBorder(new Insets(10, 10, 10, 10)));
add(container);
pack();
setTitle("internal_test V0.1");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(width, height);
setLocationRelativeTo(null);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
internal_test c = new internal_test();
c.setVisible(true);
}
});
}
}
The dragFrame is going to be a DragLayout since that layout does what I need it to, but the button menu could technically be any layout, as long as it would allow me to place buttons/other items in a list with a label next to each.
Any help is greatly appreciated.
I would use the BoxLayout and for the spacing use
panel.add(Box.createRigidArea(new Dimension(x, y)));
Here are some decent examples.
I Suggest GridBagLayout
beacause it is more easy to intent spaces between the components
This should help you add the type of border you want:
http://docs.oracle.com/javase/tutorial/uiswing/components/border.html
You can start with a red line border like this:
buttonMenu.setBorder(BorderFactory.createLineBorder(Color.red));