I have a simple java program and when I run it, using eclipse, it displays the 3 JButtons that I have set to the layout. The buttons are set to change the alignment of the layout. So you press left to align left and right to align right and center to align center.
While the buttons do this, the alignment doesn't change in the window till you resize it.
Ive tried updating both the jdk and eclipse and didnt make a difference and I cant see a problem with the code itself.
Anyone know why this is?
import javax.swing.JFrame;
public class Main {
public static void main(String []args){
Layout_buttonsAndActionEvents layout = new Layout_buttonsAndActionEvents();
layout.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
layout.setSize(300,300);
layout.setVisible(true);
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Layout_buttonsAndActionEvents extends JFrame {
private static final long serialVersionUID = 1L;
private JButton leftButton;
private JButton rightButton;
private JButton centerButton;
private FlowLayout layout;
private Container container;
public Layout_buttonsAndActionEvents(){
super("The Title");
layout = new FlowLayout();
container = new Container();
setLayout(layout);
leftButton = new JButton("Left");
add(leftButton);
//Align to the left
leftButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.LEFT);
layout.layoutContainer(container);
}
});
centerButton = new JButton("Center");
add(centerButton);
//Align to the right
centerButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.CENTER);
layout.layoutContainer(container);
}
});
rightButton = new JButton("Right");
add(rightButton);
//Align to the right
rightButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.RIGHT);
layout.layoutContainer(container);
}
});
}
}
Because you are adding the buttons to the JFrame's content
pane ( via the add() method which is really a call to
getContentPane().add() under the covers ) you need to call revalidate() on
the content pane.
In the three action listeners, change:
layout.setAlignment(FlowLayout.XXX);
layout.layoutContainer(container);
to:
layout.setAlignment(FlowLayout.XXX);
getContentPane().revalidate();
Also, you can remove all references to the variable named 'container' as it does nothing in your example.
When you resize a JFrame, it is re-validated with the new size and layout. Similarly, you must validate the and repaint the frame after adding the altered layout to apply a visual difference.
Make sure to call these methods in this order after altering the layout:
setLayout(layout);
repaint();
revalidate();
Related
I'm trying to get my labels to be in the center of the window when I press the corresponding button, but it instead just sits on top of the button instead of sitting in the middle and i'm not sure why
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class navigator extends JFrame
{
Container con;
public navigator(){
super("JFrame");
JFrame newFrame = new JFrame("Navigator");
newFrame.setSize(400, 400);
newFrame.setVisible(true);
newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
con = getContentPane();
BorderLayout newLayout = new BorderLayout();
con.setLayout(newLayout);
JButton newButton = new JButton("Up");
newFrame.add(newButton, BorderLayout.NORTH);
JButton newButton2 = new JButton("Left");
newFrame.add(newButton2, BorderLayout.WEST);
JButton newButton3 = new JButton("Down");
newFrame.add(newButton3, BorderLayout.SOUTH);
JButton newButton4 = new JButton("Right");
newFrame.add(newButton4, BorderLayout.EAST);
JLabel newLabel = new JLabel("Going up!");
newFrame.add(newLabel, BorderLayout.CENTER);
newLabel.setVisible(false);
newButton.add(newLabel);
JLabel newLabel2 = new JLabel("Going left!");
newFrame.add(newLabel2, BorderLayout.CENTER);
newLabel2.setVisible(false);
newButton2.add(newLabel2);
JLabel newLabel3 = new JLabel("Going down!");
newFrame.add(newLabel3, BorderLayout.CENTER);
newLabel3.setVisible(false);
newButton3.add(newLabel3);
JLabel newLabel4 = new JLabel("Going right!");
newFrame.add(newLabel4, BorderLayout.CENTER);
newLabel4.setVisible(false);
newButton4.add(newLabel4);
newButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
newLabel.setVisible(true);
newLabel2.setVisible(false);
newLabel3.setVisible(false);
newLabel4.setVisible(false);
}
});
newButton2.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
newLabel2.setVisible(true);
newLabel.setVisible(false);
newLabel3.setVisible(false);
newLabel4.setVisible(false);
}
});
newButton3.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
newLabel3.setVisible(true);
newLabel2.setVisible(false);
newLabel.setVisible(false);
newLabel4.setVisible(false);
}
});
newButton4.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
newLabel4.setVisible(true);
newLabel2.setVisible(false);
newLabel3.setVisible(false);
newLabel.setVisible(false);
}
});
}
public static void main(String[] args){
navigator myNavigator = new navigator();
}
}
JLabel newLabel = new JLabel("Going up!");
newFrame.add(newLabel, BorderLayout.CENTER);
newLabel.setVisible(false);
newButton.add(newLabel); // ???
A component can only have a single parent. So you can't add the label to the frame and the button. I'm not even sure why you would be attempting to add the label to the button.
In any case you can't add four labels to the center of the frame. The BorderLayout only allows one component in each area, so only the last component added will ever be visible. The BorderLayout will only set the size of the last button added. All the other buttons will have a size of (0, 0) so there is nothing to paint.
So just add a single label and then change the text using the setText(...) method in your ActionListener.
However, once you fix this you will still have a problem. By default a label is painted at the left of the space available to the label.
If you want the text displayed in the center then you need to use:
label.setHorizontalAlignment(JLabel.CENTER);
Also, all components should be added to the frame before making the frame visible.
Finally, class names should start with an upper case character. Look at the class names of the JDK API and follow the conventions used their.
When using a BorderLayout, you can only put one control in each section. So you can only put one button in CENTER, for instance.
If you want to put more things in one area, then you need to create a new JPanel, put it in CENTER, and then place the buttons on the newly created JPanel. (Of course following the same layout rules for it). You can recursively add as many jpanels as you like.
I have both texts and icons for my buttons. I want to hide texts, if user resize the frame and make one the buttons invisible. I found a workaround with scroll pane, but I want to know if there is a better solution. Thanks in advance.
My solution:
public class IconButtonTest extends JFrame {
private JScrollPane buttonScrollPane;
private JButton button1;
private JButton button2;
private JButton button3;
public IconButtonTest() {
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
ImageIcon icon = new ImageIcon();
button1 = new JButton("Button1", icon);
button2 = new JButton("Button2", icon);
button3 = new JButton("Button2", icon);
buttonPanel.add(button1);
buttonPanel.add(button2);
buttonPanel.add(button3);
buttonScrollPane = new JScrollPane(buttonPanel);
buttonScrollPane.setBorder(null);
add(buttonScrollPane, BorderLayout.NORTH);
addComponentListener(new ResizeListener());
setSize(300, 300);
setVisible(true);
}
public static void main(String[] args) {
new IconButtonTest();
}
private class ResizeListener extends ComponentAdapter {
#Override
public void componentResized(ComponentEvent e) {
button1.setText("Button1");
button2.setText("Button2");
button3.setText("Button2");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (buttonScrollPane.getHorizontalScrollBar().isVisible()) {
button1.setText("");
button2.setText("");
button3.setText("");
}
}
});
}
}
}
I added buttons to JPanel and add that panel to the frame with a scroll pane. In ResizeListener I am checking if horizontal scroll visible or not. If it is visible it means buttonPanel is overflowed the visible area.
I found a workaround with scroll pane, but I want to know if there is a better solution.
Don't know if it is better but there is no need for the scroll pane. Just add the listener to the panel, then you can check the preferred width against the actual width:
button1.setText("Button1");
button2.setText("Button2");
button3.setText("Button2");
JPanel panel = (JPanel)e.getComponent();
if (panel.getSize().width < panel.getPreferredSize().width)
{
button1.setText("");
button2.setText("");
button3.setText("");
}
I want to hide texts, if user resize the frame and make one the buttons invisible.
If you are just trying to make sure all the buttons are accessible then you might be able to:
Use the Wrap Layout. The button will wrap to a new line and the height of the panel will be increased.
Use the concept of the ScrollContainer. Buttons will be added to the start/end of the container as required to allow you to scroll through buttons that are not currently visible. See: Moving left right in a JPanel
I'm new to programming world, and I need some help. I will try to be as clear as possible.
This is my current situation:
I'm programming a simple game.
On a Jframe, I've added a Jlabel on which I attached an image. I've also added a Jbutton on the Jframe.
I would like that when I click on the Jbutton, the image appears and on the next click the image hides.
How could I do it?
Thanks in advance and excuse me for the possible english mistakes.
EDIT
Following some instructions given by people, I've reached this point:
button.addActionListener(new Actionbox());
final class Actionbox implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
if (label.getIcon() == null)
label.setIcon(new ImageIcon(myimage));
else
label.setIcon(null);
}
}
Eclipse is giving me an error message on the left side of the code editor, near the number lines. It says "Actionbox cannot be resolved to a type".
How could I solve it?
I would like that when I click on the Jbutton, the image appears and on the next click the image hides
add/remove an Icon from the label:
public void actionPerformed(ActionEvent e)
{
if (label.getIcon() == null)
label.setIcon(...);
else
label.setIcon( null );
}
Or instead of setting the Icon null, you may want to have a blank Icon so that the size of the label doesn't keep changing every time you show an image.
Don't fiddle with your button's visibility, and don't make it a final local variable. For something like this, the label should be a field. Place it in your GUI and leave it visible, since if it doesn't hold an icon or have text, nothing will show on it. Instead in your button's ActionListener, simply change the JLabel's ImageIcon via its setIcon(...) method. Pass in an Icon if you want to show an image and pass in null if you want to show nothing. Make your JLabel a field of the class, not a final local variable.
Regarding your code, one way to create your JButton's ActionListener is to use an anonymous inner class rather than a static private class. I'd also recommend reading in the image just once perhaps in your class's constructor and not each time the button is pressed. For example,
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial") // have GUI extend JPanel
public class ButtonSwapImageGui extends JPanel {
private static final String IMAGE_PATH = "https://duke.kenai.com/iconSized/duke.gif";
private Icon imageIcon; // hold our image
private Icon nullImageIcon; // hold a blank image as a placeholder
private JLabel label = new JLabel("", SwingConstants.CENTER);
// throw an exception if image can't be read
public ButtonSwapImageGui() throws IOException {
// read in an image from the internet
URL imageUrl = new URL(IMAGE_PATH);
BufferedImage image = ImageIO.read(imageUrl);
// create a blank placeholder image the same size as
// the image read in from internet
int width = image.getWidth();
int height = image.getHeight();
BufferedImage nullImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// create ImageIcon objects with images read in above
imageIcon = new ImageIcon(image);
nullImageIcon = new ImageIcon(nullImage);
// set JLabel with the placeholder nullImageIcon
label.setIcon(nullImageIcon);
// create our button
JButton button = new JButton("Swap Image");
// add an anonymous inner class ActionListener to button
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// get the JLabel's Icon
Icon currentIcon = label.getIcon();
// if the Icon matches the null icon
if (currentIcon == nullImageIcon) {
// set label with image
label.setIcon(imageIcon);
} else {
// otherwise the label is displaying the image
// so now set label with the null (blank) icon
label.setIcon(nullImageIcon);
}
}
});
// JPanel to hold our button
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
// set our GUI's layout to BorderLayout
setLayout(new BorderLayout());
// add the JLabel to the BorderLayout.CENTER position
add(label, BorderLayout.CENTER);
// add button JPanel to the bottom
add(buttonPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
// declare our GUI JPanel
ButtonSwapImageGui mainPanel = null;
try {
mainPanel = new ButtonSwapImageGui();
} catch (IOException e) {
// if we're here, the image could not be read in
e.printStackTrace();
System.exit(-1); // can't get image -- exit program
}
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel); // add GUI to JFrame
frame.pack(); // tell layout managers to layout components
frame.setLocationRelativeTo(null); // center GUI
frame.setVisible(true); // display GUI
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You can do something like this:
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jLabel.setVisible(!jLabel.isVisible()); //Note! jLabel has to be a final variable.
}
}
You should note that any variables used inside coming from outside the ActionListener have to be final ones. This largely restricts you into working with objects
I usually use set bounds (0,0,0,0); whenever I want to hide swing components
button.addActionListener(new Actionbox());
final class Actionbox implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
if (label.getIcon() == null) {
label.setIcon(new ImageIcon(myimage));
else{
label.setIcon(null);
}
}
I am trying to create a basic game menu for a game right now. I am just testing out the menu for now, and most of the options I wrote are just to test out whether the menu actually works or not. So I have a Menu class and a OptionPanel class as well.
Here is the Menu Class:
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
public class Main extends JFrame {
JPanel cardPanel;
public Main(String title) {
super(title);
setBounds(100, 100, 800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cardPanel = new JPanel();
CardLayout cl = new CardLayout();
cardPanel.setLayout(cl);
OptionPanel panel1 = new OptionPanel(this);
Board panel2 = new Board();
Rules panel3 = new Rules();
cardPanel.add(panel1,"1");
cardPanel.add(panel2,"2");
cardPanel.add(panel3,"3");
add(cardPanel);
setVisible(true);
}
public static void main(String[] args)
{
Main w = new Main("AP Animation Demo");
}
public void changePanel() {
((CardLayout)cardPanel.getLayout()).next(cardPanel);
requestFocus();
}
}
And here is my Option Panel class:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class OptionPanel extends JPanel implements ActionListener {
Main w;
public OptionPanel(Main w) {
this.w = w;
JButton button = new JButton("Press me!");
button.addActionListener(this);
add(button);
JButton button2 = new JButton("Game rules");
button2.addActionListener(this);
add(button2);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.BLACK);
}// Call JPanel's paintComponent method to paint the background
public void actionPerformed(ActionEvent e) {
w.changePanel();
}
}
How do I make it so when the menu pops up, I can click on one button that leads to the game, and when clicking on another button, get linked to another screen. I think it has something to do with the actionPerformed thing, so I tried adding if (e.getSource == button) and stuff like that, but it could not find any button variable. Any advice/feedback?
If you want the actionPerformed() method to be able to access a button variable, then the variable has to have an instance scope (or static, less preferable almost always). Referring to it in the method as you have it written won't work because the button variable is local to the constructor.
The suggestion in the comments is to make a separate ActionListener for each button; you only need to use the if (e.getSource() == button) if the one actionPerformed() method is getting called for multiple buttons. The difference between these is a little much for a SO answer; you can get a tutorial on action listeners in the Java tutorials at Oracle.
The way you have started above suggests you are going to use the OptionPanel as a single action listener for all buttons, and therefore it needs to test which button invoked it. If instead you have a separate action listener for each button, then it knows which button invoked it and doesn't need to test.
Try looking up "anonymous inner classes" as they relate to action listeners in Java.
Here is the code of my Layout class.
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class Layout extends JFrame {
private JButton lb;
private JButton cb;
private JButton pb;
private FlowLayout layout;
private Container container;
public Layout() {
super("The Title");
layout = new FlowLayout();
container = new Container();
setLayout(layout);
//*Left
lb = new JButton("L");
add(lb);
lb.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.LEFT);
layout.layoutContainer(container);
}
}
);
//*Center
cb = new JButton("C");
add(cb);
cb.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.CENTER);
layout.layoutContainer(container);
}
}
);
//*Right
pb = new JButton("R");
add(pb);
pb.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.RIGHT);
layout.layoutContainer(container);
}
}
);
}
}
I'm learning java through thenewboston youtube tutorials (this code is from this tutorial). But this one doesn't work like it should. When I click the right button (R) it should drag all the buttons to the right side of the window instantly. It doesnt. However when I click that right button and then forcibly resize the window then it do what it should. By adding setResizable(false) in the main method I cant resize the program so it doesnt work.
What have I done wrong?
Forgive me for my poor English btw.
replace
container = new Container();
by
container = getContentPane();
The simplest way would be to set a new FlowLayout and call invalidate():
setLayout(new FlowLayout(FlowLayout.LEFT));
invalidate();
validate();
Updating the current FlowLayout has no effect.