NullPointerException in simple JOGL test case - java

I'm trying a very simple JOGL tutorial using NetBeans and Swing and it seems no matter how I arrange things I keep getting a null pointer exception. Here is the code I am using (adapted from a tutorial):
package testjogl;
import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.GLCanvas;
import java.awt.Dimension;
public class OpenGLTest extends javax.swing.JFrame implements GLEventListener {
public OpenGLTest() {
initComponents();
}
public void doMain() {
GLCanvas canvas = new GLCanvas();
canvas.addGLEventListener(this);
canvas.setPreferredSize(new Dimension(640, 480));
this.getContentPane().add(canvas); // <--- This is where the exception happens
this.pack();
this.setVisible(true);
}
#Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
#Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { }
#Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
}
#Override
public void dispose(GLAutoDrawable drawable) { }
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new OpenGLTest().doMain();
}
});
}
// Variables declaration - do not modify
// End of variables declaration
}
At the line where I add the canvas to my form, I get:
Exception java.lang.NullPointerException(null) breakpoint hit in sun.awt.image.OffScreenImageSource at line 189 by thread AWT-EventQueue-0.
I've tried several different JOGL tutorials and all of them keep throwing this exception when I add the canvas to my form. I couldn't find the code to OffScreenImageSource, but when I step through, it dies at line 1119 in Container.java. The code is:
invalidateIfValid();
if (peer != null) {
comp.addNotify(); // <---- Dies right here
}
Does anyone have any ideas as to what might be causing this?

Your problem is you don't give enough time for Swing to initialize the component correctly with the OS GDI: As soon as you create the OpenGLTest() instance, you call doMain(). Give Swing some breath and it should work.
public static void main(String args[]) {
OpenGLTest test;
java.awt.EventQueue.invokeLater(() -> {
test = new OpenGLTest()
});
java.awt.EventQueue.invokeLater(() -> {
test.doMain();
});
}
FYI, I didn't validate the syntax.

Related

isDisplayable(),isShowing(),isVisible() giving wrong values for JDialog

