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);
}
}
Related
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.
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();
}
}
In the code below I would like to write onto JEditorPane the numbers 0 to 10000. However, the JEditorPane does not display anything unless either it is completely done ( printing all 0 to 10000 at once) or when the os gives it time to refresh and display the contents. Either case, the application becomes unresponsive for a while that the user thinks the application has crashed. Is there anyway we can force the jEditorPane to display the updated contents, even if it is still busy ? I tried invokeAndWait but does not help here as we cannot call invokeAndWait from the event dispatcher thread.
In other words, if I replace the Thread.sleep(0) with Thread.sleep(50), it works fine and displays the print of results as they happen, but adding the 50 mill sec delay makes it extremely slow. all I want is to update the JEditorPane from time to time so that the user does not think the application crashed. I prefer to only modify the updateMessages().
Here is my code:
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
public class CMessageWindowStack {
private static final String MESSAGE = "msg";
private JScrollPane scrollPane;
public JEditorPane editorPane;
private HTMLEditorKit kit;
private String msgBuffer=new String("");
private static CMessageWindowStack window=null;
private static JFrame frameContainer=null;
private CMessageWindowStack()
{
editorPane = new JEditorPane ();
editorPane.setEditable(false);
editorPane.setContentType("text/html");
kit = new HTMLEditorKit();
editorPane.setEditorKit(kit);
StyleSheet styleSheet = kit.getStyleSheet();
styleSheet.addRule("."+MESSAGE+" {font: 10px monaco; color: black; }");
Document doc = kit.createDefaultDocument();
editorPane.setDocument(doc);
scrollPane = new JScrollPane(editorPane);
}
public static CMessageWindowStack getInstance(){
if (null==window)
{window=new CMessageWindowStack();}
return window;
}
/**
* The core
* #param sMessage
* #param sType
*/
private void updateMessages(final String sMessage, final String sType)
{
SwingUtilities.invokeLater( new Runnable() {
public void run() {
String sMessageHTML="";
String sTypeText="";
if (!sMessage.equals("\r\n")){
sTypeText = sType+": ";
}
sMessageHTML = sMessage.replaceAll("(\r\n|\n)", "<br/>");
if (!sMessageHTML.equals("<br/>"))
{
sMessageHTML = "<SPAN CLASS="+sType+">"+ sTypeText+sMessageHTML + "</SPAN>";
}
msgBuffer=msgBuffer.concat( sMessageHTML);
editorPane.setText(msgBuffer);
if ((editorPane.getDocument()).getLength()>1){
editorPane.setCaretPosition((editorPane.getDocument()).getLength()-1);
}
}
});
}
public void setContainerFrame(JFrame jFrame){
frameContainer = jFrame;
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(frameContainer.getContentPane());
frameContainer.getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollPane)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 217, Short.MAX_VALUE))
);
}
public void setVisible(boolean bVisible){
editorPane.setVisible(bVisible);
scrollPane.setVisible(bVisible);
}
public void printMsg(String sMessage){
String sType = MESSAGE;
updateMessages(sMessage,sType);
}
public void printlnMsg(String sMessage){
sMessage=sMessage.concat("\r\n");
printMsg(sMessage);
}
public static void main(String args[]){
CMessageWindowStack m_LogMgr;
JFrame frame = new JFrame();
m_LogMgr=CMessageWindowStack.getInstance();
m_LogMgr.setContainerFrame(frame);
frame.setVisible(true);
frame.setSize(500, 500);
for(int i=0;i<10000;++i){
try {
Thread.sleep(0);//becomes unresponsive if sleep(0)
} catch (Exception e) {
}
m_LogMgr.printlnMsg(i+"-----------------------");
}
}
}
You would probably need to use a SwingWorker. Start by initially loading the JEditorPane with your basic HTML. Then you would need to publish each line of data. When the data gets published you would then need to insert the text into the editor pane.
The basic idea is you can't just create an entire HTML string at once.
I've never been able to really understand how to use a JEditorPane with dynamically changing HTML. Maybe you can just use a JTextPane. It supports different fonts and colors and is much easier to update dynamically.
well - as a hack you could try something like this:
for(int i=0;i<10000;++i){
try {
if( i%100 == 0 ) {
Thread.sleep(10);//becomes unresponsive if sleep(0)
}
} catch (Exception e) {
}
m_LogMgr.printlnMsg(i+"-----------------------");
}
You can try using Thread and giving it highest priority. Also, you can add -XmX2020 option to java.exe.
Other solution may be if you use JTextArea instead of JEdiorPane. It seems like all you do with HTML is styling fonts. You can do this using java.awt.Font property on JTextArea.
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
Our application displays a 2D view of our data (mainly maps) and then allows the user to change to a 3D view. The 2D and 3D views are generated by custom C++ code that is SWIG'ed into our Swing GUI and wrapped within a JComponent. These JComponents are then displayed within another parent JComponent.
Our problem is that when we change from the 2D to the 3D view and then back to the 2D view, when we resize the window the 2D view does not get resized. The resize events don't get sent to the 2D view.
Our application runs under Linux (Fedora 11). We're running Java version 1.6.0_12.
Here is some sample code in which I've replaced the 2D view and 3D view with two 2 JButtons, that produces the same behaviour. Once you go to 3D and then back to 2D, resizing the window does not cause the 2D view to be resized.
/* TestFrame.java
* Compile with: $ javac TestFrame.java
* Run with: $ java TestFrame
*/
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.JButton;
public class TestFrame extends javax.swing.JFrame {
private boolean mode2D = true;
private JButton view2D = null;
private JButton view3D = null;
private Container parent = null;
public TestFrame() {
initComponents();
containerPanel.setLayout(new BorderLayout());
view2D = new JButton("2D View");
view2D.addComponentListener(new MyListener("2D VIEW"));
containerPanel.add(view2D);
}
private void changerButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (parent == null) {
parent = view2D.getParent();
}
if (mode2D) {
System.out.println("Going from 2D to 3D");
view2D.setVisible(false);
if (view3D != null) {
view3D.setVisible(true);
} else {
view3D = new JButton("3D View");
view3D.addComponentListener(new MyListener("3D VIEW"));
parent.add(view3D);
}
((JButton) evt.getSource()).setText("Change to 2D");
mode2D = false;
} else {
System.out.println("Going from 3D to 2D");
view3D.setVisible(false);
view2D.setVisible(true);
((JButton) evt.getSource()).setText("Change to 3D");
mode2D = true;
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
private javax.swing.JPanel containerPanel;
private javax.swing.JButton changerButton;
private class MyListener implements ComponentListener {
private String name;
public MyListener(String name) {
this.name = name;
}
#Override
public void componentHidden(ComponentEvent event) {
System.out.println("### [" + name + "] component Hidden");
}
#Override
public void componentResized(ComponentEvent event) {
System.out.println("### [" + name + "] component Resized");
}
#Override
public void componentShown(ComponentEvent event) {
System.out.println("### [" + name + "] component Shown");
}
#Override
public void componentMoved(ComponentEvent event) {
System.out.println("### [" + name + "] component Moved");
}
};
#SuppressWarnings("unchecked")
private void initComponents() {
containerPanel = new javax.swing.JPanel();
changerButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
containerPanel.setBorder(new javax.swing.border.MatteBorder(null));
javax.swing.GroupLayout containerPanelLayout = new javax.swing.GroupLayout(containerPanel);
containerPanel.setLayout(containerPanelLayout);
containerPanelLayout.setHorizontalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 374, Short.MAX_VALUE)
);
containerPanelLayout.setVerticalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 239, Short.MAX_VALUE)
);
changerButton.setText("Change to 3D");
changerButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
changerButtonActionPerformed(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()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(changerButton))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(changerButton)
.addContainerGap())
);
pack();
}
}
(My apologies for the Netbeans generated GUI code)
I should mention that when we call parent.remove(view2D) and parent.add(view3D) to change the views the X Windows ID of our 3D view changes and we're unable to get our 3D view back. Therefore parent.remove(view2D) and parent.add(view3D) is not really a solution and we have to call setVisible(false) and setVisible(true) on the JComponents that contain our 2D and 3D views in order to hide and show them.
Any help will be greatly appreciated.
Why don't you use a CardLayout to switch from the 2D to 3D component?
CardLayout is exactly done for this kind of purpose in my understanding.
Another benefit would be that it will simplify your code.
After your remove() and add() methods to change the component, you should call:
parent.revalidate(); //To make the layout manager do its work.
parent.repaint(); //This could be necessary, to suggest a repaint of the panel
Javadoc for JComponent#revalidate() :
Supports deferred automatic layout.
Calls invalidate and then adds this
component's validateRoot to a list of
components that need to be validated.
Validation will occur after all
currently pending events have been
dispatched. In other words after this
method is called, the first
validateRoot (if any) found when
walking up the containment hierarchy
of this component will be validated.
By default, JRootPane, JScrollPane,
and JTextField return true from
isValidateRoot.
This method will automatically be
called on this component when a
property value changes such that size,
location, or internal layout of this
component has been affected. This
automatic updating differs from the
AWT because programs generally no
longer need to invoke validate to get
the contents of the GUI to update.
I've found a solution. You need to add/remove the components from the layout manager:
private void changerButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (parent == null) {
parent = view2D.getParent();
}
LayoutManager layoutMgr = parent.getLayout();
if (mode2D) {
System.out.println("Going from 2D to 3D");
view2D.setVisible(false);
layoutMgr.removeLayoutComponent(view2D);
if (view3D != null) {
view3D.setVisible(true);
if (layoutMgr != null && layoutMgr instanceof LayoutManager2) {
((LayoutManager2) layoutMgr).addLayoutComponent(view3D, null);
}
} else {
view3D = new JButton("3D View");
view3D.addComponentListener(new MyListener("3D VIEW"));
parent.add(view3D);
}
((JButton) evt.getSource()).setText("Change to 2D");
mode2D = false;
} else {
System.out.println("Going from 3D to 2D");
view3D.setVisible(false);
layoutMgr.removeLayoutComponent(view3D);
view2D.setVisible(true);
if (layoutMgr != null && layoutMgr instanceof LayoutManager2) {
((LayoutManager2) layoutMgr).addLayoutComponent(view2D, null);
}
((JButton) evt.getSource()).setText("Change to 3D");
mode2D = true;
}
}