I'm attempting to create a game and I'm starting with the loading screen, where it will load all the needed files. I want to show a percentage of completion but its not working. The JPanel Loading only repaints() after Loading_files is finished. I don't know whats wrong.
Main.java
package Main;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JFrame{
//-------------- Final Variables --------------
//Screen Related
public final static int JFRAME_WIDTH = 800;
public final static int JFRAME_HEIGHT = 600;
public final static Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize();
public final static int SCREEN_WIDTH = SCREEN_SIZE.width;
public final static int SCREEN_HEIGHT = SCREEN_SIZE.height;
//Game Related
public final static String NAME = "Xubris";
public final static String IMAGE_DIRECTORY = System.getProperty("user.dir") + "\\images\\";
public static final int FPS = 1000 / 36;
//-------------- Dynamic Variables --------------
//Global
public static JFrame main;
public static void main(String[] args) {
//Start the Loading screen
Loading load = new Loading();
main = new JFrame(NAME);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setSize(JFRAME_WIDTH, JFRAME_HEIGHT);
main.setLocation((SCREEN_WIDTH-JFRAME_WIDTH)/2, (SCREEN_HEIGHT-JFRAME_HEIGHT)/2);
//Add Content
main.getContentPane().add(load);
main.setResizable(false);
main.setUndecorated(false);
main.setVisible(true);
}
}
Loading.java
package Main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class Loading extends JPanel implements Runnable{
//Pictures
BufferedImage background;
//-------------- Final Variables --------------
private final int num_of_files = 32;
//-------------- Dynamic Variables --------------
//Global Variables
private double loading_percentage = 0;
private int num_of_loaded_files = 0;
public Loading(){
try {
background = ImageIO.read(new File(Main.IMAGE_DIRECTORY + "Background_Loading.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
//Start the thread
new Thread(new LoadingFiles()).start();
new Thread(this).start();
}
public void paint(Graphics g){
g.drawImage(background, 0, 0, this);
for(int i = 0; i < loading_percentage; i=i+15){
g.setColor(new Color(20,241,47));
g.drawRect(180 + (i/15)*(50+10), 375, 50, 50);
}
}
#Override
public void run(){
while(true){
repaint();
}
}
class LoadingFiles implements Runnable{
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
num_of_loaded_files++;
loading_percentage = (num_of_loaded_files/num_of_files)*100;
if(num_of_loaded_files!=32)
run();
}
}
}
Blocking the EDT and repaint coalescing where my first ideas as well (that's why I upvoted the comments). But got curious - neither is the real problem :-)
it's perfectly valid to call repaint from whatever thread (though doing so in a tight while-loop certainly slows down ui reactivity)
doesn't repaint as expected even after some cleanup (see below). The culprit for that is purely arithmetic
the following line:
loading_percentage = (num_of_loaded_files/num_of_files)*100;
which is 0 until
num_of_loaded_files == num_of_files
that is until everything loaded. We all are guilty of jumping to conclusions :-)
Some cleanup:
following java naming conventions makes code easier to read
don't override paint, instead override paintComponent
always call super in paintComponent (by default a JPanel reports to be opaque, that is, it must fill its area)
no need for intertwined threads, simply let the loading thread call repaint after having loaded the next image
get the arithmetic correct :-)
Code:
public class Loading extends JPanel {
// Pictures
private BufferedImage background;
// -------------- Final Variables --------------
private final int numOfFiles = 32;
// -------------- Dynamic Variables --------------
// Global Variables
private double loadingPercentage = 0;
private int numOfLoadedFiles = 0;
public Loading() {
background = XTestUtils.loadDefaultImage("moon.jpg");
// Start the thread
new Thread(new LoadingFiles()).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, this);
for (int i = 0; i < loadingPercentage; i = i + 15) {
g.setColor(new Color(20, 241, 47));
g.drawRect(180 + (i / 15) * (50 + 10), 375, 50, 50);
}
}
class LoadingFiles implements Runnable {
#Override
public void run() {
while (numOfLoadedFiles < 32) {
numOfLoadedFiles++;
loadingPercentage = (double) numOfLoadedFiles / numOfFiles
* 100;
repaint();
try {
// simulate the loading
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
JFrame frame = new JXFrame("", true);
frame.add(new Loading());
frame.setSize(600, 600);
frame.setVisible(true);
}
}
Related
For this small program I am attempting to generate a list of squares to be drawn on a panel. Each thread will generate a list and then set the list in the GUI class. In the GUI class I have a swing timer which repaints the panel every 500 milliseconds. Whenever a thread completes their set of squares I want to display it in the GUI. I also want to be sure to overwrite the variable so that the squares from one set do not overlap with another. My program consists of a custom thread class, a main class, a GUI class, and a custom jpanel class. I understand that currently the threads are quite fast, but if they each took different amounts of time, I still am getting data race errors if 2 threads generate a solution at the same time. Is there some sort of waiting function that can occur where a thread will not be able to overwrite until another thread has finished?
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.CopyOnWriteArrayList;
class Custom extends Thread {
private CopyOnWriteArrayList<Point> squarelist = new CopyOnWriteArrayList<>();
private static volatile CopyOnWriteArrayList<CopyOnWriteArrayList<Point>> listoflists = new CopyOnWriteArrayList<>();
private GUI g;
Custom(GUI g) {
this.g = g;
}
private void generate() {
int x = (int) (Math.random() * (600 - 20 + 1) + 20);
int y = (int) (Math.random() * (600 - 20 + 1) + 50);
squarelist.add(new Point(x,y));
}
public void run() {
for (int i = 0; i < 5; i++) {
generate();
}
CopyOnWriteArrayList<Point> copy = new CopyOnWriteArrayList<>(squarelist);
System.out.println("SOLUTION = " + copy.toString());
listoflists.add(copy);
SwingUtilities.invokeLater(() -> {
g.setSquares(new CopyOnWriteArrayList<>(copy));
});
}
}
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GUI g = new GUI();
g.setVisible(true);
Thread[] threads = new Thread[32];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Custom(g);
threads[i].start();
}
});
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.CopyOnWriteArrayList;
public class GUI extends JFrame implements ActionListener {
private MyPanel m;
GUI() {
initialize();
}
private void initialize() {
this.setLayout(new FlowLayout());
Timer timer = new Timer(500, e -> {
m.setPaint();
m.repaint();
});
int height = 600;
int width = 600;
m = new MyPanel(height, width);
this.setSize(1000,1000);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(m);
timer.start();
}
#Override
public void actionPerformed(ActionEvent e) {
}
void setSquares(CopyOnWriteArrayList<Point> squarelist) {
m.setSquares(squarelist);
}
}
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.CopyOnWriteArrayList;
public class MyPanel extends JPanel implements ActionListener {
private boolean paint;
private CopyOnWriteArrayList<Point> squarelist;
MyPanel(int h, int w) {
squarelist = new CopyOnWriteArrayList<>();
paint = false;
this.setPreferredSize(new Dimension(w,h));
this.setBackground(Color.pink);
Border blackline = BorderFactory.createLineBorder(Color.black);
this.setBorder(blackline);
}
#Override
public void actionPerformed (ActionEvent e) {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(paint) {
for(Point p : squarelist) {
g.setColor(Color.BLUE);
g.drawRect((int) p.getX(),(int) p.getY(),20,20);
g.fillRect((int) p.getX(),(int) p.getY(),20,20);
}
}
}
void setPaint() {
paint = true;
}
void setSquares(CopyOnWriteArrayList<Point> squarelist) {
this.squarelist = squarelist;
}
}
I'm trying to draw over a vlcj (java binding of the VLC library) panel so that I can play a video and draw over it. And I have encounter some issues. Here is the full base code:
Code-listing 1: AppOverlay.java
package app;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.sun.jna.platform.WindowUtils;
#SuppressWarnings("serial")
public class AppOverlay extends Window implements Runnable {
private final boolean isRunning;
private final int fps;
private BufferedImage graphics;
private BufferedImage img;
private int x, y;
private boolean ltr;
public AppOverlay(Window owner) {
super(owner, WindowUtils.getAlphaCompatibleGraphicsConfiguration());
setBackground(new Color(0,0,0,0));
graphics = new BufferedImage(1280,800, BufferedImage.TYPE_INT_ARGB);
isRunning = true;
img = null;
ltr = true;
fps = 60;
x = 0;
y = 0;
}
#Override
public void run(){
while(isRunning){
try{
Thread.sleep(1000/fps);
} catch(InterruptedException e){
e.printStackTrace();
}
if(ltr) {
if(x < 1280) x++;
else ltr = false;
} else {
if(x < 0) ltr = true;
else x--;
}
repaint();
}
}
public void createAndShowGUI() {
setVisible(true);
Thread thread = new Thread(this);
thread.start();
String path = "Drive:\\path\\to\\image.png";
try {
img = ImageIO.read(new java.io.FileInputStream(path));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
Graphics2D gfx = graphics.createGraphics();
gfx.setColor(new Color(255,255,255,0));
gfx.clearRect(0, 0, 1280, 800);
if(img != null) gfx.drawImage(img, x, y, null);
gfx.dispose();
g2d.drawImage(graphics, 0, 0, null);
}
}
Code-listing 2: AppPlayer.java
package app;
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
#SuppressWarnings("serial")
public class AppPlayer extends EmbeddedMediaPlayerComponent {
}
Code-listing 3: AppFrame.java
package app;
import java.awt.Dimension;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class AppFrame extends JFrame {
private AppPlayer appPlayer;
private AppOverlay overlay;
public AppFrame(){
super();
}
public void createAndShowGUI() {
appPlayer = new AppPlayer();
appPlayer.setPreferredSize(new Dimension(1280,800));
getContentPane().add(appPlayer);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("App");
setVisible(true);
pack();
overlay = new AppOverlay(this);
appPlayer.mediaPlayer().overlay().set(overlay);
appPlayer.mediaPlayer().overlay().enable(true);
overlay.createAndShowGUI();
}
}
Code-listing 4: Main.java
package main;
import javax.swing.SwingUtilities;
import app.AppFrame;
public class Main {
public static void main(String[] args) {
final AppFrame app = new AppFrame();
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
app.createAndShowGUI();
}
});
}
}
with that and the vlcj-4 library you should be able to test my code yourself. My issue is that the Overlay (AppOverlay class that extends the Window class) doesn't display or refresh the animation unless I deselect the window (I click on another window or on the desktop or the OS toolbar) so that the window (application) is inactive then select the window (the application) again. It will only load one frame and that's it. I have to deselect and reselect the window again for it to load another frame (this is only the case for the Overlay i.e. if I play a video in the AppPlayer class the video will be playing just fine.
What I want is to be able to draw some animated graphics on the overlay. I know that with the JPanel class there is the paintComponent() method but the Window class doesn't have that method (only the paint() and repaint() methods are available).
What should I do to fix this?
EDIT:
I tried adding a JPanel on which I draw instead of drawing directly on the AppOverlay
Code-listing 5: AppPanel.java
package app;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class AppPanel extends JPanel implements Runnable {
private int x, y;
private boolean ltr;
public AppPanel() {
x = 0;
y = 0;
ltr = true;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new Color(0,0,0,0));
g.clearRect(0, 0, 1280, 800);
g.setColor(Color.RED);
g.fillRect(x, y, 100, 100);
}
#Override
public void run() {
while(true){
try{
Thread.sleep(1000/60);
} catch(InterruptedException e){
e.printStackTrace();
}
if(ltr) {
if(x < 1280) x++;
else ltr = false;
} else {
if(x < 0) ltr = true;
else x--;
}
repaint();
}
}
}
then adding it to the AppOverlay.
Code-listing 6: AppOverlay.java with partial modification
public class AppOverlay extends Window implements Runnable {
//previous field declaration above ...
AppPanel panel;
AppPlayer player = null;
public AppOverlay(Window owner) {
//previous constructor instructions above...
panel = new AppPanel();
add(panel);
}
public void createAndShowGUI(AppPlayer player) {
setVisible(true);
/*
Thread thread = new Thread(this);
thread.start();
String path = "Drive:\\path\\to\\image.png";
try {
img = ImageIO.read(new java.io.FileInputStream(path));
} catch (IOException e) {
e.printStackTrace();
}
*/
Thread panelThread = new Thread(panel);
panelThread.start();
}
}
Doing this will display the graphics of the JPanel and animate them as needed.
If you know a way to make the JPanel background transparent (so that we can see through it) while still letting it display its graphics. That would solve the issue for sure.
I played around a bit with your example and came up with something working, but I wouldn't call it a nice solution.
The main issue seems to be that there is no way to tell the overlay to refresh (or I just have not found it). Just repainting the overlay does not update it on screen, so the workaround I used is to hide and show it again.
For the timeing of the update interval I used a javax.swing.Timer.
(In a real version you probably want to start and stop the timer via the MediaPlayerEventListener).
As a side effect the repaint method is called and the x coordinate is adjusted to move the image around the screen.
In the simplified example below (use your main to run it), I moved a red rectangle with the x coordinate instead of some unknown image.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;
import com.sun.jna.platform.WindowUtils;
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.OverlayApi;
public class AppFrame extends JFrame {
private static final long serialVersionUID = -1569823648323129877L;
public class Overlay extends Window {
private static final long serialVersionUID = 8337750467830040964L;
private int x, y;
private boolean ltr = true;
public Overlay(Window owner) throws HeadlessException {
super(owner, WindowUtils.getAlphaCompatibleGraphicsConfiguration());
setBackground(new Color(0,0,0,0));
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (ltr) {
if (x < 1180)
x += 1;
else
ltr = false;
} else {
if (x < 0)
ltr = true;
else
x -= 1;
}
g.setColor(Color.RED);
g.fillRect(x, y, 100, 100);
String s = Integer.toString(x);
g.setColor(Color.WHITE);
g.drawChars(s.toCharArray(), 0, s.length(), x+10, y+50);
}
}
private EmbeddedMediaPlayerComponent appPlayer;
public void createAndShowGUI() {
appPlayer = new EmbeddedMediaPlayerComponent();
appPlayer.setPreferredSize(new Dimension(1280, 800));
getContentPane().add(appPlayer);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("App");
setVisible(true);
pack();
Overlay overlay = new Overlay(this);
OverlayApi api = appPlayer.mediaPlayer().overlay();
api.set(overlay);
api.enable(true);
//appPlayer.mediaPlayer().media().play(" ... ");
Timer timer = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
api.enable(false);
api.enable(true);
}
});
timer.setRepeats(true);
timer.setDelay(200);
timer.start();
}
}
If that is an option for you, it might be far easier to use an animated gif instead. At least that is working on its own (no need for the Timer).
Update:
As you figured out using a JPanel seems to work better.
Just use setOpaque(false) to make it transparent.
Here an adjusted example.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.OverlayApi;
public class AppFrame2 extends JFrame {
private static final long serialVersionUID = -1569823648323129877L;
public class OverlayPanel extends JPanel {
private static final long serialVersionUID = 8070414617530302145L;
private int x, y;
private boolean ltr = true;
public OverlayPanel() {
this.setOpaque(false);
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (ltr) {
if (x < 1180)
x += 1;
else
ltr = false;
} else {
if (x < 0)
ltr = true;
else
x -= 1;
}
g.setColor(Color.RED);
g.fillRect(x, y, 100, 100);
String s = Integer.toString(x);
g.setColor(Color.WHITE);
g.drawChars(s.toCharArray(), 0, s.length(), x+10, y+50);
}
}
public class Overlay extends Window {
private static final long serialVersionUID = 8337750467830040964L;
OverlayPanel panel;
public Overlay(Window owner) throws HeadlessException {
super(owner);
setBackground(new Color(0,0,0,0));
panel = new OverlayPanel();
this.add(panel);
}
}
private EmbeddedMediaPlayerComponent appPlayer;
public void createAndShowGUI() {
appPlayer = new EmbeddedMediaPlayerComponent();
appPlayer.setPreferredSize(new Dimension(1280, 800));
getContentPane().add(appPlayer);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("App");
setVisible(true);
pack();
Overlay overlay = new Overlay(this);
OverlayApi api = appPlayer.mediaPlayer().overlay();
api.set(overlay);
api.enable(true);
//appPlayer.mediaPlayer().media().play(" ... ");
Timer timer = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
overlay.panel.repaint();
}
});
timer.setRepeats(true);
timer.setDelay(17);
timer.start();
}
}
You have already done the bulk of the work. Simply repaint the frame every time you draw over it by calling app.repaint();
You can use the following methods from JComponent: ( http://download.oracle.com/javase/6/docs/api/javax/swing/JComponent.html )
void repaint(long tm, int x, int y, int width, int height)
//**Adds the specified region to the dirty region list if the component is showing.*//
void repaint(Rectangle r)
/**Adds the specified region to the dirty region list if the component is showing.*//
You can call those before redraw()
I'm pretty new to java coding, but i know the basic structures of how to code. I am not familiar with awt/swing, and don't know what my error is.
Background: I searched up ways to animate with java, found zetcode tutorials.
I copy/pasted their code, and tested the program, to make sure it works. the JFrame opened, but nothing drew. Maybe this is a system compatibility error? if so, how would I fix it?
these are the two separate classes:
package com.zetcode;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class ThreadAnimationExample extends JFrame {
public ThreadAnimationExample() {
initUI();
}
private void initUI() {
add(new Board());
setResizable(false);
pack();
setTitle("Star");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame ex = new ThreadAnimationExample();
ex.setVisible(true);
}
});
}
}
This is the main class.
Board.java
package com.zetcode;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Board extends JPanel
implements Runnable {
private final int B_WIDTH = 350;
private final int B_HEIGHT = 350;
private final int INITIAL_X = -40;
private final int INITIAL_Y = -40;
private final int DELAY = 25;
private Image star;
private Thread animator;
private int x, y;
public Board() {
initBoard();
}
private void loadImage() {
ImageIcon ii = new ImageIcon("star.png");
star = ii.getImage();
}
private void initBoard() {
setBackground(Color.BLACK);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
setDoubleBuffered(true);
loadImage();
x = INITIAL_X;
y = INITIAL_Y;
}
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawStar(g);
}
private void drawStar(Graphics g) {
g.drawImage(star, x, y, this);
Toolkit.getDefaultToolkit().sync();
}
private void cycle() {
x += 1;
y += 1;
if (y > B_HEIGHT) {
y = INITIAL_Y;
x = INITIAL_X;
}
}
#Override
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (true) {
cycle();
repaint();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;
if (sleep < 0) {
sleep = 2;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("Interrupted: " + e.getMessage());
}
beforeTime = System.currentTimeMillis();
}
}
}
When I run the program, I get a blank black window. The program is supposed to draw a star. Here is what it is supposed to look like.
So I am working on making a version of "Who what to be a millionaire" in netbeans and I am having problems with the timer. My working code basically changes the color of the number to red after 11 seconds and it disappears( turns white ) at 1 second. What i am trying to do is make the numbers flash after second 6 from 5,4,3,2,1 flash. But i can't find a was to make that happen. I have tried changing
Thread.sleep(1000);
so i can write a more detailed if statement like
if (counter < 5.75 )
g.setColor(Color.WHITE);
if (counter < 5.25 )
g.setColor(Color.BLACK);
but it didn't work..
This is what I've done up to now:
package timer2;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class thread extends JPanel implements Runnable {
private static Object ga;
int counter;
Thread cd;
public void start() {
counter =30 ;
cd = new Thread(this);
cd.start();
}
public void stop()
{
cd = null;
}
public void run() {
while (counter>0 && cd!=null) {
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
--counter;
}
}
public void paintComponent( Graphics g)
{
repaint();
super.paintComponent(g);
g.setColor(Color.BLACK);
if (counter < 1 )
g.setColor(Color.WHITE);
g.setFont(new Font("Times New Roman",Font.BOLD,35));
if (counter < 11)
g.setColor(Color.RED);
if (counter < 1 )
g.setColor(Color.WHITE);
g.setFont(new Font("Times New Roman",Font.BOLD,100));
g.drawString(String.valueOf(counter),600,600);
}
public static void main(String[] args) {
JFrame j=new JFrame();
thread t=new thread();
t.setBackground(Color.WHITE);
t.start();
j.add(t);
j.setVisible(true);
j.getContentPane().setBackground( Color.WHITE );
j.setBounds(-8,-8,500,500);
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
}
First and foremost -- get repaint() out of paintComponent. This should never be called from there.
You want to call your repaint from the timer code itself.
For ease, avoid directly using background threading and a while (true) loop, but rather will want to use the much simpler Swing Timer to do your counting.
I don't see any flashing code in there -- how are you trying to do this?
Also I recommend that you try to improve the formatting of your code that you post in here and your code in general. Good formatting including using an indentation style that is uniform and consistent will help others (us!) to better understand your code, and more importantly, it will help you to better understand your code and thus fix your own bugs. Also it shows that you're willing to put in extra effort to make it easier for the volunteers here to help you, and that effort is much appreciated.
To flash -- use a Timer with a shorter period, say 200 mSec, and change the color within the Timer.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Formatter;
import javax.swing.*;
#SuppressWarnings("serial")
public class CountDownTimer extends JPanel {
private static final String FORMAT = "%02d";
private static final Color[] TIMER_COLORS = {Color.BLACK, Color.WHITE};
private static final int LABEL_PTS = 90;
private static final Font TIMER_LABEL_FONT = new Font("Times New Roman", Font.BOLD, LABEL_PTS);
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 100;
public static final int FLASH_TIME = 6;
private JLabel timerLabel = new JLabel("");
private Timer timer;
private int timerColorIndex = 0;
public CountDownTimer(int seconds) {
setTimerCount(seconds);
setLayout(new GridBagLayout());
add(timerLabel);
timer = new Timer(TIMER_DELAY, new TimerListener(seconds));
timer.start();
}
public final void setTimerCount(int count) {
String text = String.format(FORMAT, count);
timerLabel.setText(text);
timerLabel.setFont(TIMER_LABEL_FONT);
}
public void flash() {
timerColorIndex++;
timerColorIndex %= TIMER_COLORS.length;
timerLabel.setForeground(TIMER_COLORS[timerColorIndex]);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
private int mSeconds;
public TimerListener(int secondsLeft) {
this.mSeconds = 1000 * secondsLeft;
}
#Override
public void actionPerformed(ActionEvent e) {
mSeconds -= TIMER_DELAY;
int seconds = (mSeconds + 999) / 1000;
if (seconds < FLASH_TIME) {
flash();
}
setTimerCount(seconds);
if (seconds == 0) {
((Timer) e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
int seconds = 20;
CountDownTimer mainPanel = new CountDownTimer(20);
JFrame frame = new JFrame("CountDownTimer");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
I looked and the codes seems fine to me. Got an error but hopefully it's the source code, not something wrong with the cpu I have nor JDK.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.*;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
public static int width = 300;
public static int height = width / 16*9;
public static int scale = 3;
private Thread thread;
private boolean running = false;
private JFrame frame;
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try{
thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void run(){
while(running){
tick();
render();
}
}
public void tick() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if(bs==null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
bs.dispose();
bs.show();
}
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Title");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Then I got this error, even when I countlessly modified the source code I had.
Exception in thread "Display" java.lang.NullPointerException
at java.awt.Component$BltBufferStrategy.showSubRegion(Component.java:4307)
at java.awt.Component$BltBufferStrategy.show(Component.java:4255)
at com.thecherno.Rain.Game.render(Game.java:58)
at com.thecherno.Rain.Game.run(Game.java:39)
at java.lang.Thread.run(Thread.java:695)
Im starting to seem if it because of an outdated JDK. Current Version I have is JDK 6.
You state:
What Im trying to do is change color as seen in the render method. The background to be black.
Use Swing components such as a JComponent or JPanel.
Simply call setBackground(Color.BLACK) on the component will do.
You appear to be creating a game loop of some type. Consider using a Swing Timer for this.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Game2 extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = PREF_W / 16 * 9;
private static final int SCALE = 3;
private static final Color BACKGROUND = Color.BLACK;
private static final int TIMER_DELAY = 20;
private Timer swingTimer;
public Game2() {
setBackground(BACKGROUND);
swingTimer = new Timer(TIMER_DELAY, new TimerListener());
swingTimer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// TODO: add any custom painting here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W * SCALE, PREF_H * SCALE);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO add code that gets called in game loop
}
}
private static void createAndShowGui() {
Game2 mainPanel = new Game2();
JFrame frame = new JFrame("Game2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Note that this code is based on your stated requirements and what I'm guessing are other requirements based on your code. If there are further requirements not mentioned, please elaborate them for us.
Try using g.dispose(); followed by bs.show(); and then
g = (Graphics2D)bs.getDrawGraphics();. I know it looks weird, but you are emptying the canvas and then refilling it using your strategy. You may also need to do an initial check for g being null and initialize it before the first display loop.