UPDATE: I just coded each button manually. Thanks Anyways.
I am trying to make a Memory Game written in Java. For some reason Java renders all the images as the same. It appears to render the latest image to all buttons when clicked.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.ArrayList;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
/**
* #author Steven
*
*/
public class Memory extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int GRIDSIZE = 4;
private PicButton[][] liteBut = new PicButton[GRIDSIZE][GRIDSIZE];
private Random rand = new Random();
private ClassLoader cl = this.getClass().getClassLoader();
private String[] imagelist = {"images/image01.jpg", "images/image02.jpg", "images/image03.jpg", "images/image04.jpg"};
private ArrayList<String> images = new ArrayList<String>();
private volatile String icon = "";
public Memory() {
initGUI();
setTitle("Memory");
setResizable(false);
pack();
setLocationRelativeTo(null);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void initGUI() {
assignimages();
TitleLabel framedTitle = new TitleLabel("Memory");
add(framedTitle, BorderLayout.PAGE_START);
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(GRIDSIZE, GRIDSIZE));
add(centerPanel, BorderLayout.CENTER);
for (int row = 0; row < GRIDSIZE; row++) {
for (int col = 0; col < GRIDSIZE; col++) {
liteBut[row][col] = new PicButton(row, col);
if (row == 0) {
if (col == 0) {
icon = images.get(0);
System.out.println(icon);
} else if (col == 1) {
icon = images.get(1);
System.out.println(icon);
} else if (col == 2) {
icon = images.get(2);
System.out.println(icon);
} else if (col == 3) {
icon = images.get(3);
System.out.println(icon);
}
} else if (row == 1) {
if (col == 0) {
icon = images.get(0);
System.out.println(icon);
} else if (col == 1) {
icon = images.get(1);
System.out.println(icon);
} else if (col == 2) {
icon = images.get(2);
System.out.println(icon);
} else if (col == 3) {
icon = images.get(3);
System.out.println(icon);
}
}
liteBut[row][col].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PicButton button = (PicButton) e.getSource();
int row = button.getRow();
int col = button.getCol();
String id = button.getID();
System.out.println("Hi from " + id);
liteBut[row][col].setIcon(new ImageIcon(cl.getResource(icon)));
}
});
centerPanel.add(liteBut[row][col]);
}
}
}
private void assignimages() {
for (int x = 0; x < 4; x++) {
int i = rand.nextInt(GRIDSIZE);
images.add(imagelist[i]);
}
for (int x = 0; x < images.size(); x++) {
System.out.println(images.get(x));
}
}
public static void main(String[] args) {
try {
String className = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(className);
} catch (Exception e) {
}
EventQueue.invokeLater(new Runnable() {
public void run() {
new Memory();
}
});
}
public class PicButton extends JButton {
private static final long serialVersionUID = 1L;
private static final int MAXSIZE = 150;
private int row = 0;
private int col = 0;
private String id = "";
//private Boolean hasPic;
public PicButton(int row, int col) {
this.row = row;
this.col = col;
id = Integer.toString(row) + Integer.toString(col);
System.out.println(id);
setBackground(Color.BLACK);
Dimension size = new Dimension(MAXSIZE, MAXSIZE);
setPreferredSize(size);
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public String getID() {
return id;
}
public void setImage() {
setBackground(Color.RED);
//hasPic = true;
}
public void clearImage() {
setBackground(Color.BLACK);
//hasPic = false;
}
}
public class TitleLabel extends JLabel {
private static final long serialVersionUID = 1L;
public TitleLabel(String title) {
Font titleFont = new Font(Font.SERIF, Font.BOLD, 32);
setFont(titleFont);
setHorizontalAlignment(JLabel.CENTER);
setText(title);
setBackground(Color.BLACK);
setForeground(Color.WHITE);
setOpaque(true);
}
}
}
liteBut[row][col].setIcon(new ImageIcon(cl.getResource(icon)));
is assigning the last known value of icon as the image to the button (this is an instance field, so it remembers), this is not the "value" assigned to the button, but the last value assigned to icon by the for-loop in which you create the buttons, so basically, ALL the buttons will get the last icon, instead, supply the icon value the PictureButton itself so you can "update" the button when it's clicked.
This functionality could be self contained to the button itself, further making it easier to manage
Related
i have a problem with a grid i created. the buttons of this smallerGrid will not appear until i hover over them with the mouse.
each smallerGrid consists of a 3x3 grid which fits into a biggerGrid also 3x3 grid that conatins the smaller grids.
that is a brief explanation of how i am constructing the sudoku grid.
You will find the code below.
Thank you in advance.
import java.awt.*;
import javax.swing.*;
public class MyGridLayout {
private int filledFields = 0;
private JFrame mainFrame;
private JPanel panelForSolvingButton;
private JPanel smallerGridPanel;
private boolean solvingButtonAppeared = false;
SudokuCell[][] biggerGrid = new SudokuCell[10][10];
MyGridLayout() {
mainFrame = new JFrame("sudoku-solver");
mainFrame.setLayout(new BorderLayout());
smallerGridPanel = new JPanel(new GridLayout(3, 3));
mainFrame.add(smallerGridPanel, BorderLayout.CENTER);
panelForSolvingButton = new JPanel();
panelForSolvingButton.setLayout(new FlowLayout(FlowLayout.RIGHT));
mainFrame.add(panelForSolvingButton, BorderLayout.SOUTH);
mainFrame.pack();
mainFrame.setSize(600,600);
mainFrame.setLocationRelativeTo(null);
mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrame.setResizable(false);
addRegularButtons();
}
void addRegularButtons() {
int currentCol = 0;
int currentRow = 0;
int smallerGridFirstCol = 0;
int firstRowOfLayer = 0;
for (int layerOfGrids = 0; layerOfGrids < 3; ++layerOfGrids) {
for (int gridOfLayer = 0; gridOfLayer < 3; ++gridOfLayer) {
JComponent smallerGrid = new JPanel(new GridLayout(3, 3));
smallerGrid.setBorder(BorderFactory.createLineBorder(Color.BLACK));
smallerGridPanel.add(smallerGrid);
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
var cell = new SudokuCell(currentRow, currentCol);
smallerGrid.add(cell);
biggerGrid[currentRow][currentCol++] = cell;
cell.addActionListener(new CellActionListener(this));
}
currentRow++;
currentCol = smallerGridFirstCol;
}
smallerGridPanel.revalidate();
currentRow = firstRowOfLayer;
smallerGridFirstCol += 3;
currentCol = smallerGridFirstCol;
}
firstRowOfLayer += 3;
currentRow = firstRowOfLayer;
smallerGridFirstCol = currentCol = 0;
}
mainFrame.revalidate();
mainFrame.setVisible(true);
}
// checking if the solving process can begin
// (filled fields must at least reach 17)
void makeSolveButtonAppear() {
JButton solveButton = new JButton();
solveButton.setBackground(Color.white);
solveButton.setFont(new Font("Arial", Font.PLAIN, 20));
solveButton.setOpaque(false);
solveButton.setText("Solve ?");
panelForSolvingButton.add(solveButton);
}
public boolean isSolvingButtonAppeared() {
return solvingButtonAppeared;
}
public void setSolvingButtonAppeared(boolean solvingButtonAppeared) {
this.solvingButtonAppeared = solvingButtonAppeared;
}
public int getFilledFields() {
return filledFields;
}
public void setFilledFields(int filledFields) {
this.filledFields = filledFields;
}
public JPanel getPanelForSolvingButton() {
return panelForSolvingButton;
}
public static void main(String[] args) {
var gridLayout = new MyGridLayout();
}
}
package mainFrame;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;
public class SudokuCell extends JButton {
private int x;
private int y;
public SudokuCell(int x, int y) {
this.x = x;
this.y = y;
setBackground(Color.white);
setOpaque(true);
setFont(new Font("Arial", Font.PLAIN, 20));
}
#Override
public int getX() {
return x;
}
#Override
public int getY() {
return y;
}
}
package mainFrame;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CellActionListener implements ActionListener {
private int clicked = 0;
MyGridLayout currentGrid;
CellActionListener(MyGridLayout currentGrid) {
this.currentGrid = currentGrid;
}
#Override
public void actionPerformed(ActionEvent e) {
if(clicked ==0) currentGrid.setFilledFields(currentGrid.getFilledFields()+1);
//clicked (number of clicks) must remain between 0 and 9
clicked = (clicked % 9) + 1;
((JButton) e.getSource()).setText(Integer.toString(clicked));
//first click on the button means an entry has been made
//which means one less needed filledField out of 17
if(!currentGrid.isSolvingButtonAppeared() && currentGrid.getFilledFields() >= 17) {
currentGrid.makeSolveButtonAppear();
currentGrid.setSolvingButtonAppeared(true);
}
}
}```
My program generates random numbers from 0 to 12 but if the result is 12 it would set dash as the text of JLabel, instead of the number generated.
Now, I wanted to sort my JPanel in ascending order based on the JLabel contents. In case of similarities in numbers, the black JPanels are placed on the left. It works fine except when there are dashes included, in which it doesn't sort properly. I would like to insert the JPanels containing dashes anywhere but it's not working as expected.
Screencaps from a shorter version of my program:
Pure numbers:
Dash included:
Here's the shorter version of my code (using the logic of integer sorting):
import java.awt.*;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.Comparator;
public class SortFrames extends JFrame
{
static ArrayList<JPanel> panels = new ArrayList<JPanel>();
JPanel panel = new JPanel();
JPanel sortPane = new JPanel();
int toWrite = 0;
int colorGen = 0;
int comparison = 0;
Random rand = new Random();
public SortFrames()
{
for(int i = 0; i<4;i++)
{
panels.add(new JPanel());
}
for(JPanel p: panels)
{
toWrite = rand.nextInt(13);
colorGen = rand.nextInt(2);
p.add(new JLabel());
JLabel lblToSet = (JLabel)p.getComponent(0);
if(colorGen == 0)
{
p.setBackground(Color.BLACK);
lblToSet.setForeground(Color.WHITE);
}
if(colorGen == 1)
{
p.setBackground(Color.WHITE);
lblToSet.setForeground(Color.BLACK);
}
if(toWrite != 12){lblToSet.setText("" +toWrite);}
if(toWrite == 12){lblToSet.setText("-");}
p.setPreferredSize(new Dimension(30, 30));
panel.add(p);
}
sortMethod();
for(JPanel p: panels)
{
panel.add(p);
panel.revalidate();
}
add(panel);
panel.setPreferredSize(new Dimension(300, 300));
setPreferredSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
setLocationRelativeTo(null);
}
public void sortMethod()
{
for(int i = 0; i<(panels.size());i++)
{
for(int j = i+1; j<(panels.size());j++)
{
JLabel one = (JLabel)(panels.get(i)).getComponent(0);
JLabel two = (JLabel)(panels.get(j)).getComponent(0);
String lblOne = one.getText();
String lblTwo = two.getText();
if(!lblOne.equals("-") && !lblTwo.equals("-"))
{
int comp1 = Integer.parseInt(lblOne);
int comp2 = Integer.parseInt(lblTwo);
JPanel pnl1 = panels.get(i);
JPanel pnl2 = panels.get(j);
if(comp1 == comp2)
{
if(pnl1.getBackground() == Color.BLACK && pnl2.getBackground() == Color.WHITE)
{
panels.set(i, pnl1);
panels.set(j, pnl2);
}
if(pnl1.getBackground() == Color.WHITE && pnl2.getBackground() == Color.BLACK)
{
panels.set(i, pnl2);
panels.set(j, pnl1);
}
}
if(comp1 != comp2)
{
if(comp1>comp2)
{
panels.set(i, pnl2);
panels.set(j, pnl1);
}
}
}
if(lblOne.equals("-") && !lblTwo.equals("-"))
{
JPanel pnl1 = panels.get(i);
panels.set(rand.nextInt(panels.size()), pnl1);
}
if(!lblOne.equals("-") && lblTwo.equals("-"))
{
JPanel pnl2 = panels.get(j);
panels.set(rand.nextInt(panels.size()), pnl2);
}
}
}
}
public static void main(String args[])
{
new SortFrames();
}
}
I also have another method, which is by using Comparator class which also creates the same problem (this sorts equal numbers based on foreground but still the same as to sort equal numbers based on background so it has no effect on the said issue).
private static class JPanelSort implements Comparator<JPanel>
{
#Override
public int compare(JPanel arg0, JPanel arg1)
{
JLabel one = ((JLabel) arg0.getComponent(0));
JLabel two = ((JLabel) arg1.getComponent(0));
String firstContent = one.getText();
String secondContent = two.getText();
try
{
comparisonRes = Integer.compare(Integer.parseInt(firstContent), Integer.parseInt(secondContent));
if(comparisonRes == 0)
{
if(one.getForeground() == Color.BLACK && two.getForeground() == Color.WHITE)
{
comparisonRes = 1;
}
if(two.getForeground() == Color.BLACK && one.getForeground() == Color.WHITE)
{
comparisonRes = -1;
}
}
}
catch(NumberFormatException e)
{
comparisonRes = 0;
}
return comparisonRes;
}
}
Please tell me your ideas. Thank you.
It's much easier to sort data than to sort JPanels.
Here's mu GUI displaying your numbers.
So, lets create a Java object to hold the card data.
public class DataModel {
private final int number;
private final int colorNumber;
private final Color backgroundColor;
private final Color foregroundColor;
public DataModel(int number, int colorNumber, Color backgroundColor,
Color foregroundColor) {
this.number = number;
this.colorNumber = colorNumber;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
}
public int getNumber() {
return number;
}
public int getColorNumber() {
return colorNumber;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public Color getForegroundColor() {
return foregroundColor;
}
}
Pretty straightforward. We have fields to hold the information and getters to retrieve the information. We can make all the fields final since we're not changing anything once we set the values.
The sort class is pretty simple as well.
public class DataModelComparator implements Comparator<DataModel> {
#Override
public int compare(DataModel o1, DataModel o2) {
if (o1.getNumber() < o2.getNumber()) {
return -1;
} else if (o1.getNumber() > o2.getNumber()) {
return 1;
} else {
if (o1.getColorNumber() < o2.getColorNumber()) {
return -1;
} else if (o1.getColorNumber() > o2.getColorNumber()) {
return 1;
} else {
return 0;
}
}
}
}
Since we keep the color number, sorting by color is as easy as sorting a number.
Now that we've moved the data to it's own List, we can concentrate on creating the GUI.
package com.ggl.testing;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SortFrames implements Runnable {
private List<DataModel> dataModels;
private JPanel[] panels;
private JLabel[] labels;
private Random random = new Random();
public SortFrames() {
this.dataModels = new ArrayList<>();
this.random = new Random();
for (int i = 0; i < 4; i++) {
int number = random.nextInt(13);
int colorNumber = random.nextInt(2);
Color backgroundColor = Color.BLACK;
Color foregroundColor = Color.WHITE;
if (colorNumber == 1) {
backgroundColor = Color.WHITE;
foregroundColor = Color.BLACK;
}
dataModels.add(new DataModel(number, colorNumber, backgroundColor,
foregroundColor));
}
Collections.sort(dataModels, new DataModelComparator());
}
#Override
public void run() {
JFrame frame = new JFrame("Sort Frames");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
panels = new JPanel[dataModels.size()];
labels = new JLabel[dataModels.size()];
for (int i = 0; i < dataModels.size(); i++) {
DataModel dataModel = dataModels.get(i);
panels[i] = new JPanel();
panels[i].setBackground(dataModel.getBackgroundColor());
labels[i] = new JLabel(getDisplayText(dataModel));
labels[i].setBackground(dataModel.getBackgroundColor());
labels[i].setForeground(dataModel.getForegroundColor());
panels[i].add(labels[i]);
mainPanel.add(panels[i]);
}
frame.add(mainPanel);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private String getDisplayText(DataModel dataModel) {
if (dataModel.getNumber() == 12) {
return "-";
} else {
return Integer.toString(dataModel.getNumber());
}
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new SortFrames());
}
public class DataModel {
private final int number;
private final int colorNumber;
private final Color backgroundColor;
private final Color foregroundColor;
public DataModel(int number, int colorNumber, Color backgroundColor,
Color foregroundColor) {
this.number = number;
this.colorNumber = colorNumber;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
}
public int getNumber() {
return number;
}
public int getColorNumber() {
return colorNumber;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public Color getForegroundColor() {
return foregroundColor;
}
}
public class DataModelComparator implements Comparator<DataModel> {
#Override
public int compare(DataModel o1, DataModel o2) {
if (o1.getNumber() < o2.getNumber()) {
return -1;
} else if (o1.getNumber() > o2.getNumber()) {
return 1;
} else {
if (o1.getColorNumber() < o2.getColorNumber()) {
return -1;
} else if (o1.getColorNumber() > o2.getColorNumber()) {
return 1;
} else {
return 0;
}
}
}
}
}
The lessons to be learned here are:
Separate the data from the view.
Focus on one part of the problem at a time. Divide and conquer.
I am trying to code a board game in Java.
I have 11 classes including Main. Board class which extends JPanel and draws the board image as well as the dice image. The class Player which extends JCoponent and implements Runnable(Thread). Every player instance is a pawn-animation that it is moving across the board. The player class draws the pawn on the board.
Pattern
How the code it looks like :
Board b=new Board();
Player p=new Player();
b.add(p);
JPanel panel=new JPanel();
panel.add(b);
add(panel); //adding the panel to the frame.
The problem is that I can't have more than one pawn simultaneously on the board. I have already tried to re-paint all the players (as non-animation) in another class but it didn't work. I also tried JLayeredPane but maybe I am doing something wrong. Unfortunately, I can't change the above pattern so don't make this suggestion.
Thank you in advance for your help.
P.S: I can't post any code because its huge.
P.P.S: more clarifications will be given, if you ask me.
EDIT: I reform my question. Is it possible to have two animations simultaneously on the same panel? if the answer is a yes ..how I can do that?
It's most likely possible to have many components moving all at once. Either use javax.swing.Timer ou SwingWorker for this to work.
Here is a quick example showing you this. It puts 16 pawns on a board and moves them randomly from one place to another.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestAnimation {
private static final String PAWN_URL = "http://files.chesskidfiles.com/images_users/tiny_mce/BoundingOwl/bishop_happywhite.png";
private Image pawn;
private Map<Location, Pawn> pawnLocations = new HashMap<>();
private Board board;
private Timer timer;
private JLayeredPane glassPane;
public TestAnimation() {
try {
pawn = new ImageIcon(new URL(PAWN_URL)).getImage();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
private static class Location {
public final int row;
public final int col;
public Location(int row, int col) {
super();
this.row = row;
this.col = col;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + col;
result = prime * result + row;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Location other = (Location) obj;
return (col == other.col && row == other.row);
}
}
private static class Cell extends JPanel {
private final Location location;
public Cell(Location location) {
super(new BorderLayout());
this.location = location;
setOpaque(true);
setBackground(((location.row + location.col) % 2) == 0 ? Color.WHITE : Color.BLACK);
}
#Override
protected void addImpl(Component comp, Object constraints, int index) {
while (getComponentCount() > 0) {
remove(0);
}
super.addImpl(comp, constraints, index);
}
}
private static class Board extends JPanel {
private Map<Location, Cell> cells = new HashMap<>();
public Board() {
super(new GridLayout(8, 8));
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
Cell cell = new Cell(new Location(i, j));
add(cell);
cells.put(new Location(i, j), cell);
}
}
}
public void add(Pawn pawn, Location location) {
cells.get(location).add(pawn);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public Cell getCell(Location location) {
return cells.get(location);
}
}
private class Pawn extends JComponent {
public Pawn() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(pawn, 0, 0, getWidth(), getHeight(), this);
}
}
protected void initUI() {
JFrame frame = new JFrame(TestAnimation.class.getSimpleName());
board = new Board();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 2; j++) {
Location location = new Location(i, j);
Pawn aPawn = new Pawn();
board.add(aPawn, location);
pawnLocations.put(location, aPawn);
}
}
for (int i = 0; i < 8; i++) {
for (int j = 6; j < 8; j++) {
Location location = new Location(i, j);
Pawn aPawn = new Pawn();
board.add(aPawn, location);
pawnLocations.put(location, aPawn);
}
}
timer = new Timer(7000, new Animation());
timer.setInitialDelay(0);
timer.setRepeats(true);
timer.setCoalesce(false);
glassPane = new JLayeredPane();
glassPane.setOpaque(false);
frame.add(board);
frame.setGlassPane(glassPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
timer.start();
glassPane.setVisible(true);
}
public class Animation implements ActionListener {
private Map<Location, Pawn> futureLocations;
private Random random = new Random();
private Timer subTimer;
private List<Pawn> movingPawns;
private Map<Pawn, Point> originalCoordinates = new HashMap<>();
private Map<Pawn, Point> futureCoordinates = new HashMap<>();
#Override
public void actionPerformed(ActionEvent e) {
futureLocations = new HashMap<>();
movingPawns = new ArrayList<>();
for (Pawn p : pawnLocations.values()) {
int row = random.nextInt(8);
int col = random.nextInt(8);
Location location;
while (futureLocations.containsKey((location = new Location(row, col)))) {
row = random.nextInt(8);
col = random.nextInt(8);
}
futureLocations.put(location, p);
Cell futureCell = board.getCell(location);
futureCoordinates.put(p, SwingUtilities.convertPoint(futureCell, 0, 0, glassPane));
movingPawns.add(p);
}
for (Pawn p : movingPawns) {
Point locationInGlassPane = SwingUtilities.convertPoint(p.getParent(), 0, 0, glassPane);
glassPane.add(p);
p.setLocation(locationInGlassPane);
originalCoordinates.put(p, locationInGlassPane);
}
subTimer = new Timer(50, new AnimationSteps());
subTimer.setInitialDelay(0);
subTimer.setCoalesce(true);
subTimer.setRepeats(true);
subTimer.start();
}
public class AnimationSteps implements ActionListener {
private int step = 0;
#Override
public void actionPerformed(ActionEvent e1) {
if (step < 50 + 1) {
for (Pawn p : movingPawns) {
Point p1 = originalCoordinates.get(p);
Point p2 = futureCoordinates.get(p);
int x = (int) (p1.x + ((p2.x - p1.x) * (double) step / 50));
int y = (int) (p1.y + ((p2.y - p1.y) * (double) step / 50));
p.setLocation(x, y);
}
} else {
for (Entry<Location, Pawn> e : futureLocations.entrySet()) {
board.add(e.getValue(), e.getKey());
}
board.revalidate();
subTimer.stop();
pawnLocations = futureLocations;
}
step++;
}
}
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestAnimation().initUI();
}
});
}
}
Maybe your problem is trying to develop a program with a thread for each object, most popular games run with a single thread, two at most. The reason: It will be very complex to synchronize threads with each other, not to mention that your performance will be poor. Even the graphics engine in Java is single threaded and that means you won't have two threads drawing at the same time.
however I am not sure where I am supposed to enter the whoWins() method. Do I enter this method in the actionperformed Method of the buttons or do i need to something different. Please help.
public class TTT extends JFrame implements ActionListener {
private JButton buttons[] = new JButton[9];
private JButton exitButton;
public JLabel title;
public JPanel titlePanel, panel;
private int count = 0;
int symbolCount = 0;
private boolean win = false;
public TTT() {
title = new JLabel("Welcome to my Tic Tac Toe Game!");
titlePanel = new JPanel();
title.setFont(new Font(Font.SERIF, 0, 30));
titlePanel.add(title);
this.add(titlePanel, BorderLayout.NORTH);
panel = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton();
panel.add(buttons[i]);
buttons[i].setEnabled(true);
buttons[i].addActionListener(this);
}
this.add(panel, BorderLayout.CENTER);
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
exitButton = new JButton("Quit");
panel1.add(exitButton);
this.add(panel1, BorderLayout.SOUTH);
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(WIDTH);
}
});
}
public void whoWins() {
//Determines who wins using for the horizontal rows.
if (buttons[0].getText() == buttons[1].getText() && buttons[1].getText() == buttons[2].getText() && buttons[0].getText() != "") {
win = true;
} else if (buttons[3].getText() == buttons[4].getText() && buttons[4].getText() == buttons[5].getText() && buttons[3].getText() != "") {
win = true;
} else if (buttons[6].getText() == buttons[7].getText() && buttons[7].getText() == buttons[8].getText() && buttons[6].getText() != "") {
win = true;
} //Determines the verticles wins
else if (buttons[0].getText() == buttons[3].getText() && buttons[3].getText() == buttons[6].getText() && buttons[0].getText() != "") {
win = true;
} else if (buttons[1].getText() == buttons[4].getText() && buttons[4].getText() == buttons[7].getText() && buttons[1].getText() != "") {
win = true;
} else if (buttons[2].getText() == buttons[5].getText() && buttons[5].getText() == buttons[8].getText() && buttons[2].getText() != "") {
win = true;
}
// Diagnol Wins
else if (buttons[0].getText()==buttons[4].getText()&&buttons[4].getText()==buttons[8].getText()&& buttons[0].getText()!= "") {
win = true;
}else if (buttons[2].getText()==buttons[4].getText()&&buttons[4].getText()==buttons[6].getText()&& buttons[1].getText()!= "") {
win = true;
}else {
win = false;
}
//who won
if (win = true) {
JOptionPane.showMessageDialog(null, "wins");
}else if (count == 9 && win == false) {
JOptionPane.showMessageDialog(null, "Tie game");
}
}
public static void main(String[] args) {
TTT ref1 = new TTT();
ref1.setTitle("Tic Tac Toe");
ref1.setVisible(true);
ref1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ref1.setSize(500, 500);
ref1.setLocationRelativeTo(null);
// ref1.whoWins();
}
#Override
public void actionPerformed(ActionEvent e) {
count++;
for (JButton button : buttons) {
if (button == e.getSource()) {
if (symbolCount % 2 == 0) {
button.setText("X");
button.setEnabled(false);
} else {
button.setText("O");
button.setEnabled(false);
}
}
}
if (count >= buttons.length) {
JOptionPane.showMessageDialog(null, "End");
}
symbolCount++;
}
}
If you really want to do this right, then I suggest making some big changes, some M-V-C type changes:
First and foremost, separate out the logic of the game from the game GUI. This would mean that the code that determines who wins should not be in any code that contains GUI type code. This will be your "model"
Next you should never have GUI code implement listener interfaces, so try to get that out of the GUI and possibly have it go into its own class, the "Control" class.
Finally the GUI or "View" class will concern itself with displaying the model's state and getting input from the user and transmitting this input to the control.
For example,...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.EnumMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class TicTacToeMain {
private static void createAndShowGui() {
TttView view = null;
try {
view = new TttView();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
TttModel model = new TttModel();
new TttControl(model, view);
JFrame frame = new JFrame("Tic Tac Toe");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(view.getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum TttPiece {
EMPTY, X, O
}
class TttView {
public static final String IMAGE = "/imgFolder/TicTacToe.png";
private static final int GAP = 5;
private JPanel mainPanel = new JPanel();
private JPanel tttPanel = new JPanel();
private Map<TttPiece, Icon> iconMap = new EnumMap<>(TttPiece.class);
private JLabel[][] grid = new JLabel[TttModel.ROWS][TttModel.COLS];
private TttControl control;
public TttView() throws IOException {
BufferedImage img = ImageIO.read(getClass().getResourceAsStream(IMAGE));
Icon[] imgIcons = splitImg(img);
iconMap.put(TttPiece.X, imgIcons[0]);
iconMap.put(TttPiece.O, imgIcons[1]);
iconMap.put(TttPiece.EMPTY, createEmptyIcon(imgIcons[0]));
tttPanel.setLayout(new GridLayout(grid.length, grid[0].length, GAP, GAP));
tttPanel.setBackground(Color.black);
MyMouseAdapter mouseAdapter = new MyMouseAdapter();
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
grid[row][col] = new JLabel(iconMap.get(TttPiece.EMPTY));
grid[row][col].setOpaque(true);
grid[row][col].setBackground(Color.LIGHT_GRAY);
grid[row][col].addMouseListener(mouseAdapter);
tttPanel.add(grid[row][col]);
}
}
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0));
btnPanel.add(new JButton(new ClearAction("Clear", KeyEvent.VK_C)));
btnPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
int blGap = 2;
mainPanel.setLayout(new BorderLayout(blGap, blGap));
mainPanel.setBorder(BorderFactory.createEmptyBorder(blGap, blGap, blGap,
blGap));
mainPanel.add(tttPanel, BorderLayout.CENTER);
mainPanel.add(btnPanel, BorderLayout.SOUTH);
}
public void setControl(TttControl control) {
this.control = control;
}
public JComponent getMainPanel() {
return mainPanel;
}
private Icon createEmptyIcon(Icon icon) {
int width = icon.getIconWidth();
int height = icon.getIconHeight();
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
return new ImageIcon(img);
}
private Icon[] splitImg(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
int gap = 5;
Icon[] icons = new ImageIcon[2];
icons[0] = new ImageIcon(img.getSubimage(0, 0, w / 2 - gap, h / 2 - gap));
icons[1] = new ImageIcon(img.getSubimage(w / 2 + gap, 0, w / 2 - gap, h
/ 2 - gap));
return icons;
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (control == null) {
return;
}
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] == e.getSource()) {
control.gridPress(row, col);
}
}
}
}
}
private class ClearAction extends AbstractAction {
public ClearAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
if (control != null) {
control.clear();
}
}
}
private class ExitAction extends AbstractAction {
public ExitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
if (control != null) {
control.exit(evt);
}
}
}
public void setGridIcon(int row, int col, TttPiece tttPiece) {
grid[row][col].setIcon(iconMap.get(tttPiece));
}
}
class TttControl {
private TttModel model;
private TttView view;
public TttControl(TttModel model, TttView view) {
this.model = model;
this.view = view;
view.setControl(this);
model.addPropertyChangeListener(new ModelListener());
}
public void exit(ActionEvent evt) {
Window win = SwingUtilities
.getWindowAncestor((Component) evt.getSource());
win.dispose();
}
public void gridPress(int row, int col) {
try {
model.gridPress(row, col);
} catch (TttException e) {
// TODO: notify user
// e.printStackTrace();
}
}
public void clear() {
model.clear();
}
private class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (TttModel.GRID_POSITION.equals(evt.getPropertyName())) {
TttPiece[][] tttGrid = model.getTttGrid();
for (int row = 0; row < tttGrid.length; row++) {
for (int col = 0; col < tttGrid[row].length; col++) {
view.setGridIcon(row, col, tttGrid[row][col]);
}
}
}
}
}
}
class TttModel {
public static final int ROWS = 3;
public static final int COLS = ROWS;
public static final String GRID_POSITION = "grid position";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private TttPiece[][] tttGrid = new TttPiece[ROWS][COLS];
private TttPiece player = TttPiece.X;
private boolean gameOver;
public TttModel() {
clear();
}
public void setGridPosition(int row, int col, TttPiece piece)
throws TttException {
if (gameOver) {
return;
}
if (tttGrid[row][col] == TttPiece.EMPTY) {
tttGrid[row][col] = piece;
checkForWin(row, col, piece);
nextPlayer();
pcSupport.firePropertyChange(GRID_POSITION, null, tttGrid);
} else {
String message = "Invalid setGridPosition for row: %d, col: %d, piece: %s. "
+ "Spot already occupied by piece: %s";
message = String.format(message, row, col, piece, tttGrid[row][col]);
throw new TttException(message);
}
}
public TttPiece[][] getTttGrid() {
return tttGrid;
}
public void gridPress(int row, int col) throws TttException {
setGridPosition(row, col, player);
}
public void nextPlayer() {
player = player == TttPiece.X ? TttPiece.O : TttPiece.X;
}
private void checkForWin(int row, int col, TttPiece piece) {
// TODO finish
}
public void clear() {
for (int row = 0; row < tttGrid.length; row++) {
for (int col = 0; col < tttGrid[row].length; col++) {
tttGrid[row][col] = TttPiece.EMPTY;
}
}
player = TttPiece.X;
pcSupport.firePropertyChange(GRID_POSITION, null, tttGrid);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
#SuppressWarnings("serial")
class TttException extends Exception {
public TttException() {
super();
}
public TttException(String message) {
super(message);
}
}
Using for my images:
With GUI looking like:
I am also interested in writing a Tic Tac Toe game, so I copied your code, and did a little modification, and it passed test, check following:
package eric.j2se.swing;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
* <p>
* Simple game of Tic Tac Toe.
* </p>
*
* #author eric
* #date Apr 16, 2014 11:03:48 AM
*/
#SuppressWarnings("serial")
public class TicTacToe extends JFrame implements ActionListener {
// 2 players
public static final char playerX = 'X';
public static final char playerO = 'O';
// null player
public static final char playerN = 'N';
// the winer, init to null player
private Character winner = playerN;
// indicate whether game over
private boolean gameOver = false;
// count of button used,
private int count = 0;
private Character buttonPlayers[] = new Character[9];
private JButton buttons[] = new JButton[9];
private JButton exitButton;
public JLabel title;
public JPanel titlePanel, panel;
public TicTacToe() {
// init buttonPlayers
for (int i = 0; i < 9; i++) {
buttonPlayers[i] = playerN;
}
// init title
title = new JLabel("Welcome to Tic Tac Toe!");
titlePanel = new JPanel();
title.setFont(new Font(Font.SERIF, 0, 30));
titlePanel.add(title);
this.add(titlePanel, BorderLayout.NORTH);
// init 9 button
panel = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton();
panel.add(buttons[i]);
buttons[i].setEnabled(true);
buttons[i].addActionListener(this);
}
// init exit button
this.add(panel, BorderLayout.CENTER);
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
exitButton = new JButton("Quit");
panel1.add(exitButton);
this.add(panel1, BorderLayout.SOUTH);
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(WIDTH);
}
});
}
public void whoWins() {
// determine winner - horizontal rows
if (!gameOver) {
for (int i = 0; i < 3; i++) {
if ((buttonPlayers[0 + i * 3] != playerN) && (buttonPlayers[0 + i * 3].equals(buttonPlayers[1 + i * 3]))
&& buttonPlayers[1 + i * 3].equals(buttonPlayers[2 + i * 3])) {
winner = buttonPlayers[0 + i * 3];
gameOver = true;
break;
}
}
}
// determine winner - vertical rows
if (!gameOver) {
for (int i = 0; i < 3; i++) {
if ((buttonPlayers[i + 0 * 3] != playerN) && (buttonPlayers[i + 0 * 3].equals(buttonPlayers[i + 1 * 3]))
&& buttonPlayers[i + 1 * 3].equals(buttonPlayers[i + 2 * 3])) {
winner = buttonPlayers[i + 0 * 3];
gameOver = true;
break;
}
}
}
// determine winner - diagonal rows
if (!gameOver) {
int winButtonIndex = -1;
if ((buttonPlayers[0] != playerN) && (buttonPlayers[0].equals(buttonPlayers[4])) && buttonPlayers[4].equals(buttonPlayers[8])) {
winButtonIndex = 0;
} else if ((buttonPlayers[2] != playerN) && (buttonPlayers[2].equals(buttonPlayers[4])) && buttonPlayers[4].equals(buttonPlayers[6])) {
winButtonIndex = 2;
}
if (winButtonIndex >= 0) {
winner = buttonPlayers[winButtonIndex];
gameOver = true;
}
}
// full
if (count == 9) {
gameOver = true;
}
if (gameOver) {
String tip = "";
switch (winner) {
case playerO:
tip = "Player O win!";
break;
case playerX:
tip = "Player X win!";
break;
default:
tip = "Draw game!";
break;
}
JOptionPane.showMessageDialog(null, tip);
}
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < buttons.length; i++) {
JButton button = buttons[i];
if (button == e.getSource()) {
Character currentPlayer = (count % 2 == 1 ? playerX : playerO);
button.setText(String.valueOf(currentPlayer));
buttonPlayers[i] = currentPlayer;
button.setEnabled(false);
break;
}
}
count++;
whoWins();
}
public static void main(String[] args) {
TicTacToe ref1 = new TicTacToe();
ref1.setTitle("Tic Tac Toe");
ref1.setVisible(true);
ref1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ref1.setSize(500, 500);
ref1.setLocationRelativeTo(null);
}
}
about when to call the win check:
check each time you click 1 of the 9 buttons,
about the flag:
I use 2 flag instead of 1 flag to indicate game over & winner, because in TTT game, draw game is very usual, after play several times, you always get draw game ...
a little suggestion to your code:
when compare string, use equals(), not ==,
define const values in variable, not write it in logic, e.g. 'O' 'X',
don't repeat code, try use logic control to make it short & easy to read & easy to maintain,
I want to create a text field that will be for dates and will have dd.mm.YYYY format. Now what I want the user to type only the numbers, not the dots to. So the field would be like:
_ _. _ _ . _ _ _ _
So when the user wants to type the date: 15.05.2010 for example, he will only type the numbers in the sequence 15052010.
Also I would like, when he presses on left or right arrow, the cursor to go from one field (not JTextField, but field in the JTextField) to the next. So lets say I have JTextField with this text in it: 15.05.2010 If the user is on the beginning and he presses the right arrow, the cursor should go to the .05 field.
I hope you understand me because right now I don't have any idea how to make this, or at least how to look for it on google.
Well, here are 4 classes that solve your problem.
In my case its version control but IP address has the same structure and its easy to modify it.
package com.demo.textfield.version;
import javax.swing.text.Document;
/**
* create documents for text fields
*/
public class DocumentsFactory {
private DocumentsFactory() {}
public static Document createIntDocument() {
return createIntDocument(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
public static Document createIntDocument(int maxValue) {
return createIntDocument(maxValue, Integer.MAX_VALUE);
}
public static Document createIntDocument(int maxValue, int maxLength) {
IntDocument intDocument = new IntDocument();
intDocument.setMaxVal(maxValue);
intDocument.setMaxLength(maxLength);
return intDocument;
}
}
in the followed class we define view:
package com.demo.textfield.version;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JPanel;
public class GridbagPanel extends JPanel {
private static final long serialVersionUID = 1L;
public static final Insets NO_INSETS = new Insets(0, 0, 0, 0);
public GridBagConstraints constraints;
private GridBagLayout layout;
public GridbagPanel() {
layout = new GridBagLayout();
constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.NONE;
constraints.anchor = GridBagConstraints.WEST;
constraints.insets = NO_INSETS;
setLayout(layout);
}
public void setHorizontalFill() {
constraints.fill = GridBagConstraints.HORIZONTAL;
}
public void setNoneFill() {
constraints.fill = GridBagConstraints.NONE;
}
public void add(Component component, int x, int y, int width, int
height, int weightX, int weightY) {
GridBagLayout gbl = (GridBagLayout) getLayout();
gbl.setConstraints(component, constraints);
add(component);
}
public void add(Component component, int x, int y, int width, int height) {
add(component, x, y, width, height, 0, 0);
}
public void setBothFill() {
constraints.fill = GridBagConstraints.BOTH;
}
public void setInsets(Insets insets) {
constraints.insets = insets;
}
}
We use a plain document that contains our main logic (your changes should be here):
package com.demo.textfield.version;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
/**
* a class for positive integers
*/
public class IntDocument extends PlainDocument {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String NUMERIC = "0123456789";
private int maxVal = -1;
private int maxLength = -1;
public IntDocument() {
this.maxVal = -1;
maxVal = Integer.MAX_VALUE;
maxLength = Integer.MAX_VALUE;
}
public void setMaxLength(int maxLength) {
if (maxLength < 0)
throw new IllegalArgumentException("maxLength<0");
this.maxLength = maxLength;
}
public void setMaxVal(int maxVal) {
this.maxVal = maxVal;
}
public void insertString
(int offset, String str, AttributeSet attr)
throws BadLocationException {
if (str == null)
return;
if (str.startsWith(" ") && offset == 0) {
beep();
str = "";
}
if (!isValidForAcceptedCharsPolicy(str))
return;
if (validateLength(offset, str) == false)
return;
if (!isValidForMaxVal(offset, str))
return;
super.insertString(offset, str, attr);
}
public boolean isValidForAcceptedCharsPolicy(String str) {
if (str.equals("")) {
beep();
return false;
}
for (int i = 0; i < str.length(); i++) {
if (NUMERIC.indexOf(String.valueOf(str.charAt(i))) == -1) {
beep();
return false;
}
}
return true;
}
public boolean isValidForMaxVal(int offset, String toAdd) {
String str_temp;
//String str_text = "";
String str1 = "";
String str2 = "";
try {
str1 = getText(0, offset);
str2 = getText(offset, getLength() - offset);
} catch (Exception e) {
e.printStackTrace();
}
int i_value;
str_temp = str1 + toAdd + str2;
//str_temp = str_temp.trim();
i_value = Integer.parseInt(str_temp);
if (i_value > maxVal) {
beep();
return false;
} else
return true;
}
private boolean validateLength(int offset, String toAdd) {
String str_temp;
//String str_text = "";
String str1 = "";
String str2 = "";
try {
str1 = getText(0, offset);
str2 = getText(offset, getLength() - offset);
} catch (Exception e) {
e.printStackTrace();
}
str_temp = str1 + toAdd + str2;
if (maxLength < str_temp.length()) {
beep();
return false;
} else
return true;
}
private void beep() {
//java.awt.Toolkit.getDefaultToolkit().beep();
}
}
And this is last one with main method that implements all above posted code and you get pretty good view. In my case I used list of 4 text fields separated by dot. You can jump from one "window" to another by using arrows or tab or dot or if your number length reached 4. It will work with implementation of FocusAdapter class:
package com.demo.textfield.version;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.FocusManager;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
/**
* diplays an version text field
*/
![enter image description here][1]public class VersionTextField extends GridbagPanel {
private static final long serialVersionUID = 1L;
/**
* a text field for each byte
*/
private JTextField[] textFields;
/**
* dots between text fields
*/
private JLabel[] dotsLabels;
/**
* used to calculate enable/disable color; never shown
*/
private static JTextField sampleTextField = new JTextField();
/**
* listen to changes in the byte fields
*/
private MyDocumentListener documentListener;
/**
* list of key listeners
*/
private List<KeyListener> keyListenersList;
/**
* List of Focus Adapter that select all data in JTextFiled during action
* */
private List<FocusAdapter> focusAdapterList;
/**
* list of key listeners
*/
private List<FocusListener> focusListenersList;
private int maxHeight = 0;
public VersionTextField() {
this(4);
}
/**
* #param byteCount
* number of bytes to display
*/
private VersionTextField(int byteCount) {
textFields = new JTextField[byteCount];
for (int i = 0; i < textFields.length; i++) {
textFields[i] = new JTextField(4);
}
//layout
//constraints.insets = new Insets(0, 0, 0, 0);
List<JLabel> dotsLabelsList = new ArrayList<JLabel>();
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setHorizontalAlignment(JTextField.CENTER);
Document document = DocumentsFactory.createIntDocument(9999);
textField.setDocument(document);
if (i < textFields.length-1) {
add(textField, i * 2, 0, 1, 1);
if (textField.getPreferredSize().height > maxHeight)
maxHeight = textField.getPreferredSize().height;
JLabel label = new JLabel(".");
add(label, (i * 2) + 1, 0, 1, 1);
if (label.getPreferredSize().height > maxHeight)
maxHeight = label.getPreferredSize().height;
dotsLabelsList.add(label);
} else
add(textField, i * 2, 0, 1, 1);
}
//dotsLabels = new JLabel[dotsLabelsList.size()];
dotsLabels = new JLabel[dotsLabelsList.size()];
dotsLabels = dotsLabelsList.toArray(dotsLabels);
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setBorder(BorderFactory.createEmptyBorder());
}
//init
Color backgroundColor = UIManager.getColor("TextField.background");
setBackground(backgroundColor);
Border border = UIManager.getBorder("TextField.border");
setBorder(border);
//register listeners
for (int i = 1; i < textFields.length; i++) {
JTextField field = textFields[i];
field.addKeyListener(new BackKeyAdapter());
}
documentListener = new MyDocumentListener();
for (int i = 0; i < textFields.length - 1; i++) {
JTextField field = textFields[i];
field.getDocument().addDocumentListener(documentListener);
field.addKeyListener(new ForwardKeyAdapter());
}
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.addKeyListener(new MyKeyListener());
}
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.addFocusListener(new MyFocusAdapter());
}
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.addFocusListener(new MyFocusAdapter());
}
keyListenersList = new ArrayList<KeyListener>();
focusListenersList = new ArrayList<FocusListener>();
focusAdapterList = new ArrayList<FocusAdapter>();
}
public synchronized void addKeyListener(KeyListener l) {
super.addKeyListener(l);
keyListenersList.add(l);
}
public synchronized void addFocusListener(FocusListener l) {
super.addFocusListener(l);
if (focusListenersList != null)
focusListenersList.add(l);
}
public synchronized void removeKeyListener(KeyListener l) {
super.removeKeyListener(l);
if (focusListenersList != null)
keyListenersList.remove(l);
}
public synchronized void removeFocusListener(FocusListener l) {
super.removeFocusListener(l);
keyListenersList.remove(l);
}
public void setEnabled(boolean b) {
super.setEnabled(b);
sampleTextField.setEnabled(b);
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setEnabled(b);
}
for (int i = 0; i < dotsLabels.length; i++) {
JLabel dotsLabel = dotsLabels[i];
dotsLabel.setEnabled(b);
}
setBackground(sampleTextField.getBackground());
setForeground(sampleTextField.getForeground());
setBorder(sampleTextField.getBorder());
}
public void requestFocus() {
super.requestFocus();
textFields[0].requestFocus();
}
public void setEditable(boolean b) {
sampleTextField.setEditable(b);
setBackground(sampleTextField.getBackground());
setForeground(sampleTextField.getForeground());
setBorder(sampleTextField.getBorder());
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setEditable(b);
}
for (int i = 0; i < dotsLabels.length; i++) {
JLabel dotsLabel = dotsLabels[i];
dotsLabel.setForeground(sampleTextField.getForeground());
}
}
public boolean isFieldEmpty() {
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
String sCell = textField.getText().trim();
if (!(sCell.equals("")))
return false;
}
return true;
}
public Dimension getPreferredSize() {
if (super.getPreferredSize().height > maxHeight)
maxHeight = super.getPreferredSize().height;
return new Dimension(super.getPreferredSize().width, maxHeight);
}
/**
* clears current text in text fiekd
*/
private void reset() {
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.getDocument().removeDocumentListener(documentListener);
textField.setText("");
textField.getDocument().addDocumentListener(documentListener);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("test");
VersionTextField ipTextField = new VersionTextField();
ipTextField.setText("9.1.23.1479");
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(ipTextField);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void setText(String version) {
if (version == null || "".equals(version) || "null".equals(version))
reset();
else {
setVer(version.split("[.]"));
}
}
private void setVer(String[] ver) {
if (ver == null) {
reset();
return;
}
Enumeration<String> enumeration = Collections.enumeration(Arrays.asList(ver));
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
String s = (String) enumeration.nextElement();
textField.getDocument().removeDocumentListener(documentListener);
textField.setText(s);
textField.getDocument().addDocumentListener(documentListener);
}
}
public void setToolTipText(String toolTipText) {
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
textField.setToolTipText(toolTipText);
}
}
private class MyDocumentListener implements DocumentListener {
#Override
public void insertUpdate(DocumentEvent e) {
Document document = e.getDocument();
try {
JTextField textField = (JTextField) FocusManager.getCurrentManager().getFocusOwner();
String s = document.getText(0, document.getLength());
if (s.length() == 4){ // && textField.getCaretPosition() == 2) {
textField.transferFocus();
}
} catch (BadLocationException e1) {
e1.printStackTrace();
return;
}
}
public void removeUpdate(DocumentEvent e) {
}
#Override
public void changedUpdate(DocumentEvent e) {
// Document document = e.getDocument();
// try {
// Component component = FocusManager.getCurrentManager().getFocusOwner();
// String s = document.getText(0, document.getLength());
//
// // get selected integer
// int valueInt = Integer.parseInt(s);
//
// if (valueInt > 25) {
// component.transferFocus();
// }
//
// } catch (BadLocationException e1) {
// e1.printStackTrace();
// return;
// }
}
}
private class BackKeyAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
JTextField textField = (JTextField) e.getComponent();
if (textField.getCaretPosition() == 0
&& KeyEvent.VK_LEFT == e.getKeyCode()
&& e.getModifiers() == 0)
textField.transferFocusBackward();
if (textField.getCaretPosition() == 0
&& KeyEvent.VK_BACK_SPACE == e.getKeyCode()
&& e.getModifiers() == 0) {
textField.transferFocusBackward();
}
}
}
private class ForwardKeyAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
JTextField textField = (JTextField) e.getComponent();
if (KeyEvent.VK_RIGHT == e.getKeyCode() && e.getModifiers() == 0) {
int length = textField.getText().length();
int caretPosition = textField.getCaretPosition();
if (caretPosition == length) {
textField.transferFocus();
e.consume();
}
}
if (e.getKeyChar() == '.' &&
textField.getText().trim().length() != 0) {
textField.setText(textField.getText().trim());
textField.transferFocus();
e.consume();
}
}
}
/**
* #return current text in ip text field
*/
public String getText() {
StringBuffer buffer = new StringBuffer();
String ipResult;
for (int i = 0; i < textFields.length; i++) {
JTextField textField = textFields[i];
if(textField.getText().trim().equals("")){
return "";
}
buffer.append(Integer.parseInt(textField.getText()));
if (i < textFields.length - 1){
buffer.append('.');
}
}
ipResult = buffer.toString();
return ipResult;
}
/**
* general purpose key listener
*/
private class MyKeyListener implements KeyListener {
public void keyPressed(KeyEvent e) {
for (int i = 0; i < keyListenersList.size(); i++) {
KeyListener keyListener = keyListenersList.get(i);
keyListener.keyPressed(new KeyEvent(VersionTextField.this,
e.getID(), e.getWhen(), e.getModifiers(), e
.getKeyCode(), e.getKeyChar(), e
.getKeyLocation()));
}
}
public void keyReleased(KeyEvent e) {
for (int i = 0; i < keyListenersList.size(); i++) {
KeyListener keyListener = keyListenersList.get(i);
keyListener.keyReleased(new KeyEvent(VersionTextField.this, e
.getID(), e.getWhen(), e.getModifiers(),
e.getKeyCode(), e.getKeyChar(), e.getKeyLocation()));
}
}
public void keyTyped(KeyEvent e) {
for (int i = 0; i < keyListenersList.size(); i++) {
KeyListener keyListener = keyListenersList.get(i);
keyListener.keyTyped(new KeyEvent(VersionTextField.this, e.getID(),
e.getWhen(), e.getModifiers(), e.getKeyCode(), e
.getKeyChar(), e.getKeyLocation()));
}
}
}
private class MyFocusAdapter extends FocusAdapter {
public void focusGained(FocusEvent e) {
for (int i = 0; i < focusListenersList.size(); i++) {
FocusListener focusListener = focusListenersList.get(i);
focusListener.focusGained(new FocusEvent(
VersionTextField.this,
e.getID(),
e.isTemporary(),
e.getOppositeComponent()
));
}
if(e.getComponent() instanceof javax.swing.JTextField){
highlightText((JTextField)e.getSource());
}
}
public void focusLost(FocusEvent e) {
for (int i = 0; i < focusListenersList.size(); i++) {
FocusListener focusListener = focusListenersList.get(i);
focusListener.focusLost(new FocusEvent(
VersionTextField.this,
e.getID(),
e.isTemporary(),
e.getOppositeComponent()
));
}
}
public void highlightText(javax.swing.JTextField ctr){
//ctr.setSelectionColor(Color.BLUE);
//ctr.setSelectedTextColor(Color.WHITE);
ctr.setSelectionStart(0);
ctr.setSelectionEnd(ctr.getText().length());
System.out.println(ctr.getText());
}
}
}
here a view what we got:
here you go
JFormattedTextField