Env:
OS: Win 10
IDE: Netbeans 8.1
Java: JDK 1.8u112 Oracle
jre: 10.0.2
JTattoo laf: HiFiLookAndFeel from http://www.jtattoo.net/
Context:
Creating a Look And Feel ("laf") switching class.
Desc:
There is a class A ("A") that extends JFrame("frame"). It has some GUI components like a JFileChooser("fc"), buttons etc. Its main("main") method comprises of making (inside the EDT via Swingutilities.invokeLater()("swingU")) an instace of A, setting A visible then invoking a doClick on a button(placed in the frame) that calls fc.showOpenDilaog(this). At this point a frame and fc are visible on screen.
Coming back to the main. swingU returns to main. A delay of ~3 seconds is cretaed(see code) then the laf change is caused.
laf change is caused via another class called changer. It has a method called change, that
obtains all open windows via Window.getWindows()
sorts them into Jframes, JDialogs("dialog") and remaining into Windows by checking if their class has JFrame or JDialog as a superclass.
For each dialog records its visibility,sets a titlebar, disposes it, updates its UI then restores it as per its original visibility(see code)(not related but code also does the same for the frames)
The above steps themselves are exeecuted on the EDT via swingU.
Problem:
The laf change causes fc to disappear while A stays visible with the new laf.
Expected:
both fc and A should stay visible exhibiting the new laf.
Headway into the problem:
Used System.out.println("sop")(inside change method) to show the
dialog's isDisplayable(),isShowing(),isVisible(). All of these
returned false inspite of the fact that fc was clearly visible. After loooking into their source("src"), used the
dialog.getParent()(this returned A) and soped its
isDisplayable(),isShowing(),isVisible().These returned true. Doesn't make sense!
fc.showOpenDilaog(null) makes the problem disappear.
Even tried to look through sun.awt.AppContext--could't make heads or tails.
Catch:
The changer class can't access the memebers of A e.g. fc is private in A so is button...for all intents an purposes changer doesn't know the identitiy of the frame/dialog its analyzing.
The only thing special about the given configuration of lafs(from WindowsLookAndFeel to HiFiLookAndFeel) is that the later returns true for getSupportsWindowDecorations()
Upon Andrew's advice, the SSCE
import com.jtattoo.plaf.hifi.HiFiLookAndFeel;
import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
import java.awt.Container;
import java.awt.Window;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class A extends javax.swing.JFrame {
public A()
{
initComponents();
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jFileChooser1 = new javax.swing.JFileChooser();
button = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
button.setText("jButton1");
button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
buttonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(128, 128, 128)
.addComponent(button)
.addContainerGap(195, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(71, 71, 71)
.addComponent(button)
.addContainerGap(197, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
jFileChooser1.showOpenDialog(this);
//jFileChooser1.showOpenDialog(null) has no problem
}
public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, InterruptedException, InvocationTargetException {
UIManager.setLookAndFeel(new HiFiLookAndFeel());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
A x = new A();
x.setVisible(true);
x.button.doClick();
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
Thread.sleep(3000);
changer.change(new WindowsLookAndFeel());
}
// Variables declaration - do not modify
private javax.swing.JButton button;
private javax.swing.JFileChooser jFileChooser1;
// End of variables declaration
}
class changer {
public static void change(LookAndFeel laf) throws UnsupportedLookAndFeelException, InterruptedException, InvocationTargetException {
UIManager.setLookAndFeel(laf);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ArrayList<JFrame> frames = new ArrayList<>();
ArrayList<JDialog> dialogs = new ArrayList<>();
ArrayList<Window> winds = new ArrayList<>();
Window[] wins = Window.getWindows();
if (wins == null || wins.length == 0) {
return;
}
for (int i = 0; i < wins.length; i++) {
Class cls = wins[i].getClass();
if (JFrame.class.isAssignableFrom(cls)) {
frames.add((JFrame) wins[i]);
} else if (JDialog.class.isAssignableFrom(cls)) {
dialogs.add((JDialog) wins[i]);
} else {
winds.add(wins[i]);
}
}
boolean initialState = false;
if (frames.size() > 0) {
for (JFrame fr : frames) {
fr.getRootPane().setWindowDecorationStyle(JRootPane.NONE);
initialState = fr.isVisible();
fr.dispose();
fr.setUndecorated(false);
SwingUtilities.updateComponentTreeUI(fr);
fr.pack();
fr.setVisible(initialState);
}
}
if (dialogs.size() > 0) {
for (JDialog dia :dialogs) {
dia.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
Container par = dia.getParent();
sop("par----");
sop(par);
sop("disp:" + par.isDisplayable());
sop("vis:" + par.isVisible());
sop("show:" + par.isShowing());
sop("dia----");
sop("disp:" + dia.isDisplayable());
sop("vis:" + dia.isVisible());
sop("show:" + dia.isShowing());
initialState = dia.isVisible();
dia.dispose();
dia.setUndecorated(false);
SwingUtilities.updateComponentTreeUI(dia);
dia.pack();
dia.setVisible(initialState);
}
}
}
});
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}

JButton can't enabled, when exdending GUI form

