TL;DR: Drawing Canvas3D off-screen to an image, then drawing the image on the screen. View in example should continously increase its distance to the cube; instead does so only when window gets resized.
In the following sample code, the Canvas3D object does not update the scene when I change the camera transform.
It stays as it is until I resize the window, at which point it updates once and doesn't do so again until I resize again. So it only updates on a resize event.
Any help in resolving this problem would be greatly appreciated!
EDIT: Minimal Example:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ImageComponent;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Transform3D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.vecmath.Vector3d;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
public class eg extends JComponent implements ActionListener {
SimpleUniverse m_universe = new SimpleUniverse(new Canvas3D(SimpleUniverse.getPreferredConfiguration(), true));
JFrame frame = new JFrame();
#Override
public void actionPerformed(ActionEvent arg0) {
repaint();
}
eg() {
// setup Screen3D
m_universe.getCanvas().getScreen3D().setSize(600, 600);
m_universe.getCanvas().getScreen3D().setPhysicalScreenHeight(0.0254/90.0 * 600);
m_universe.getCanvas().getScreen3D().setPhysicalScreenWidth(0.0254/90.0 * 600);
// setup scene
BranchGroup group = new BranchGroup();
group.addChild(new ColorCube(0.5f));
m_universe.addBranchGraph(group);
m_universe.getViewingPlatform().setNominalViewingTransform();
// setup JFrame
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setVisible(true);
// repaint() every half second
Timer timer = new Timer(500, this);
timer.start();
}
BufferedImage render(int width, int height) {
BufferedImage returnValue = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
ImageComponent2D buffer = new ImageComponent2D(ImageComponent.FORMAT_RGBA, returnValue);
buffer.setCapability(ImageComponent.ALLOW_IMAGE_WRITE);
m_universe.getCanvas().setOffScreenBuffer(buffer);
m_universe.getCanvas().renderOffScreenBuffer();
m_universe.getCanvas().waitForOffScreenRendering();
returnValue = m_universe.getCanvas().getOffScreenBuffer().getImage();
return returnValue;
}
private Transform3D m_cameraTransform = new Transform3D();
private Vector3d m_cameraPosition = new Vector3d();
#Override
public void paintComponent(Graphics target) {
// Move camera back along z.
m_universe.getViewingPlatform().getViewPlatformTransform().getTransform(m_cameraTransform);
m_cameraTransform.get(m_cameraPosition);
m_cameraPosition.z += 0.05;
m_cameraTransform.set(m_cameraPosition);
m_universe.getViewingPlatform().getViewPlatformTransform().setTransform(m_cameraTransform);
System.out.println(m_cameraPosition.z);
// Draw canvas.
Graphics2D buffer = (Graphics2D) target;
buffer.drawImage(render(getWidth(), getHeight()), null, 0, 0);
}
public static void main(String[] args) {
eg test = new eg();
}
}
I made jbutton and added ActionListner to it but the code in public void actionPerformed(ActionEvent e){} exectues twice.It prints test twice,instead of just once.Here is my code
JButton testbut=new JButton("Test");
ListenForButton2 l=new ListenForButton2();
testbut.addActionListener(l);
private class ListenForButton2 implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == testbut){System.out.println("tEST");}
}
}
Here is complete code,in case this is no eneough.Looks like problem was adding two action listeners to my button."if (testbut.getActionListeners().length<1)) testbut.addActionListener(l); "fixed it.But can you find where i added two action listeneres to test button
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Arc2D;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.QuadCurve2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Game extends JFrame {
JButton but1 = new JButton("MakeMoney");
JButton button1 = new JButton("Current money");
JButton testbut=new JButton("Make money");
int money = 0;
double currentMoney;
String moneyString = "";
String box1txt="Text for box one";
String[] boxtext={"Newspaper Delivery","Car wash","Pizza Delivery","Donut shop","Shrimp boat","Hockey team","Movie Studio","Bank","Oil Company"};
String[] prices={"60.00","720.00","8,640.00","103,680.00","1,244,160.00","14,929,920.00","179,159,040.00","2.149 billion","25.798 billion"};
public static void main(String[] args) {
new Game();
}
public Game() {
try {
this.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("C:/Users/TPC/workspace/ProjectMoney/Resources/backgroundForApp.png")))));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.setLayout(new BorderLayout());
button1.setContentAreaFilled(false);
ListenForButton lforButton = new ListenForButton();
but1.addActionListener(lforButton);
JPanel thePanel = new JPanel();
thePanel.add(button1);
thePanel.add(but1);
//thePanel.add(testbut);
this.setSize(1042, 617);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Project Money");
this.add(thePanel, BorderLayout.NORTH);
this.add(new DrawStuff(), BorderLayout.CENTER);
this.setResizable(true);
this.setVisible(true);
Sound sound1 = new Sound();
String sound = "file:C:/Users/TPC/Downloads/sound.wav";
sound1.playMusic(sound);
}
private class ListenForButton implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == but1) {
money += 10;
moneyString = Integer.toString(money);
button1.setText("$" + moneyString);
}
}
}
private class ListenForButton2 implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == testbut){System.out.println("tEST");}
}
}
private class DrawStuff extends JComponent {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graph2 = (Graphics2D) g;
graph2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Shape drawRoundRec = new RoundRectangle2D.Double(170,40,250,66,45, 45);
//first num xpos,secound num ypost,third num sirina,fourht num duzina
int x1=170; int y1=40; int x2=250; int y2=66; int def=45;
Shape drawRoundRec2=new RoundRectangle2D.Double(x1,(y1+80),x2,y2,def,def);
Shape drawRoundRec3=new RoundRectangle2D.Double(x1,(y1+80+80),x2,y2,def,def);
Shape drawRoundRec4=new RoundRectangle2D.Double(x1,(y1+80+80+80),x2,y2,def,def);
Shape drawRoundRec5=new RoundRectangle2D.Double(x1,(y1+80+80+80+80),x2,y2,def,def);
Shape drawRoundRect6=new RoundRectangle2D.Double(x1+330,40,250,66,def, def);
Shape drawRoundRect7=new RoundRectangle2D.Double(x1+330,(y1+80),250,66,def, def);
Shape drawRoundRect8=new RoundRectangle2D.Double(x1+330,(y1+80+80),250,66,def, def);
Shape drawRoundRect9=new RoundRectangle2D.Double(x1+330,(y1+80+80+80),250,66,def, def);
Shape drawRoundRect10=new RoundRectangle2D.Double(x1+330,(y1+80+80+80+80),250,66,def, def);
graph2.setPaint(Color.BLACK);
graph2.setColor(Color.LIGHT_GRAY);
graph2.fill(drawRoundRec); graph2.fill(drawRoundRec2);
graph2.fill(drawRoundRec3); graph2.fill(drawRoundRec4); graph2.fill(drawRoundRec5); graph2.fill(drawRoundRect6);
graph2.fill(drawRoundRect7); graph2.fill(drawRoundRect8); graph2.fill(drawRoundRect9); graph2.fill(drawRoundRect10);
graph2.setPaint(Color.BLACK);
graph2.draw(drawRoundRec2); graph2.draw(drawRoundRec3); graph2.draw(drawRoundRec4);
graph2.draw(drawRoundRec5); graph2.draw(drawRoundRect6); graph2.draw(drawRoundRect7); graph2.draw(drawRoundRect8);
graph2.draw(drawRoundRect9); graph2.draw(drawRoundRect10);
Font font=new Font("Serif",Font.PLAIN,30);
g.setFont(font); g.drawString(box1txt,190,80); g.drawString(boxtext[0],190,150); g.drawString(boxtext[1],190,150+80); g.drawString(boxtext[2],190,150+90+70);
g.drawString(boxtext[3],190,150+90+70+80);
g.drawString(boxtext[4],520,80); g.drawString(boxtext[5],520,150); g.drawString(boxtext[6],520,150+80); g.drawString(boxtext[7],520,150+90+70);
g.drawString(boxtext[8],520,150+90+70+80);
g.drawString(prices[0],190,150+30); g.drawString(prices[1],190,150+80+30); g.drawString(prices[2],190,150+90+70+30);
g.drawString(prices[3],190,150+90+70+80+30);
g.drawString(prices[4],520,80+25); g.drawString(prices[5],520,150+30); g.drawString(prices[6],520,150+80+30); g.drawString(prices[7],520,150+90+70+30);
g.drawString(prices[8],520,150+90+70+80+30);
testbut.setLocation(180,70);
Dimension d = new Dimension(100,40);
testbut.setSize(d);
ListenForButton2 l=new ListenForButton2();
if (testbut.getActionListeners().length<1) testbut.addActionListener(l);
this.add(testbut);
}
}
}
Make sure to add your action listener just once.
You get the listeners count via testbut.getActionListeners().length .
Update - multiple calls
Within the paintComponent of the DrawStuff class which extends JComponent you are only adding the listener once. Same as for the first listener.
The difference is, the first is added within a constructor. While the paintComponent method of the JComponent which can be called multiples times.
As to how and when it is called, this answer might help you.
So I am making a little game to learn some graphical java and I am having trouble with a button. It is drawing 2, one is the correct size and in the correct location and then there is a very small button centered at the top of the application. THere should only be the one button at (0,0,200,50). I do not know what is wrong but here is the code for the button, if you need something more then this let me know!
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
EDIT1: the 2 classes where error will be: board.java:
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Board extends JPanel {
public Board() {
}
#Override
public void paintComponent(Graphics g) {
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
}
private void drawRectangle(Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawRect(x, y, width, height);
}
}
and the main:
import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class main extends JFrame {
public main() {
initUI();
}
private void initUI() {
add(new Board());
setSize(800, 600);
setTitle("Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
main ex = new main();
ex.setVisible(true);
}
});
}
}
If you try to resize window, you will see that buttons are spawning.
This happens because of your paintComponent method, which is called every painting iteration.
You should move button addition, for example, to constructor which is called once:
public Board() {
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
}
I have a two class project, one class reads one file, and checks each entry in said file against a website, and posts the return data in another file.
If the return data says true(for example), the data point in the file is flashed on the screen. This functionality works.
I invoke this through the following if statement within a while loop.
if (!query.text().contains("unavailable") && !query.text().contains("at least 3 characters long to acquire.") && line != null) {
HitBox h = new HitBox(line); //GUI Class.
fos.write(query.text().getBytes());
fos.write("\n".getBytes());
fos.flush();
}
Below is my GUI class.
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
public class HitBox {
private Timer t;
JWindow frame = new JWindow();
public HitBox(String s) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
frame.setAlwaysOnTop(true);
t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e2) {
SwingUtilities.getWindowAncestor(frame.getComponent(0))
.dispose();
}
});
}
});
frame.setBackground(new Color(0, 0, 0, 0));
TranslucentPane tp = new TranslucentPane(s);
frame.setContentPane(tp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
t.start();
}
}
class TranslucentPane extends JPanel {
public TranslucentPane(String s) {
add(new JLabel(s));
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.85f));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
This happens using the same set of input data, even if I override the web query, and just return a set value, # a random point in runtime, a JWindow will appear, a nullpointer will be thrown (# my call of the start method of my timer object).
This leads me to believe I'm implementing the timer incorrectly; I'm intrigued by how with consistent data, and return, there is variation in the point it throws the nullpointer.
Exception in thread "main" java.lang.NullPointerException
at HitBox.<init>(HitBox.java:51)
at OriginalGangster.main(OriginalGangster.java:38)
You're not starting your GUI on the GUI thread. You need to move it into the Runnable and be sure to start the Timer after it has been constructed.
e.g.,
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
public class TestHitBox {
public static void main(String[] args) {
String text = "Hello world! This is Hovercraft!";
int seconds = 5;
float composite = 0.85f;
float points = 48f;
HitBox.showMessage(text, seconds, composite, points);
}
}
class HitBox {
public static void showMessage(final String text, final int seconds, final float composite, final float points) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
final JWindow frame = new JWindow();
frame.setBackground(new Color(0, 0, 0, 0));
TranslucentPane tp = new TranslucentPane(text, composite, points);
frame.setContentPane(tp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
new Timer(1000 * seconds, new TimerListener(frame)).start();
}
});
}
}
class TimerListener implements ActionListener {
private JWindow frame;
public TimerListener(JWindow frame) {
this.frame = frame;
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispose();
((Timer) e.getSource()).stop();
}
}
#SuppressWarnings("serial")
class TranslucentPane extends JPanel {
private float composite;
public TranslucentPane(String s, float composite, float points) {
this.composite = composite;
JLabel label = new JLabel(s);
label.setFont(label.getFont().deriveFont(Font.BOLD, points));
add(label);
setOpaque(false); // this breaks a rule
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(composite));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose(); // dispose of any graphics we create
}
}
Code updated.
The main code has been moved to a public static method, since this appears to be code to display a message to the user and not to share state with any other code, similar to a JOptionPane message, so I'm making it behave like a JOptionPane.
Timer's ActionListener moved out of constructor for cleanliness.
Added parameters for alpha composite, display time, and message font point size.
below is a working Java-Code which I do not understand.
I have outprinted the times where the programm invokes the getPreferredsize()- and paintComponent()-methods. I have found out that every time I resize the DialogWindow it calls once the getPreferredsize-method() and twice the paintcomponent-method().
Why?
package examples;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
public class Bsp {
public static void main(String[] args) {
JFrame frame = new MyFrame();
}
}
class MyFrame extends JFrame {
JPanel panel=new JPanel(new GridBagLayout());
private class MyLine extends JLabel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(5));
System.out.println("PaintComponent: "+getWidth()+" "+getHeight());
g2d.drawLine(0, panel.getHeight()/2, panel.getWidth(), panel.getHeight()/2);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
System.out.println("PreferredSize: "+panel.getWidth()+" "+panel.getHeight());
return new Dimension(panel.getWidth(),panel.getHeight());
}
}
public MyFrame() {
JLabel label=new MyLine();
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(3, 1));
panel.add(label);
add(new JButton("A"));
add(new JButton("B"));
add(panel);
pack();
centeringWindow();
setVisible(true);
}
public void borderingJPanel(JComponent panel, String jPanelname,
String fontStyle) {
Font font = new Font(fontStyle, Font.BOLD + Font.ITALIC, 12);
if (jPanelname != null) {
panel.setBorder(BorderFactory.createTitledBorder(BorderFactory
.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY,
Color.WHITE), jPanelname,
TitledBorder.DEFAULT_JUSTIFICATION,
TitledBorder.DEFAULT_POSITION, font));
} else if (jPanelname == null || fontStyle == null) {
panel.setBorder(BorderFactory.createTitledBorder(BorderFactory
.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY,
Color.WHITE)));
}
panel.setOpaque(false);
}
public void centeringWindow() {
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x;
int y;
x = (int) (dimension.getWidth() - getWidth()) / 2;
y = (int) (dimension.getHeight() - getHeight()) / 2;
setLocation(x, y);
}
public BufferedImage getBufferedImage(){
BufferedImage buffImage=null;
try {
buffImage=ImageIO.read(MyFrame.class.getClassLoader().getResourceAsStream("examples/rightAnswerSign.png"));
} catch (IOException e) {
e.printStackTrace();
}
return buffImage;
}
}