I am trying to modify a JSlider so that the thumb (knob) appears upon clicking the track. I am adapting code found here to achieve this goal. Essentially, I hide the thumb by initially setting its size to 0,0. When the mouse clicks the track, the thumb changes its size so that it appears. The problem I have encountered is that the track does not appear either. However, it appears once the track is clicked. Is there away modify the thumb (or hide it somehow) without altering the track? Any suggestions would be appreciated.
public class SliderUI extends MetalSliderUI {
private boolean displayThumb = false;
private int x = 0;
private int y = 0;
public SliderUI(){
super();
}
#Override
protected Dimension getThumbSize() {
return new Dimension(x, y);
}
#Override
protected void scrollDueToClickInTrack(int direction) {
//keep displaying thumb once true
if(!displayThumb){
x = 15;
y = 20;
displayThumb = true;
}
int value = slider.getValue();
if (slider.getOrientation() == JSlider.HORIZONTAL) {
value = this.valueForXPosition(slider.getMousePosition().x);
} else if (slider.getOrientation() == JSlider.VERTICAL) {
value = this.valueForYPosition(slider.getMousePosition().y);
}
slider.setValue(value);
}
}
Update: I also tried a similar approach with paintThumb(), but to no avail. I received a null pointer exception error. Here is what I tried:
public class SliderUI extends MetalSliderUI {
private boolean displayThumb = false;
protected static Icon horizThumbIcon;
protected static Icon vertThumbIcon;
private static Icon SAFE_HORIZ_THUMB_ICON;
private static Icon SAFE_VERT_THUMB_ICON;
public SliderUI(){
super();
}
private static Icon getHorizThumbIcon() {
if (System.getSecurityManager() != null) {
return SAFE_HORIZ_THUMB_ICON;
} else {
return horizThumbIcon;
}
}
private static Icon getVertThumbIcon() {
if (System.getSecurityManager() != null) {
return SAFE_VERT_THUMB_ICON;
} else {
return vertThumbIcon;
}
}
#Override
public void paintThumb(Graphics g) {
//keep displaying thumb once true
if(!displayThumb){
displayThumb = true;
return;
}
Rectangle knobBounds = thumbRect;
g.translate( knobBounds.x, knobBounds.y );
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
getHorizThumbIcon().paintIcon( slider, g, 0, 0 );
}
else {
getVertThumbIcon().paintIcon( slider, g, 0, 0 );
}
g.translate( -knobBounds.x, -knobBounds.y );
}
#Override
protected void scrollDueToClickInTrack(int direction) {
int value = slider.getValue();
if (slider.getOrientation() == JSlider.HORIZONTAL) {
value = this.valueForXPosition(slider.getMousePosition().x);
} else if (slider.getOrientation() == JSlider.VERTICAL) {
value = this.valueForYPosition(slider.getMousePosition().y);
}
slider.setValue(value);
}
}
For future reference, here is a simple solution to my question:
public class SliderUI extends MetalSliderUI {
private boolean displayThumb = false;
public SliderUI(){
super();
}
#Override
public void paintThumb(Graphics g) {
if(displayThumb){
super.paintThumb(g);
}
}
#Override
protected void scrollDueToClickInTrack(int direction) {
//keep displaying thumb once true
if(!displayThumb){
displayThumb = true;
}
int value = slider.getValue();
if (slider.getOrientation() == JSlider.HORIZONTAL) {
value = this.valueForXPosition(slider.getMousePosition().x);
} else if (slider.getOrientation() == JSlider.VERTICAL) {
value = this.valueForYPosition(slider.getMousePosition().y);
}
slider.setValue(value);
}
}
Related
I'm working on a snake game, and I'm trying to make the snake move to the right. The issue here is the snake isn't actually moving, it just seems to copy itself to the right and also it's not going to the right automatically you have to keep pressing the key.
I am really not sure what the issue is, I made some code without any images. That should make the code run able for testing as it is.
public class Game{
static Graphics g;
public static void main(String[] args) {
JFrame b = new JFrame("Snake");
b.setBounds(300,60,905,700);
b.setBackground(Color.DARK_GRAY);
b.setResizable(false);
Snake snake = new Snake();
b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b.add(snake);
b.setVisible(true);
}
}
public class Snake extends JPanel implements KeyListener,ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private int[] snakeXlength = new int [750];
private int[] snakeYlength = new int [750];
private boolean right = true;
private boolean left = false;
private boolean up = false;
private boolean down = false;
private ImageIcon rightmouth;
private ImageIcon snakeimage;
private ImageIcon leftmouth;
private ImageIcon downmouth;
private ImageIcon upmouth;
private ImageIcon enemy;
private Timer timer;
private int snakeDelay = 100;
private int moves = 1;
private int lengtOfSnake = 3;
public Snake(){
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
timer = new Timer(snakeDelay, this);
timer.start();
}
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.drawRect (20, 24, 851, 612);
g.setColor(Color.BLACK);
g.fillRect (21, 25, 850, 610);
if (moves == 0) {
snakeXlength[2]= 63;
snakeXlength[1]= 83;
snakeXlength[0]= 100;
snakeYlength[2]= 100;
snakeYlength[1]= 100;
snakeYlength[0]= 98;
rightmouth = new ImageIcon("rightmouth.png");
rightmouth.paintIcon(this, g, snakeXlength[0], snakeYlength[0]);
}
for(int a = 0; a < lengtOfSnake; a++) {
if (a == 0 && right) {
if (a == 0 && right) {
g.setColor(Color.RED);
g.drawRect(5,10,snakeXlength[a],snakeYlength[a]);
g.fillRect (snakeXlength[a],snakeYlength[a],21,21);
g.drawRect(5,10,snakeXlength[a],snakeYlength[a]);
// rightmouth = new ImageIcon("rightmouth.png");
//rightmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
if (a == 0 && left) {
leftmouth = new ImageIcon("leftmouth.png");
leftmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
if (a == 0 && down) {
downmouth = new ImageIcon("downmouth.png");
downmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
if (a == 0 && up) {
upmouth = new ImageIcon("uptmouth.png");
upmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
if (a != 0) {
g.setColor(Color.GREEN);
g.fillOval(snakeXlength[a],snakeYlength[a],17,17);
//snakeimage = new ImageIcon("snakeimage.png");
//snakeimage.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
}
g.dispose();
}
public void keyPressed(KeyEvent e) {
timer.start();
if(right) {
for (int r = lengtOfSnake-1; r >= 0;r--) {
snakeYlength[r+1] = snakeYlength[r];
}
for(int r = lengtOfSnake;r >=0;r--) {
if(r==0) {
snakeXlength[r] = snakeXlength[r] +25;
}
else {
snakeXlength[r] = snakeXlength[r-1];
}
if(snakeXlength[r] > 850){
snakeXlength[r] = 25;
}
}
repaint();
}
if(left) {
}
if(up) {
}
if(down) {
}
}
#Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
moves++;
right = true;
if(left != true) {
right = true;
}
else
{
right = false;
left = true;
}
down = false;
up = false;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
moves++;
left = true;
if(right != true) {
left = true;
}
else
{
left = false;
right = true;
}
down = false;
up = false;
} if(e.getKeyCode() == KeyEvent.VK_UP) {
moves++;
up = true;
if(down != true) {
up = true;
}
else
{
up = false;
down = true;
}
left = false;
right = false;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
moves++;
down = true;
if(up != true) {
down = true;
}
else
{
up = true;
down = false;
}
left = false;
right = false;
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
it just seems to copy itself to the right
public void paint(Graphics g)
{
g.setColor(Color.WHITE);
Custom painting should be done by overriding paintComponent(...) and then you need to invoke super.paintComponent(...):
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.WHITE);
This will make sure the background of the panel is cleared before doing the custom painting.
it's not going to the right automatically you have to keep pressing the key.
Well, that is usually the way a game is designed. You only have motion when the key is pressed as this will keep generating events. Then if you don't want motion you just don't press any keys.
If you want animation then you use a Swing Timer. Each time the Timer fires you invoke a move(...) method. This method would need to look at your "direction" variable to determine whether to move the snake left, right, up or down.
Check out:
Motion Using the Keyboard for animation when a key is pressed and held and
get width and height of JPanel outside of the class for continuous animation
I am creating a program in Java, and would like to make my own button class as opposed to using a JButton. I've got all the aesthetics sorted out but I'm not sure how to get the mouse pressed event in Java.
This is my code:
// Button.java
package cella;
import java.awt.Color;
import java.awt.Point;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
public class Button extends MouseAdapter {
int x, y, w, h;
String ph, val;
boolean mouseDown;
Color LIGHTGRAY = new Color(200, 200, 200);
public Button(int xt, int yt, int wt, int ht, String pht, String valt) {
x = xt;
y = yt;
w = wt;
h = ht;
ph = pht;
val = valt;
mouseDown = false;
}
public void draw(Graphics g, Point mouse) {
if (contains(mouse)) {
g.setColor(Color.GRAY);
} else {
g.setColor(LIGHTGRAY);
}
g.fillRect(x, y, w, h);
g.setColor(Color.BLACK);
g.drawRect(x, y, w, h);
g.drawString(ph, x + 5, y + h - 5);
}
private boolean contains(Point pos) {
if (pos.x > x && pos.x < x + w && pos.y > y && pos.y < y + h) {
return true;
} else {
return false;
}
}
public boolean pressed(Point pos) {
if (contains(pos) && mouseDown) {
System.out.println("Pressed");
return true;
}
else return false;
}
}
The boolean mouseDown will be set to true when the mouse is pressed and then false when released however i can't find a way to catch these events, mouseListener gives errors about needing abstract classes when i try to implement it. Thanks for any help you can give me.
Full code
Try this.
JButton button = new JButton("Click!");
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.NOBUTTON) {
textArea.setText("No button clicked...");
} else if (e.getButton() == MouseEvent.BUTTON1) {
textArea.setText("Button 1 clicked...");
}
}
});
See available methods
Hope this help!
You can add a listener to your button that handles the event.
JButton button = new JButton("Click for Stuff");
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
switch(e.getButton())
{
case MouseEvent.NOBUTTON : // do stuff on button release
break;
case MouseEvent.BUTTON1 : // do stuff on click
break;
}
}
});
I know this question is a few years old, but I thought my input might be useful to someone down the road trying to accomplish the same task, considering I have some experience in custom UIs.
If you want a fully non-JComponent button, then you're going to need to also program your mouselistener and a UI Object Registry and a render/update function all operating on their required threads. I've done that, complete with NumberInputFields, Buttons, PasswordFields, TextFields, TextAreas, Graphics, and a variety of other UI objects. You don't want to unless you're going for a radically different look and feel than what is already supplied with very different functionality (for instance, my TextArea and TextField took in BitLines made up of TextBits rather than Strings, which allowed for each character to individually be formatted or colored or sized, complete with customized hover and click events). If such a different result is desired, you would do well to look into everything that goes into making a full UI within a Canvas object. If not, you have a couple other options.
Option 1: Extend the JButton class like has already been suggested. This is the easiest and likely the best option for you. It's fairly simple, and you can make that button be whatever you want it to be (within reason, of course).
Option 2: Create your own custom look and feel by extending the BasicLookAndFeel class. This is more complex and may take a bit of time and research, but in the end you can format all of your program to have a consistent L&F throughout, giving a satisfying and unique look to your software.
Here's an example of what it can take to make a button with basic functionality, completely separate from the JComponent class. Please note that this does NOT include the many background classes required to make this operate, such as the registry, the renderer, the animation and image loaders, the listeners, etc.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import dev.blue.neuron.storage.Animation;
public class Button extends UIObject {
private Animation whileDown;
private Animation whileUp;
private int tooltipTimer = 0;
private boolean showTooltip = false;
private boolean useTooltip = false;
protected boolean showingClicked = false;
protected boolean isSelected;
private boolean showID;
private int fontSize;
private Color color = Color.BLACK;
public Button(String id, boolean showID, boolean useTooltip, int fontSize, int x, int y, int width, int height,
int animationSpeed, Animation whileDown, Animation whileUp) {
this.id = id;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.whileDown = whileDown;
this.whileUp = whileUp;
this.bounds = new Rectangle(x, y, width, height);
this.showID = showID;
this.fontSize = fontSize;
this.useTooltip = useTooltip;
}
public void render(Graphics g) {
animate();
this.whileUp.render(g);
this.whileDown.render(g);
if (this.showID) {
g.setFont(new Font("Helvetica", 1, this.fontSize));
g.setColor(this.color);
g.drawString(this.id, this.x + this.width / 2 - g.getFontMetrics().stringWidth(this.id) / 2,
(int) ((this.y + this.height / 2) + g.getFontMetrics().getHeight() / 3.5D));
}
if (this.showTooltip && this.useTooltip) {
g.setFont(new Font("Helvetica", 0, 12));
g.setColor(Color.GRAY);
g.drawString(this.id, this.x, (int) (this.y + g.getFontMetrics().getHeight() * 1.5D));
}
}
public void setColor(Color color) {
this.color = color;
}
public void update() {
if (this.hovering) {
this.tooltipTimer++;
} else if (this.showingClicked) {
this.showingClicked = false;
}
if (this.tooltipTimer >= 50)
this.showTooltip = true;
runOnUpdate();
}
public void runOnUpdate() {
}
public void onMouseMove(Point p) {
if (this.bounds.contains(p)) {
if (!this.hovering) {
this.hovering = true;
runOnHover();
}
} else if (this.hovering) {
this.hovering = false;
this.showTooltip = false;
this.tooltipTimer = 0;
runOnStopHover();
}
}
private void animate() {
if (this.showingClicked) {
if (!this.whileDown.isRunning()) {
this.whileUp.end();
this.whileDown.run();
}
} else if (!this.whileUp.isRunning()) {
this.whileDown.end();
this.whileUp.run();
}
}
public boolean onClick(int button, Point p) {
if (this.bounds.contains(p)) {
runClick();
return true;
}
return false;
}
public void runOnMissedClick() {
}
public boolean onMouseDown(int button, Point p) {
if (this.bounds.contains(p)) {
(App.getInstance().getMouseManager()).clickedObject = this;
runMouseDown();
this.showingClicked = true;
return true;
}
return false;
}
public boolean onMouseUp(int button, Point p) {
if ((App.getInstance().getMouseManager()).clickedObject == this)
(App.getInstance().getMouseManager()).clickedObject = null;
if (!this.bounds.contains(p))
runOnMissedClick();
if (this.showingClicked) {
this.showingClicked = false;
if (this.bounds.contains(p)) {
runMouseUp();
onClick(button, p);
return true;
}
return false;
}
return false;
}
public void onType(KeyEvent e) {
}
public void onKeyPressed(KeyEvent e) {
}
public Animation getWhileUpAnim() {
return this.whileUp;
}
public Animation getWhileDownAnim() {
return this.whileDown;
}
public void setWhileUpAnim(Animation whileUp) {
this.whileUp = whileUp;
}
public void setWhileDownAnim(Animation whileDown) {
this.whileDown = whileDown;
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
}
I have a large program that I will post some classes of and hopefully you guys can find the problem. Basically, sometimes when I start it, it creates the game just fine, and others the background is up a few pixels to the north and west directions leaving very unsightly whitespace. I cannot seem to find the missing piece of code that decides whether not it does this. It honestly feel like some kind of rendering glitch on my machine. At any rate, I have put a background getX and getY method in for debugging and have noticed that whether the background is fully stretched to the screen(its a custom background so the pixel height and width match perfectly), or its up and to the left, the background still reads that it is displaying at (0,0). I will post all the methods from the main thread to the creating of the background in the menu. I will leave notes indicating the path it takes through this code that gets it to creating the background. Thank you for your help and I will check in regularly for edits and more information.
EDIT: added background.java
EDIT2: added pictures explaining problem
Menu.java *ignore the FileIO code, the main point is the creation of a new GamePanel()
public class Menu {
private static File file;
public static void main(String[] args) throws IOException {
file = new File("saves.txt");
if(file.exists()){
FileIO.run();
FileIO.profileChoose();
}
else{
FileIO.profileCreate();
FileIO.run();
}
JFrame window = new JFrame("Jolly Jackpot Land");
window.setContentPane(new GamePanel());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
}
}
Next is the GamePanel.java
public class GamePanel extends JPanel implements Runnable, KeyListener {
// ID
private static final long serialVersionUID = 1L;
// Dimensions
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int SCALE = 2;
// Thread
private Thread thread;
private boolean running;
private int FPS = 30;
private long targetTime = 1000 / FPS;
// Image
private BufferedImage image;
private Graphics2D g;
// Game State Manager
private GameStateManager gsm;
public GamePanel() {
super();
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
addKeyListener(this);
thread.start();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
private void init() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
running = true;
gsm = new GameStateManager();
}
#Override
public void run() {
init();
long start;
long elapsed;
long wait;
// Game Loop
while (running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - (elapsed / 1000000);
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void update() {
gsm.update();
}
private void draw() {
gsm.draw(g);
}
private void drawToScreen() {
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
g2.dispose();
}
#Override
public void keyPressed(KeyEvent k) {
gsm.keyPressed(k.getKeyCode());
}
#Override
public void keyReleased(KeyEvent k) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
This calls for the creation of a new GameStateManager object in its init() method and the class for that is here.
GameStateManager.java
public class GameStateManager {
private ArrayList<GameState> gameStates;
private int currentState;
public static final int MENUSTATE = 0;
public static final int SLOTGAMESTATE = 1;
public static final int DICEGAMESTATE = 2;
public static final int ROULETTEGAMESTATE = 3;
public static final int LEADERBOARDSTATE = 4;
public static final int SETTINGSSTATE = 5;
public static final int HELPSTATE = 6;
public GameStateManager() {
gameStates = new ArrayList<GameState>();
currentState = 0;
gameStates.add(new MenuState(this));
gameStates.add(new SlotGameState(this));
gameStates.add(new DiceGameState(this));
gameStates.add(new RouletteGameState(this));
gameStates.add(new LeaderboardState(this));
gameStates.add(new SettingsState(this));
gameStates.add(new HelpState(this));
}
public void setState(int state){
currentState = state;
gameStates.get(currentState).init();
currentState = 0;
}
public int getState() {
return currentState;
}
public void update() {
gameStates.get(currentState).init();
}
public void draw(java.awt.Graphics2D g){
gameStates.get(currentState).draw(g);
}
public void keyPressed(int k){
gameStates.get(currentState).keyPressed(k);
}
public void keyReleased(int k) {
gameStates.get(currentState).keyReleased(k);
}
}
GameState is an abstract class I have so its not worth posting, it only contains init(), draw(), etc. This next class is the last and final class and is called because GameStateMananger starts at MENUSTATE or 0, and when GSM is initialized it initializes its current state, thus taking us to the class MenuState
MenuState.java
public class MenuState extends GameState {
private Background bg;
public FontMetrics fontMetrics;
private int choice = 0;
private String[] options = { "Slot Machine", "Dice Toss", "Roulette Wheel", "Leaderboards", "Settings", "Help",
"Quit" };
private Color titleColor;
private Font titleFont;
private Font font;
public MenuState(GameStateManager gsm) {
this.gsm = gsm;
try {
bg = new Background("/Backgrounds/happybg.png");
titleColor = Color.WHITE;
titleFont = new Font("Georgia", Font.PLAIN, 28);
} catch (Exception e) {
e.printStackTrace();
}
font = new Font("Arial", Font.PLAIN, 12);
}
#Override
public void init() {
}
#Override
public void update() {
}
#Override
public void draw(Graphics2D g) {
Canvas c = new Canvas();
fontMetrics = c.getFontMetrics(font);
// Draw BG
bg.draw(g);
// Draw title
g.setColor(titleColor);
g.setFont(titleFont);
String title = "Jolly Jackpot Land!";
g.drawString(title, 36, 60);
g.setFont(font);
for (int i = 0; i < options.length; i++) {
if (i == choice)
g.setColor(Color.RED);
else
g.setColor(Color.WHITE);
g.drawString(options[i], 30, 120 + i * 15);
}
g.setColor(Color.WHITE);
g.setFont(new Font("Arial", Font.PLAIN, 10));
g.drawString("v1.1", 165, 235);
Object[] a = { ("Name: " + Player.getName()), ("Gil: " + Player.getGil()),
("Personal Best: " + Player.getPersonalBest()), ("Winnings: " + Player.getWinnings()),
("Wins: " + Player.getWins()), ("Losses: " + Player.getLosses()),
("Win/Loss Ratio: " + String.format("%.2f", Player.getRatio()) + "%") };
g.setFont(font);
if (Player.getName() != null) {
for (int x = 0; x < a.length; x++) {
g.drawString(a[x].toString(), GamePanel.WIDTH - fontMetrics.stringWidth(a[x].toString()) - 30,
120 + x * 15);
}
}
}
private void select() {
if (choice == 0) {
// Slots
gsm.setState(GameStateManager.SLOTGAMESTATE);
}
if (choice == 1) {
// Dice
gsm.setState(GameStateManager.DICEGAMESTATE);
}
if (choice == 2) {
// Roulette
gsm.setState(GameStateManager.ROULETTEGAMESTATE);
}
if (choice == 3) {
// Leaderboards
gsm.setState(GameStateManager.LEADERBOARDSTATE);
}
if (choice == 4) {
// Settings
gsm.setState(GameStateManager.SETTINGSSTATE);
}
if (choice == 5) {
// Help
gsm.setState(GameStateManager.HELPSTATE);
}
if (choice == 6) {
// Quit
System.exit(0);
}
}
#Override
public void keyPressed(int k) {
if (k == KeyEvent.VK_ENTER) {
select();
}
if (k == KeyEvent.VK_UP) {
choice--;
if (choice == -1) {
choice = options.length - 1;
}
}
if (k == KeyEvent.VK_DOWN) {
choice++;
if (choice == options.length) {
choice = 0;
}
}
}
#Override
public void keyReleased(int k) {
}
}
Background.java
public class Background {
private BufferedImage image;
private double x;
private double y;
public Background(String s) {
try {
image = ImageIO.read(getClass().getResourceAsStream(s));
} catch (Exception e) {
e.printStackTrace();
}
}
public void setPosition(double x, double y) {
this.setX(x);
this.setY(y);
}
public void draw(Graphics2D g) {
g.drawImage(image, 0, 0, null);
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
This is where it waits for input in the game loop basically. I know this is a lot of code, but a lot of it is skimming till a method call takes you to the next class. I just can't figure out why it only happens sometimes, if it was consistent I could debug it. Any help would be extremely appreciated.
These are both from clicking the .jar of the above program, exact same .jar, exact same source code, different result. I am bewildered.
In android, I can do like that where user can click outside of editview to hide the virtual keyboard.
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
View v = getCurrentFocus();
boolean ret = super.dispatchTouchEvent(event);
if (v instanceof EditText) {
View w = getCurrentFocus();
int scrcoords[] = new int[2];
w.getLocationOnScreen(scrcoords);
float x = event.getRawX() + w.getLeft() - scrcoords[0];
float y = event.getRawY() + w.getTop() - scrcoords[1];
if (event.getAction() == MotionEvent.ACTION_UP
&& (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w
.getBottom())) {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus()
.getWindowToken(), 0);
}
}
return ret;
}
What about in blackberry? I want to run for VirtualKeyboard.isSupported() only.
Update
public class Custom_EditField extends EditField {
private int width, row, color;
private MainScreen mainscreen;
Custom_EditField(long style, int width, int row, MainScreen mainscreen) {
super(style);
this.width = width;
this.row = row;
this.mainscreen = mainscreen;
}
public int getPreferredHeight() {
return Font.getDefault().getHeight() * row;
}
public int getPreferredWidth() {
return width;
}
protected void onFocus(int direction) {
if (VirtualKeyboard.isSupported())
mainscreen.getVirtualKeyboard().setVisibility(
VirtualKeyboard.SHOW_FORCE);
invalidate();
super.onFocus(direction);
}
protected void onUnfocus() {
if (VirtualKeyboard.isSupported())
mainscreen.getVirtualKeyboard().setVisibility(
VirtualKeyboard.HIDE_FORCE);
invalidate();
super.onUnfocus();
}
public boolean isFocusable() {
return true;
}
protected void layout(int maxWidth, int maxHeight) {
super.layout(maxWidth,
Math.min(maxHeight, Font.getDefault().getHeight() * row));
super.setExtent(maxWidth,
Math.min(maxHeight, Font.getDefault().getHeight() * row));
}
protected void paint(Graphics graphics) {
int rectHeight = getPreferredHeight();
int rectWidth = getPreferredWidth();
try {
color = Color.BLACK;
graphics.setColor(color);
graphics.drawRect(0, 0, rectWidth, rectHeight);
super.paint(graphics);
} finally {
graphics.setColor(color);
}
}
}
This editfield will hide the keypad if you click on another field but not anypoint.
I have this utility code for showing, or hiding the keyboard. This should be valid for OS 4.7 and above. Let me know if you need to support lower OS versions.
/** Hides the virtual keyboard, if there is one showing. */
public static void hideKeyboard() {
VirtualKeyboard kb = UiApplication.getUiApplication().getActiveScreen().getVirtualKeyboard();
if (kb != null) {
kb.setVisibility(VirtualKeyboard.HIDE);
}
}
/** #return TRUE if the virtual keyboard is hidden, or not supported */
public static boolean isKeyboardHidden() {
if (VirtualKeyboard.isSupported()) {
VirtualKeyboard kb = UiApplication.getUiApplication().getActiveScreen().getVirtualKeyboard();
if (kb != null) {
int visibility = kb.getVisibility();
return ((visibility == VirtualKeyboard.HIDE)
|| (visibility == VirtualKeyboard.HIDE_FORCE));
}
}
return true;
}
Note that I made these static functions. So, if you put them in a class named UiUtilities, then you would call them like:
if (!UiUtilities.isKeyboardHidden()) {
UiUtilities.hideKeyboard();
}
As far as where to trigger this code, here's what I recommend, instead of overriding onUnfocus(). I'm not sure this is the easiest, or most efficient way to solve the problem (so I welcome other answers!), but I think this will work.
I told you a couple answers ago that you normally should not override the touchEvent() method in your code. For things like normal buttons, I think that's true. This might be one example where you need to. You should have a Manager (or VerticalFielManager, or similar) that represents the screen that this EditField is on. In that manager, implement the touchEvent() method like this:
import net.rim.device.api.ui.TouchEvent;
protected boolean touchEvent(TouchEvent event) {
// We take action when the user completes a click (a.k.a. unclick)
int eventCode = event.getEvent();
if ((eventCode == TouchEvent.UNCLICK) || (eventCode == TouchEvent.DOWN)) {
// Get the touch location, within this Manager
int x = event.getX(1);
int y = event.getY(1);
if ((x >= 0) && (y >= 0) && (x < getWidth()) && (y < getHeight())) {
int field = getFieldAtLocation(x, y);
if (field >= 0) {
// Let event propagate to child field
return super.touchEvent(event);
} else {
if (eventCode == TouchEvent.UNCLICK) {
// A completed click anywhere else in this manager should dismiss the keyboard
UiUtilities.hideKeyboard();
} else {
// This is just a soft touch (TouchEvent.DOWN), without full click
setFocus();
}
// Consume the event
return true;
}
}
}
// Event wasn't for us, let superclass handle in default manner
return super.touchEvent(event);
}
Try that. You might need to change my logic, depending on whether you want to hide the keyboard for a full click, versus a simple touch down (if you're new to BlackBerry, it might not be clear what the difference between those are). But, I think this should get you close(r).
I've been working my way through Developing Games in Java by David Brackeen and have come across a problem. I am modifying the game and pulling it apart to better understand how it works. I have no idea however how to add a menu like the one that was demonstrated in chapter Chapter 3. Any guidance is appreciated.
I have been looking in the ScreenManager and the GameManager for an idea on how to do this. I know how the game gets the screen size, I just need a push on how to get a menu to display.
Here is the code:
ScreenManager.java
package com.brackeen.javagamebook.graphics;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
The ScreenManager class manages initializing and displaying
full screen graphics modes.
*/
public class ScreenManager {
private GraphicsDevice device;
/**
Creates a new ScreenManager object.
*/
public ScreenManager() {
GraphicsEnvironment environment =
GraphicsEnvironment.getLocalGraphicsEnvironment();
device = environment.getDefaultScreenDevice();
}
/**
Returns a list of compatible display modes for the
default device on the system.
*/
public DisplayMode[] getCompatibleDisplayModes() {
return device.getDisplayModes();
}
/**
Returns the first compatible mode in a list of modes.
Returns null if no modes are compatible.
*/
public DisplayMode findFirstCompatibleMode(
DisplayMode modes[])
{
DisplayMode goodModes[] = device.getDisplayModes();
for (int i = 0; i < modes.length; i++) {
for (int j = 0; j < goodModes.length; j++) {
if (displayModesMatch(modes[i], goodModes[j])) {
return modes[i];
}
}
}
return null;
}
/**
Returns the current display mode.
*/
public DisplayMode getCurrentDisplayMode() {
return device.getDisplayMode();
}
/**
Determines if two display modes "match". Two display
modes match if they have the same resolution, bit depth,
and refresh rate. The bit depth is ignored if one of the
modes has a bit depth of DisplayMode.BIT_DEPTH_MULTI.
Likewise, the refresh rate is ignored if one of the
modes has a refresh rate of
DisplayMode.REFRESH_RATE_UNKNOWN.
*/
public boolean displayModesMatch(DisplayMode mode1,
DisplayMode mode2)
{
if (mode1.getWidth() != mode2.getWidth() ||
mode1.getHeight() != mode2.getHeight())
{
return false;
}
if (mode1.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI &&
mode2.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI &&
mode1.getBitDepth() != mode2.getBitDepth())
{
return false;
}
if (mode1.getRefreshRate() !=
DisplayMode.REFRESH_RATE_UNKNOWN &&
mode2.getRefreshRate() !=
DisplayMode.REFRESH_RATE_UNKNOWN &&
mode1.getRefreshRate() != mode2.getRefreshRate())
{
return false;
}
return true;
}
/**
Enters full screen mode and changes the display mode.
If the specified display mode is null or not compatible
with this device, or if the display mode cannot be
changed on this system, the current display mode is used.
<p>
The display uses a BufferStrategy with 2 buffers.
*/
public void setFullScreen(DisplayMode displayMode) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.setIgnoreRepaint(true);
frame.setResizable(false);
device.setFullScreenWindow(frame);
if (displayMode != null &&
device.isDisplayChangeSupported())
{
try {
device.setDisplayMode(displayMode);
}
catch (IllegalArgumentException ex) { }
// fix for mac os x
frame.setSize(displayMode.getWidth(),
displayMode.getHeight());
}
// avoid potential deadlock in 1.4.1_02
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
frame.createBufferStrategy(2);
}
});
}
catch (InterruptedException ex) {
// ignore
}
catch (InvocationTargetException ex) {
// ignore
}
}
/**
Gets the graphics context for the display. The
ScreenManager uses double buffering, so applications must
call update() to show any graphics drawn.
<p>
The application must dispose of the graphics object.
*/
public Graphics2D getGraphics() {
Window window = device.getFullScreenWindow();
if (window != null) {
BufferStrategy strategy = window.getBufferStrategy();
return (Graphics2D)strategy.getDrawGraphics();
}
else {
return null;
}
}
/**
Updates the display.
*/
public void update() {
Window window = device.getFullScreenWindow();
if (window != null) {
BufferStrategy strategy = window.getBufferStrategy();
if (!strategy.contentsLost()) {
strategy.show();
}
}
// Sync the display on some systems.
// (on Linux, this fixes event queue problems)
Toolkit.getDefaultToolkit().sync();
}
/**
Returns the window currently used in full screen mode.
Returns null if the device is not in full screen mode.
*/
public JFrame getFullScreenWindow() {
return (JFrame)device.getFullScreenWindow();
}
/**
Returns the width of the window currently used in full
screen mode. Returns 0 if the device is not in full
screen mode.
*/
public int getWidth() {
Window window = device.getFullScreenWindow();
if (window != null) {
return window.getWidth();
}
else {
return 0;
}
}
/**
Returns the height of the window currently used in full
screen mode. Returns 0 if the device is not in full
screen mode.
*/
public int getHeight() {
Window window = device.getFullScreenWindow();
if (window != null) {
return window.getHeight();
}
else {
return 0;
}
}
/**
Restores the screen's display mode.
*/
public void restoreScreen() {
Window window = device.getFullScreenWindow();
if (window != null) {
window.dispose();
}
device.setFullScreenWindow(null);
}
/**
Creates an image compatible with the current display.
*/
public BufferedImage createCompatibleImage(int w, int h,
int transparancy)
{
Window window = device.getFullScreenWindow();
if (window != null) {
GraphicsConfiguration gc =
window.getGraphicsConfiguration();
return gc.createCompatibleImage(w, h, transparancy);
}
return null;
}
}
GameManager.java
package com.brackeen.javagamebook.tilegame;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Iterator;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.sampled.AudioFormat;
import com.brackeen.javagamebook.graphics.*;
import com.brackeen.javagamebook.sound.*;
import com.brackeen.javagamebook.input.*;
import com.brackeen.javagamebook.test.GameCore;
import com.brackeen.javagamebook.tilegame.sprites.*;
/**
GameManager manages all parts of the game.
*/
public class GameManager extends GameCore {
public static void main(String[] args) {
new GameManager().run();
}
// uncompressed, 44100Hz, 16-bit, mono, signed, little-endian
private static final AudioFormat PLAYBACK_FORMAT =
new AudioFormat(44100, 16, 1, true, false);
private static final int DRUM_TRACK = 1;
public static final float GRAVITY = 0.002f;
private Point pointCache = new Point();
private TileMap map;
private MidiPlayer midiPlayer;
private SoundManager soundManager;
private ResourceManager resourceManager;
private Sound prizeSound;
private Sound boopSound;
private Sound jacksound;
private InputManager inputManager;
private TileMapRenderer renderer;
public Boolean panimation = false;
public Boolean playing = false;
private int points;
private GameAction moveLeft;
private GameAction moveRight;
private GameAction jump;
private GameAction exit;
private GameAction pause;
public void init() {
super.init();
// set up input manager
initInput();
// start resource manager
resourceManager = new ResourceManager(
screen.getFullScreenWindow().getGraphicsConfiguration());
// load resources
renderer = new TileMapRenderer();
renderer.setBackground(
resourceManager.loadImage("background.png"));
// load first map
map = resourceManager.loadNextMap();
// load sounds
soundManager = new SoundManager(PLAYBACK_FORMAT);
prizeSound = soundManager.getSound("sounds/prizes.wav");
boopSound = soundManager.getSound("sounds/boop2.wav");
jacksound = soundManager.getSound("sounds/jack.wav");
// start music
midiPlayer = new MidiPlayer();
Sequence sequence =
midiPlayer.getSequence("sounds/music.midi");
midiPlayer.play(sequence, true);
toggleDrumPlayback();
}
/**
Closes any resurces used by the GameManager.
*/
public void stop() {
super.stop();
midiPlayer.close();
soundManager.close();
}
public void pause() {
if(!panimation){
panimation = true;
soundManager.setPaused(true);
midiPlayer.setPaused(true);
}
else{
panimation = false;
soundManager.setPaused(false);
midiPlayer.setPaused(false);
}
}
private void initInput() {
moveLeft = new GameAction("moveLeft");
moveRight = new GameAction("moveRight");
jump = new GameAction("jump",
GameAction.DETECT_INITAL_PRESS_ONLY);
exit = new GameAction("exit",
GameAction.DETECT_INITAL_PRESS_ONLY);
pause = new GameAction("pause",
GameAction.DETECT_INITAL_PRESS_ONLY);
inputManager = new InputManager(
screen.getFullScreenWindow());
inputManager.setCursor(InputManager.INVISIBLE_CURSOR);
inputManager.mapToKey(moveLeft, KeyEvent.VK_LEFT);
inputManager.mapToKey(moveRight, KeyEvent.VK_RIGHT);
inputManager.mapToKey(jump, KeyEvent.VK_SPACE);
inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE);
inputManager.mapToKey(pause, KeyEvent.VK_F1);
}
private void checkInput(long elapsedTime) {
if (exit.isPressed()) {
stop();
String spoints = Integer.toString(points);
System.out.println("Points: " + spoints);
}
if (pause.isPressed()){
pause();
}
Player player = (Player)map.getPlayer();
if (player.isAlive()) {
float velocityX = 0;
if (moveLeft.isPressed()) {
velocityX-=player.getMaxSpeed();
}
if (moveRight.isPressed()) {
velocityX+=player.getMaxSpeed();
}
if (jump.isPressed()) {
player.jump(false);
}
player.setVelocityX(velocityX);
}
}
public void draw(Graphics2D g) {
renderer.draw(g, map,
screen.getWidth(), screen.getHeight());
}
/**
Gets the current map.
*/
public TileMap getMap() {
return map;
}
/**
Turns on/off drum playback in the midi music (track 1).
*/
public void toggleDrumPlayback() {
Sequencer sequencer = midiPlayer.getSequencer();
if (sequencer != null) {
sequencer.setTrackMute(DRUM_TRACK,
!sequencer.getTrackMute(DRUM_TRACK));
}
}
/**
Gets the tile that a Sprites collides with. Only the
Sprite's X or Y should be changed, not both. Returns null
if no collision is detected.
*/
public Point getTileCollision(Sprite sprite,
float newX, float newY)
{
float fromX = Math.min(sprite.getX(), newX);
float fromY = Math.min(sprite.getY(), newY);
float toX = Math.max(sprite.getX(), newX);
float toY = Math.max(sprite.getY(), newY);
// get the tile locations
int fromTileX = TileMapRenderer.pixelsToTiles(fromX);
int fromTileY = TileMapRenderer.pixelsToTiles(fromY);
int toTileX = TileMapRenderer.pixelsToTiles(
toX + sprite.getWidth() - 1);
int toTileY = TileMapRenderer.pixelsToTiles(
toY + sprite.getHeight() - 1);
// check each tile for a collision
for (int x=fromTileX; x<=toTileX; x++) {
for (int y=fromTileY; y<=toTileY; y++) {
if (x < 0 || x >= map.getWidth() ||
map.getTile(x, y) != null)
{
// collision found, return the tile
pointCache.setLocation(x, y);
return pointCache;
}
}
}
// no collision found
return null;
}
/**
Checks if two Sprites collide with one another. Returns
false if the two Sprites are the same. Returns false if
one of the Sprites is a Creature that is not alive.
*/
public boolean isCollision(Sprite s1, Sprite s2) {
// if the Sprites are the same, return false
if (s1 == s2) {
return false;
}
// if one of the Sprites is a dead Creature, return false
if (s1 instanceof Creature && !((Creature)s1).isAlive()) {
return false;
}
if (s2 instanceof Creature && !((Creature)s2).isAlive()) {
return false;
}
// get the pixel location of the Sprites
int s1x = Math.round(s1.getX());
int s1y = Math.round(s1.getY());
int s2x = Math.round(s2.getX());
int s2y = Math.round(s2.getY());
// check if the two sprites' boundaries intersect
return (s1x < s2x + s2.getWidth() &&
s2x < s1x + s1.getWidth() &&
s1y < s2y + s2.getHeight() &&
s2y < s1y + s1.getHeight());
}
/**
Gets the Sprite that collides with the specified Sprite,
or null if no Sprite collides with the specified Sprite.
*/
public Sprite getSpriteCollision(Sprite sprite) {
// run through the list of Sprites
Iterator i = map.getSprites();
while (i.hasNext()) {
Sprite otherSprite = (Sprite)i.next();
if (isCollision(sprite, otherSprite)) {
// collision found, return the Sprite
return otherSprite;
}
}
// no collision found
return null;
}
/**
Updates Animation, position, and velocity of all Sprites
in the current map.
*/
public void update(long elapsedTime) {
Creature player = (Creature)map.getPlayer();
// player is dead! start map over
if (player.getState() == Creature.STATE_DEAD) {
map = resourceManager.reloadMap();
return;
}
// get keyboard/mouse input
checkInput(elapsedTime);
if (!panimation) { //If game is paused, it stops the updating of the animation.
// update player
updateCreature(player, elapsedTime);
player.update(elapsedTime);
// update other sprites
Iterator i = map.getSprites();
while (i.hasNext()) {
Sprite sprite = (Sprite)i.next();
if (sprite instanceof Creature) {
Creature creature = (Creature)sprite;
if (creature.getState() == Creature.STATE_DEAD) {
i.remove();
}
else {
updateCreature(creature, elapsedTime);
}
}
// normal update
sprite.update(elapsedTime);
}
}
}
/**
Updates the creature, applying gravity for creatures that
aren't flying, and checks collisions.
*/
private void updateCreature(Creature creature,
long elapsedTime)
{
// apply gravity
if (!creature.isFlying()) {
creature.setVelocityY(creature.getVelocityY() +
GRAVITY * elapsedTime);
}
// change x
float dx = creature.getVelocityX();
float oldX = creature.getX();
float newX = oldX + dx * elapsedTime;
Point tile =
getTileCollision(creature, newX, creature.getY());
if (tile == null) {
creature.setX(newX);
}
else {
// line up with the tile boundary
if (dx > 0) {
creature.setX(
TileMapRenderer.tilesToPixels(tile.x) -
creature.getWidth());
}
else if (dx < 0) {
creature.setX(
TileMapRenderer.tilesToPixels(tile.x + 1));
}
creature.collideHorizontal();
}
if (creature instanceof Player) {
checkPlayerCollision((Player)creature, false);
}
// change y
float dy = creature.getVelocityY();
float oldY = creature.getY();
float newY = oldY + dy * elapsedTime;
tile = getTileCollision(creature, creature.getX(), newY);
if (tile == null) {
creature.setY(newY);
}
else {
// line up with the tile boundary
if (dy > 0) {
creature.setY(
TileMapRenderer.tilesToPixels(tile.y) -
creature.getHeight());
}
else if (dy < 0) {
creature.setY(
TileMapRenderer.tilesToPixels(tile.y + 1));
}
creature.collideVertical();
}
if (creature instanceof Player) {
boolean canKill = (oldY < creature.getY());
checkPlayerCollision((Player)creature, canKill);
}
}
/**
Checks for Player collision with other Sprites. If
canKill is true, collisions with Creatures will kill
them.
*/
public void checkPlayerCollision(Player player,
boolean canKill)
{
if (!player.isAlive()) {
return;
}
// check for player collision with other sprites
Sprite collisionSprite = getSpriteCollision(player);
if (collisionSprite instanceof PowerUp) {
acquirePowerUp((PowerUp)collisionSprite);
}
else if (collisionSprite instanceof Creature) {
Creature badguy = (Creature)collisionSprite;
if (canKill) {
// kill the badguy and make player bounce
soundManager.play(boopSound);
badguy.setState(Creature.STATE_DYING);
player.setY(badguy.getY() - player.getHeight());
player.jump(true);
}
else {
// player dies!
player.setState(Creature.STATE_DYING);
points = 0;
}
}
}
/**
Gives the player the speicifed power up and removes it
from the map.
*/
public void acquirePowerUp(PowerUp powerUp) {
// remove it from the map
map.removeSprite(powerUp);
Player player = (Player)map.getPlayer();
if (powerUp instanceof PowerUp.Star) {
// do something here, like give the player points
soundManager.play(prizeSound);
points = points + 5;
}
else if (powerUp instanceof PowerUp.Music) {
// change the music
player.setMaxSpeed();
if (! playing){
soundManager.play(jacksound);
playing = true;
}
else
{
//Do nothing
}
toggleDrumPlayback();
}
else if (powerUp instanceof PowerUp.Goal) {
// advance to next map
soundManager.play(prizeSound,
new EchoFilter(2000, .7f), false);
map = resourceManager.loadNextMap();
}
}
}
The book has an example menu in the chapter.
MenuTest.java
package com.brackeen.javagamebook.tilegame;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.brackeen.javagamebook.graphics.*;
import com.brackeen.javagamebook.sound.*;
import com.brackeen.javagamebook.input.*;
import com.brackeen.javagamebook.test.GameCore;
import com.brackeen.javagamebook.tilegame.sprites.*;
/**
Extends the InputManagerTest demo and adds Swing buttons
for pause, config and quit.
*/
public class Menu extends InputManager
implements ActionListener
{
public static void main(String[] args) {
new Menu().run();
}
protected GameAction configAction;
private JButton playButton;
private JButton configButton;
private JButton quitButton;
private JButton pauseButton;
private JPanel playButtonSpace;
public void init() {
super.init();
// make sure Swing components don't paint themselves
NullRepaintManager.install();
// create an addtional GameAction for "config"
configAction = new GameAction("config");
// create buttons
quitButton = createButton("quit", "Quit");
playButton = createButton("play", "Continue");
pauseButton = createButton("pause", "Pause");
configButton = createButton("config", "Change Settings");
// create the space where the play/pause buttons go.
playButtonSpace = new JPanel();
playButtonSpace.setOpaque(false);
playButtonSpace.add(pauseButton);
JFrame frame = super.screen.getFullScreenWindow();
Container contentPane = frame.getContentPane();
// make sure the content pane is transparent
if (contentPane instanceof JComponent) {
((JComponent)contentPane).setOpaque(false);
}
// add components to the screen's content pane
contentPane.setLayout(new FlowLayout(FlowLayout.LEFT));
contentPane.add(playButtonSpace);
contentPane.add(configButton);
contentPane.add(quitButton);
// explicitly layout components (needed on some systems)
frame.validate();
}
/**
Extends InputManagerTest's functionality to draw all
Swing components.
*/
public void draw(Graphics2D g) {
super.draw(g);
JFrame frame = super.screen.getFullScreenWindow();
// the layered pane contains things like popups (tooltips,
// popup menus) and the content pane.
frame.getLayeredPane().paintComponents(g);
}
/**
Changes the pause/play button whenever the pause state
changes.
*/
public void setPaused(boolean p) {
super.setPaused(p);
playButtonSpace.removeAll();
if (isPaused()) {
playButtonSpace.add(playButton);
}
else {
playButtonSpace.add(pauseButton);
}
}
/**
Called by the AWT event dispatch thread when a button is
pressed.
*/
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if (src == quitButton) {
// fire the "exit" gameAction
super.exit.tap();
}
else if (src == configButton) {
// doesn't do anything (for now)
configAction.tap();
}
else if (src == playButton || src == pauseButton) {
// fire the "pause" gameAction
super.pause.tap();
}
}
/**
Creates a Swing JButton. The image used for the button is
located at "../images/menu/" + name + ".png". The image is
modified to create a "default" look (translucent) and a
"pressed" look (moved down and to the right).
<p>The button doesn't use Swing's look-and-feel and
instead just uses the image.
*/
public JButton createButton(String name, String toolTip) {
// load the image
String imagePath = "../images/menu/" + name + ".png";
ImageIcon iconRollover = new ImageIcon(imagePath);
int w = iconRollover.getIconWidth();
int h = iconRollover.getIconHeight();
// get the cursor for this button
Cursor cursor =
Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
// make translucent default image
Image image = screen.createCompatibleImage(w, h,
Transparency.TRANSLUCENT);
Graphics2D g = (Graphics2D)image.getGraphics();
Composite alpha = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, .5f);
g.setComposite(alpha);
g.drawImage(iconRollover.getImage(), 0, 0, null);
g.dispose();
ImageIcon iconDefault = new ImageIcon(image);
// make a pressed iamge
image = screen.createCompatibleImage(w, h,
Transparency.TRANSLUCENT);
g = (Graphics2D)image.getGraphics();
g.drawImage(iconRollover.getImage(), 2, 2, null);
g.dispose();
ImageIcon iconPressed = new ImageIcon(image);
// create the button
JButton button = new JButton();
button.addActionListener(this);
button.setIgnoreRepaint(true);
button.setFocusable(false);
button.setToolTipText(toolTip);
button.setBorder(null);
button.setContentAreaFilled(false);
button.setCursor(cursor);
button.setIcon(iconDefault);
button.setRolloverIcon(iconRollover);
button.setPressedIcon(iconPressed);
return button;
}
}