I have four small class: one extends from JFrame and has GUI form, second — extends from him and contains button work logic. Third class call second's class method, when second — call him :)). My problem in second method in second class: button can't enable! I click — it disabled, but, when calling method enableButton — nothing do!
First class:
public class ClassParent extends JFrame {
protected JButton button;
private JPanel mainJPanel;
public ClassParent() {
super("Window");
setContentPane(mainJPanel);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public void showWindow() {
setVisible(true);
}
}
Second class:
public class ClassChildren extends ClassParent {
private CallerClass callerClass;
public ClassChildren(CallerClass callerClass) {
super();
this.callerClass = callerClass;
callerClass.setClassChildren(this);
button.addActionListener(a -> {
callerClass.callMe();
button.setEnabled(false);
});
}
public void enableButton() {
button.setEnabled(true);
}
}
Third class:
public class CallerClass {
private ClassChildren classChildren;
public void setClassChildren(ClassChildren classChildren) {
this.classChildren = classChildren;
}
public void callMe() {
classChildren.enableButton();
}
}
Main class:
public class Main {
public static void main(String[] args) {
new ClassChildren(new CallerClass()).showWindow();
}
}
And GUI form photo (I can't find code, other than open it in notepad :)):
Why is this happening and how fix it?
Apparently the OP has solved his problem, but I think this is an interesting and common-enough problem, so I've created a Minimal, Complete and Verifiable Example of what my recommended approach would be, for future reference.
You can check it out below, or you can get the full project from the GitHub repository.
(Reviews, suggestions, revisions and feedback are also welcome!)
Main JFrame:
/**
* #author Rodrigo Legendre Lima Rodrigues (AKA ArchR / AlmightyR)
* <rodrigolegendre.developer#gmail.com>
*/
public class Main extends javax.swing.JFrame {
/**
* A public method so we can enable/disable state from outside the class
* (while keeping the components encapsulated).
*
* #param enabled The input state the components should assume.
*/
public void setInputState(boolean enabled) {
this.startProcessButton.setEnabled(enabled);
}
/**
* Creates new form Main
*/
public Main() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
startProcessButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Primary Frame");
startProcessButton.setText("Process");
startProcessButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
startProcessButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(startProcessButton, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(startProcessButton)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
#SuppressWarnings("Convert2Lambda")
private void startProcessButtonActionPerformed(java.awt.event.ActionEvent evt) {
//We need a non-annonymous reference for this frame to use within our annonymous 'run()'.
Main main = this;
//Here is were we disable input for (the components of) this frame before running the secondary frame.
this.setInputState(false);
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Secondary(main).setVisible(true);
}
});
}
/**
* #param args the command line arguments
*/
#SuppressWarnings("Convert2Lambda")
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Main().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton startProcessButton;
// End of variables declaration
}
Secondary JFrame:
/**
*
* #author Rodrigo Legendre Lima Rodrigues (AKA ArchR)
* <rodrigolegendre.developer#gmail.com>
*/
public class Secondary extends javax.swing.JFrame {
/**
* A variable to hold a reference to the main frame. We need this to enable
* the input of main again after this frame's work is done.
*/
private Main main;
/**
* A self-reference to this frame. We need this to hide the frame from
* within the worker, after it's job is done.
*/
private Secondary secondary;
/**
* A SwingWorker executes a process without interfering with the UI's
* execution, which could otherwise cause delays or complete "locking" of
* the visual and input processes.
*/
SwingWorker<Integer, Integer> swingWorker = new SwingWorker<Integer, Integer>() {
#Override
#SuppressWarnings("SleepWhileInLoop")
protected Integer doInBackground() throws Exception {
//Execute the process...
for (int i = 0; i <= 100; i++) {
progressBar.setValue(i);
Thread.sleep(100);
}
//We handle reactivating the main frame's inputs on the closing event,
//to make sure they get enabled after this frame is closed,
//regardless of sucess, cancelation or failure.
//We close and dispose of the secondary frame.
//Note: We have set default close behavior for this frame to be disposing, so we simply send it a closing event.
secondary.dispatchEvent(new WindowEvent(secondary, WindowEvent.WINDOW_CLOSING));
//Alternatively:
//main.setInputState(true);
//secondary.setVisible(false);
//secondary.dispose();
return 100;
}
};
/**
* In order to start the process while keeping all related code contained
* within this class, we make it listen to it's own WindowOpened event.
*
* In order to avoid calling an overridable method ('addListener()') from
* the constructor, which could be "forgotten" on extensions, we create a
* private method to initialize all self-listeners.
*/
private void initSelfListeners() {
WindowListener taskStarterWindowListener = new WindowListener() {
#Override
public void windowOpened(WindowEvent e) {
//This starts the process when the window opens.
System.out.println("Performing task...");
swingWorker.execute();
}
//<editor-fold defaultstate="collapsed" desc="UNUSED EVENTS/METHODS">
#Override
public void windowClosing(WindowEvent e) {
//Do nothing.
}
#Override
public void windowClosed(WindowEvent e) {
//Do nothing.
}
#Override
public void windowIconified(WindowEvent e) {
//Do nothing.
}
#Override
public void windowDeiconified(WindowEvent e) {
//Do nothing.
}
#Override
public void windowActivated(WindowEvent e) {
//Do nothing.
}
#Override
public void windowDeactivated(WindowEvent e) {
//Do nothing.
}
//</editor-fold>
};
//Here is where the magic happens. We make (a listener within) the frame start listening to the frame's own WindowOpened event.
this.addWindowListener(taskStarterWindowListener);
}
/**
* Creates new form Secondary
*/
#SuppressWarnings("LeakingThisInConstructor")
private Secondary() {
initComponents();
initSelfListeners();
this.secondary = this;
}
public Secondary(Main main) {
this();
this.main = main;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
processingLabel = new javax.swing.JLabel();
progressBar = new javax.swing.JProgressBar();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Secondary Frame");
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
});
processingLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
processingLabel.setText("Processing...");
progressBar.setStringPainted(true);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(processingLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(processingLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void formWindowClosing(java.awt.event.WindowEvent evt) {
//When the window is closed, we enable the input in the main frame again.
//This is advantageous as it handles most cases in one go...
//The cases were the window closes after the process is complete,
//the cases there the window closes due to cancelation,
//or the cases where it is closed by the user (after an error message) after a failure.
main.setInputState(true);
}
/**
* #param args the command line arguments
*/
#SuppressWarnings("Convert2Lambda")
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Secondary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Secondary().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JLabel processingLabel;
private javax.swing.JProgressBar progressBar;
// End of variables declaration
}
Problem was in that I call firstly callMe() and enable buttons and then — I disabled they in listeners......

I'm trying to make chart with a string of number but if I try to repaint my paintComponent(Graphics g) method won't be called

I'm trying to make chart with a string of number but if I try to repaint my paintComponent(Graphics g) method won't be called. I debugged the file and i really don't understand why this happens. This class extends JPanel and the method: "verwerkData(String s)" is called when I press a button on my JFrame.
Try-catch is used because when I start the program paintComponent(Graphics g) is called and "punt" and "punti" aren't initialized yet that's why i throw a NullPointerException.
package grafiek;
import java.awt.Graphics;
public class Grafiek extends javax.swing.JPanel {
private String[] punt;
private int[] punti;
private int afstandX, afstandY, puntX1=0, puntY1=0, puntX2=0, puntY2=0;
private int max=0;
/**
* Creates new form Grafiek
*/
public Grafiek() {
initComponents();
}
#Override
public void paintComponent(Graphics g) {
try{
for(int i=0; i<punti.length; i++) {
if(max >= punti[i]) {
max = punti[i];
}
}
afstandX = getWidth()/punt.length;
afstandY = getHeight()/max;
for(int i=0; i<punti.length; i++) {
puntX1 = puntX2;
puntY1 = puntY2;
puntX2 += afstandX;
puntY2 = punti[i]*afstandY;
System.out.println(puntX1+" "+puntY1+" "+puntX2+" "+puntY2);
g.drawLine(puntX1, puntY1, puntX2, puntY2);
}
}catch(java.lang.NullPointerException npe) {
super.paintComponent(g);
}
}
public void verwerkData(String s) {
punt = s.split(" ");
punti = new int[punt.length];
for(int i=0; i<punt.length; i++) {
punti[i] = Integer.parseInt(punt[i]);
}
repaint();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setBackground(new java.awt.Color(204, 204, 204));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
}// </editor-fold>
}
EDIT : When you call repaint(), you only tell the system to call paintComponent() as soon as possible. But the actual call to paintComponent() is done by another thread (the Event dispatch thread). This is explained well in the Swing Custom Painting Tutorial
The computation of max was wrong: max remained zero, which caused an ArithmeticException due to division by zero. This may already have messed up some things. Fixing this and inserting a main method caused the program to run properly for me, and to display the data... somehow.
Apart from that: NEVER catch a NullPointerException. Instead, check whether the respective variables are null, and skip further computations if necessary.
The initComponents method is useless here (I don't really like these "Visual GUI Builders", but some may find them convenient).
Another very general hint: You should try to keep the scope of variables as small as possible!. Particularly, the variables afstandX .... puntY2 are only needed in paintComponent. So you should also declare them in paintComponent.
Your way of drawing the lines was not perfect. It worked partially, but some variables have not been reset to zero (which is related to the previous point that I mentioned), and the fact that all computations are made with int values may have undesirable effects.
A slightly cleaned up MCVE. One could go very far with further improvements, but then, this answer would become "A tutorial for writing a line-chart plotter", which is beyond the scope that such an answer should have. If you want to draw sophisticated line charts, you should consider using an appropriate library, as it was already suggested in the comments.
package stackoverflow;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Grafiek extends javax.swing.JPanel {
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Grafiek g = new Grafiek();
g.verwerkData("50 100 60 90 70 80");
f.getContentPane().add(g);
f.setSize(300,300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private String[] punt;
private int[] punti;
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
System.out.println("paintComponent is being called!");
if (punt == null || punti == null)
{
return;
}
int max = Integer.MIN_VALUE;
for(int i=0; i<punti.length; i++) {
if(max < punti[i]) {
max = punti[i];
}
}
int afstandX = getWidth()/(punt.length-1);
int afstandY = getHeight()/max;
int puntX1 = 0;
int puntY1 = punti[0] * afstandY;
for(int i=1; i<punti.length; i++) {
int puntX2 = puntX1 + afstandX;
int puntY2 = punti[i]*afstandY;
System.out.println(puntX1+" "+puntY1+" "+puntX2+" "+puntY2);
g.drawLine(puntX1, puntY1, puntX2, puntY2);
puntX1 = puntX2;
puntY1 = puntY2;
}
}
public void verwerkData(String s) {
punt = s.split(" ");
punti = new int[punt.length];
for(int i=0; i<punt.length; i++) {
punti[i] = Integer.parseInt(punt[i]);
}
repaint();
}
}

Java paint only updates when the window (un?)focuses

I'm having a little problem with my Java code. For a school project, we have to write a simple Java program. I have some programming experience, but not with Java.
We're using Netbeans, and we have to make a JFrame, containing a panel containing an applet. The applet should be a simple traffic light (red/orange/green), and the JFrame should contain three buttons "Red", "Orange" and "Green", which should update the traffic light.
I got most of it working: I have an applet that draws the traffic light based on the booleans red, orange and green, and the updating using the buttons works too.
The problem is that the screen only redraws when I hide the window behind others, and then make it appear again. I have very limited understanding of how painting works in Java, and I can't really find any solutions for this problem on the internet. Can anyone help me?
Here's my code:
DeFrame.java
package my.AppletInPanel;
public class DeFrame extends javax.swing.JFrame {
private DeApplet applet;
/** Creates new form DeFrame */
public DeFrame() {
initComponents();
applet = new DeApplet();
jPanel1.add(applet);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// [Generated code]
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
applet.SetDaColor(true, false, false);
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
applet.SetDaColor(false, true, false);
}
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
applet.SetDaColor(false, false, true);
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DeFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JButton jButton3;
private javax.swing.JPanel jPanel1;
// End of variables declaration
}
And DeApplet.java:
package my.AppletInPanel;
import java.applet.Applet;
import java.awt.*;
public class DeApplet extends Applet {
public boolean rood = true, oranje = false, groen = false;
public DeApplet(){
setLayout(null);
setSize(50, 150);
}
public void SetDaColor(boolean r, boolean o, boolean g){
rood = r;
oranje = o;
groen = g;
}
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.white);
g.drawRect(0, 0, 50, 150);
g.fillRect(0, 0, 50, 150);
if(rood){
g.setColor(Color.red);
g.fillOval(0 , 0, 50 ,50);
}
if (oranje){
g.setColor(Color.orange);
g.fillOval(0 , 50, 50 ,50);
}
if (groen){
g.setColor(Color.green);
g.fillOval(0 , 100, 50 ,50);
}
String s1 = (new Boolean(rood).toString());
String s2 = (new Boolean(oranje).toString());
String s3 = (new Boolean(groen).toString());
g.setColor(Color.black);
g.drawString(s1, 25, 25);
g.drawString(s2, 25, 75);
g.drawString(s3, 25, 125);
}
}
try repainting the panel and/or the frame
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
applet.SetDaColor(false, true, false);
applet.repaint();
}
You should have a look at Java Swing revalidate() vs repaint(), which discusses methods of importance to you.
Since this is for school, I would also like to point out that your "which color to show" logic would be greatly improved by use of Java Enums, where you could not wind up in the weird state that e.g. groen and rood are both true at the same time.

