I have created a simple game in Swing which has a screen. Clicking on a cell results in color change of two adjacent cells. This is achieved by this code:
public class SelfGrid extends BattleGrid {
#Override
protected JPanel getCell()
{
JPanel panel = new JPanel();
panel.setBackground(Color.black);
panel.setBorder(BorderFactory.createLineBorder(Color.blue, 1));
panel.setPreferredSize(new Dimension(20, 20));
panel.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e)
{
panel.setSize(new Dimension(20,80));
panel.setBackground(Color.orange);
}
}
});
return panel;
}
}
public abstract class Battle extends JPanel {
public BattleGrid() {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel grid = new JPanel();
grid.setLayout(new GridLayout(0,10));
JPanel panel = new JPanel();
panel = getCell();
grid.add(panel);
}
}
this.add(grid);
}
protected abstract JPanel getCell();
}
When I use setVisible(boolean) method to toggle between two screens and the original screen is brought back, only the cells that were clicked on remain colored. In other words, the dimension of each JPanel is restored to 20,20. I was told that this is because setVisible() method actually repaints components on the screen. How can I bring back the original screen without any changes being made to it contents? Thank you.
Instead of making programatic color changes directly to the UI elements, create a two dimensional array that represents the colors of the cells, and modify that. Then, repaint the cells based off the values in the array each time visibility changes or a cell is clicked.
Related
Good afternoon,
As a personal project intended to help me practice using JPanels and subclasses, I am coding a professional web portfolio containing my education, work and volunteer experience, and other notable works using JApplets.
I have the layout set to BorderLayout with the JButtons aligned WEST. When a button is clicked, the JPanels in the CENTER are supposed to switch out with the appropriate panel. However, I am not that far yet.
As of now, I only have a JLabel onto my Home JPanel that says "Home," because I'd like to make sure the method from the Home JPanel class is working before doing anything more. The issue is that the JPanel isn't displaying on the applet.
The thing is, when I move all the code into from the JPanel's class onto the main class, it displays just fine. So I know the problem is with either how I'm constructing the method, or with how I constructed my JPanel's class.
I've tried setting it to visible-- that didn't work. I've tried setting the LayoutManager as a parameter for the class constructor, I've tried adding paintComponent and super.paint(g), I tried using this.home.addHomePanel-- but nothing worked.
I know I'm missing a few things. It would be appreciated if someone could give me a hand. Please let me know if you need more information. Thank you for reading.
Main Class:
public class myWebFolio extends JApplet implements ActionListener
{
JButton[ ] menu =
{
new JButton("Home"),
new JButton("Education"),
new JButton("Work Experience"),
new JButton("Programming Projects"),
new JButton("Other")
};
//adds panel to memory
private JPanel buttonPanel = new JPanel();
private Home home;
public void init()
{
setLayout (new BorderLayout( ) ); //changes the layout of the appl
home = new Home();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
/*
* Adds an ActionListener to each button
* and then adds the button to the buttonPanel.
* Also adds an invisible componenet to give the buttons
* spacing.
*/
for (int i=0; i<menu.length; i++)
{
menu[i].addActionListener(this);
buttonPanel.add(Box.createVerticalStrut(100));
buttonPanel.add(menu[i]);
}
add(buttonPanel,BorderLayout.WEST);
home.addHomePanel();
}
public void actionPerformed(ActionEvent event)
{
}
public void paintComponent(Graphics g)
{
super.paint(g);
}
}
Home Panel's Class:
public class Home extends JPanel
{
JPanel homePanel = new JPanel(new FlowLayout());
JLabel label = new JLabel("Home");
/**
* Constructor for objects of class Home
*/
public Home()
{
}
public void addHomePanel()
{
homePanel.add(label, FlowLayout.LEFT);
homePanel.setVisible(true);
add(homePanel, BorderLayout.CENTER);
}
public void paintComponent(Graphics g)
{
super.paint(g);
}
}
I'm trying to make a game which involves moving pieces by dragging and dropping them from square to square. However, I'm trying to do so using buttons with labels (as an exercise). So, for instance, a button with the label "W" should change its label to "" (blank) when I press the mouse on it and release on a second valid button (one with another blank label). Then that second button should change its label from "" (blank) to "W".
Using graphics in Java is entirely new to me. Suffice it to say, I'm not sure how to accomplish the aforementioned task. Here's my code so far:
import javax.swing.*;
import javax.swing.JButton;
import java.awt.GridLayout;
import java.awt.event.*;
class Boardgame extends JFrame implements MouseListener {
JFrame frame = new JFrame("Boardgame");
JButton[][] bogrid;
public Boardgame ()
{
frame.setLayout(new GridLayout(8,8));
bogrid = new JButton[8][8];
for (int i=0;i<8;i++)
{
for (int j=0;j<2;j++)
{
bogrid[j][i] = new JButton("B");
frame.add(bogrid[j][i]);
}
for (int j=2;j<6;j++)
{
bogrid[j][i] = new JButton();
frame.add(bogrid[j][i]);
}
for (int j=6;j<8;j++)
{
bogrid[j][i] = new JButton("W");
frame.add(bogrid[j][i]);
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setSize(405, 450);
frame.setVisible(true);
}
public void mouseClicked(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
class MyAction implements ActionListener {
Boardgame bo;
MyAction(Boardgame b)
{
bo = b;
}
}
}
First off, you'll need to use a MouseListener to listen for mousePressed and mouseReleased actions. This means that you most definitely should not be using JButtons for this type of program but rather either JLabels, or a logical grid of images, since JButtons should respond to ActionListeners, not MouseListeners (with rare exceptions). I suggest using JLabels, since it will be easy for them to hold and set text and to give you the text they hold.
Next, you would add your MouseListener to your JLabels, and on mousePressed, get the text held by the pressed JLabel. The MouseEvent parameter's getSource() method will return to you the pressed (and released) JLabel.
So inside of your for loops, you will need to add something like:
bogrid[j][i] = new JLabel("B");
bogrid[j][i].addMouseListener(myMouseListener);
frame.add(bogrid[j][i]);
Where myMouseListener is your MouseListener object.
Edit
You ask in comment:
Initial question: using JLabel instead of JButton yields a window that appears to be a large empty field with a bunch of floating labels. How do I make it appear as a grid with lines demarcating the individual spaces?
Consider giving your JLabel a border, and consider giving the GridLayout some horizontal and vertical gaps.
For the layout use the GridLayout constructor that takes 4 int parameters, not 2, with the 3rd and 4th parameters being for the horizontal and vertical gaps:
int gap = 4; // or whatever number looks nice
frame.setLayout(new GridLayout(8, 8, gap, gap));
For the border, consider using a LineBorder that is added to the JLabel in the loop where you create it. If that Border crowds your text too much, you could use a CompoundBorder where the inner border is an EmptyBorder with suitable constants and the outer border is a LineBorder.
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
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
I am trying to place a JPanel on top of another JPanel which contains a JTextArea and a button and i want to the upper apnel to be transparent. I have tried it by making the setOpaque(false) of the upper panel. but it is not working. Can anyone help me to get through this? Thanks in advance!
public class JpanelTest extends JPanel
{
public JpanelTest()
{
super();
onInit();
}
private void onInit()
{
setLayout(new BorderLayout());
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextArea(100,100),BorderLayout.CENTER);
panel.add(new JButton("submit"),BorderLayout.SOUTH);
JPanel glass = new JPanel();
glass.setOpaque(false);
add(panel,BorderLayout.CENTER);
add(glass,BorderLayout.CENTER);
setVisible(true);
}
public static void main(String args[])
{
new JpanelTest();
}
}
Indeed, it would be useful to tell the reason why you want panels one over another.
Starting with your code, and changing it a lot, I got it to work, but it might not do what you expect...
import java.awt.*;
import javax.swing.*;
public class Test extends JFrame
{
public Test()
{
super();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 200);
onInit();
setVisible(true);
}
private void onInit()
{
JLayeredPane lp = getLayeredPane();
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextArea(), BorderLayout.CENTER);
panel.add(new JButton("Submit"), BorderLayout.SOUTH);
panel.setSize(300, 150); // Size is needed here, as there is no layout in lp
JPanel glass = new JPanel();
glass.setOpaque(false); // Set to true to see it
glass.setBackground(Color.GREEN);
glass.setSize(300, 150);
glass.setLocation(10, 10);
lp.add(panel, Integer.valueOf(1));
lp.add(glass, Integer.valueOf(2));
}
public static void main(String args[])
{
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new Test();
}
});
}
}
If totally transparent, well, it is like it isn't here! When opaque, it just covers some of the GUI, but doesn't prevent mouse clicks, for example.
1) there are a few ways, there no issue to put JPanel, with covering full JFrames/JPanel area or only part of Rectangle / Dimension that returns JFrames/JPanel
use JLayer(Java7) based on JXLayer (Java6)
use GlassPane
use JViewport
use OverlayLayout
use transucent JDialog / JWindow
2) everything depends of if you want to protect against mouse and key events from the top layer to bottom, or not (to avoiding redispatch events from - to and vice versa)
Check out this tutorial on using Swing Root Panes.
The glass pane is useful when you want to be able to catch events or paint over an area that already contains one or more components. For example, you can deactivate mouse events for a multi-component region by having the glass pane intercept the events. Or you can display an image over multiple components using the glass pane.