I was trying to answer a question related to moving a ball across the screen while changing its color over time, however I came through a weird bug, (most probably in my code) and while asking this question I came to a related question but that question is using a Client-Server architecture while mine is simply a Swing app running itself.
What is happening is that when the circle / ball, however you want to name it, reaches the half width of the JPanel or JFrame it becomes invisible or stops.
At first I thought it could be my JPanel being badly positioned, but I added a Border to it, so I could see its dimensions, but it's showing the whole border around the whole space of the JFrame.
Next I thought it could be some arithmetical problem, so I decided to make the ball larger and smaller than what I was originally painting it, giving me the same result, and having the same issue when I enlarge or reduce the window's size.
To get the following output I needed to change the increment by 9 instead of 10 that I was adding originally, because if I change it to 10 it becomes invisible:
The below code produces the above output:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ChangingColorBall {
private JFrame frame;
private Timer timer;
private BallPane ballPane;
public static void main(String[] args) {
SwingUtilities.invokeLater(new ChangingColorBall()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
ballPane = new BallPane();
timer = new Timer(100, e -> {
ballPane.increaseX();
});
ballPane.setBorder(BorderFactory.createLineBorder(Color.RED));
frame.add(ballPane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
timer.start();
}
#SuppressWarnings("serial")
class BallPane extends JPanel {
private int x;
private static final int Y = 50;
private static final int SIZE = 20;
private Color color;
private Random r;
public void increaseX() {
x += 9;
r = new Random();
color = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
revalidate();
repaint();
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(color);
// g2d.fill(new Ellipse2D.Double(x, Y, SIZE, SIZE));
g2d.fillOval(x, Y, SIZE, SIZE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 100);
}
}
}
I also thought it could be something related to the Shapes API, and decided to change it to fillOval as well with the same results, I can't post a GIF yet, but will add it later if necessary.
I'm working under macOS Sierra 10.12.6 (16G29) on a MacBook Pro (13'' Retina display, early 2015) compiling and running it under Java 1.8
I'll test this code later as well on my own PC and not my work's Mac, however, could this be a bug related to Swing's API or a bug in my own code? If so, what am I doing wrong? Since it doesn't seem clear to me
The issue is that you are inadvertently overriding the getX() method defined in JComponent in your BallPane class.
As a result the x coordinate of the the JPanel whenever accessed by getX() is also changing as getX() now returns your field x which is defining how the ball moves and thus resulting in this behavior. You should either remove the method getX() from BallPane or rename it.
Related
I am working on a simple 2D game. Each tick, I want to check an effects queue that will start a thread for a certain effect(fading transitions, audio fade in and out, etc). For example, pressing "Play" on the menu screen will add a "FadeOut" message to this queue, which will be processed and start a thread to draw a black rectangle with an increasing alpha value over my GamePanel.
I'm overriding paintComponent() and sending my Graphics object to my GameStateManager, which passes along the Graphics object to the current states' draw(). I currently don't have an effects state (which maybe I should) to route the paintComponent() graphics object to, but I do pass my gamepanel to my effects thread, where I can use getGraphics() to draw on it. Drawing a rectangle to the GamePanel directly just causes flickering, as the gameloop is still rendering the game.
I found I can draw a black rectangle with increasing alpha to a BufferedImage, set the composite to AlphaComposite.Src (which causes the new draw to replace the old) then draw the BufferedImage over the game panel. The problem is the BufferedImages drawn to the game panel don't get overridden each draw, so the fade out happens really quickly because these black BufferedImages of various alphas just stack on each other.
I wrote this short program to test composite settings and see what is getting overridden. All drawing is done in the draw(), which would be my run() in the effects thread.
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ScratchPad extends JPanel implements Runnable
{
private JFrame oFrame = null;
private Thread oGameThread = null;
private Graphics2D oPanelGraphics = null;
private Graphics2D oImageGraphics = null;
private BufferedImage oImage = null;
public static void main(String args[]) throws Exception
{
new ScratchPad();
}
public ScratchPad()
{
createFrame();
initPanel();
addAndShowComponents();
oGameThread = new Thread(this, "Game_Loop");
oGameThread.start();
}
private void addAndShowComponents()
{
oFrame.add(this);
oFrame.setVisible(true);
}
private void initPanel()
{
this.setOpaque(true);
this.setBackground(Color.cyan);
}
private void createFrame()
{
oFrame = new JFrame("Fade");
oFrame.setSize(700, 300);
oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
oFrame.setLocationRelativeTo(null);
}
public void run()
{
oImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
while(true)
{
try
{
draw();
Thread.sleep(100);
}
catch(InterruptedException e)
{
}
}
}
private void draw()
{
oPanelGraphics = (Graphics2D)this.getGraphics();
oImageGraphics = oImage.createGraphics();
oImageGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,90));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.setColor(new Color(0,0,0,60));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 220, 10, null);
oImageGraphics.setColor(new Color(0,0,0,30));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 430, 10, null);
// Drawing this image over location of first image, should overwrite first
// after setting composite to 'Src'
oPanelGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,10));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.dispose();
oPanelGraphics.dispose();
}
} // end class
What's interesting is setting the composite on 'oPanelGraphics' causes any alpha to the BufferedImage to go away, resulting in a fully opaque black image being drawn over the image that was previously there. Even setting the color to something other than black doesn't have an effect.
What's also interesting is setting the composite for the BufferedImage to:
oImageGraphics.setComposite(AlphaComposite.SrcIn);
causes nothing to be shown. The Oracle documentation on compositing graphics in Java2D states this for 'SrcIn':
"If pixels in the source and the destination overlap, only the source pixels in the overlapping area are rendered."
So, I would expect this to have the same behavior I get with AlphaComposite.Src.
Maybe someone out there can shed some light on whats going on with these composites, and how I could achieve my desired effect.
There are a number issues with what you "seem" to be trying to do
Don't call getGraphics on a component. This can return null and only returns a snapshot of what was last painted during a Swing paint cycle. Anything you paint to it will be erased on the next paint cycle
You should also never dispose of Graphics context you did not create, doing so could effect other components that are painted by Swing
Painting is compounding, this means that painting to the same Graphics context (or BufferedImage) over and over again, will continue to apply those changes over the top of what was previously painted
You also don't seem to have a concept of how animation should work. Instead of trying to paint your fade effect in a single pass, where the results can't be applied to the screen, you need to apply a phase on each cycle and allow that to be updated to the screen before the next pass runs.
The following is a really basic example of what I'm talking about. It takes a "base" image (this could be the "base" state of the game, but I've used a static image) and the paints effects over the top.
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
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();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Engine engine;
private Image frame;
public TestPane() {
engine = new Engine();
engine.setEngineListener(new EngineListener() {
#Override
public void updateDidOccur(Image img) {
frame = img;
repaint();
}
});
engine.start();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
engine.addEffect(new FadeOutEffect(Color.BLACK));
}
});
}
#Override
public Dimension getPreferredSize() {
return engine.getSize();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (frame != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(frame, 0, 0, null);
g2d.dispose();
}
}
}
public interface EngineListener {
public void updateDidOccur(Image img);
}
public class Engine {
// This is the "base" image, without effects
private BufferedImage base;
private Timer timer;
private EngineListener listener;
private List<Effect> effects = new ArrayList<Effect>(25);
public Engine() {
try {
base = ImageIO.read(new File("/Volumes/Big Fat Extension/Dropbox/MegaTokyo/megatokyo_omnibus_1_3_cover_by_fredrin-d4oupef 50%.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int width = base.getWidth();
int height = base.getHeight();
BufferedImage frame = new BufferedImage(width, height, base.getType());
Graphics2D g2d = frame.createGraphics();
g2d.drawImage(base, 0, 0, null);
Iterator<Effect> it = effects.iterator();
while (it.hasNext()) {
Effect effect = it.next();
if (!effect.applyEffect(g2d, width, height)) {
it.remove();
}
}
g2d.dispose();
if (listener != null) {
listener.updateDidOccur(frame);
}
}
});
}
public void start() {
timer.start();
}
public void stop() {
timer.stop();
}
public void addEffect(Effect effect) {
effects.add(effect);
}
public void setEngineListener(EngineListener listener) {
this.listener = listener;
}
public Dimension getSize() {
return base == null ? new Dimension(200, 200) : new Dimension(base.getWidth(), base.getHeight());
}
}
public interface Effect {
public boolean applyEffect(Graphics2D context, int width, int height);
}
public class FadeOutEffect implements Effect {
private int tick = 0;
private Color fadeToColor;
public FadeOutEffect(Color fadeToColor) {
this.fadeToColor = fadeToColor;
}
#Override
public boolean applyEffect(Graphics2D context, int width, int height) {
tick++;
float alpha = (float) tick / 100.0f;
if (alpha > 1.0) {
return false;
}
Graphics2D g2d = (Graphics2D) context.create();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
g2d.setColor(fadeToColor);
g2d.fillRect(0, 0, width, height);
g2d.dispose();
return true;
}
}
}
Remember, every effect or change should be applied within the same "main loop", this means you shouldn't have multiple threads, in fact, since Swing is not thread safe, you should avoid having any additional threads if possible. This example make use of a Swing Timer to act as the "main loop" because the ActionListers actionPerformed method is called within the context of the EDT, making it safe to update the UI from. It also provides a simple synchronisation method, as the UI can't be painted while the actionPerformed method is been called
Hi I am creating a news ticker/ text scroller.
I am using the following method:
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Scroll1 extends JPanel{
private int x;
private int x2;
private int y;
private String text;
final int startX=-100;
public Scroll1(int startX)
{
x2=-650;
x = 20;
y=150;
text= "Some Words and others, and now this must be a longer text that takes up the whole panel/ frame for this test to work ";
}
#Override
public void paint(Graphics g)
{
g.setColor(Color.white);
g.fillRect(0, 0, 400, 300);
g.setColor(Color.black);
g.drawString(text, x, y);
g.drawString(text, x2, y);
FontMetrics fm= g.getFontMetrics();
System.out.println(fm.stringWidth(text));;
}
public void start() throws InterruptedException{
while(true){
while(x<= 650){
x++;
x2++;
y = getHeight()/2;
repaint();
Thread.sleep(10);
if(x2>650)
x2=-650;
}
if(x>=0)
{
x=-650;
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Scrolling Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Scroll1 scrolling = new Scroll1(-100);
frame.getContentPane().add(scrolling);
frame.setSize(400, 300);
frame.setVisible(true);
try {
scrolling.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Basically it has two strings that are being drawn. One starts at the 0 position and the other starts at -650. I got the -650 number by using the font metrics inside of the paint method. The problem is that I had to hard code that number, and if I did a different string that has different metrics, it would not work. I tried making a instance variable called width that stores the font metrics, but it seems that the width is not inputted until the paint method is called. Is there anyway I can get the metrics before it starts drawing it?
Is there anyway I can get the metrics before it starts drawing it?
Just initialize the variable in the first call to paint (or better yet, paintComponent - see below) - you can do this using a boolean flag, or initialize it's value to an extreme and do a check on the value.
int x = Integer.MIN_VALUE;
...
protected void paintComponent(Graphics g){
super.paintComponent(g);
if ( x == Integer.MIN_VALUE ){
x = -g.getFontMetrics().stringWidth(text);
}
...
}
Some other tips:
Use a Swing Timer to perform animation, or be sure to dispatch Swing specific calls to the EDT using SwingUtilities.
Don't override paint, rather override paintComponent (and be sure to call the parent method super.paintComponent(g))
I've been taking AP Computer Science this year as a sophomore in high school and we mainly cover material like loops, classes, methods, general CS logic, and some math stuff. I am missing what I really loved about coding in the first place, making games. Now every game I have made had some sort of way to manage it whether it was using timers in visual basic or a XNA plugin for c# that setup a update method for me. The problem is I have not learned how to do this for java in my course. I've read up a little on threads and implements runnable but i'm not really sure where I'm going with it.
Class 1
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class GFXScreen extends JFrame
{
/**
* #param screenHeigth
* #param screenHeigth
* #param The file name of the image. Make sure to include the extension type also
* #param The title at the top of the running screen
* #param The height of the screen
* #param The width of the screen
*/
public GFXScreen(String fileName, String screenTitle, int screenHeight, int screenWidth)
{
setLayout(new FlowLayout());
image1 = new ImageIcon(getClass().getResource(fileName));
label1 = new JLabel(image1);
this.add(label1);
//Set up JFrame
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setTitle(screenTitle);
this.setSize(screenWidth, screenHeight);
}
/**
* #param desired amount to move picture
*/
public void updatePic(int increment)
{
//update pos
label1.setBounds(label1.bounds().x, label1.bounds().y - increment,
label1.bounds().width, label1.bounds().height);
}
private ImageIcon image1;
private JLabel label1;
}
Class 2
public class MainClass implements Runnable {
public static void main(String[] args)
{
(new Thread(new MainClass())).start();
GFXScreen gfx = new GFXScreen("pixel_man.png", "pixel_Man", 1000, 1000);
}
public void run()
{
gfx.updatePic(1);
}
}
In this instance what I want to happen is, I want a picture that starts in the top to slowly move down smoothly to the bottom. How would i do this?
Suggestions:
Again, a Swing Timer works well for simple Swing animations or simple game loops. It may not be the greatest choice for complex or rigorous tame loops as its timing is not precise.
Most game loops will not be absolutely precise with time slices
And so your game model should take this into consideration and should note absolute time slices and use that information in its physics engine or animation.
If you must use background threading, do take care that most all Swing calls are made on the Swing event thread. To do otherwise will invite pernicious infrequent and difficult to debug program-ending exceptions. For more details on this, please read Concurrency in Swing.
I avoid using null layouts, except when animating components, as this will allow my animation engine to place the component absolutely.
When posting code here for us to test, it's best to avoid code that uses local images. Either have the code use an image easily available to all as a URL or create your own image in your code (see below for a simple example).
Your compiler should be complaining to you about your using deprecated methods, such as bounds(...), and more importantly, you should heed those complaints as they're there for a reason and suggest increased risk and danger if you use them. So don't use those methods, but instead check the Java API for better substitutes.
Just my own personal pet peeve -- please indicate that you've at least read our comments. No one likes putting effort and consideration into trying to help, only to be ignored. I almost didn't post this answer because of this.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class GfxPanel extends JPanel {
private static final int BI_WIDTH = 26;
private static final int BI_HEIGHT = BI_WIDTH;
private static final int GAP = 6;
private static final Point INITIAL_LOCATION = new Point(0, 0);
private static final int TIMER_DELAY = 40;
public static final int STEP = 1;
private ImageIcon image1;
private JLabel label1;
private Point labelLocation = INITIAL_LOCATION;
private int prefW;
private int prefH;
private Timer timer;
public GfxPanel(int width, int height) {
// the only time I use null layouts is for component animation.
setLayout(null);
this.prefW = width;
this.prefH = height;
// My program creates its image so you can run it without an image file
image1 = new ImageIcon(createMyImage());
label1 = new JLabel(image1);
label1.setSize(label1.getPreferredSize());
label1.setLocation(labelLocation);
this.add(label1);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(prefW, prefH);
}
public void startAnimation() {
if (timer != null && timer.isRunning()) {
timer.stop();
}
labelLocation = INITIAL_LOCATION;
timer = new Timer(TIMER_DELAY, new TimerListener());
timer.start();
}
// My program creates its image so you can run it without an image file
private Image createMyImage() {
BufferedImage bi = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = bi.createGraphics();
g2.setColor(Color.red);
g2.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g2.setColor(Color.blue);
int x = GAP;
int y = x;
int width = BI_WIDTH - 2 * GAP;
int height = BI_HEIGHT - 2 * GAP;
g2.fillRect(x, y, width, height);
g2.dispose();
return bi;
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int x = labelLocation.x + STEP;
int y = labelLocation.y + STEP;
labelLocation = new Point(x, y);
label1.setLocation(labelLocation);
repaint();
if (x + BI_WIDTH > getWidth() || y + BI_HEIGHT > getHeight()) {
System.out.println("Stopping Timer");
((Timer) e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
final GfxPanel gfxPanel = new GfxPanel(900, 750);
JButton button = new JButton(new AbstractAction("Animate") {
#Override
public void actionPerformed(ActionEvent arg0) {
gfxPanel.startAnimation();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
JFrame frame = new JFrame("GFXScreen");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(gfxPanel);
frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
What I always use is an infinite loop that calls an update method each iteration, in that method, you would do whatever was required to update the state of the game or render a GUI.
Example
public static void main(String[] args){
// Initialise game
while(true){
updateGame();
}
}
public static void updateGame(){
// Update things here.
}
What I also do ,which is a little more complex, is create and interface called IUpdateListener and have certain classes that are specialised for a certain element of the game. I would example have an InputListener, an AIListener, each handling a certain element of game updating.
public interface IUpdateListener{
public void update();
}
public class Main{
public static ArrayList<IUpdateListener> listeners = new ArrayList<IUpdateListener>();
public static void main(String[] args){
listeners.add(new InputListener());
while(true){
for(IUpdateListener listener : listeners){
listener.update();
}
}
}
}
public class InputListener implements IUpdateListener{
public void update(){
// Handle user input here etc
}
}
I'm attempting to partially fill a JTextArea based on an object's member field that is between 0 and 1. If I hard code the percentage in the paintComponent function, it works great. But when I try to use the member field as the percentage value, it's always 0.0 in the debugger and no rectangle is painted behind the text.
Why are the member fields seemingly uninitialized within paintComponent()? After calling setPercent(), percentFilled is correct. (I do invalidate the container of the BarGraphText objects after their setPercent() are called.)
EDIT: setPercent() is called after an ActionListener is triggered by a button. Would the separate gui thread have something to do with this failing? It works when the class below is in a JFrame by itself. Update: Having a button change the percent and redraw the component makes no difference when I have this in a separate project.
Solved: I was clearing the values at the wrong spot in my program. I'll leave this question published.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JTextArea;
public class BarGraphText extends JTextArea {
double percentFilled;
Color fillColor;
BarGraphText( String s )
{
super(s);
setOpaque(false);
percentFilled = 0.0;
}
#Override
public void paintComponent( Graphics g )
{
int width, height;
Rectangle bounds = g.getClipBounds();
if( bounds != null )
{
height = bounds.height;
width = bounds.width;
}
else
{
System.err.println("Error [BarGraphText]: Clipping bounds unknown.");
height = width = 0;
}
g.setColor(fillColor);
g.fillRect(0, 0, (int) (width*percentFilled), height);
super.paintComponent(g);
}
public void setPercent( int myResp, int totResp )
{
percentFilled = (float)myResp / totResp;
}
public void setColor( Color c )
{
fillColor = c;
}
}
I was clearing the values at the wrong spot in my program. This is not in the code published above.
I tried making a program that flips a coin(shows image of heads first and later shows image of tails) and I encountered problems trying to have the image of the coin viewed when I ran the problem; only a blank screen would show. I don't know whether this is from an improper saving method of the jpg images or from an error in the code. I also came across an error before again coding the program where I had the heads image show and tails image not show.
CoinTest.java runs coin runner and Coin.java is the class for the program.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CoinTest extends JPanel
implements ActionListener
{
private Coin coin;
public CoinTest ()
{
Image heads = (new ImageIcon("quarter-coin-head.jpg")).getImage();
Image tails = (new ImageIcon("Indiana-quarter.jpg")).getImage();
coin = new Coin(heads, tails);
Timer clock = new Timer(2000, this);
clock.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
int x = getWidth() / 2;
int y = getHeight() / 2;
coin.draw(g, x, y);
}
public void actionPerformed(ActionEvent e)
{
coin.flip();
repaint();
}
public static void main(String[] args)
{
JFrame w = new JFrame("Flipping coin");
w.setSize(300, 300);
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CoinTest panel = new CoinTest();
panel.setBackground(Color.WHITE);
Container c = w.getContentPane();
c.add(panel);
w.setVisible(true);
}
}
Now the actual Coin class.
import java.awt.Image;
import java.awt.Graphics;
public class Coin
{
private Image heads;
private Image tails;
private int side = 1;
public Coin(Image h, Image t)
{
heads = h;
tails = t;
}
//flips the coin
public void flip()
{
if (side == 1)
side = 0;
else
side = 1;
}
//draws the appropriate side of the coin - centered in the JFrame
public void draw(Graphics g, int x, int y)
{
if (side == 1)
g.drawImage(heads, heads.getWidth(null)/3, heads.getHeight(null)/3, null);
else
g.drawImage(heads, tails.getWidth(null)/3, tails.getHeight(null)/3, null);
}
}
Firstly, ensure that both images are in the correct location to load.
Secondly, you have a typo here:
if (side == 1)
g.drawImage(heads, heads.getWidth(null)/3, heads.getHeight(null)/3, null);
else
g.drawImage(heads, tails.getWidth(null)/3, tails.getHeight(null)/3, null);
^^^^
should be tails...
The width and height of the applet are coded in the tag. The code that draws the applet uses the two methods to get these values at run time. So now, different tags can ask for the same applet to paint different sized rectangles. The source code does not need to be recompiled for different sizes.