I am running this simple code to display a window in eclipse using lwjgl:
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
#SuppressWarnings("unused")
public class DisplayExample {
public void start() {
try {
Display.setDisplayMode(new DisplayMode(1920, 1080));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(0);
}
// init OpenGL here
while (!Display.isCloseRequested()) {
// render OpenGL here
Display.update(); //flushes OpenGL pipeline and swaps back and front buffers. perhaps waits for v-sync.
}
Display.destroy();
}
public static void main(String[] argv) {
DisplayExample displayExample = new DisplayExample();
displayExample.start();
}
}
However the screen appears like this and is flickering:
http://tinypic.com/r/33upp2u/6
This is running on a mac, any ideas what is going wrong?
You aren't clearing the screen before you update the display. Add GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); before // render OpenGL here. You also need to import the org.lwjgl.opengl.GL11 class for this.
Related
https://github.com/terryaa/KOSTA_MAC/tree/master/Java/NetBeans/day13_01_15/src/ex1
What I'm trying to do is to draw circles, but one circle on a canvas at a time and then moving on to drawing next circle using Runnable join. It should draw a circle using .start() and the other .start() shouldn't start until formal .start()'s drawing circle is done.
In linked page's package, Ex3_Canvas1 class has main and use Runnable MyThread0 class to draw a circle using basic .start() and .join() and it does perfectly what I want.
I created NetBean's automatic JFrame class Ex2_CanvasDemo and tried to do the same and failed. JFrame window pops up after drawing a full circle and then shows creating of next circle. What I want is that the window should first appear and it shows creation of both circles ,not simulataneously but sequently, like Ex3_Canvas1.
I guess it's because main thread waits for th(Ex2_CanvasDemo) to finish so window doesn't apply for changes. But shouldn't Ex1_Canvas1 should do the same? Is this differences due to automatically generated code by netbeans? How can I do the same as Ex1_Canvas1 in Ex2_CanvasDemo.
I tried making a Runnable class and used in Ex2_CanvasDemo but failed also..
Any help?
I'm using jdk 8 and netbeans8 on mac.
--Thread part of Ex2_CanvasDemo--
public Ex2_CanvasDemo() {
initComponents();
Thread th=new Thread(new Runnable() {
#Override
public void run() {
for(int i=0;i<370;i+=10){
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
arcNUm=i;
System.out.println("circle"+arcNUm);
canvas1.repaint();
}
}
});
th.start();
try {
th.join();
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
th=new Thread(new Runnable() {
#Override
public void run() {
for(int i=0;i<370;i+=10){
System.out.println("circle"+i);
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
arcNum2=i;
canvas2.repaint();
}
}
});
th.start();
// try {
// th.join();
// } catch (InterruptedException ex) {
// Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
// }
}
Caveat
Animation is hard, good animation is really hard. You need to repeat this to yourself, because animation done right is, really hard.
What you need to know...
Animation is basically the illusion of change over time. Very rarely do you want to perform linear animation, animation is normally done over a period of time, as it allows for performance difference in the platform to be smoothed out in away which is not as harsh to the user.
Swing is single threaded and not thread safe. This means that you should not block the event dispatching thread and that you must only update the UI from within the context of the event dispatching thread.
See Concurrency in Swing for more details
This makes life a little difficult, as you can't simply run a linear loop in the EDT, as this will block the UI and it's difficult to do it from a Thread because it's a mess of synchronisation.
One of the simplest solutions is to make use of the available API and use a Swing Timer, which acts as a pseudo loop, putting in a small delay between call backs, in which you can perform some operations
Example...
While there are a number of ways you might approach this, I've set up a simple List which contains a bunch of Animatables which "do stuff" and then simply run one after the other in serial.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
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();
}
TestPane testPane = new TestPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(testPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
testPane.play();
}
});
}
});
}
public class TestPane extends JPanel {
private List<Animatable> animations;
private Animatable animation;
private Timer timer;
public TestPane() {
animations = new ArrayList<>(25);
animations.add(new CircleAnimation(Color.RED));
animations.add(new CircleAnimation(Color.BLUE));
timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (animation == null) {
animation = animations.remove(0);
}
if (animation.update(getBounds())) {
if (animations.isEmpty()) {
((Timer)e.getSource()).stop();
} else {
animation = animations.remove(0);
}
}
repaint();
}
});
}
public void play() {
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (animation != null) {
Graphics2D g2d = (Graphics2D) g.create();
animation.paint(g2d);
g2d.dispose();
}
}
}
public interface Animatable {
public boolean update(Rectangle bounds);
public void paint(Graphics2D g2d);
}
public class CircleAnimation implements Animatable {
private Color color;
private Ellipse2D circle;
private double delta = -1;
public CircleAnimation(Color color) {
this.color = color;
}
#Override
public boolean update(Rectangle bounds) {
if (circle == null) {
circle = new Ellipse2D.Double(bounds.width, (bounds.height / 2) - 10, 20, 20);
}
Rectangle rect = circle.getBounds();
rect.x += delta;
circle.setFrame(rect);
return rect.x + 20 < bounds.x;
}
#Override
public void paint(Graphics2D g2d) {
if (circle == null) {
return;
}
g2d.setColor(color);
g2d.fill(circle);
}
}
}
I have a problem with a task that seemed to be pretty easy. I have to create a program that will show images (.jpg,.png and .gif) consecutively. Images have to be the contents of some files, that is given as an argument to the program. When I have to load the images separately, it works, but the issue occurs when I load them one after another with a sleep between them.
Here is my code:
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new MyFrame(args[0],Integer.parseInt(args[1]));
//First argument is path to file with images, second - amount of time (in seconds) which every image has to stay on the screen until the next one appears
}
});
}
}
import java.io.File;
import javax.swing.*;
public class MyFrame extends JFrame{
public MyFrame(String path, int time){
super("Obrazki");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
MyPanel panel = new MyPanel();
panel.setVisible(true);
this.add(panel);
pack();
File file = new File(path);
String[] tabs = file.list();
for(int i=0; i<tabs.length; i++)
{
panel.loadImage(path+"\\"+tabs[i]);
this.repaint();
try {
Thread.sleep(time*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import javax.swing.JPanel;
public class MyPanel extends JPanel
{
Image img;
public void loadImage(String s)
{
img = Toolkit.getDefaultToolkit().getImage(s);
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(img, 1);
while(!tracker.checkID(1)) {
try {
tracker.waitForID(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.repaint();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.drawImage(this.img, 0, 0, this.getSize().width, this.getSize().height, this);
}
}
but the issue is when i load them one after another with sleep time between them.
You are causing the Event Dispatch Thread (EDT) to sleep, which means the GUI can't respond to events or repaint itself. Read the section from the Swing tutorial on Concurrency for more information.
Don't use Thread.sleep() when code is executing on the EDT.
For animation you can:
use a SwingWorker (with Thread.sleep())and publish the Icon you want to paint, or
use a Swing Timer. The tutorial also has a section on How to Use Swing Timers.
I have strange problem when running my Java program.
It's designed to:
run external app specified in bat file and display fullscreen wallpaper
"hide" wallpaper for some time when buttons combination pressed
warn user that 5sec left so he can save work
when timeout occures display again fullscreen wallpaper and do some other stuff from bats
quit program when button combination pressed
warinng user is realized as displaying fullscreen red box for 200ms
I'm using visible function to do this.
It shows standard fullscreen frame discaring color settings. but only when I comment frame.setUndecorated(true). when uncommented I see only icon in taskbar.
On the other hand when I launch (Using BlueJ) only function visible
the red frame is displayed for specified amount of time. Simply standalone function works perfectly (in my oppinion) even if frame.setUndecorated(true) is used .
what can be wrong that I can't launch that red frame in fullscreen?
olympicApp class:
import java.awt.*;
import java.awt.Color;
import java.awt.event.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Graphics;
import java.awt.image.*;
import java.io.*;
import java.io.IOException;
import javax.imageio.*;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComponent;
public class olympicApp extends JComponent {
alertApp alert;
BufferedImage img;
public olympicApp()
{
try
{
img = ImageIO.read(new File("wallpaper.jpg"));
}
catch (IOException e)
{
}
}
public void paint(Graphics g)
{
g.drawImage(img, 0, 0, null);
}
public Dimension getPreferredSize()
{
if (img == null)
{
return new Dimension(200,200);
}
else
{
return new Dimension(img.getWidth(null), img.getHeight(null));
}
}
public static void visible()
{
JFrame frame = new JFrame();
frame.getContentPane().setBackground(Color.red);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.dispose();
//frame.setUndecorated(true);
frame.setAlwaysOnTop(true);
frame.pack();
frame.setVisible(true);
try
{
frame.setVisible(true);
Thread.sleep(500);
frame.setVisible(false);
}
catch(Exception ex)
{
}
frame.setAlwaysOnTop(false);
frame.setVisible(false);
}
public static void main(String[] args)
{
//alertApp reminder = new alertApp();
try
{
Process process = Runtime.getRuntime().exec("start-lv.bat");
Thread.sleep(500);
}
catch (IOException | InterruptedException e)
{
}
JFrame f = new JFrame("olympic");
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setUndecorated(true);
f.setAlwaysOnTop(true);
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
f.add(new olympicApp());
f.pack();
f.setVisible(true);
f.addKeyListener(new KeyListener()
{
public void keyPressed(KeyEvent kevt)
{
if(kevt.getKeyChar()=='l')
{
if(kevt.isAltDown())
{
f.setAlwaysOnTop(false);
f.setVisible(false);
try
{
Thread.sleep(5*1000);
visible();
Thread.sleep(5*1000);
//Process process = Runtime.getRuntime().exec("saving.bat");
Thread.sleep(500);
f.setAlwaysOnTop(true);
f.setVisible(true);
Process process2 = Runtime.getRuntime().exec("kopia.bat");
}
catch(IOException | InterruptedException e)
{
}
}
}
if(kevt.getKeyChar()=='q')
{
if(kevt.isAltDown())
{
System.exit(0);
}
}
}
public void keyTyped(KeyEvent kevt)
{
}
public void keyReleased(KeyEvent kevt)
{
}
});
}
}
I would imagine that you're going to have to do something in here...
public class alertApp {
public static void main(String[] args) {
// Sample loop to flash every 2 seconds
}
}
This is called when your program starts and where you should put the code to get the program running
I would also strogly recommend that you take a look at Code Conventions for the Java TM Programming Language, it will make it easier for people to read your code and for you to read others
As well as Concurrency in Swing and How to use Swing Timers which will help you solve other potential issues
I put neccessary code in visible funciton. I can see the frame but color information is discarted. Thanks for Concurrency and Timers, but I think the problem isn't connected to thread.sleep()
Then you didn't read the links...
public void keyPressed(KeyEvent kevt) {
if (kevt.getKeyChar() == 'l') {
if (kevt.isAltDown()) {
f.setAlwaysOnTop(false);
f.setVisible(false);
try {
Thread.sleep(5 * 1000);
visible();
Thread.sleep(5 * 1000);
//Process process = Runtime.getRuntime().exec("saving.bat");
Thread.sleep(500);
f.setAlwaysOnTop(true);
f.setVisible(true);
Process process2 = Runtime.getRuntime().exec("kopia.bat");
} catch (IOException | InterruptedException e) {
}
}
}
keyPressed is executed within the context of the Event Dispatching Thread, so when you call Thread.sleep, it prevents the EDT from processing the Event Queue, preventing it from painting or responding to other events
I recevie 0 errors but I get this in the console:
>Exception in thread "main" java.lang.NullPointerException
>>at org.lwjgl.opengl.GL11.glMatrixMode(GL11.java:2052)
>>>at game.engine.GameLoop.start(GameLoop.java:22)
>>>>at game.engine.GameLoop.main(GameLoop.java:15)
I tried to put the actual value into "glMatrixMode()" instead of "GL11.GL_PROJECTION" but it returns same Exception.
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Display;
public class GameLoop
{
//Main
public static void main(String[] argv)
{
GameLoop.start();
}
//Metodo che gestisce il loop
public static void start()
{
//Inizializzazione OpenGL
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 600, 0, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
try
{
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create();
} catch (LWJGLException e)
{
e.printStackTrace();
System.exit(0);
}
while(!Display.isCloseRequested())
{
Entità.pulisci();
Entità.colora();
Entità.disegna();
Display.update();
}
}
}
import org.lwjgl.opengl.GL11;
public class Entità
{
//Disegna un poligono
public static void disegna()
{
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(100,100);
GL11.glVertex2f(200,100);
GL11.glVertex2f(200,200);
GL11.glVertex2f(100,200);
GL11.glEnd();
}
//Pulisce il buffer
public static void pulisci()
{
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
}
//Setta il colore al poligono
public static void colora()
{
GL11.glColor3f(0.5f,0.5f,1.0f);
}
}
I don't have any experience with Java or LWJGL, but from looking at your code it seems
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create();
creates the actual display canvas (or however you may call it) which also sets up the OpenGL context. Thus calling any OpenGL function (like GL11.glMatrixMode) before those is likely to result in some error, as in your case a null pointer exception.
So try to put those four functions after the display creation. You are making changes to the OpenGL context, thus you first need a valid context.
My ultimate goal is to be able to make use of additional mouse buttons in Java. Currently, LWJGL's JInput doesn't seem capable of detecting more than three buttons. To make use of Java's System.setProperty("sun.awt.enableExtraMouseButtons", "true"), I've tried mounting the Display onto an AWT Canvas, within a JFrame. Unfortunately, this does not appear to work, and I am unsure why. [I should note that I've been away from Java for a some time]
import java.awt.Canvas;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
public class MainCanvas extends Canvas implements MouseListener
{
private static final long serialVersionUID = 1L;
public void mouseClicked(MouseEvent e)
{
System.out.println(e.getButton());
}
public void mouseEntered(MouseEvent e)
{
System.out.println(e.getButton());
}
public void mouseExited(MouseEvent e)
{
System.out.println(e.getButton());
}
public void mousePressed(MouseEvent e)
{
System.out.println(e.getButton());
}
public void mouseReleased(MouseEvent e)
{
System.out.println(e.getButton());
}
public void init()
{
}
public static void main(String[] args)
{
MainCanvas mainCanvas = new MainCanvas();
JFrame mainFrame = new JFrame("Simplify");
mainFrame.setSize(640, 480);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.getContentPane().add(mainCanvas);
mainFrame.setVisible(true);
mainCanvas.addMouseListener(mainCanvas);
try
{
DisplayMode mainDisplay = new DisplayMode(640, 480);
Display.setDisplayMode(mainDisplay);
Display.setParent(mainCanvas);
Display.create();
}
catch (LWJGLException le)
{
System.out.println("Oh dear.");
}
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 640, 480, 0, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
while (!Display.isCloseRequested())
{
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glColor3f(0.5f,0.5f,1.0f);
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(100,100);
GL11.glVertex2f(100+200,100);
GL11.glVertex2f(100+200,100+200);
GL11.glVertex2f(100,100+200);
GL11.glEnd();
Display.update();
}
Display.destroy();
}
}
I spoke with the fellows in the FreeNode IRC some months back. The gist is because the canvas is a heavyweight component, events would not rise to the JFrame level. A Frame has to be used in its stead.
Basically, the answer is you can't: i.e with lwjgl 2.8.2 on Windows only.
The reason is that the Windows implementation of lwjgl clobbers a key data structure that AWT requires for event handling.
http://www.java-gaming.org/topics/cannot-add-mouselistener-to-java-awt-canvas-with-lwjgl-on-windows/24650/msg/208505/view.html#msg208505
Try adding the mouse listener to the JFRame instead. I ran into this before, and I think that's how I solved it.