This is the method im trying to invoke.
public void update(int status) {
if (status == 1)
{
setBorder(new LineBorder(Color.YELLOW, BORDERSIZE+1));
}
else if (status == 2)
{
setBorder(new LineBorder(Color.CYAN, BORDERSIZE+1));
}
else if (status == 3)
{
setBorder(new LineBorder(Color.BLACK, BORDERSIZE));
}
revalidate();
}
This is the code trying to use it.
private void handleMouseClick(int x, int y, int button) {
try {
// This is called by the board squares when they are clicked
// Handle the logic of updates to the client/game here
if(button == 1){
if(x != -1 && y != -1){
update(1);
x = -1;
y = -1;
updateGrids();
}
else{
update(3);
}
}
else if(button == 3){
}
}
catch (IOException ex) {
System.err.println(ex);
}
The update method is inside a class called GridLayout, I've tried to just simply use GridLayout.update(aninteger); but it didn't work for me.
You need an instance of GridLayout object in order to call the update function.
Withouth knowning how GridLayout is related to your existing code I cannot advice further. However if GridLayout is a temporary object you could try:
GridLayout worker = new GridLayout(... whatever ...);
worker.update(aninteger);
Otherwise, you might need to get it from the framework involved, or something along these lines:
this.getGridLayout().update(aninteger);
Related
I am wondering what is an elegant and effective way of simplifying the following snippet of code. Since I have many more buttons and their mechanics all behave in the same way, the symmetry of the methods, and the alternation from color.green -> color.red suggests there may exist a way of simplifying this down to a function?
I have been scratching my head on this design problem for a while, the way I am coding it seems definitely wrong and cumbersome.
GameFrame Class
public class GameFrame extends JFrame{
// (...)
static void initializeComponents(GameFrame frame, GamePanel GamePanel) {
// (...)
ArrayList<JGradientButton> buttons = new ArrayList<JGradientButton>();
Collections.addAll(buttons, b1,b2,b3,b4,b5);
for(JGradientButton button : buttons) {
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(button == b1) {
GamePanel.b1Pressed();
} else if (button == b2) {
GamePanel.b2Pressed();
if(GamePanel.removeFlag) {
button.color = Color.green;
} else {
button.color = Color.red;
}
button.repaint();
} else if (button == b3) {
GamePanel.b3Pressed();
if(!GamePanel.collisionFlag) {
button.color = Color.green;
} else {
button.color = Color.red;
}
button.repaint();
} else if (button == b4) {
GamePanel.b4Pressed();
if(!GamePanel.electricFlag) {
button.color = Color.green;
} else {
button.color = Color.red;
}
button.repaint();
} else {
GamePanel.b5Pressed();
if(!GamePanel.gravityFlag) {
button.color = Color.green;
} else {
button.color = Color.red;
}
button.repaint();
}
}
});
}
// (...)
}
I am unsatisfied with the above method since I have many buttons and the code for them alternating takes up easily ~100 lines of code. The symmetry of alternation suggests to me that there might exist a better approach for this design.
I have tried writing a function that takes the buttons list but the fact that we are overriding with actionPerformed confuses me a lot, and I don't know if there actually exists a way of simplifying this.
Any number of ways you might do this, but one might be to take the common state information you need and apply it to a method, for example...
protected void update(JGradientButton button, boolean state, Color trueState, Color falseState) {
if (state) {
button.color = trueState;
} else {
button.color = falseState;
}
button.repaint();
}
And then you might call it using something like...
for (JGradientButton button : buttons) {
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (button == b1) {
GamePanel.b1Pressed();
} else if (button == b2) {
GamePanel.b2Pressed();
update(button, GamePanel.removeFlag, Color.green, Color.red);
} else if (button == b3) {
GamePanel.b3Pressed();
update(button, GamePanel.collisionFlag, Color.green, Color.red);
} else if (button == b4) {
GamePanel.b4Pressed();
update(button, GamePanel.electricFlag, Color.green, Color.red);
} else {
GamePanel.b5Pressed();
update(button, GamePanel.gravityFlag, Color.green, Color.red);
}
}
});
I might also consider looking at what bXPressed is doing and what it might be able to do instead and if the functionality can be handed off to them instead.
You could also make use of the Action API, but the problem is, which flag are you looking at? That would require some kind of delegation lookup to determine the state, so you kind of end up in the same place as you would with the above.
I have built a snake game where a JPanel that implements a card layout manager is placed onto the JFrame. Three other JPanels are added to the card layout.
public void init () {
JOptionPane.showMessageDialog (this, "Don't let the snake hit the borders or you lose!", "Introduction to the Snake Game", JOptionPane.INFORMATION_MESSAGE);
appleCounter.label.setBorder (new LineBorder (Color.yellow, 1));
mainPanel.setLayout (card);//CHANGING THE LAYOUT MANAGER FOR THE JPANEL TO CARDLAYOUT
Screens [0] = new Screen ();//CREATING AN INSTANCE OF A JPANEL
mainPanel.add (Screens [0], "one");//ADDING THE JPANEL TO THE CARD LAYOUT
add (mainPanel, BorderLayout.CENTER);//ADDING THE JPANEL TO THE JFRAME
add (appleCounter.label, BorderLayout.SOUTH);
pack ();
setLocationRelativeTo (null);
setVisible (true);
}
This is so that after the snake collides with the border of the frame, a JDialog appears asking if they'd like to try again. If the player clicks 'yes' the next JPanel from the card layout will appear.
if (xCoor < 0 || xCoor > 80 || yCoor < 0 || yCoor > 60) {//IF THE SNAKE COLLIDES WITH THE BORDER OF THE FRAME
number = 1;
collide = true;
createApples ();
stop ();//CALLING THE METHOD THAT I AM HAVING PROBLEMS WITH
}
However, I am having issues with the stop method because when the snake collides with the border & the player clicks "yes" the next JPanel from the card layout appears. But the JPanel doesn't listen for any key inputs from the player, as a result, the snake cannot change directions.
public void stop () {
running = false;
try {
int response = JOptionPane.showConfirmDialog (this, "Do you want to play again?", "Opps looks like you lost", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (response == JOptionPane.YES_OPTION) {
if (digit < 3) {
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
Frame.Screens [digit] = null;
digit++;
Frame.Screens [digit] = new Screen ();
if (digit == 1) {
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
Frame.Screens [digit] = null;
Frame.mainPanel.add (Frame.Screens [digit], "two");
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
} else if (digit == 2) {
Frame.mainPanel.add (Frame.Screens [digit], "three");
}
} else if (response == JOptionPane.NO_OPTION) {
System.exit (0);
} else if (response == JOptionPane.CLOSED_OPTION) {
System.exit (0);
}
thread.join ();
} catch (InterruptedException e) {
e.printStackTrace ();
}//CLOSE CATCH
}
The JPanel instances are created using the Screen class which extends from JPanel class, even though the two JPanels in the card layout setFocusable to true so it should throw keyEvents.
public Screen () {
setFocusable (true);//THE JPANEL COMPONENT WILL BE AN EVENT SOURCE, THROWING KEY EVENTS TO THE KEY INSTANCE
addKeyListener (new Key ());//REGISTER THE KEY INSTANCE TO LISTEN TO KEY EVENTS
setPreferredSize (new Dimension (WIDTH, HEIGHT));
r = new Random ();
apples = new ArrayList <Apple> ();
start ();
}
Here is the inner class which has the keyPressed () that is called when the player clicks a directional key:
public class Key implements KeyListener {
public void keyPressed (KeyEvent e) {
int key = e.getKeyCode ();
if (key == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if (key == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if (key == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if (key == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
public void keyReleased (KeyEvent e) {}
public void keyTyped (KeyEvent e) {}
I am a beginner at Java so I would appreciate it if when answering this question there is a minimal amount of technical language or that the answer is explained in a way a beginner can understand. To clarify only the first Screen instance created in the init () listens for key inputs, the other two Screen instances cannot.
I was trying to manipulate an amateur animation using Swing in Java. The goal was to start an animation if I hover over a certain button. That was easy. But the problem is, I want to manipulate the speed of the timer of the animation according to the coordinates of the button.
For example, the more right I go on the button the more speedy the animation gets (delay time decreases) and vice-versa. The code I wrote works if I move the arrow out of the button then enter again. Then the delay changes according to co-ordinates. But not if I move the arrow within the region of the button. I used mouseEntered here. That may cause cause the problem. But the mouseMove function seems not to work too.
Here's my code:
private void jButton1MouseEntered(java.awt.event.MouseEvent evt)
{
// TODO add your handling code here:
PointerInfo inf = MouseInfo.getPointerInfo();
Point a = inf.getLocation();
double x = a.getX();
final int n = (int) (x - 161);
//String str=""+x;
//Output.setText(str);
ActionListener taskPerformer = null;
taskPerformer = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent evt)
{
//...Perform a task...
//if(t>0)timer.setDelay(1000);
if (t > 0)
{
timer.setDelay(500 + 50 * n);
}
if (label1 == 0)
{
jTextField1.setText(" A");
}
else if (label1 == 1)
{
jTextField1.setText(" B");
}
else if (label1 == 2)
{
jTextField1.setText(" C");
}
else if (label1 == 3)
{
jTextField1.setText(" D");
}
else if (label1 == 4)
{
jTextField1.setText(" E");
}
else if (label1 == 5)
{
jTextField1.setText(" F");
}
else if (label1 == 6)
{
jTextField1.setText(" G");
}
if (label1 >= 7)
{
label1 = 0;
}
else
{
label1++;
}
t++;
//System.out.printf("Reading SMTP Info. %d\n",x);
//System.out.printf("Reading SMTP Info. %d\n",label1t);
//jLabel3.setText("fsd");
}
private Object getContentPane()
{
throw new UnsupportedOperationException("Not supported yet.");
}
};
timer = new Timer(500, taskPerformer);
timer.start();
//timer.setRepeats(false);
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
Logger.getLogger(Keyboard_Gui.class.getName()).log(Level.SEVERE, null, ex);
}
}
But the mouseMove function seems not to work too.
The mouseMoved event is generated by a MouseMotionListener (not a MouseListener) so you will also need to implement that listener to manipulate the Timer interval.
I'm new to Java so please forgive me asking for help, but after 4 hours of searching for a solution I'm really getting desperate.
I'm currently setting up a game and want to implement key controls. I tried to do this via KeyListener and KeyEventDispatcher but I just can't get it to work.
The KeyListener just won't react. I think that the method that is supposed to use it has the focus.
Here's the code:
public class Sins extends JFrame implements KeyEventDispatcher {
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED ) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
} else if (e.getID() == KeyEvent.KEY_TYPED) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
}
return false;
}
and here is the method where it is supposed to be working at:
public void run() {
setFocusable(true);
backgroundGraphics = (Graphics2D) background.getGraphics();
long fpsWait = (long) (1.0 / 30 * 1000);
requestFocusInWindow();
main: while (isRunning==true) {
long renderStart = System.nanoTime();
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(this);
x++;
requestFocusInWindow();
// Update Graphics
do {
Graphics2D bg = getBuffer();
if (isRunning == false) {
break main;
}
renderGame(backgroundGraphics); // this calls your draw method
if (scale != 1) {
bg.drawImage(background, 0, 0, width * scale, height
* scale, 0, 0, width, height, null);
} else {
bg.drawImage(background, 0, 0, null);
}
bg.dispose();
requestFocusInWindow();
this.requestFocus();
if(x ==5000){
isRunning=false;
}
} while (!updateScreen());
// Better do some FPS limiting here
long renderTime = (System.nanoTime() - renderStart) / 10000;
try {
Thread.sleep(Math.max(0, fpsWait - renderTime));
} catch (InterruptedException e) {
Thread.interrupted();
break;
}
renderTime = (System.nanoTime() - renderStart) / 10000;
}
this.dispose();
System.exit(0);
}
The program is currently closing itself after counting up to 5000. For test purposes I'm trying to close it via the up button but it just won't close that way.
I would really appreciate some help, as I said I'm new to Java.
The first problem you were facing with KeyListener is a well know and well documented (here on SO especially). KeyListener will only on respond if the component they are attached to is focusable and has keyboard focus. Think of a text field, when it doesn't have focus, it won't update.
Your second problem is using the KeyBoardFocusManager, which is simply overkill for this problem.
Instead, you should make use of the [Key Bindings] API, which is simpler the having to monitor the KeyBoardFocusManager and more robust then KeyListeners
I have made a custom BasicScrollBarUI.
I have replaced the incrButton / decrButton by JLabels.
Therefore i had to override the InstallListeners(), to add the Listener to the incr/decrLabel instead of the JButtons.
//TODO
protected void installListeners() {
trackListener = createTrackListener();
buttonListenerCustom = createArrowButtonListenerCustom();
modelListener = createModelListener();
propertyChangeListener = createPropertyChangeListener();
scrollbar.addMouseListener(trackListener);
scrollbar.addMouseMotionListener(trackListener);
scrollbar.getModel().addChangeListener(modelListener);
scrollbar.addPropertyChangeListener(propertyChangeListener);
// scrollbar.addFocusListener(getHandler());
if (incrLabel != null) {
incrLabel.addMouseListener(buttonListenerCustom);
System.out.println("OK gemacht");
}
if (decrLabel != null) {
decrLabel.addMouseListener(buttonListenerCustom);
}
scrollListener = createScrollListener();
scrollTimer = new Timer(scrollSpeedThrottle, scrollListener);
scrollTimer.setInitialDelay(300); // default InitialDelay?
}
Therefore i had to override the ArrowButtonListener, to react on the Labels.
protected class ArrowButtonListenerCustom extends MouseAdapter {
boolean handledEvent;
public void mousePressed(MouseEvent e) {
if (!scrollbar.isEnabled()) {
return;
}
// not an unmodified left mouse button
// if(e.getModifiers() != InputEvent.BUTTON1_MASK) {return; }
if (!SwingUtilities.isLeftMouseButton(e)) {
return;
}
int direction;
if (e.getSource() == incrLabel) {
direction = 1;
incrLabel.setIcon(new ImageIcon(increaseButtonPressedImage));
} else {
direction = -1;
decrLabel.setIcon(new ImageIcon(decreaseButtonPressedImage));
}
scrollByUnit(direction);
scrollTimer.stop();
scrollListener.setDirection(direction);
scrollListener.setScrollByBlock(false);
scrollTimer.start();
handledEvent = true;
if (!scrollbar.hasFocus() && scrollbar.isRequestFocusEnabled()) {
scrollbar.requestFocus();
}
}
public void mouseReleased(MouseEvent e) {
scrollTimer.stop();
handledEvent = false;
scrollbar.setValueIsAdjusting(false);
incrLabel.setIcon(new ImageIcon(increaseButtonImage));
decrLabel.setIcon(new ImageIcon(decreaseButtonImage));
}
}
Of course createArrowButtonListenerCustom() returns a new instance of ArrowButtonListenerCustom.
Now my Problem:
When I click on the incr/decrLabel, the List scrolls correctly, but the thumb of the ScrollBar doesn't move (or better: the Thumb isn't repainted. If I move the Mouse over the thumb, it gets repainted on the right place). I have the same problem, when I scroll with the MouseWheel.
I don't understand, why this doesn't work.
Thanks for your help!