TicTacToe with Java Swing - java

At the moment I've got some problems with programming a TicTacToe game with Java Swing.
-the frame shall consist of 9 blank JLabels
-with a click X or an O appears
-the first click on a blank label shall show a X or O but more clicks on the same label have no more influence
-when the last click was an X, the next one should be an O
-it doesn't matter if you start with a X or an O
I wrote those two Classes:
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TicTacToe extends JFrame{
JPanel p = new JPanel();
SignLabel labels[]= new SignLabel[9];
public TicTacToe() {
super("TicTacToe");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300,300);
p.setLayout(new GridLayout(3, 3));
for(int i=0;i<9;i++) {
labels[i] = new SignLabel();
p.add(labels[i]);
}
add(p);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
TicTacToe t = new TicTacToe();
}
});
}
}
SignLabel
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JLabel;
public class SignLabel extends JLabel implements MouseListener {
int value = 0;
public SignLabel() {
this.addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
value++;
value%=2;
switch(value) {
case 0:
if(this.getText() == null) {
this.setText("X");
} else if(this.getText() == "O") {
break;
} else if(this.getText() == "X") {
break;
}
case 1:
if(this.getText() == null) {
this.setText("O");
} else if(this.getText() == "O") {
break;
} else if(this.getText() == "X") {
break;
}
}
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
If i want to compile the code and start the java file, the wanted window will appear but either there are no labels or the mouse event doesn't work.
I guess the whole stuff with the getText() etc is wrong and the method above doesn't really do what I thought, too.
I would be glad about some help!
Thank you!

Here is your code corrected.
SignLabel.java
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JLabel;
public class SignLabel extends JLabel implements MouseListener {
static boolean value = false;
public SignLabel() {
this.addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
value = !value;
if(getText().length() == 0){
if(value){
setText("X");
}else{
setText("O");
}
}
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
TicTacToe.java
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.*;
public class TicTacToe extends JFrame{
JPanel p = new JPanel();
SignLabel labels[]= new SignLabel[9];
public TicTacToe() {
super("TicTacToe");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300,300);
p.setLayout(new GridLayout(3, 3));
for(int i=0;i<9;i++) {
labels[i] = new SignLabel();
labels[i].setBorder(BorderFactory.createLineBorder(Color.black));
p.add(labels[i]);
}
add(p);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
TicTacToe t = new TicTacToe();
}
});
}
}
Ok, a few things here:
your label are actually drawn, but without anything written to it you can't see them. At line 17 of ticTacToe.java you can see how I added borders to make sure the labels were there. They are.
Labels always have a String as a text. Empty, but they have. And empty String is a valid object, so the null comparision will be false. To see if the text is empty you can just check the length of the string getText() returns.
the whole check to see if there is X or O in the label is useless. Once you know there is something, you can just ignore the click.
I turned value to a boolean, so you can just switch between the two signs with a not. Also, to make it work, it must be static, otherwise every SignLabel you create will have its own value and you will always mark with an X (I forgot it and i've seen it myself, you remove the static and you can see it too.)

Related

How to fix when JPanel.repaint() doesn't call paintComponent //nothing I found that work

I'm going to create a JPanel Howto, which is rendering 6 images in order and then add the back button to go back to title.
I'm trying check if it call paintComponent method in class howto or not. And it doesn't so the value i is still 0 and end up stuck in loop
Here's my Howto class
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JPanel;
import Audio.HitSound;
import Graphic.DrawingUtility;
public class Howto extends JPanel implements Runnable{
private JButton back;
private static int i;
public Howto(){
this.setPreferredSize(new Dimension(800, 600));
this.setLayout(null);
repaint();
HitSound h = new HitSound();
i=0;
this.setVisible(true);
}
public void run() {
// TODO Auto-generated method stub
try {
while(i<6)
{
GameManager.frame.repaint();
Thread.sleep(10);
System.out.println("i: " + i);
}
} catch (Exception e) {
// TODO: handle exception
Thread.interrupted();
}
}
public void paintComponent(Graphics g){
if(GameManager.thread.isAlive()){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(DrawingUtility.getHowto(i), 0, 0, 800, 600,null);
i++;
}
}
}
and this what in my GameManager class
public static void startThread() {
thread = new Thread(howto);
thread.start();
}
public static void runHowto() {
howto = new Howto();
howto.setVisible(true);
frame.switchScene(howto);
howto.repaint();
startThread();
while (thread.isAlive()) {
//frame.repaint();
}
if (!thread.isAlive()) {
JButton back = new JButton();
back.setBorderPainted(false);
back.setContentAreaFilled(false);
back.setFocusPainted(false);
back.setOpaque(false);
back.setBounds(640, 446, 132, 132);
back.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
HitSound h = new HitSound();
h.play(3);
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
GameManager.goToTitle();
}
});
}
but when I call runHowto(); it's still looping and i == 0 and not increase i
So I think it's may have problem with paintComponent and repaint method
So please help me fixing it Thanks in advance :)
The while (thread.isAlive()) loop blocks the AWT Event Dispatch Thread (EDT).
You need to return to the event dispatch loop from runHowto. Have your Howto task to post back to the EDT with java.awt.EventQueue.invokeLater to construct your back button and presumably add it to a panel.

