I'm banging my head against the wall and have a feeling that I'm going about this completely incorrectly. I'm creating a simple hangman game and cannot, for the life of me, get the result of my paintComponent() method to display with the buttons I've created using a JFrame.
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class hangman extends JPanel implements ActionListener {
public static final int youLose=6;
public int wrongGuess;
public String message;
public String theWord;
public StringBuffer guessWord;
public JButton restartButton;
public JButton playButton;
public JTextArea userInput;
public static void main(String[] args) {
hangman h = new hangman();
h.initialize();
}
public void initialize() {
userInput = new JTextArea();
restartButton = new JButton("Restart");
playButton = new JButton("Play");
JFrame frame = new JFrame("Hangman");
frame.setVisible(true);
frame.setLayout(new GridLayout(1,4));
frame.setBounds(0, 0, 500, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(restartButton);
frame.add(playButton);
frame.add(new JLabel("Enter guess: "));
frame.add(userInput);
restartButton.addActionListener(this);
playButton.addActionListener(this);
startGame();
}
public void paintComponent(Graphics g) {
//(left, top, right, bottom)
g.drawLine(90, 250,200,250);
g.drawLine(125,250,125,150);
g.drawLine(125,150,175,150);
g.drawLine(175,150,175,175);
if (wrongGuess > 0){ //head
g.drawOval(170,175,10,12);
}
if (wrongGuess > 1){ //body
g.drawLine(175,187,175,205);
}
if (wrongGuess > 2){ //left arm
g.drawLine(163,185,173,190);
}
if (wrongGuess > 3){ //right arm
g.drawLine(177,190,187,185);
}
if (wrongGuess > 4){ //left leg
g.drawLine(168,220,173,205);
}
if (wrongGuess > 5){ //right leg
g.drawLine(177,205,182,220);
}
g.drawString( message, 40, 290 );
g.drawString( new String (guessWord), 40, 275);
}
public void actionPerformed(ActionEvent event){
if (event.getSource() == restartButton){
restart();
startGame();
}
if (event.getSource() == playButton){
analyzeGuess();
userInput.setText("");
repaint();
}
setVisible(true);
}
public void restart() {
Graphics g = getGraphics();
Dimension d = getSize();
Color c = getBackground();
g.setColor(c);
g.fillRect(0,0,d.width,d.height);
repaint();
}
public void startGame() {
wrongGuess = 0;
String[] wordArray = {"computer", "science", "java", "application", "programming", "university",
"homework", "assignment", "cactus", "flower", "button", "keyboard", "graphic", "interface",
"collegiate", "graduate", "headphones", "building", "radiator", "flora", "fauna", "suitcase",
"sweater", "television", "library", "elevator", "precidence", "ancient", "basketball", "bracket",
"alphabetical", "christmas", "hannukah"};
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(wordArray.length);
theWord = new String(wordArray[randomInt]);
char positions[] = new char[theWord.length()];
for (int i=0; i<theWord.length(); i++) {
positions[i] = '_';
}
String s = new String(positions);
guessWord = new StringBuffer(s);
userInput.setText("");
message="";
repaint();
}
private void analyzeGuess() {
String userGuess, temp;
char letter;
userGuess = userInput.getText();
letter = userGuess.charAt(0);
if (!Character.isLetter(letter)){
message="Invalid character";
return;
}
if (userGuess.length()>1){
message="Only enter one letter";
return;
}
temp = new String(guessWord);
if (temp.indexOf(userGuess) != -1){
message="Letter has already been guessed";
return;
}
if (theWord.indexOf(userGuess) == -1){
message="";
message = new String(message);
wrongGuess++;
message = "You have "+ (youLose-wrongGuess) + " guesses left.";
if (wrongGuess==youLose){
message="You lose! The word was '"+theWord+"'"+"\nClick restart to try again.";
}
return;
}
for (int i=0; i<theWord.length(); i++){
if (theWord.charAt(i) == letter){
guessWord.setCharAt(i, letter);
}
}
temp = new String(guessWord);
if (temp.indexOf('_') == -1){
message="You win!";
return;
}
message="";
repaint();
}
}
As I see it, the major problem you have is here...
public void restart() {
// May return null and is only a snapshot of what's current within the components
// graphics buffer...
Graphics g = getGraphics();
Dimension d = getSize();
Color c = getBackground();
g.setColor(c);
g.fillRect(0,0,d.width,d.height);
// Every thing you just did will not be discard as when paintComponent
// is called...
repaint();
}
You should also be called super.paintComponent as the first statement within your paintComponent method
All painting should be done in your paintComponent method.
Check out Painting in AWT and Swing for more details about the paint engine.
Working Example
Basically, your controls are hiding your custom painting.
One of the most important aspects of OO is separation of responsibility. That is, each class should do one job (and do it well).
In your case, your HangMan class was trying to manage the UI controls, custom painting and basic game rules...
The example blow separates the game rules/state into a model which is shared by the main view and the panel responsible for painting the state of the game....
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestHangMan01 {
public static void main(String[] args) {
new TestHangMan01();
}
public TestHangMan01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new Hangman());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HangManModel {
public int youLose;
public int wrongGuess;
public String message;
public String theWord;
public StringBuffer guessWord;
private Set<ChangeListener> listeners;
public HangManModel() {
listeners = new HashSet<>(25);
}
public void setTheWord(String theWord) {
this.theWord = theWord;
guessWord = new StringBuffer(theWord.length());
while (guessWord.length() < theWord.length()) {
guessWord.append("_");
}
youLose = theWord.length();
wrongGuess = 0;
message = "";
fireStateChanged();
}
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener);
}
protected void fireStateChanged() {
if (listeners.size() > 0) {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : listeners) {
listener.stateChanged(evt);
}
}
}
public int getWrongGuess() {
return wrongGuess;
}
public String getMessage() {
return message;
}
public String getGuessWord() {
return guessWord.toString();
}
public void setMessage(String value) {
if (message == null ? value != null : !message.equals(value)) {
this.message = value;
fireStateChanged();
}
}
public void guess(char letter) {
if (!Character.isLetter(letter)) {
setMessage("Invalid character");
} else {
String temp = new String(guessWord);
if (temp.indexOf(letter) != -1) {
message = "Letter has already been guessed";
} else {
if (theWord.indexOf(letter) == -1) {
wrongGuess++;
if (wrongGuess == youLose) {
setMessage("You lose! The word was '" + theWord + "'" + "\nClick restart to try again.");
} else {
setMessage("You have " + (youLose - wrongGuess) + " guesses left.");
}
} else {
for (int i = 0; i < theWord.length(); i++) {
if (theWord.charAt(i) == letter) {
guessWord.setCharAt(i, letter);
}
}
temp = new String(guessWord);
if (temp.indexOf('_') == -1) {
setMessage("You win!");
} else {
setMessage("");
}
}
}
}
}
}
public class HangManPane extends JPanel implements ChangeListener {
private HangManModel model;
public HangManModel getModel() {
return model;
}
public void setModel(HangManModel value) {
if (model != value) {
if (model != null) {
model.removeChangeListener(this);
}
this.model = value;
if (model != null) {
model.addChangeListener(this);
}
repaint();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
HangManModel model = getModel();
//(left, top, right, bottom)
g.drawLine(90, 250, 200, 250);
g.drawLine(125, 250, 125, 150);
g.drawLine(125, 150, 175, 150);
g.drawLine(175, 150, 175, 175);
if (model.getWrongGuess() > 0) { //head
g.drawOval(170, 175, 10, 12);
}
if (model.getWrongGuess() > 1) { //body
g.drawLine(175, 187, 175, 205);
}
if (model.getWrongGuess() > 2) { //left arm
g.drawLine(163, 185, 173, 190);
}
if (model.getWrongGuess() > 3) { //right arm
g.drawLine(177, 190, 187, 185);
}
if (model.getWrongGuess() > 4) { //left leg
g.drawLine(168, 220, 173, 205);
}
if (model.getWrongGuess() > 5) { //right leg
g.drawLine(177, 205, 182, 220);
}
g.drawString(model.getMessage(), 40, 290);
g.drawString(model.getGuessWord(), 40, 275);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
public void stateChanged(ChangeEvent e) {
repaint();
}
}
public class Hangman extends JPanel implements ActionListener {
public JButton restartButton;
public JButton playButton;
public JTextField userInput;
private HangManModel model;
public Hangman() {
setModel(new HangManModel());
setLayout(new BorderLayout());
userInput = new JTextField();
restartButton = new JButton("Restart");
playButton = new JButton("Play");
JPanel controls = new JPanel(new GridLayout(1, 4));
controls.add(restartButton);
controls.add(playButton);
controls.add(new JLabel("Enter guess: "));
controls.add(userInput);
add(controls, BorderLayout.NORTH);
userInput.addActionListener(this);
restartButton.addActionListener(this);
playButton.addActionListener(this);
HangManPane hangManPane = new HangManPane();
hangManPane.setModel(getModel());
add(hangManPane);
startGame();
}
public void setModel(HangManModel model) {
this.model = model;
}
public HangManModel getModel() {
return model;
}
public void actionPerformed(ActionEvent event) {
if (event.getSource() == restartButton) {
restart();
startGame();
}
if (event.getSource() == playButton || event.getSource() == userInput) {
analyzeGuess();
userInput.setText("");
repaint();
}
setVisible(true);
}
public void restart() {
startGame();
}
public void startGame() {
String[] wordArray = {"computer", "science", "java", "application", "programming", "university",
"homework", "assignment", "cactus", "flower", "button", "keyboard", "graphic", "interface",
"collegiate", "graduate", "headphones", "building", "radiator", "flora", "fauna", "suitcase",
"sweater", "television", "library", "elevator", "precidence", "ancient", "basketball", "bracket",
"alphabetical", "christmas", "hannukah"};
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(wordArray.length);
String theWord = new String(wordArray[randomInt]);
getModel().setTheWord(theWord);
userInput.setText("");
}
private void analyzeGuess() {
String userGuess = userInput.getText();
if (userGuess.trim().length() > 0) {
getModel().guess(userGuess.charAt(0));
}
}
}
}
Related
I have a class called SuggestionField It will show the user a list of items to autocomplete his input. he let of inputs is displayed in a JDialog(suggestionFrame). I need to set the JDialogs position to be below its parent, but I can not get the parents (JTextField) X and Y relative to the screen.
Example of the issue
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Arrays;
public class Runner {
public static void main(String[] args) {
JFrame frame = new JFrame();
String[] items = new String[]{"Tiger", "Wolf", "Car", "Cat", "Space", "Sing", "Scene"};
SuggestionField suggestionField = new SuggestionField(new ArrayList<>(Arrays.asList(items)), frame);
frame.setDefaultCloseOperation(3);
frame.setSize(100, 65);
frame.setLocationRelativeTo(null);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,1));
panel.add(suggestionField);
frame.add(panel);
frame.setVisible(true);
}
public static class SuggestionField extends JTextField implements DocumentListener, KeyListener {
String[] values = new String[0];
ArrayList<String> displayValues = new ArrayList<>(0);
JDialog suggestionFrame;
JPanel suggestionPanel = new JPanel();
Color backGround = new Color(109, 104, 104, 133);
Color selectBackGround = new Color(109, 104, 104, 133);
Color textColor = new Color(5, 19, 88, 255);
Color selectTextColor = new Color(115, 134, 238, 255);
BoxLayout bl = new BoxLayout(suggestionPanel, BoxLayout.Y_AXIS);
int selectedEntry = 0;
public SuggestionField(ArrayList<String> values, JFrame parentDisplay) {
this.getDocument().addDocumentListener(this);
this.addKeyListener(this);
suggestionFrame = new JDialog(parentDisplay);
suggestionFrame.add(suggestionPanel);
suggestionFrame.setUndecorated(true);
suggestionFrame.setAlwaysOnTop(true);
suggestionFrame.setFocusable(false);
suggestionPanel.setFocusable(false);
bl.maximumLayoutSize(suggestionPanel);
this.values = values.toArray(this.values).clone();
}
public boolean updateSuggestions() {
boolean added = false;
boolean add;
displayValues.clear();
for (int i = 0;i < values.length;i++) {
add = true;
for (int k = 0;k < this.getText().length() && k < values[i].length();k++) {
if (values[i].toUpperCase().charAt(k) != this.getText().toUpperCase().charAt(k)) {
add = false;
break;
}
}
if (add && !values[i].equalsIgnoreCase(this.getText()) && values[i].length() > this.getText().length()) {
added = true;
displayValues.add(values[i]);
}
}
return added;
}
private void updateDisplay() {
suggestionFrame.setSize(this.getWidth(), 16 * displayValues.size());
suggestionPanel.removeAll();
suggestionPanel.setLayout(new BoxLayout(suggestionPanel, BoxLayout.Y_AXIS));
for (int i = 0;i < displayValues.size();i++) {
JLabel a = new JLabel(displayValues.get(i));
if (i == selectedEntry) {
a.setBackground(selectBackGround);
a.setForeground(selectTextColor);
} else {
a.setBackground(backGround);
a.setForeground(textColor);
}
suggestionPanel.add(a);
}
suggestionPanel.revalidate();
suggestionFrame.revalidate();
suggestionFrame.setLocation(this.getX(), this.getY() + this.getHeight());
suggestionFrame.setVisible(true);
}
#Override
public void insertUpdate(DocumentEvent e) {
if (updateSuggestions()) {
updateDisplay();
} else suggestionFrame.setVisible(false);
selectedEntry = 0;
this.requestFocus();
}
#Override
public void removeUpdate(DocumentEvent e) {
if (updateSuggestions()) {
updateDisplay();
} else suggestionFrame.setVisible(false);
selectedEntry = 0;
this.requestFocus();
}
#Override
public void changedUpdate(DocumentEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
int ID = e.getKeyCode();
switch (ID) {
case 40:
if (selectedEntry < displayValues.size() - 1) selectedEntry++;
updateDisplay();
break;
case 38:
if (selectedEntry > 0) selectedEntry--;
updateDisplay();
break;
case 10:
this.setText(displayValues.get(selectedEntry));
break;
case 27:
suggestionFrame.setVisible(false);
break;
}
this.requestFocus();
this.grabFocus();
}
#Override
public void keyReleased(KeyEvent e) {
}
}
}
Is there any way that inside the updateDisplay() (line 97) method I could get the absolute position of the JTextField for suggestionFrame
You can use SwingUtilities.convertPointToScreen to do this.
Just pass (x, y+height) and your input field to get the starting point to display your dropdown.
JButton component = new JButton();
Point pt = new Point(component.getLocation());
pt.y += component.getHeight();
SwingUtilities.convertPointToScreen(pt, component);
// pt is now in screen coords... so you can use it to position the pop-up
The full documentation can be found here: https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html
I need to set the JDialogs position to be below its parent..
Use Window.setLocationRelativeTo(Component).
This will just place the JDialog ontop of the JTextFiled
Actually, it's more subtle than that. It will take into account if the dialog would otherwise be off the screen, for example, and move it back on. That is something that would need to be explicitly handled, if basing the position on the 'location on screen'.
The following code is working in jdk 1.8 update 45 and in java 1.8 update 31 but NOT in java 1.8 update 45.
The program is a button moving back and forth until the user presses the button and makes it stop and the text is changed to "MOVE". When the button is pressed again, the button starts moving and the text is changed to "STOP".
In java 8 update 45, the button does not start moving but the text changes. Why?
package mainpackage;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class mainPanel implements ActionListener {
JFrame frame1;
JPanel panel1;
JButton button = new JButton("STOP");
boolean buttonPressed = false;
boolean move = true;
// 0 = left & 1 = right
int direction = 1;
int x = 0;
public static void main(String[] args) {
new mainPanel().loadGUI();
}
public void loadGUI() {
frame1 = new JFrame("Moving button");
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setVisible(true);
frame1.setSize(300, 58);
frame1.setResizable(false);
panel1 = new JPanel(); // Xwidth=294, Yheight=272
panel1.setSize(300, 30);
panel1.setLayout(null);
frame1.add(panel1);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
frame1.setLocation(dim.width/2-frame1.getSize().width/2, dim.height/2-frame1.getSize().height/2);
button.setSize(80, 30); //X, Y
panel1.add(button);
button.addActionListener(this);
while(true) moveButton();
}
public void moveButton() {
while(move == true) {
switch(direction) {
// left
case 0: {
while(x > 0) {
if(move == false) break;
button.setLocation(x, 0);
x--;
panel1.repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(mainPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
if(buttonPressed == true) {
direction = 0;
buttonPressed = false;
} else if(buttonPressed == false) {
direction = 1;
buttonPressed = false;
}
}
// right
case 1: {
while(x < panel1.getWidth() - button.getWidth()) {
if(move == false) break;
button.setLocation(x, 0);
x++;
panel1.repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(mainPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
if(buttonPressed == true) {
direction = 1;
buttonPressed=false;
} else if(buttonPressed == false) {
direction=0;
buttonPressed=false;
}
}
}
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (move == true){
move=false;
} else if (move == false) {
move=true;
}
buttonPressed = true;
if((button.getText()).equals("STOP")) {
button.setText("MOVE");
} else button.setText("STOP");
}
}
Yours is broken code to begin with since it ignores Swing threading rules, and frankly I'm surprised that it worked in previous versions of Java. You're calling a while (true) loop that will tie up any thread that it is called in. Java 8 is correctly trying to start your Swing GUI on the Swing event thread, something that all Swing programs should do. If you get rid of the while (true) loops that risk being called on the Swing event dispatch thread, and instead use a Swing Timer your code should work. The Timer will run a loop in a background thread, but all code called repeatedly in its ActionListener will be called on the Swing event thread.
For example:
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MyMainPanel extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = 30;
private static final int TIMER_DELAY = 20;
public static final int DELTA_X = 3;
private JButton moveButton = new JButton(new MoveButtonAction("Move"));
private Timer moveTimer = new Timer(TIMER_DELAY, new MoveTimerListener());
private boolean moveRight = true;
public MyMainPanel() {
moveButton.setSize(moveButton.getPreferredSize());
int y = (getPreferredSize().height - moveButton.getPreferredSize().height) / 2;
moveButton.setLocation(0, y);
setLayout(null); // !! lord I hate this
add(moveButton);
moveTimer.start();
}
#Override
public Dimension getPreferredSize() {
Dimension superSz = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSz;
}
int prefW = Math.max(superSz.width, PREF_W);
int prefH = Math.max(superSz.height, PREF_H);
return new Dimension(prefW, prefH);
}
private class MoveButtonAction extends AbstractAction {
public MoveButtonAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
moveRight = !moveRight;
}
}
private class MoveTimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (moveRight) {
if (moveButton.getLocation().x + moveButton.getWidth() >= getWidth()) {
moveRight = false;
}
} else {
if (moveButton.getLocation().x <= 0) {
moveRight = true;
}
}
int x = moveButton.getLocation().x + (moveRight ? DELTA_X : -DELTA_X);
int y = moveButton.getLocation().y;
moveButton.setLocation(new Point(x, y));
repaint();
}
}
private static void createAndShowGui() {
MyMainPanel mainPanel = new MyMainPanel();
JFrame frame = new JFrame("GUI Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You will want to read up on Swing thread safety to see why your program is failing. See Lesson: Concurrency in Swing to see more on this.
Edit: code that stops and starts movement:
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyMainPanel extends JPanel {
private static final String MOVE = "Move";
private static final String STOP = "Stop";
private static final int PREF_W = 300;
private static final int PREF_H = 30;
private static final int TIMER_DELAY = 20;
public static final int DELTA_X = 3;
private MoveButtonAction moveButtonAction = new MoveButtonAction(STOP);
private JButton moveButton = new JButton(moveButtonAction);
private Timer moveTimer = new Timer(TIMER_DELAY, new MoveTimerListener());
private boolean moveRight = true;
public MyMainPanel() {
moveButton.setSize(moveButton.getPreferredSize());
int y = (getPreferredSize().height - moveButton.getPreferredSize().height) / 2;
moveButton.setLocation(0, y);
setLayout(null); // !! lord I hate this
add(moveButton);
moveTimer.start();
}
#Override
public Dimension getPreferredSize() {
Dimension superSz = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSz;
}
int prefW = Math.max(superSz.width, PREF_W);
int prefH = Math.max(superSz.height, PREF_H);
return new Dimension(prefW, prefH);
}
private class MoveButtonAction extends AbstractAction {
public MoveButtonAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
if (MOVE.equals(getValue(NAME))) {
moveTimer.start();
putValue(NAME, STOP);
int mnemonic = (int) STOP.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
} else {
moveTimer.stop();
putValue(NAME, MOVE);
int mnemonic = (int) MOVE.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
AbstractButton button = (AbstractButton) e.getSource();
button.setSize(button.getPreferredSize());
repaint();
}
}
private class MoveTimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (moveRight) {
if (moveButton.getLocation().x + moveButton.getWidth() >= getWidth()) {
moveRight = false;
}
} else {
if (moveButton.getLocation().x <= 0) {
moveRight = true;
}
}
int x = moveButton.getLocation().x + (moveRight ? DELTA_X : -DELTA_X);
int y = moveButton.getLocation().y;
moveButton.setLocation(new Point(x, y));
repaint();
}
}
private static void createAndShowGui() {
MyMainPanel mainPanel = new MyMainPanel();
JFrame frame = new JFrame("GUI Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Just added some methods and fixed some lines in your code, you can try it now:
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class mainPanel implements ActionListener {
JFrame frame1;
JPanel panel1;
JButton button = new JButton("START");
boolean buttonPressed = false;
boolean move = false;
Timer timer;
int direction = 1;
int x = 0;
public static void main(String[] args) {
new mainPanel().loadGUI();
}
public void loadGUI() {
frame1 = new JFrame("Moving button");
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setVisible(true);
frame1.setSize(300, 58);
frame1.setResizable(false);
panel1 = new JPanel(); // Xwidth=294, Yheight=272
panel1.setSize(300, 30);
panel1.setLayout(null);
frame1.add(panel1);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
frame1.setLocation(dim.width / 2 - frame1.getSize().width / 2, dim.height / 2 - frame1.getSize().height / 2);
button.setSize(80, 30); //X, Y
panel1.add(button);
button.addActionListener(this);
moveButton();
}
public void moveButton() {
if (timer == null) {
initTimer();
}
move = !move;
if (move) {
button.setText("STOP");
direction = (direction == 0) ? 1 : 0;
timer.start();
} else {
button.setText("MOVE");
timer.stop();
}
}
public void initTimer() {
timer = new Timer(10, (e) -> {
switch (direction) {
case 0: // right
x++;
if (x >= panel1.getWidth() - button.getWidth()) {
direction = 1;
}
break;
case 1: // left
x--;
if (x <= 0) {
direction = 0;
}
break;
}
button.setLocation(x, 0);
panel1.repaint();
});
}
#Override
public void actionPerformed(ActionEvent e) {
moveButton();
}
}
So far I have this:
The logic is that:
a.)I will press the keybutton 'S' then the game will start
b.)The JTextArea will show the conversation of the users(note: I didn't disable it for debugging purposes)
c.)The JTextField will be the field the user will type text.
I have these working code:
package game;
//import
public class Game extends JFrame {
public static final String SERVER_IP = "localhost";
public static final int WIDTH = 1200;
public static final int HEIGHT = 800;
public static final int SCALE = 1;
private final int FPS = 60;
private final long targetTime = 1000 / FPS;
private BufferedImage backBuffer;
public KeyboardInput input;
private Stage stage;
public String username = "";
public GameClient client;
public static Game game;
public static String message = "";
private Tank tank;
private javax.swing.JButton jButton1;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
private javax.swing.JTextField jTextField1;
public Game() throws HeadlessException {
setSize(1000, 1000);
addWindowListener(new WinListener());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
//setUndecorated(false);
addKeyListener(input);
setVisible(true);
}
public void init() {
this.game = this;
input = new KeyboardInput();
//this.setSize(WIDTH, HEIGHT);
//this.setLocationRelativeTo(null);
//this.setResizable(false);
Dimension expectedDimension = new Dimension(900, 50);
Dimension expectedDimension2 = new Dimension(100, 50);
jButton1 = new JButton("jButton1");
jTextArea1 = new JTextArea(6,6);
jTextArea1.setBounds(0,200,200,200);
jTextArea1.setBackground(Color.BLUE);
//jTextArea1.setFocusable(false);
jTextField1 = new JTextField("jTextField1");
JPanel panel2 = new JPanel();
panel2.setLayout(new FlowLayout());
panel2.add(jTextField1);
panel2.add(jButton1);
panel2.setBackground(Color.BLACK); // for debug only
panel2.setPreferredSize(expectedDimension);
panel2.setMaximumSize(expectedDimension);
panel2.setMinimumSize(expectedDimension);
jPanel1 = new JPanel();
jPanel1.setLayout(new BoxLayout(jPanel1, BoxLayout.Y_AXIS));
jPanel1.add(jTextArea1);
jPanel1.add(panel2);
jPanel1.setBackground(Color.RED); // for debug only
jPanel1.setPreferredSize(expectedDimension2);
jPanel1.setMaximumSize(expectedDimension2);
jPanel1.setMinimumSize(expectedDimension2);
jScrollPane1 = new JScrollPane(jPanel1,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
setContentPane(jScrollPane1);
System.out.println("init");
revalidate();
client = new GameClient(SERVER_IP, this);
backBuffer = new BufferedImage(800* SCALE,600 * SCALE, BufferedImage.TYPE_INT_RGB);
}
public Stage getStage() {
return stage;
}
public class WinListener extends WindowAdapter {
#Override
public void windowClosing(WindowEvent e) {
disconnect();
System.exit(0);
}
}
public void disconnect() {
Packet01Disconnect p = new Packet01Disconnect(username);
p.writeData(client);
client.closeSocket();
System.exit(0);
}
private Font font = new Font("Munro Small", Font.PLAIN, 96);
private Font font2 = new Font("Munro Small", Font.PLAIN, 50);
private Font fontError = new Font("Munro Small", Font.PLAIN, 25);
private int op = 0;
public void updateMenu() {
if (input.up.isPressed()) {
if (op == 1) {
op = 0;
} else {
op++;
}
input.up.toggle(false);
} else if (input.down.isPressed()) {
if (op == 0) {
op = 1;
} else {
op--;
}
input.down.toggle(false);
} else if (input.enter.isPressed() && op == 0) {
runningMenu = false;
input.enter.toggle(false);
} else if (input.enter.isPressed() && op == 1) {
System.exit(0);
}
}
public void drawMenu() {
Graphics g = getGraphics();
Graphics bbg = backBuffer.getGraphics();
bbg.setFont(font);
bbg.setColor(Color.white);
bbg.drawString("Sample", 189, 180);
bbg.setFont(font2);
if (op == 0) {
bbg.setColor(Color.red);
bbg.drawString("Start", 327, 378);
bbg.setColor(Color.white);
bbg.drawString("Quit", 342, 425);
} else if (op == 1) {
bbg.setColor(Color.white);
bbg.drawString("Start", 327, 378);
bbg.setColor(Color.red);
bbg.drawString("Quit", 342, 425);
}
g.drawImage(backBuffer, 0, 0, this);
}
public void draw() {
Graphics g = getGraphics();
Graphics bbg = backBuffer.getGraphics();
bbg.setColor(Color.black);
bbg.fillRect(0, 0, WIDTH, HEIGHT);
stage.drawStage(bbg, this);
for (Tank t : stage.getPlayers()) {
t.draw(bbg, SCALE, this);
}
g.drawImage(backBuffer, 0, 0, this);
}
public void update() {
tank.update(stage);
stage.update();
}
private long time = 0;
public void updateLogin() {
if (username.length() < 8) {
if (input.letter.isPressed()) {
username += (char) input.letter.getKeyCode();
input.letter.toggle(false);
}
}
if (input.erase.isPressed() && username.length() > 0) {
username = username.substring(0, username.length() - 1);
input.erase.toggle(false);
}
if (input.enter.isPressed() && username.length() > 0) {
input.enter.toggle(false);
time = System.currentTimeMillis();
Packet00Login packet = new Packet00Login(username, 0, 0, 0);
packet.writeData(client);
}
if (message.equalsIgnoreCase("connect server success")) {
time = 0;
runningLogin = false;
return;
}
if (message.equalsIgnoreCase("Username already exists")) {
drawLogin();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
message = "";
username = "";
time = 0;
}
if (message.equalsIgnoreCase("Server full")) {
drawLogin();
try {
Thread.sleep(2000);
} catch (Exception e) {
}
System.exit(0);
}
if (time != 0 && message.equals("") && (System.currentTimeMillis() - time) >= 5000) {
message = "cannot connect to the server";
drawLogin();
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
}
message = "";
time = 0;
}
}
public void drawLogin() {
Graphics g = getGraphics();
Graphics bbg = backBuffer.getGraphics();
bbg.setColor(Color.black);
bbg.fillRect(0, 0, 800, 600);
bbg.setColor(Color.red);
bbg.setFont(fontError);
bbg.drawString(message, 100, 100);
bbg.setFont(font2);
bbg.setColor(Color.white);
bbg.drawString("Username", 284, 254);
bbg.setColor(Color.red);
bbg.drawString(username, 284, 304);
g.drawImage(backBuffer, 0, 0, this);
}
public static String waitPlayers = "Waiting for others players";
public String auxWaitPlayers = waitPlayers;
public static int quantPlayers = 0;
public class StringWait extends Thread {
public void run() {
while (true) {
try {
waitPlayers = "waiting for others players";
Thread.sleep(1000);
waitPlayers = "waiting for others players.";
Thread.sleep(1000);
waitPlayers = "waiting for others players..";
Thread.sleep(1000);
waitPlayers = "waiting for others players...";
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
}
}
public void updateWaitPlayers() {
if (quantPlayers == 1) {
runningWaitPlayer = false;
}
}
public void drawWaitPlayers() {
Graphics g = getGraphics();
Graphics bbg = backBuffer.getGraphics();
bbg.setColor(Color.black);
bbg.fillRect(0, 0, 800, 600);
bbg.setColor(Color.white);
bbg.setFont(fontError);
bbg.drawString(waitPlayers, 100, 100);
g.drawImage(backBuffer, 0, 0, this);
}
public boolean runningMenu = true, runningLogin = true, runningWaitPlayer = true, runningGame = true;
public int op2 = 0;
public void start() {
long start;
long elapsed;
long wait;
init();
while (true) {
runningGame = true;
runningMenu = true;
runningWaitPlayer = true;
runningLogin = true;
switch (op2) {
//..
}
}
public void setGameState(boolean state) {
//...
}
public static void main(String[] args) throws InterruptedException {
Game g = new Game();
Thread.sleep(1000);
g.start();
}
}
And these is my objective interface:
I hope someone will help me with my problem.
Set the "main" containers layout manager to BorderLayout
On to this, add the GameInterface in the BorderLayout.CENTER position
Create another ("interaction") container and set it's layout manager to BorderLayout, add this to the "main" container's BorderLayout.SOUTH position
Wrap the JTextArea in a JScrollPane and add it to the BorderLayout.CENTER position of your "interaction" container
Create another container ("message"), this could use a GridBagLayout. On to this add the JTextField (with GridBagConstraints#weightx set to 0 and GridBagConstraints#weightx set to 1) and add the button to the next cell (GridBagConstraints#gridx set to 1 and GridBagConstraints#weightx set to 0)
For more details, see:
Laying Out Components Within a Container
How to Use Borders
How to Use GridBagLayout
Note:
Graphics g = getGraphics(); is NOT how custom painting should be done. Instead, override the paintComponent of a component like JPanel and perform your custom painting there!
For more details see
Painting in AWT and Swing
Performing Custom Painting
Example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JPanel master = new JPanel(new BorderLayout());
master.setBackground(Color.BLUE);
JPanel gameInterface = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
};
gameInterface.setBackground(Color.MAGENTA);
master.add(gameInterface);
JPanel interactions = new JPanel(new BorderLayout());
interactions.add(new JScrollPane(new JTextArea(5, 20)));
JTextField field = new JTextField(15);
JButton btn = new JButton("Button");
JPanel message = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
message.add(field, gbc);
gbc.gridx = 1;
gbc.weightx = 0;
message.add(btn, gbc);
interactions.add(message, BorderLayout.SOUTH);
master.add(interactions, BorderLayout.SOUTH);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(master);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Am trying to modify a java code that implements Analog Clock using BufferedImage. I want the face of the clock to be changed dynamically when a user clicks on a button that scrolls through an array preloaded with the locations of images. So far my attempts have failed. I have two classes; The first Class creates and displays the Analog, and the second class attempts to change the face of the Analog clock using a mutator (setAnalogClockFace()) and an accessor (getAnalogClockFace()). The following is the code for the first Class as found on here, with minor modifications:
package panels;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.*;
public class Clock extends JPanel{
/**
*
*/
private static final long serialVersionUID = 1L;
private int hours = 0;
private int minutes = 0;
private int seconds = 0;
private int millis = 0;
private static final int spacing = 10;
private static final float threePi = (float)(3.0 * Math.PI);
private static final float radPerSecMin = (float)(Math.PI/30.0);
private int size; //height and width of clockface
private int centerX;//X coord of middle of clock
private int centerY;//Y coord of middle of clock
private BufferedImage clockImage;
private BufferedImage imageToUse;
private javax.swing.Timer t;
public Clock(){
this.setPreferredSize(new Dimension(203,203));
this.setBackground(getBackground());
this.setForeground(Color.darkGray);
t = new javax.swing.Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent ae){
update();
}
});
}
public void update(){
this.repaint();
}
public void start(){
t.start();
}
public void stop(){
t.stop();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
size = ((w < h) ? w : h) - 2 * spacing;
centerX = size/2 + spacing;
centerY = size/2 + spacing;
setClockFace(new AnalogClockTimer().getAnalogClockFace());
clockImage = getClockFace();
if (clockImage == null | clockImage.getWidth() != w | clockImage.getHeight() != h){
clockImage = (BufferedImage)(this.createImage(w,h));
Graphics2D gc = clockImage.createGraphics();
gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawClockFace(gc);
}
Calendar now = Calendar.getInstance();
hours = now.get(Calendar.HOUR);
minutes = now.get(Calendar.MINUTE);
seconds = now.get(Calendar.SECOND);
millis = now.get(Calendar.MILLISECOND);
g2d.drawImage(clockImage, null, 0, 0);
drawClockHands(g);
}
private void drawClockHands(Graphics g){
int secondRadius = size/2;
int minuteRadius = secondRadius * 3/4;
int hourRadius = secondRadius/2;
float fseconds = seconds + (float)millis/1000;
float secondAngle = threePi - (radPerSecMin * fseconds);
drawRadius(g, centerX, centerY, secondAngle, 0, secondRadius);
float fminutes = (float)(minutes + fseconds/60.0);
float minuteAngle = threePi - (radPerSecMin * fminutes);
drawRadius(g, centerX, centerY, minuteAngle, 0 , minuteRadius);
float fhours = (float)(hours + fminutes/60.0);
float hourAngle = threePi - (5 * radPerSecMin * fhours);
drawRadius(g, centerX, centerY, hourAngle, 0 ,hourRadius);
}
private void drawClockFace(Graphics g){
//g.setColor(Color.lightGray);
g.fillOval(spacing, spacing, size, size);
//g.setColor(new Color(168,168,168));
g.drawOval(spacing, spacing, size, size);
for(int sec = 0; sec < 60; sec++){
int tickStart;
if(sec%5 == 0){
tickStart = size/2-10;
}else{
tickStart = size/2-5;
}
drawRadius(g, centerX, centerY, radPerSecMin * sec, tickStart, size/2);
}
}
private void drawRadius(Graphics g, int x, int y, double angle,
int minRadius, int maxRadius){
float sine = (float)Math.sin(angle);
float cosine = (float)Math.cos(angle);
int dxmin = (int)(minRadius * sine);
int dymin = (int)(minRadius * cosine);
int dxmax = (int)(maxRadius * sine);
int dymax = (int)(maxRadius * cosine);
g.drawLine(x+dxmin, y+dymin, x+dxmax,y+dymax);
}
public void setClockFace(BufferedImage img){
if(img != null){
imageToUse = img;
}else{
try{
imageToUse =
ImageIO.read(getClass().getClassLoader().getResource("http://imgur.com/T8x0I29"));
}catch(IOException io){
io.printStackTrace();
}
}
}
public BufferedImage getClockFace(){
return imageToUse;
}
}
The second Class that attempts to set the Clock face is:
package panels;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import panels.Clock;
public class AnalogClockTimer extends javax.swing.JPanel implements ActionListener,
MouseListener {
private Clock clock;
/**
*
*/
private static final long serialVersionUID = 1L;
private JButton prevBtn;
private JTextField clockFaceCount;
private JButton nextBtn;
private JPanel buttonedPanel,leftPanel,rightPanel;
private BufferedImage image;
String[] clockFace;
int arrayPointer = 1;
/**
* Auto-generated main method to display this
* JPanel inside a new JFrame.
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new AnalogClockTimer());
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public AnalogClockTimer() {
super();
initGUI();
}
private void initGUI() {
try {
BorderLayout thisLayout = new BorderLayout();
this.setLayout(thisLayout);
this.setPreferredSize(new java.awt.Dimension(283, 233));
this.setBackground(getBackground());
{
clock = new Clock();
add(clock,BorderLayout.CENTER);
clock.start();
clock.setSize(203, 203);
}
{
buttonedPanel = new JPanel();
FlowLayout buttonedPanelLayout = new FlowLayout();
buttonedPanel.setLayout(buttonedPanelLayout);
this.add(buttonedPanel, BorderLayout.SOUTH);
buttonedPanel.setPreferredSize(new java.awt.Dimension(283, 30));
{
prevBtn = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_rest.png")));
prevBtn.setPreferredSize(new java.awt.Dimension(20, 19));
prevBtn.setBackground(getBackground());
prevBtn.setBorderPainted(false);
prevBtn.setEnabled(false);
prevBtn.addMouseListener(this);
prevBtn.addActionListener(this);
buttonedPanel.add(prevBtn);
}
{
nextBtn = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_rest.png")));
nextBtn.setPreferredSize(new java.awt.Dimension(20, 19));
nextBtn.setBackground(getBackground());
nextBtn.setBorderPainted(false);
nextBtn.addMouseListener(this);
nextBtn.addActionListener(this);
}
{
clockFaceCount = new JTextField();
clockFaceCount.setPreferredSize(new java.awt.Dimension(50, 19));
clockFaceCount.setBackground(getBackground());
clockFaceCount.setBorder(null);
clockFaceCount.setHorizontalAlignment(SwingConstants.CENTER);
clockFaceCount.setEditable(false);
buttonedPanel.add(clockFaceCount);
buttonedPanel.add(nextBtn);
}
{
clockFace = new String[]{"http://imgur.com/079QSdJ","http://imgur.com/vQ7tZjI",
"http://imgur.com/T8x0I29"};
for(int i = 1; i <= clockFace.length; i++){
if(i == 1){
nextBtn.setEnabled(true);
prevBtn.setEnabled(false);
}
clockFaceCount.setText(arrayPointer+" of "+clockFace.length);
}
}
{
leftPanel = new JPanel();
leftPanel.setPreferredSize(new Dimension(40, getHeight()));
add(leftPanel,BorderLayout.WEST);
}
{
rightPanel = new JPanel();
rightPanel.setPreferredSize(new Dimension(40,getHeight()));
add(rightPanel,BorderLayout.EAST);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void mouseClicked(MouseEvent me) {
if(me.getSource() == prevBtn)
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_pressed.png")));
else
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_pressed.png")));
}
#Override
public void mouseEntered(MouseEvent me) {
if(me.getSource()==prevBtn)
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_hover.png")));
else
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_hover.png")));
}
#Override
public void mouseExited(MouseEvent me) {
if(me.getSource() == prevBtn)
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_rest.png")));
else
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_rest.png")));
}
#Override
public void mousePressed(MouseEvent me) {
if(me.getSource() == prevBtn){
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_pressed.png")));
}else{
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_pressed.png")));
}
}
#Override
public void mouseReleased(MouseEvent me) {
if(me.getSource() == prevBtn)
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_hover.png")));
else
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_hover.png")));
}
#Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource() == nextBtn){
{
if(arrayPointer < clockFace.length){
++arrayPointer;
prevBtn.setEnabled(true);
if(arrayPointer == clockFace.length)
nextBtn.setEnabled(false);
}
clockFaceCount.setText(arrayPointer + " of " + clockFace.length);
setAnalogClockFace(arrayPointer);
}
}else if(ae.getSource() == prevBtn){
{
if(arrayPointer > 1){
--arrayPointer;
nextBtn.setEnabled(true);
if(arrayPointer == 1){
clockFaceCount.setText(arrayPointer+" of "+clockFace.length);
prevBtn.setEnabled(false);
}
}
clockFaceCount.setText(arrayPointer + " of "+clockFace.length);
setAnalogClockFace(arrayPointer);
}
}
}
private void setAnalogClockFace(int pointerPosition) {
try{
image = ImageIO.read(getClass().getClassLoader().getResource(clockFace[pointerPosition]));
}catch(IOException io){
io.printStackTrace();
}
}
public BufferedImage getAnalogClockFace(){
return image;
}
}
I've been working on this for days, can someone please help me understand what am not doing right? Any help would be greatly appreciated.
Here is an MCVE using a JLabel to achieve the same result:
package panels;
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JTextField;
import java.awt.event.*;
import java.awt.BorderLayout;
#SuppressWarnings({"serial"})
public class ClockPanel extends javax.swing.JPanel implements ActionListener {
private JLabel clockImageLabel;
private JPanel buttonsPanel;
private JButton next,prev;
private JTextField displayCount;
String[] imageFaces;
int pointer = 1;
/**
* Auto-generated main method to display this
* JPanel inside a new JFrame.
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new ClockPanel());
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public ClockPanel() {
super();
initGUI();
}
private void initGUI() {
try {
setPreferredSize(new Dimension(203, 237));
BorderLayout panelLayout = new BorderLayout();
setLayout(panelLayout);
{
clockImageLabel = new JLabel();
clockImageLabel.setPreferredSize(new Dimension(203,203));
clockImageLabel.setHorizontalAlignment(SwingConstants.CENTER);
clockImageLabel.setVerticalAlignment(SwingConstants.CENTER);
add(clockImageLabel,BorderLayout.NORTH);
}
{
buttonsPanel = new JPanel();
{
next = new JButton(">");
next.addActionListener(this);
}
{
prev = new JButton("<");
prev.addActionListener(this);
displayCount = new JTextField();
displayCount.setBorder(null);
displayCount.setEditable(false);
displayCount.setBackground(getBackground());
displayCount.setHorizontalAlignment(SwingConstants.CENTER);
buttonsPanel.add(prev);
buttonsPanel.add(displayCount);
displayCount.setPreferredSize(new java.awt.Dimension(45, 23));
buttonsPanel.add(next);
add(buttonsPanel,BorderLayout.SOUTH);
}
{
imageFaces = new String[]{"http://imgur.com/T8x0I29",
"http://imgur.com/079QSdJ","http://imgur.com/vQ7tZjI"
};
for(int i = 1; i < imageFaces.length; i++){
if(i == 1){
next.setEnabled(true);
prev.setEnabled(false);
}
displayCount.setText(pointer+" of "+imageFaces.length);
setLabelImage(pointer);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void setLabelImage(int pointerPosition){
clockImageLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource(imageFaces[pointerPosition])));
this.repaint();
}
#Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource() == next){
if(pointer < imageFaces.length){
++pointer;
prev.setEnabled(true);
if(pointer == imageFaces.length)next.setEnabled(false);
displayCount.setText(pointer+" of "+imageFaces.length);
setLabelImage(pointer);
}
}else if(ae.getSource() == prev){
if(pointer > 1){
--pointer;
next.setEnabled(true);
if(pointer == 1)prev.setEnabled(false);
displayCount.setText(pointer+" of "+imageFaces.length);
setLabelImage(pointer);
}
}
}
}
Here are 1/2 Images for the code:
HandlessAnalogClock 1
HandlessAnalogClock 2
HandlessAnalogClock 3
This MCVE will successfully flip between two of the three images, but still has problems with ArrayIndexOutOfBoundsException.
That last part is 'Batteries Not Included' (left as an exercise for the user to correct).
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.net.URL;
#SuppressWarnings({"serial"})
public class ClockPanel extends JPanel implements ActionListener {
private JLabel clockImageLabel;
private JPanel buttonsPanel;
private JButton next, prev;
private JTextField displayCount;
BufferedImage[] images;
int pointer = 1;
/**
* Auto-generated main method to display this JPanel inside a new JFrame.
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new ClockPanel());
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.pack();
frame.setVisible(true);
}
public ClockPanel() {
super();
initGUI();
}
private void initGUI() {
try {
setPreferredSize(new Dimension(203, 237));
BorderLayout panelLayout = new BorderLayout();
setLayout(panelLayout);
clockImageLabel = new JLabel();
clockImageLabel.setPreferredSize(new Dimension(203, 203));
clockImageLabel.setHorizontalAlignment(SwingConstants.CENTER);
clockImageLabel.setVerticalAlignment(SwingConstants.CENTER);
add(clockImageLabel, BorderLayout.NORTH);
buttonsPanel = new JPanel();
next = new JButton(">");
next.addActionListener(this);
prev = new JButton("<");
prev.addActionListener(this);
displayCount = new JTextField();
displayCount.setBorder(null);
displayCount.setEditable(false);
displayCount.setBackground(getBackground());
displayCount.setHorizontalAlignment(SwingConstants.CENTER);
buttonsPanel.add(prev);
buttonsPanel.add(displayCount);
displayCount.setPreferredSize(new java.awt.Dimension(45, 23));
buttonsPanel.add(next);
add(buttonsPanel, BorderLayout.SOUTH);
String[] imageFaces = new String[]{
"http://i.imgur.com/T8x0I29.png",
"http://i.imgur.com/079QSdJ.png",
"http://i.imgur.com/vQ7tZjI.png"
};
images = new BufferedImage[imageFaces.length];
for (int ii=0; ii<imageFaces.length; ii++) {
System.out.println("loading image: " + ii);
images[ii] = ImageIO.read(new URL(imageFaces[ii]));
System.out.println("loaded image: " + images[ii]);
}
setLabelImage(0);
} catch (Exception e) {
e.printStackTrace();
}
}
private void setLabelImage(int pointerPosition) {
System.out.println("setLabelImage: " + pointerPosition);
clockImageLabel.setIcon(new ImageIcon(images[pointerPosition]));
this.repaint();
}
#Override
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == next) {
if (pointer < images.length) {
++pointer;
prev.setEnabled(true);
if (pointer == images.length) {
next.setEnabled(false);
}
displayCount.setText(pointer + " of " + images.length);
setLabelImage(pointer);
}
} else if (ae.getSource() == prev) {
if (pointer > 1) {
--pointer;
next.setEnabled(true);
if (pointer == 1) {
prev.setEnabled(false);
}
displayCount.setText(pointer + " of " + images.length);
setLabelImage(pointer);
}
}
}
}
Expanding on #Andrew's example, consider arranging for the index of the current image to wrap-around, as shown in the example cited here.
private int pointer = 0;
...
private void initGUI() {
...
setLabelImage(pointer);
...
}
private void setLabelImage(int pointerPosition) {
System.out.println("setLabelImage: " + pointerPosition);
clockImageLabel.setIcon(new ImageIcon(images[pointerPosition]));
displayCount.setText((pointerPosition + 1) + " of " + images.length);
this.repaint();
}
#Override
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == next) {
pointer++;
if (pointer >= images.length) {
pointer = 0;
}
} else if (ae.getSource() == prev) {
pointer--;
if (pointer < 0) {
pointer = images.length - 1;
}
}
setLabelImage(pointer);
}
As an exercise, try to factor out the repeated instantiation of ImageIcon in setLabelImage() by creating a List<ImageIcon> in initGUI().
I have a menu that has a variety of buttons on display, I'm able to make the buttons call their respective JPanels when clicked. The thing is I would like to make the Jpanel slide in when its called instead of instantaneously popping in. I tried using tween engine and as Java beginner, I find it really overwhelming, so I decided to use timed animation. I was able to make the Jpanel on top to slide to one side but for some reason the next panel doesn't want to display, im really tired, can someone help please! There code is below:
public class Listener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
new Timer(0, new ActionListener() {
public void actionPerformed(ActionEvent e) {
mainpane.setLocation(mainpane.getX() - 10, 0);
if (mainpane.getX() + mainpane.getWidth() == 0)
{
((Timer) e.getSource()).stop();
System.out.println("Timer stopped");
}
}
}).start();
}
}
Sliding panels can be tricky. Here is some starter code. Modify to fit
your needs. Add error checking and exception handling as necessary.
This example uses JButtons and a JTree as content but you can use just about any type of content.
Usage:
static public void main(final String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
final JFrame jFrame = new JFrame() {
{
final PanelSlider42<JFrame> slider = new PanelSlider42<JFrame>(this);
final JPanel jPanel = slider.getBasePanel();
slider.addComponent(new JButton("1"));
slider.addComponent(new JButton("22"));
slider.addComponent(new JButton("333"));
slider.addComponent(new JButton("4444"));
getContentPane().add(jPanel);
setSize(300, 300);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
}
};
}
});
}
The impl is lengthy ...
package com.java42.example.code;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
public class PanelSlider42<ParentType extends Container> {
private static final int RIGHT = 0x01;
private static final int LEFT = 0x02;
private static final int TOP = 0x03;
private static final int BOTTOM = 0x04;
private final JPanel basePanel = new JPanel();
private final ParentType parent;
private final Object lock = new Object();
private final ArrayList<Component> jPanels = new ArrayList<Component>();
private final boolean useSlideButton = true;
private boolean isSlideInProgress = false;
private final JPanel glassPane;
{
glassPane = new JPanel();
glassPane.setOpaque(false);
glassPane.addMouseListener(new MouseAdapter() {
});
glassPane.addMouseMotionListener(new MouseMotionAdapter() {
});
glassPane.addKeyListener(new KeyAdapter() {
});
}
public PanelSlider42(final ParentType parent) {
if (parent == null) {
throw new RuntimeException("ProgramCheck: Parent can not be null.");
}
if ((parent instanceof JFrame) || (parent instanceof JDialog) || (parent instanceof JWindow) || (parent instanceof JPanel)) {
}
else {
throw new RuntimeException("ProgramCheck: Parent type not supported. " + parent.getClass().getSimpleName());
}
this.parent = parent;
attach();
basePanel.setSize(parent.getSize());
basePanel.setLayout(new BorderLayout());
if (useSlideButton) {
final JPanel statusPanel = new JPanel();
basePanel.add(statusPanel, BorderLayout.SOUTH);
statusPanel.add(new JButton("Slide Left") {
private static final long serialVersionUID = 9204819004142223529L;
{
setMargin(new Insets(0, 0, 0, 0));
}
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slideLeft();
}
});
}
});
statusPanel.add(new JButton("Slide Right") {
{
setMargin(new Insets(0, 0, 0, 0));
}
private static final long serialVersionUID = 9204819004142223529L;
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slideRight();
}
});
}
});
statusPanel.add(new JButton("Slide Up") {
{
setMargin(new Insets(0, 0, 0, 0));
}
private static final long serialVersionUID = 9204819004142223529L;
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slideTop();
}
});
}
});
statusPanel.add(new JButton("Slide Down") {
{
setMargin(new Insets(0, 0, 0, 0));
}
private static final long serialVersionUID = 9204819004142223529L;
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slideBottom();
}
});
}
});
}
}
public JPanel getBasePanel() {
return basePanel;
}
private void attach() {
final ParentType w = this.parent;
if (w instanceof JFrame) {
final JFrame j = (JFrame) w;
if (j.getContentPane().getComponents().length > 0) {
throw new RuntimeException("ProgramCheck: Parent already contains content.");
}
j.getContentPane().add(basePanel);
}
if (w instanceof JDialog) {
final JDialog j = (JDialog) w;
if (j.getContentPane().getComponents().length > 0) {
throw new RuntimeException("ProgramCheck: Parent already contains content.");
}
j.getContentPane().add(basePanel);
}
if (w instanceof JWindow) {
final JWindow j = (JWindow) w;
if (j.getContentPane().getComponents().length > 0) {
throw new RuntimeException("ProgramCheck: Parent already contains content.");
}
j.getContentPane().add(basePanel);
}
if (w instanceof JPanel) {
final JPanel j = (JPanel) w;
if (j.getComponents().length > 0) {
throw new RuntimeException("ProgramCheck: Parent already contains content.");
}
j.add(basePanel);
}
}
public void addComponent(final Component component) {
if (jPanels.contains(component)) {
}
else {
jPanels.add(component);
if (jPanels.size() == 1) {
basePanel.add(component);
}
component.setSize(basePanel.getSize());
component.setLocation(0, 0);
}
}
public void removeComponent(final Component component) {
if (jPanels.contains(component)) {
jPanels.remove(component);
}
}
public void slideLeft() {
slide(LEFT);
}
public void slideRight() {
slide(RIGHT);
}
public void slideTop() {
slide(TOP);
}
public void slideBottom() {
slide(BOTTOM);
}
private void enableUserInput(final ParentType w) {
if (w instanceof JFrame) {
((JFrame) w).getGlassPane().setVisible(false);
}
if (w instanceof JDialog) {
((JDialog) w).getGlassPane().setVisible(false);
}
if (w instanceof JWindow) {
((JWindow) w).getGlassPane().setVisible(false);
}
}
private void disableUserInput(final ParentType w) {
if (w instanceof JFrame) {
((JFrame) w).setGlassPane(glassPane);
}
if (w instanceof JDialog) {
((JDialog) w).setGlassPane(glassPane);
}
if (w instanceof JWindow) {
((JWindow) w).setGlassPane(glassPane);
}
glassPane.setVisible(true);
}
private void enableTransparentOverylay() {
if (parent instanceof JFrame) {
((JFrame) parent).getContentPane().setBackground(jPanels.get(0).getBackground());
parent.remove(basePanel);
parent.validate();
}
if (parent instanceof JDialog) {
((JDialog) parent).getContentPane().setBackground(jPanels.get(0).getBackground());
parent.remove(basePanel);
parent.validate();
}
if (parent instanceof JWindow) {
((JWindow) parent).getContentPane().setBackground(jPanels.get(0).getBackground());
parent.remove(basePanel);
parent.validate();
}
}
private void slide(final int slideType) {
if (!isSlideInProgress) {
isSlideInProgress = true;
final Thread t0 = new Thread(new Runnable() {
#Override
public void run() {
parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
disableUserInput(parent);
slide(true, slideType);
enableUserInput(parent);
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
isSlideInProgress = false;
}
});
t0.setDaemon(true);
t0.start();
}
else {
Toolkit.getDefaultToolkit().beep();
}
}
private void slide(final boolean useLoop, final int slideType) {
if (jPanels.size() < 2) {
System.err.println("Not enough panels");
return;
}
synchronized (lock) {
Component componentOld = null;
Component componentNew = null;
if ((slideType == LEFT) || (slideType == TOP)) {
componentNew = jPanels.remove(jPanels.size() - 1);
componentOld = jPanels.get(0);
jPanels.add(0, componentNew);
}
if ((slideType == RIGHT) || (slideType == BOTTOM)) {
componentOld = jPanels.remove(0);
jPanels.add(componentOld);
componentNew = jPanels.get(0);
}
final int w = componentOld.getWidth();
final int h = componentOld.getHeight();
final Point p1 = componentOld.getLocation();
final Point p2 = new Point(0, 0);
if (slideType == LEFT) {
p2.x += w;
}
if (slideType == RIGHT) {
p2.x -= w;
}
if (slideType == TOP) {
p2.y += h;
}
if (slideType == BOTTOM) {
p2.y -= h;
}
componentNew.setLocation(p2);
int step = 0;
if ((slideType == LEFT) || (slideType == RIGHT)) {
step = (int) (((float) parent.getWidth() / (float) Toolkit.getDefaultToolkit().getScreenSize().width) * 40.f);
}
else {
step = (int) (((float) parent.getHeight() / (float) Toolkit.getDefaultToolkit().getScreenSize().height) * 20.f);
}
step = step < 5 ? 5 : step;
basePanel.add(componentNew);
basePanel.revalidate();
if (useLoop) {
final int max = (slideType == LEFT) || (slideType == RIGHT) ? w : h;
final long t0 = System.currentTimeMillis();
for (int i = 0; i != (max / step); i++) {
switch (slideType) {
case LEFT: {
p1.x -= step;
componentOld.setLocation(p1);
p2.x -= step;
componentNew.setLocation(p2);
break;
}
case RIGHT: {
p1.x += step;
componentOld.setLocation(p1);
p2.x += step;
componentNew.setLocation(p2);
break;
}
case TOP: {
p1.y -= step;
componentOld.setLocation(p1);
p2.y -= step;
componentNew.setLocation(p2);
break;
}
case BOTTOM: {
p1.y += step;
componentOld.setLocation(p1);
p2.y += step;
componentNew.setLocation(p2);
break;
}
default:
new RuntimeException("ProgramCheck").printStackTrace();
break;
}
try {
Thread.sleep(500 / (max / step));
} catch (final Exception e) {
e.printStackTrace();
}
}
final long t1 = System.currentTimeMillis();
}
componentOld.setLocation(-10000, -10000);
componentNew.setLocation(0, 0);
}
}
}
I have searched for that problem some time ago.I found this sample code somewhere - saved in my evernote for future reference. This is the shortest way to implement that when I googled that in the past
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SlidingPanel {
JPanel panel;
public void makeUI() {
panel = new JPanel();
panel.setBackground(Color.RED);
panel.setBounds(0, 0, 400, 400);
JButton button = new JButton("Click");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
((JButton) e.getSource()).setEnabled(false);
new Timer(1, new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.setLocation(panel.getX() - 1, 0);
if (panel.getX() + panel.getWidth() == 0) {
((Timer) e.getSource()).stop();
System.out.println("Timer stopped");
}
}
}).start();
}
});
panel.add(button);
JFrame frame = new JFrame("Sliding Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setLayout(null);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SlidingPanel().makeUI();
}
});
}
}