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.
Related
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.
I am fairly new to Java programming, especially as far as GUIs are concerned.
I am trying to create a game similar to "Don't step on the white tile" and for this I need 4 rows, each with 4 rectangles, one of them being black. For this, I have created a subclass of JPanel( called MyImagePanel) in which I have overriden the method paintComponent. An object of this type represents one row out of the 4. My idea was to add 4 obbjects of type MyImagePanel to a Box and register a mouseListener with each of them. If the user clicks on the black tile in the bottom row, a new row should appear at the top and the bottom one should disappear( as if the user is stepping forwards). Otherwisem the user loses( for the moment, this only prints out a message with "Lose").
However, what actually happens is that a new row is generated at the top and the rows at the bottom simply disappear, without being replaced. I do not understand why this occurs.
This is the code for the Test class:
public class Test {
ArrayList<MyImagePanel> rows;
JFrame frame;
Box mainPanel;
public Test(){
rows=new ArrayList<MyImagePanel>();
mainPanel=new Box(BoxLayout.Y_AXIS);
}
public void go(){
frame=new JFrame();
for(int i=0;i<4;i++){
MyImagePanel panel=createPanel();
rows.add(panel);
mainPanel.add(panel);
}
frame.add(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(240, 440);
frame.setResizable(false);
frame.setVisible(true);
}
class MyMouseListener extends MouseAdapter{
public void mouseClicked(MouseEvent ev){
int x=ev.getX();
System.out.println("X coord "+x);
MyImagePanel panel=(MyImagePanel)ev.getComponent();
Color c=panel.getColor(x);
if(panel.equals(rows.get(3)) && c.equals(Color.BLACK)){
System.out.println("Ok");
rows.remove(3);
rows.add(0,createPanel());
System.out.println("List length "+rows.size());
mainPanel.remove(3);
mainPanel.add(rows.get(0), 0);
System.out.println("Components in box "+mainPanel.getComponentCount());
mainPanel.repaint();
}
else{
System.out.println("Lose");
}
}
}
private MyImagePanel createPanel(){
MyImagePanel panel=new MyImagePanel();
panel.setSize(240,100);
panel.addMouseListener(new MyMouseListener());
return panel;
}
public static void main(String[] args){
Test t=new Test();
t.go();
}
}
Because the layout is changing, you'll have to (re)validate and possibly repaint the enclosing mainPanel. The action listener in this related example replaces all of the components that might have moved.
private void createPane() {
this.removeAll();
for (JLabel label : list) add(label);
this.validate();
}
In contrast, this example updates each button's icon in place.
private void update() {
Collections.shuffle(list);
int index = 0;
for (JToggleButton b : buttons) {
b.setIcon(list.get(index++));
}
}
A more flexible approach would be to use the MVC pattern as shown here. Each time the model is updated, the listening view updates itself in response. Instead of replacing components, you update the component in place, e.g. by changing its color.
I Have applet with a image of a java cup that can be repositioned by the clicking of 5 buttons to move it in the main area of the applet window.
the issue im having is the buttons are not being displayed in im applet the only thing that is showing is my cup.gif on the blue background, can any one see the problem with the code ,i want the buttons to show and work
And yes guys I know AWT is old but i have to learn it for my course...any help would be great thanks guys!
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class moveIt extends Applet implements ActionListener
{
private Image cup;
private Panel Keypad = new Panel();
public int top = 15;
public int left = 15;
private Button Keyarray[] = new Button[5];
public void init ()
{
cup=getImage(getDocumentBase(), "cup.gif");
Canvas myCanvas= new Canvas();
Keyarray[0] = new Button ("Up");
Keyarray[1] = new Button ("Left");
Keyarray[2] = new Button ("Down");
Keyarray[3] = new Button ("Right");
Keyarray[4] = new Button ("Center");
setBackground(Color.BLUE);
Panel frame = new Panel();
frame.setLayout(new BorderLayout());
frame.add(myCanvas, BorderLayout.NORTH);
frame.add(Keypad, BorderLayout.SOUTH);
Keypad.setLayout(new BorderLayout());
Keypad.add(Keyarray[0], BorderLayout.NORTH);
Keypad.add(Keyarray[1], BorderLayout.WEST);
Keypad.add(Keyarray[2], BorderLayout.SOUTH);
Keypad.add(Keyarray[3], BorderLayout.EAST);
Keypad.add(Keyarray[4], BorderLayout.CENTER);
Keyarray[0].addActionListener(this);
Keyarray[1].addActionListener(this);
Keyarray[2].addActionListener(this);
Keyarray[3].addActionListener(this);
Keyarray[4].addActionListener(this);
}//end of method init
public void paint(Graphics g)
{
g.drawImage(cup, left, top, this);
}
public void actionPerformed(ActionEvent e)
{
String arg= e.getActionCommand();
if (arg.equals("Up"))
top -= 15;
if (arg.equals("down"))
top += 15;
if (arg.equals("Left"))
left -= 15;
if (arg.equals("Right"))
left += 15;
if (arg.equals("Center"))
{
top=60;
} left=125;
repaint();
}//end paint method
}//end of class
You never add the frame to the applet this.add(frame)
Once you do, you will have to setOpaque(false) to the frame so you can see the background
Important Side Notes:
Instead of painting on the Applet directly, you should be painting rather on a JPanel and override it's paintComponent method.
You Need to call super.paint(g) or super.paintComponent(g)(for JPanel) in the paint method, as to not break the paint chain and see all kinds of wierd paint artifacts
I just noticed the AWT components. AWT is pretty much obsolete. You should move it up to using Swing. See the Swing Tutorials
Use Java naming convention. Variables begin with lower case letters, using camelCasing e.g. Keyarray → keyArray. Class names begin with capital letters using CamelCasing e.g. moveIt → MoveIt
I'm trying to create a simple GUI with a grid containing numbered buttons.
Problem is, the buttons' text will not adjust itself to the buttons' size.
let me first show you the code, so you'll see what I mean:
import javax.swing.*;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SimpleGUI implements ActionListener {
private JFrame frame;
private JPanel grid;
private JButton[] buttons;
public SimpleGUI() {
frame=new JFrame("Buttons grid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
grid=new JPanel();
buttons=new JButton[100];
for (int i=0; i<buttons.length; i++) {
buttons[i]=new JButton(Integer.toString(i+1));
buttons[i].setActionCommand(Integer.toString(i+1));
grid.add(buttons[i]);
buttons[i].addActionListener(this);
}
frame.getContentPane().add(grid);
}
public static void main(String[] args) {
SimpleGUI gui=new SimpleGUI();
gui.go();
}
public void go() {
grid.setLayout(new GridLayout(10,10));
frame.setSize(500,500);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
String buttonNum=e.getActionCommand();
System.out.println("You've pressed "+buttonNum);
}
}
The buttons are too small for the text to fit in, so instead of numbers, three dots will appear on them. (...)
Only when I expand the window (and thus expanding the buttons' dimension accordingly), the numbers appear on the buttons properly.
Is there a way to make the text adjust itself to the buttons' dimension so it'll always be visible?
It indeed is possible to give a bit more space to the text within the buttons. The extra empty space around the text is controlled by the margins and that can be changed:
button.setMargin(new Insets(0, 0, 0, 0));
If you want to make the buttons square by default, you can override their preferred size:
buttons[i] = new JButton(Integer.toString(i + 1)) {
#Override
public Dimension getPreferredSize() {
Dimension naturalSize = super.getPreferredSize();
int sideLength = Math.max(naturalSize.width, naturalSize.height);
return new Dimension(sideLength, sideLength);
}
};
Then the initial layout will be square, when using pack() (which you should be using, as per Andrew Thompson's answer).
Edit: Changed the preferred size to take in account the button's normal preferred dimensions. (Credits to A. Thompson again).
Make the change seen below.
public void go() {
grid.setLayout(new GridLayout(10,10));
//frame.setSize(500,500);
frame.pack();
frame.setVisible(true);
}
The trick here is not to change the buttons at all, but to get the GUI to adjust to the size of the buttons. That is achieved by calling pack() which..
Causes this Window to be sized to fit the preferred size and layouts of its subcomponents. ..
In the below code I am attempting to move the three buttons to the left when you click the left button. When I click it; nothing happens currently. Can anyone explain to me what I am doing wrong here? Also, for some reason it has stopped compiling correctly and I am unsure why but I BELIEVE it is because of a mistake in my code while attempting to get the buttons to move to the left when you click the button. I do NOT want the window to move. Just the buttons within the window. Does any one see what I am doing wrong and can you explain it?
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Buttons extends JFrame {
//Control Definitions
JButton resetButton;
JButton leftButton;
JButton colorButton;
JPanel buttonPanel;
// Layout Definiton
eventHandle evt;
FlowLayout flt;
Point point; //to Hold Previous Window Position
Color color; //to Hold Previous Color
public Buttons() {
super("Buttons Window");
flt = new FlowLayout();//inialize the Flow Layout
buttonPanel = new JPanel(flt);
//inialize the buttonPanel With Flow Layout
//initialize buttons
resetButton = new JButton("Reset");
leftButton = new JButton("Left");
colorButton = new JButton("Blue");
evt = new eventHandle(); //initiate the eventhandle class
buttonPanel.add(leftButton); //add leftButton
buttonPanel.add(colorButton);//add colorButton
buttonPanel.add(resetButton);//add colorButton
getContentPane().add(buttonPanel);//buttonPanel
//add actionlistners
leftButton.addActionListener(evt);
colorButton.addActionListener(evt);
resetButton.addActionListener(evt);
setBounds(20, 120, 250, 70);
//following Initate the point with Center of Scren
point = new Point((Toolkit.getDefaultToolkit().
getScreenSize().width - getWidth()) / 2,
(Toolkit.getDefaultToolkit().getScreenSize().height
- getHeight()) / 2);
setLocation(point); //locates the window in center
color = buttonPanel.getBackground();//stores the initial color
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
class eventHandle implements ActionListener { //Event Handler
public void actionPerformed(ActionEvent e) {
{
if (e.getSource() == leftButton) ///if its from leftButton
{
leftButton.setAlignmentX(Component.LEFT_ALIGNMENT);
colorButton.setAlignmentX(Component.LEFT_ALIGNMENT);
resetButton.setAlignmentX(Component.LEFT_ALIGNMENT);
//setLocation( (point.x -150), point.y);//shift the window 150 pixels left
} else if (e.getSource() == colorButton) {
buttonPanel.setBackground(color.BLUE);
//sets the backgorund to Blue
} else {
leftButton.setAlignmentX(Component.CENTER_ALIGNMENT);
//sets the location to previous location
colorButton.setAlignmentX(Component.CENTER_ALIGNMENT);
resetButton.setAlignmentX(Component.CENTER_ALIGNMENT);
}
}
}
}
public static void main(String[] args) {
Buttons buttonwindow = new Buttons();
}
}
It has stopped compiling, because you deleted one accolade, so put one accolade "}" just above the method:
public static void main(String[] args)
and the code should compile. pls feedback.
EDIT:
Also rewrite your main method like this:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Buttons buttonwindow = new Buttons();
}
}
);
}
Every usage of Swing components must be done thorugh the Event Dispatch Thread (abbreviated EDT) or you will probably get unwanted visual effects. See here for explanation.
EDIT^2:
To achieve the desired behavior, rewrite the the action listener like this:
if (e.getSource() == leftButton) {
((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.LEFT); //1
buttonPanel.revalidate(); //2
}
else if (e.getSource() == colorButton) {
buttonPanel.setBackground(color.BLUE);
}
else {
((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.CENTER);
buttonPanel.revalidate();
}
Any change to the visual appereance to the Swing component must be done through the assigned layout manager, in this case FlowLayout - in line 1.
To see the change you must notify the Swing components layout manager to rearrange the components - in line 2 the revalidate() method "notifies" the layout manager to recalculate the new positions and eventually "notifies" the EDT to draw it on the screen.
You should update the layout manager to align the components to the left or right. Try something like;
((FlowLayout)getLayout()).setAlignment(FlowLayout.LEFT);
Instead
You code won't compile as the static main method appears inside the inner class eventHandle. You can fix simply by moving it into the class body of the outer class Buttons.
As you have all the objects references at class level, you could do the button alignment using, for instance:
flt.setAlignment(FlowLayout.RIGHT);
buttonPanel.revalidate();
...
Here you are adjusting the layout alignment of your FlowLayout and revalidating to visually reflect the updated changes on your panel.