Java - Response from button

I've tried many things to get this button bb or continue to output "Hey Buddy", yet it still does not work. It is displayed yet when i press it nothing happens. The code uses both java swing a awt.
package Game;
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
public class base extends java.applet.Applet implements ActionListener, TextListener {
//Graphics
//Graphics
#SuppressWarnings("deprecation")
public static JButton bb = new JButton("Continue");
public TextArea ta = new TextArea(30, 140);
TextArea tb = new TextArea(3, 130);
public int counter = 0;
//main class
public static void main(String[] args) {
Frame f = new Frame("---Quest---");
base ex = new base();
ex.init();
f.add("Center", ex);
f.pack();
f.show(true);
bb.addActionListener(ex);
}
public void actionPerformed1(ActionEvent Continue) {
bb.addActionListener(this);
counter++;
if (Continue.getSource() == bb && counter == 1) {
tb.append("Hey Buddy");
}
}
//graphics
public void init() {
bb.addActionListener(this);
Panel p;
setLayout(new BorderLayout());
p = new Panel();
ta.append("Hey");
bb.addActionListener(this);
p.add(bb);
p.add(ta);
p.add(tb);
p.setBackground(Color.blue);
ta.setBackground(Color.cyan);
ta.setEditable(false);
add("Center", p);
p.setVisible(true);
}
//time class
public static int nap(int time) {
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
//end of code
#Override
public void textValueChanged(TextEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
The whole code is buggy.Read the Comments inline.
1.Idk why you are adding actionListener to the button 4 times(Keep one)
2.You have to have to change the actionPerformed1 to actionPerfromed as you are implementing the ActionListener and assigning this to button's ActionListener
public TextArea ta = new TextArea(30, 140);
TextArea tb = new TextArea(3, 130);
public int counter = 0;
//main class
public static void main(String[] args) {
f.show(true);//show is deprecated use setVisible(true) instead;
bb.addActionListener(ex);//1
}
public void actionPerformed1(ActionEvent Continue) {//have to change the actionPerformed1 to actionPerfromed
bb.addActionListener(this);//2 What is this assigning inside actionPerformed Need to be removed
counter++;
if (Continue.getSource() == bb && counter == 1) {
tb.append("Hey Buddy");
}
}
//graphics
public void init() {
bb.addActionListener(this);//3
Panel p;
setLayout(new BorderLayout());
p = new Panel();
ta.append("Hey");
bb.addActionListener(this);//4
p.add(bb);
p.setVisible(true);//already called a show for JFrame why you want to set Visible of Panel
}

How to know the release listener is triggered after click operation or drag operation?

I asked a fuzzy question hours ago and hope this description can make it clear.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class TestMouseEvent {
public void createUI(){
JFrame frame = new JFrame("Test Mouse Event");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
MainPanel mainPanel = new MainPanel();
mainPanel.setPreferredSize(new Dimension(800, 600));
mainPanel.addMouseListener(new ImageMouseListener());
mainPanel.addMouseMotionListener(new ImageMouseAdapter());
frame.add(mainPanel,BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
TestMouseEvent testMouseEvent = new TestMouseEvent();
testMouseEvent.createUI();
}
#SuppressWarnings("serial")
class MainPanel extends JPanel{
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setFont(new Font("Arial", Font.PLAIN, 20));
g.drawString("I'm a panel and I'm being listened now", 200, 300);
}
}
class ImageMouseListener implements MouseListener{
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("clicked");
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("pressed");
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("released");
JOptionPane.showMessageDialog(null, "I only want to be showed when \"drag\" event over but not for click event!");
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
class ImageMouseAdapter extends MouseAdapter{
public void mouseDragged(MouseEvent e){
if (e.getModifiers() == InputEvent.BUTTON1_MASK) {
System.out.println("dragged");
}
}
}
}
I only want to show the JOptionPane right after the drag operation but not the click operation.So how can I know the difference?
Inside your ImageMouseAdapter set a flag (let's name if dragInProgressFlag) to true. On release check the flag. If it's true show the JOptionPane and reset it back to false.
First, unify your MouseListener and MouseMotionListener into a single class, you can do this simply by using MouseAdapter...
Second, add a instance variable to act as a flag to indicate if a drag operation is taking place...
class ImageMouseListener extends MouseAdapter {
private boolean isDragging = false;
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("clicked");
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
if (isDragging) {
System.out.println("released");
JOptionPane.showMessageDialog(null, "I only want to be showed when \"drag\" event over but not for click event!");
}
isDragging = false
}
public void mouseDragged(MouseEvent e) {
if (e.getModifiers() == InputEvent.BUTTON1_MASK) {
isDragging = true;
System.out.println("dragged");
}
}
}
Create a single instance of the ImageMouseListener and add it as the mouseListener and mouseMotionListener for your panel...
ImageMouseListener handler = new ImageMouseListener();
mainPanel.addMouseListener(handler);
mainPanel.addMouseMotionListener(handler);
You could consider using the inbuilt Drag'n'Drop support within in Java, depending on what you want to achieve, for example, have a look at Java - How to drag and drop JPanel with its components

I am trying to add a JButton array that I added to a panel onto my JFrame, yet nothing is showing up

Here is my code:
For some reason nothing will appear on my screen, yet I don't know why, I believe I am initializing it correctly and adding it. Help?
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class main implements MouseListener{
final int WIDTH = 800, HEIGHT = 500, BOARD_WIDTH = 10, BOARD_HEIGHT = 10;
private JButton [][]buttons = new JButton[BOARD_WIDTH][BOARD_HEIGHT];
public static void main(String[] args) {
// TODO Auto-generated method stub
new main();
}
public main()
{
Start();
}
private void Start()
{
JFrame mainFrame = new JFrame("MineSweeper");
mainFrame.setVisible(true);
mainFrame.setSize(WIDTH,HEIGHT);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setLocationRelativeTo(null);
mainFrame.setResizable(false);
mainFrame.setLayout(new BorderLayout());
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(BOARD_WIDTH, BOARD_HEIGHT));
for(int x = 0; x < BOARD_WIDTH; x++)
for(int y = 0; y < BOARD_HEIGHT; y++)
{
buttons[x][y] = new JButton("01");
buttons[x][y].addMouseListener(this);
p1.add(buttons[x][y]);
}
mainFrame.add(p1, BorderLayout.CENTER);
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
Thanks for any help!
Also sorry for any confusion it is that my buttons wont appear on the screen not that the frame will no appear.
Call mainFrame.setVisible(true); last
private void Start()
{
JFrame mainFrame = new JFrame("MineSweeper");
// Move this...
//mainFrame.setVisible(true);
//...
mainFrame.add(p1, BorderLayout.CENTER);
// To here
mainFrame.setVisible(true);
}
You should also launch you application within the context of the EDT. Take a look at Initial Threads for more details
You should also avoid using a MouseListener on buttons, they have a ActionListener API which includes notification when the use clicks the button or "active" key (usually Enter or Space)

JPanel problem - repaint on resize on normal look

I have strange problem with JPanel. I am trying to show svg image ( SVG_class extends JSVGCanvas from batik jar). Problem is when I start this program I get this
and when I resize with pointer frame a little I get normal picture like this
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.io.*;
import java.util.LinkedList;
import java.util.List;
import javax.swing.*;
import org.apache.batik.swing.JSVGCanvas;
public class Main {
static JScrollPane scrollpane;
// The frame.
protected JFrame frame;
public static void main(String[] args) {
final JFrame f = new JFrame("frame");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(700, 500);
f.setBackground(Color.blue);
SVG_class svg = new SVG_class();
JPanel p = new JPanel();
p.setSize(new Dimension(700, 500));
p.add(svg);
p.setBackground(Color.red);
scrollpane = new JScrollPane(p);
scrollpane.setPreferredSize(new Dimension(700, 500));
Container cont = f.getContentPane();
cont.add(scrollpane);
f.setVisible(true);
}
}
public class SVG_class extends JSVGCanvas {
private List<Type> list;
private int rad;
public boolean red_dot(int iX, int iY, String sX, String sY){
boolean b;
int x,y;
x=Math.abs(iX-(int)Double.parseDouble(sX));
y=Math.abs(iY-(getSize().height-(int)Double.parseDouble(sY)));
System.out.println("iX="+iX+" iY="+iY+" sX="+sX+" sY="+sY+" x="+x+" y="+y);
b=(x<=rad) &&(y<=rad);
return b;
}
public SVG_class(){
try {
this.list=CSV.getCSV("map2");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String fileName = "map2";
File file = new File("C:\\Users\\Gigabyte\\Desktop\\SVG\\"+fileName+".svg");
try {
this.setURI(file.toURL().toString());
this.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
//
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent e) {
boolean found=false;
// System.out.println("pritisnuo si x="+e.getX()+" y="+e.getY());
int x,y;
for(int i=0; i<list.size() && !found;i++ ){
found=red_dot(e.getX(), e.getY(), list.get(i).getX(), list.get(i).getY());
}
if (found) {
System.out.println("pritisao!!!!");
}
System.out.println(" ");
}
});
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Can someone tell me what is mistake ? I tried with p.repaint but it didn't help.
Posting the source for SVG_class might make it easier to see what the problem is.
As it is, I suspect the problem is because you're not explicitly telling it what kind of layout to use.
If you want svg to take up the whole window you could do p.setLayout(new GridLayout(1, 1)); after you create p.
You should call the f.setSize(700, 500); just before showing.
SVG_class has probably set its size in the constructor. Don't do that and define the size at after calling the constructor.
EDIT: Try adding
f.pack();

Categories