Java, how to get into the JPanel - java

I'm a beginner in Java. My code:
public PlanetSimulator() throws InterruptedException {
JPanel panel = new JPanel();
panel.setBounds(64, 35, 840, 600);
Draw view = new Draw();
panel.add(view);
Drawing in panel Sun and Stars and Black Background.
How can I say Java "Hey you see that panel? Draw there another thing"
But I'm saying in to Java not from the PlanetSimulator, but main function.
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
PlanetSimulator frame = new PlanetSimulator();
frame.setVisible(true);
//DrawPlanetOne DrawPlanetOne = new DrawPlanetOne()
//PlanetSimulator.panel.add(DrawPlanetOne)
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
But it doesn't work. Yes I known that I'm amateur.
Rysowanie / Draw class
http://pastebin.com/RkcTBxrN

I assume, this will be a simulation. And if you like to simulate something with 30FPS, it will be hard with a Panel. You could use a library like processing to animate your planets and stuff. It's a lot easier as using a JPane. But you could call the repaint method?

Related

Image in JFrame doesn't want to display with the call in another class

I work on a Java development software with Swing and I have a problem with my code, I want to display an image with the LoadingFrame class, its main work but when I call the constructor and the start() method in my main class, the frame opens but the image doesn't display (I have no Exception).
Why it doesn't work with my main class?
public class LoadingFrame
{
private JFrame frame;
public LoadingFrame()
{
frame = new JFrame();
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setUndecorated(true);
frame.setContentPane(new Panneau());
}
public void start()
{
frame.setVisible(true);
}
public void stop()
{
frame.setVisible(false);
}
public static void main(String[] args)
{
LoadingFrame l = new LoadingFrame();
l.start();
try
{
Thread.sleep(3000);
}
catch(Exception e)
{
e.printStackTrace();
}
l.stop();
}
}
public class Panneau extends JPanel
{
public void paintComponent(Graphics g)
{
System.out.println("hello");
try
{
Image img = ImageIO.read(new File("Images/loading.png"));
//g.drawImage(img, 0, 0, this);
//Pour une image de fond
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
The App class is my main class :
public class App {
//Attributes used to display the application
private JFrame frame;
//Attribute which display a waiting frame
private static LoadingFrame loadingFrame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
loadingFrame = new LoadingFrame();
loadingFrame.start();
App window = new App();
loadingFrame.stop();
window.frame.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public App()
{
initialize();
synchronizeScriptReferenceList();
synchronizeTests();
}
[...]
}
I was able to get this to work from App.java. For some reason, using EventQueue isn't cutting it. I tried to use SwingUtilities as well, but that doesn't work either. Finally I tried just get rid of the Thready-stuff in App.main at just straight up running it in the main thread. For some reason, this works when the other approaches do not! Here is my code:
// In the App class:
public static void main(String[] args) {
try {
loadingFrame = new LoadingFrame();
loadingFrame.start();
App window = new App();
loadingFrame.stop();
window.frame.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
When I used this code, I got it to work! (for some reason unknown to me), And here's a bonus rewrite of the Panneau class:
class Panneau extends JPanel
{
Image img;
public Panneau() {
try
{
img = ImageIO.read(new File("Images/loading.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}
There are two main difference with this class; problems which I addressed. Here they are:
I call super.paintComponent as the very first method in our own paintComponent
I only load the loading image once, in the constructor, and not every single time I want to draw, which moves everything along much smoother. (you don't want the loading screen to be CPU heavy, do you?)
Hopefully, with these improvements, I hope you can make your program work! It worked with me, so I wish the best of luck to you.
P.S. Don't call frame.pack(), that was a mistake on my part. For some reason, I think it doesn't work well with undecorated windows.

Java Graphics Update/Repaint Graphic

I'm trying to work with the Java paint
utility and it's been a bit of a hassle.
I'm trying to do something which I assume is quite basic.
I'm drawing a square Graphic to a JPanel and then trying
to move it using repaint
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
public class testGui {
static gui gc_gui;
static int gv_x;
static int gv_y;
public static void main(String[] args) {
gc_gui = new gui();
gv_x = 50;
gv_y = 50;
gc_gui.cv_frame.setVisible(true);
}
public static class gui {
JFrame cv_frame;
content cv_content;
public gui() {
cv_frame = new JFrame();
cv_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cv_frame.setTitle("Test GUI");
cv_frame.setSize(600, 400);
cv_frame.setLayout(new FlowLayout());
cv_content = new content();
cv_content.setBackground(Color.Black);
cv_content.setPreferredSize(new Dimension(500, 300));
cv_frame.add(cv_content);
gv_x = 0;
gv_y = 0;
cv_content.update();
}
}
public static class content extends JPanel {
public void paint(Graphics graphic) {
super.paint(graphic);
draw(graphic);
}
public void update() {
super.repaint();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.setPaint(Color.Red);
graphic2D.fillRect(gv_x, gv_y, 100, 100);
}
}
}
I don't know why the call to the update function isn't doing
anything though.
It draws the square at 50x and 50y, the sets it to 0x and 0y
immediately and then when I call repaint I expected it to
be moved to it's new coordinates although it's still at
50x and 50y.
Why is this?
Your solution is to use KeyBindings.
https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html
and also.
You need to create a Swing Timer, Thread, or Loop , that manages the frames to be painted. and such
Here is a link for Swing Timers as they are pretty easy to implement:
https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
A lot of programs I see also have this ( AKA. working with threads.):
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});

JFrame and GlassPane - Trouble with repaint()

This question may be a simple matter of me lacking a fundamental understanding of Java Swing or Graphics, and if so, I apologize.
I'm trying to develop a GUI application using Java Swing that can be controlled by an external device that sends pitch, yaw, and roll values via bluetooth to the Application. My idea is to create a cursor (perhaps an empty circle) that moves around when the external device moves around. I have no problems with receiving the data from the device, just the part where I need to actually paint something over all of my components.
I figured that a GlassPane was the easiest way to show a cursor over the entire application, and have it move around when the external device is moved around. I use a Thread to capture the data, and I'm trying to call repaint() afterwards, but it doesn't seem to be triggering.
Here is the relevant code:
JFrame:
public class Frame extends JFrame {
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
//Thread myoHandlerThread = new Thread(myoHandler);
//myoHandlerThread.start();
Frame frame = new Frame();
GlassPane glassPane = new GlassPane();
glassPane.setVisible(true);
frame.setGlassPane(glassPane);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Frame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(50, 50, 1000, 650);
/* Code to add and place components */
}
}
And my GlassPane:
public class GlassPane extends JComponent {
private static double pitch;
private static double yaw;
private static double roll;
Point point;
public void setPoint(Point p) {
this.point = p;
}
public void paintComponent(Graphics g) {
if (point != null) {
System.out.println("Test print statement");
g.setColor(Color.red);
g.fillOval(point.x - 10, point.y - 10, 20, 20);
}
}
public GlassPane() {
Thread handler = new Thread(deviceHandler);
handler.start();
}
private Runnable deviceHandler = new Runnable() {
#Override
public void run() {
Hub hub = new Hub("com.garbage");
System.out.println("Attempting to find device...");
Device externalDevice = hub.waitForDevice(10000);
if (externalDevice == null) {
throw new RuntimeException("Unable to find device!");
}
System.out.println("Connected");
DataCollector dataCollector = new DataCollector();
hub.addListener(dataCollector);
while (true) {
hub.run(1000/20); //gathers data and stores in dataCollector
roll = dataCollector.getRoll();
pitch = dataCollector.getPitch();
yaw = dataCollector.getYaw();
Point p = new Point();
p.setLocation(Math.abs(pitch) * 10, Math.abs(yaw) * 10);
setPoint(p);
repaint();
}
}
};
}
What I would like to happen is for a red circle to be drawn somewhere on the GUI depending on the orientation of the external device. At this point, my "test print statement" doesn't fire even once.
My guess is that I'm lacking some sort of basic understanding of Java's GlassPane or even how paint, paintComponent, and repaint even works. Could anyone point out what I'm doing wrong?
The likely cause of your frustration is trying to set the glass pane visible (Swing components are visible by default), before setting it as the frames GlassPane.
The JFrame is likely resetting the glass pane to be invisible, meaning that it won't be painted (no point painting something that's not visible)
Try setting the glass pane visible AFTER you apply it to the frame

Do Robot methods need to be run on the event queue?

Robot is part of the AWT library, but it seems quite different from most all the rest of the library. I am creating a Swing GUI that mixes Swing with Java Native Access (JNA) and Robot to allow Java to drive some MS Windows/Citrix work programs. My gut feeling is that since Robot will queue events on the "platform's native input queue" that the last thing I want to do is to run it on the EDT, but on the other hand, most of the classes in the AWT and Swing libraries should be run on the Swing event thread. So to try clarify this in my mind for me let me ask as specific a question as possible:
Should Robot methods (in particular key presses and releases, mouse moves, mouse presses and releases) be run on or off of the Swing event dispatch thread (the EDT)?
The Robot methods you mentioned should not be run on the EDT. Taking a look at the source code revealed that each one of these "event" methods has one thing in common (the afterEvent call):
public synchronized void keyPress(int keycode) {
checkKeycodeArgument(keycode);
peer.keyPress(keycode);
afterEvent();
}
public synchronized void mousePress(int buttons) {
checkButtonsArgument(buttons);
peer.mousePress(buttons);
afterEvent();
}
// etc
private void afterEvent() {
autoWaitForIdle();
autoDelay();
}
private void autoWaitForIdle() {
if (isAutoWaitForIdle) {
waitForIdle();
}
}
public synchronized void waitForIdle() {
checkNotDispatchThread();
/* snip */
}
private void checkNotDispatchThread() {
if (EventQueue.isDispatchThread()) {
throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
}
}
If you call any of these methods on the EDT while Robot.isAutoWaitForIdle is true, an exception will be thrown. This stands to reason that even if isAutoWaitForIdle is false, these methods shouldn't be called from the EDT.
API quite exactly talks, then I'm understand that that Robot should be ignore if is invoked from EDT or not
Using the class to generate input events differs from posting events to the AWT event queue or AWT components in that the events are generated in the platform's native input queue.
I'm rellative new in Java, my first touch was Java1.6.009, then I can't compare changes for AWT and (when born) Swing in Java1.3 and rest in Java1.4
my example
import javax.imageio.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
public class CaptureScreen implements ActionListener {
private JFrame f = new JFrame("Screen Capture");
private JPanel pane = new JPanel();
private JButton capture = new JButton("Capture");
private JDialog d = new JDialog();
private JScrollPane scrollPane = new JScrollPane();
private JLabel l = new JLabel();
private Point location;
public CaptureScreen() {
capture.setActionCommand("CaptureScreen");
capture.setFocusPainted(false);
capture.addActionListener(this);
capture.setPreferredSize(new Dimension(300, 50));
pane.add(capture);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(pane);
f.setLocation(100, 100);
f.pack();
f.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createPicContainer();
}
});
}
private void createPicContainer() {
l.setPreferredSize(new Dimension(700, 500));
scrollPane = new JScrollPane(l,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBackground(Color.white);
scrollPane.getViewport().setBackground(Color.white);
d.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
d.add(scrollPane);
d.pack();
d.setVisible(false);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("CaptureScreen")) {
Dimension d1 = Toolkit.getDefaultToolkit().getScreenSize(); // gets the screen size
Robot r;
BufferedImage bI;
try {
r = new Robot(); // creates robot not sure exactly how it works
Thread.sleep(1000); // waits 1 second before capture
bI = r.createScreenCapture(new Rectangle(d1)); // tells robot to capture the screen
showPic(bI);
saveImage(bI);
} catch (AWTException e1) {
e1.printStackTrace();
} catch (InterruptedException e2) {
e2.printStackTrace();
}
}
}
private void saveImage(BufferedImage bI) {
try {
ImageIO.write(bI, "JPG", new File("screenShot.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
private void showPic(BufferedImage bI) {
ImageIcon pic = new ImageIcon(bI);
l.setIcon(pic);
l.revalidate();
l.repaint();
d.setVisible(false);
location = f.getLocationOnScreen();
int x = location.x;
int y = location.y;
d.setLocation(x, y + f.getHeight());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
d.setVisible(true);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CaptureScreen cs = new CaptureScreen();
}
});
}
}
Amplifying on #mKorbel's thoughtful answer, and confirming his empirical result, note how the various Robot methods delegate to an internal instance of the RobotPeer interface, the native implementation of which varies by platform. Moreover, the methods are synchronized. The synthetic events all arrive on the EventQueue, irrespective of the source.

How can I remove a JPanel from a JFrame?

Recently I asked here how to add a new JPanel to JFrame. The answer helped me to get a working code. But not I have a related question: "How can I remove an old JPanel". I need that because of the following problem.
A new JPanel appears appears when I want (either time limit is exceeded or user press the "Submit" button). But in several seconds some element of the old JPanel appears together with the component of the new JPanel. I do not understand why it happens.
I thought that it is because I have to other threads which update the window. But the first thread just add the old panel once (so, it should be finished). And in the second thread I have a loop which is broken (so, it also should be finished).
Here is my code:
private Thread controller = new Thread() {
public void run() {
// First we set the initial pane (for the selection of partner).
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.getContentPane().add(generatePartnerSelectionPanel());
frame.invalidate();
frame.validate();
}
});
// Update the pane for the selection of the parnter.
for (int i=40; i>0; i=i-1) {
final int sec = i;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
timeLeftLabel.setText(sec + " seconds left.");
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) { }
if (partnerSubmitted) {
break;
}
}
// For the given user the selection phase is finished (either the time is over or form was submitted).
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.getContentPane().add(generateWaitForGamePanel());
frame.invalidate();
frame.validate();
}
});
}
};
Its the same whether you do add or remove a component on a visible GUI:
panel.remove(...);
panel.add(...);
panel.revalidate();
panel.repaint();
the easiest way to remove a component (panel) from a container (frame) is to keep a reference to it, and then call Container.remove(Component) ie:
private Thread controller = new Thread() {
public void run() {
final Component panel1 = generatePartnerSelectionPanel();
// First we set the initial pane (for the selection of partner).
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.getContentPane().add(panel1);
frame.invalidate();
frame.validate();
}
});
// Update the pane for the selection of the parnter.
for (int i=40; i>0; i=i-1) {
final int sec = i;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
timeLeftLabel.setText(sec + " seconds left.");
}
});
try {Thread.sleep(1000);} catch (InterruptedException e) {}
if (partnerSubmitted) {break;}
}
// For the given user the selection phase is finished (either the time is over or form was submitted).
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.getContentPane().remove(panel1);
frame.getContentPane().add(generateWaitForGamePanel());
frame.invalidate();
frame.validate();
}
});
}
};
i haven't tested this code but it should work.
I had problems with requestFocusInWindow on TextField too. The trick is to not construct the components in the JPanel constructor. But, make a build method and execute following code after it has been added to the frame.
This worked for me:
frame.getContentPane().removeAll(); //or .remove(previousPanel);
frame.getContentPane().add(newPanel);
panel.buildPanel(); // panel needs a builder method
frame.revalidate(); // in- and validate in one !!
frame.pack(); //
if you want to resize, you need preferredSize(); on panel or use repaint() if you don't need to resize frame.
Roman, the problem can be solved like that:
Do this in the beginning of your run method:
final JPanel partnerSelectionPanel = generatePartnerSelectionPanel();
Then do this
frame.getContentPane().add(partnerSelectionPanel);
Before you add the new panel do this:
partnerSelectionPanel.setVisible(false);
It works. I do not know if it is a safe and/or elegant solution but it works.

Categories

Resources