How to pause and resume a simple game in Java

i made simple game by java , it's about "tennis background" and "tennis ball" , and the ball is randomally move automatically ,
my game consist of two file , 1st file fore Jpanel , and 2nd file for JFrame ,
my question is : i need to control of "stopping and resuming" the ball by clicking the mouse ,
i tried to put wait() during thread running loop , but it's faild , i don't know what is the reason ! , so please review my code and then tell me what is the wrong , and what is the true method of "pause&resume" thread in my simple game !
tennis.java file (which contain the thread):
/*
* tennis.java
*
* Created on Nov 15, 2011, 3:35:28 PM
*/
package io;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
public class tennis extends javax.swing.JPanel implements Runnable{
BufferedImage ball;
BufferedImage bg;
int ball_h = 0;
int ball_w = 0;
int height = 0;
int width = 0;
int yPos = -1;
int xPos = 10;
int pause = 20;
// Move Speed
int xMov = 5;
int yMov = 10;
boolean clicked = false;
int play = 0;
Thread runner;
/** Creates new form tennis */
public tennis() throws IOException {
ball = ImageIO.read(new File("tennis/ball.png"));
bg = ImageIO.read(new File("tennis/bg.jpg"));
ball_h = 50;
ball_w = 50;
height = 600 - ball_h;
width = 800 - ball_w;
runner = new Thread(this);
runner.start();
}
public void start(){
if(play == 0){
play = 1;
clicked = true;
}else{
play = 0;
clicked = true;
}
System.out.println(play);
}
public void stop(){
runner = null;
}
#Override
public void paint(Graphics g){
Graphics2D g2D = (Graphics2D) g;
g2D.drawImage(bg, 0, 0, 800,600, this);
g2D.drawImage(ball, xPos, yPos,50,50, this);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
}// </editor-fold>
// Variables declaration - do not modify
// End of variables declaration
#Override
public void run() {
while(runner == runner){
if(xPos >= (width))
{
xMov *= -1;
}
xPos += xMov;
if(xPos < 1)
{
xMov *= -1;
}
if(yPos >= (height-ball_h))
{
yMov *= -1 ;
}
yPos += yMov;
if(yPos < 1)
{
yMov *= -1 ;
}
repaint();
try {
if(play == 1){
Thread.sleep(pause);
}else{
synchronized(this){
while(play == 0){
wait();
}
}
}
} catch (InterruptedException ex) {
Logger.getLogger(tennis.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Tennis3D.java file(frame for starting the game and define the thread) :
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/*
* Tennis3D.java
*
* Created on Nov 15, 2011, 3:42:42 PM
*/
package io;
import io.tennis;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Tennis3D extends javax.swing.JFrame implements MouseListener{
tennis tennis;
/** Creates new form Tennis3D */
public Tennis3D() {
super("Tennis3D");
setSize(800,600);
try {
tennis = new tennis();
add(tennis);
tennis.addMouseListener(this);
} catch (IOException ex) {
Logger.getLogger(Tennis3D.class.getName()).log(Level.SEVERE, null, ex);
}
setVisible(true);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
Tennis3D tennis = new Tennis3D();
}
// Variables declaration - do not modify
// End of variables declaration
#Override
public void mouseClicked(MouseEvent e) {
tennis.start();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
Thank you for your help :)
This is piggy-backing on what Nerdtron wrote in the comment above. Typically a game loop looks like this
while (!game.isOver())
{
if (!game.isPaused())
game.update() // this moves your ball, players, etc
}
Your approach is strange. Most games have a sort of main loop where methods update(deltaTime) and draw() are called sequentially.
Typical main loop:
initGame();
while(!gameOver)
{
readInput();
update(deltaTime);
draw();
}
update(dt) is something like
for(GameObject go : myObjectList)
{
go.update(deltaTime);
}
If you want to skip some objects you could use something like:
for(GameObject go : myObjectList)
{
if(go.isActive())
{
go.update(deltaTime);
}
}
So your task would be trivial if you use game-loop structure like that.
To stop a thread wait()ing you need to call notifyAll() on the same object.
From the Javadoc for Object.wait()
Causes current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
I would suggest you call notifyAll() in a synchronized block when you set play = 1;
A common way to achieve this is by using different states. So when you would put the game on pause it would go in PAUSE state. When resumed it would go back in RUNNING state or some other (more specific) state.
This is done by keeping the state in a variable. The C-way is to define integers like follows:
final int PAUSE = 1;
final int RUNNING = 2;
The Java-way is more like this: (using enums)
public enum State {
RUNNING,
PAUSE
}
Then, in your main loop (run method) you check the state in which the game is at that moment, and perform actions accordingly.
switch(state){
case PAUSE:
Thread.sleep(100);
break;
case RUNNING:
// do something entertaining
break;
}
so, if youre game loop includes a tick method or a particular method that updates the values of all the game objects, you can make a boolean called aused and only update the game values only if !paused.
And you can also use a class that extends Mouse adapter and add a mouselistener to your main class. so whenever the mouse clicked it checks if it is paused of not. if paused it unpauses it, if unpause then it pauses it

Categories

Resources