Hi there I'm new to GUIs in Java and was trying to make a splash screen or an image appear for 3 seconds. Then after that it it will go onto my main program. Does anyone have an ideas how to do this or can link me to any tutorials?
So far I have done this but not sure where to go from here.
public static void main(String[] args)
{
splashInit(); // initialize splash overlay drawing parameters
appInit(); // simulate what an application would do
}
Simplest one , is to create JFrame and add your screen on it then use Thread.Sleep(long millies)
Try this code:
JWindow window = new JWindow();
window.getContentPane().add(
new JLabel("", new ImageIcon(new URL("http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/SplashDemoProject/src/misc/images/splash.gif")), SwingConstants.CENTER));
window.setBounds(500, 150, 300, 200);
window.setVisible(true);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
window.setVisible(false);
JFrame frame = new JFrame();
frame.add(new JLabel("Welcome"));
frame.setVisible(true);
frame.setSize(300,100);
window.dispose();
Or you can Create a Splash Screen by using SplashScreen class
See also How to Create a Splash Screen for the AWT based splash functionality.
To print messages on the splash screen, you need to add a picture to your application and add it to the manifest.mf:
SplashScreen-Image: path/picture.jpg
Then use code like this:
private static Graphics2D splashGraphics = null;
private static SplashScreen splash;
private static int dpi;
public static void main(String[] args) {
initSplashMessages();
splashMessage("Start program...");
...
splashMessage("Load data...");
...
}
private static void initSplashMessages() {
splash = SplashScreen.getSplashScreen();
if (splash == null) return;
splashGraphics = splash.createGraphics();
if (splashGraphics == null) return;
dpi = Toolkit.getDefaultToolkit().getScreenResolution();
}
public static void splashMessage(String message) {
if (splashGraphics == null) return;
Dimension dim = splash.getSize();
splashGraphics.setColor(Color.LIGHT_GRAY);
splashGraphics.fillRect(0, dim.height - dpiX(20), dim.width, dpiX(20));
splashGraphics.setPaintMode();
splashGraphics.setColor(Color.BLACK);
splashGraphics.setFont(new Font("Arial",Font.PLAIN, dpiX(12)));
splashGraphics.drawString(message, dpiX(3), dim.height - dpiX(5));
splash.update();
}
private static int dpiX(int x) {
return (int) Math.round(1.0 * x * dpi / 96);
}
In IntelliJ add the picture.jpg to your project (use File):
For debugging use "Modify options"/"Add VM options" and write
-splash:path/picture.jpg
This works fine for me.The functions such as getScreenSize() ,getWidth() and getHeight() can be replaced by own values.
public class splash extends JWindow
{
public splash()
{
JWindow j=new JWindow();
Dimension d=Toolkit.getDefaultToolkit().getScreenSize();
Icon img= new ImageIcon(this.getClass().getResource("2.jpg"));
JLabel label = new JLabel(img);
label.setSize(200,300);
j.getContentPane().add(label);
j.setBounds(((int)d.getWidth()-722)/2,((int)d.getHeight()-401)/2,722,401);
j.setVisible(true);
try
{
Thread.sleep(6000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
j.setVisible(false);
}
public static void main(String[] args)
{
splash s=new splash();
}
}
I use this code. Maybe you need to change some parts:
import javax.swing.*;
import java.awt.*;
public class SplashScreen {
private final JWindow window;
private long startTime;
private int minimumMilliseconds;
public SplashScreen() {
window = new JWindow();
var image = new ImageIcon("C:\\example.jpg");
window.getContentPane().add(new JLabel("", image, SwingConstants.CENTER));
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
window.setBounds((int) ((screenSize.getWidth() - image.getIconWidth()) / 2),
(int) ((screenSize.getHeight() - image.getIconHeight()) / 2),
image.getIconWidth(), image.getIconHeight());
}
public void show(int minimumMilliseconds) {
this.minimumMilliseconds = minimumMilliseconds;
window.setVisible(true);
startTime = System.currentTimeMillis();
}
public void hide() {
long elapsedTime = System.currentTimeMillis() - startTime;
try {
Thread.sleep(Math.max(minimumMilliseconds - elapsedTime, 0));
} catch (InterruptedException e) {
e.printStackTrace();
}
window.setVisible(false);
}
}
And here is how to use it:
var splash = new SplashScreen();
splash.show(2000);
// Initializing...
splash.hide();
This will show the splash at least 2 seconds.
Related
I am trying to make a JComponent application which uses two JFrames, one frame with alterable sliders and textfields for the graphical display of a firework on the second. When the "fire" button is pressed, a rendering of the firework should appear. However, I have found through placing strategic print statements, that my paintComponent() method does not run even though the conditional statement wrapping the code is satisfied. I have also double checked all of my other methods to ensure that correct values are generated at the correct times. After looking through all of the JComponent literature and questions I could find, I'm afraid I cannot get it to work - this problem is most likely derived from my lack of familiarity with the library. That being said, any advice no matter how rudimentary, will be much appreciated. Abridged code is below:
*The swing timer may also be the issue for I am not sure if I have used it correctly
[fireworksCanvas.java]
public class fireworkCanvas extends JComponent implements ActionListener{
private static final long serialVersionUID = 1L;
private ArrayList<Ellipse2D> nodes = new ArrayList<Ellipse2D>();
private ArrayList<Line2D> cNodes = new ArrayList<Line2D>();
private ArrayList<QuadCurve2D> bCurves = new ArrayList<QuadCurve2D>();
private int[] arcX;
private int[] arcY;
private Color userColor;
private Random rand = new Random();
private int shellX, shellY, fType, theta, velocity;
private Timer timer;
private int time;
private double g = -9.8; //gravity in m/s
public boolean explosivesSet;
public fireworkCanvas() {
time = rand.nextInt(3000) + 2000;
timer = new Timer(time, this); // 5 seconds
timer.start();
fType = 0;
}
#Override
public void paintComponent(Graphics g){
if (explosivesSet) {
System.out.println("fType" + fType);
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g.setColor(Color.BLACK);
g.drawPolyline(arcX, arcY, arcX.length);
for (Ellipse2D e : nodes) {
System.out.println("painting nodes"); // NEVER PRINTS
g.setColor(userColor);
g.fillOval(shellX + (int) e.getX(), shellY + (int) e.getY(), (int) e.getWidth(), (int) e.getHeight());
}
for (Line2D l: cNodes) {
System.out.println("painting cNodes"); // NEVER PRINTS
g.setColor(determineColor("l"));
g.drawLine(shellX + (int) l.getX1(), shellY + (int) l.getY1(), shellX + (int) l.getX2(), shellY + (int) l.getY2());
}
for (QuadCurve2D c: bCurves) {
System.out.println("painting curves"); // NEVER PRINTS
g.setColor(determineColor("c"));
g2D.draw(c);
}
}
}
public Color determineColor(String type) {
// returns color
}
public void setExplosives() {
if (fType != 5 && fType != 0) {
nodes.clear(); // clears three array lists with FW components
cNodes.clear(); // these are the components to paint for the
bCurves.clear(); // firework explosion graphic
setArc(); // stores path of shell for a polyLine to be drawn
// builds and generates components for FW based on type chosen (fType)
setExplosivesSet(true);
repaint();
}
}
public void setArc() {
// builds int[] for shellX, shellY
}
#Override
public void actionPerformed(ActionEvent e) {
// nothing is here??
// should I use the action performed in some way?
}
[GUI.java]
public class GUI extends JFrame implements ActionListener, ChangeListener, ItemListener, MouseListener{
private static JFrame canvasFrame = new JFrame("Canvas");
private fireworkCanvas canvas = new fireworkCanvas();
private Choice fireworkChooser = new Choice();
private JSlider launchAngle = new JSlider();
private JSlider velocity = new JSlider();
private JSlider r = new JSlider();
private JSlider g = new JSlider();
private JSlider b = new JSlider();
private JPanel panel = new JPanel();
private JButton button = new JButton("Fire!");
private JLabel launchLabel = new JLabel("Launch Angle ");
private JLabel velocityLabel = new JLabel("Velocity ");
private JLabel rLabel = new JLabel("Red ");
private JLabel gLabel = new JLabel("Green ");
private JLabel bLabel = new JLabel("Blue ");
public static int fHeight = 500;
public static int fWidth = 500;
public GUI() {
this.add(panel);
panel.add(button);
panel.add(fireworkChooser);
panel.add(launchAngle);
panel.add(launchLabel);
panel.add(velocity);
panel.add(velocityLabel);
panel.add(r);
panel.add(rLabel);
panel.add(g);
panel.add(gLabel);
panel.add(b);
panel.add(bLabel);
addActionListener(this);
BoxLayout bl = new BoxLayout(getContentPane(), BoxLayout.Y_AXIS);
setLayout(bl);
fireworkChooser.addItemListener(this);
launchAngle.addChangeListener(this);
velocity.addChangeListener(this);
r.addChangeListener(this);
g.addChangeListener(this);
b.addChangeListener(this);
button.addActionListener(this);
fireworkChooser.add("Firework 1");
fireworkChooser.add("Firework 2");
fireworkChooser.add("Firework 3");
fireworkChooser.add("Firework 4");
fireworkChooser.add("Super Firework");
launchAngle.setMinimum(1);
launchAngle.setMaximum(90);
velocity.setMinimum(1);
velocity.setMaximum(50);
r.setMinimum(0);
r.setMaximum(255);
g.setMinimum(0);
g.setMaximum(255);
b.setMinimum(0);
b.setMaximum(255);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 200);
}
#Override
public void stateChanged(ChangeEvent e) {
// sets FW variables
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
canvas.setfType(fireworkChooser.getSelectedIndex()+1);
canvas.setExplosives();
canvas.repaint();
canvas.setExplosivesSet(false);
System.out.println("button fired");
}
}
public static void createAndShowGUI() {
GUI gui = new GUI();
gui.pack();
gui.setLocationRelativeTo(null);
gui.setVisible(true);
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fireworkCanvas canvas = new fireworkCanvas();
canvasFrame.pack();
canvasFrame.add(canvas);
canvasFrame.setLocationRelativeTo(null);
canvasFrame.setVisible(true);
canvasFrame.setSize(fWidth, fHeight);
canvasFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
First of all:
public fireworkCanvas()
Class names should start with an upper case character. All the other classes in your code follow this rule. Learn by example.
private Choice fireworkChooser = new Choice();
Choice is an AWT component don't mix AWT components in a Swing application. Use a JComboBox.
that my paintComponent() method does not run
fireworkCanvas canvas = new fireworkCanvas();
canvasFrame.pack();
canvasFrame.add(canvas);
You add the canvas to the frame AFTER you pack() the frame, so the size of the canvas is (0, 0) and there is nothing to paint.
The canvas should be added to the frame BEFORE the pack() and you should implement getPreferredSize() in your FireworkCanvas class so the pack() method can work properly.
Read the section from the Swing tutorial on Custom Painting for the basics and working examples to get you started.
the code below is the implementation of a splash screen for a small Java application I have developed with Eclipse. The splash screen works perfectly well on a PC but not on a MAC. On MAC OSX, the frame first appears has a gray area during 2 seconds and then the image appears for the remaining of the 4 seconds. The image should normally appears right away and for a duration of 4 seconds. Do you have any idea why there is a delay before the image appears on a MAC while everything works well on a PC? PS: I have deployed the application as an executable Jar and I'm using Java 8 on all computers. Thank you.
public static void main(String[] args)
{
SplashScreen splSplashScreen = new SplashScreen();
//Main window
FenetrePrincipale fenetrePrincipale = new FenetrePrincipale();
}
public class SplashScreen extends JWindow
{
/**
* Numéro de série
*/
private static final long serialVersionUID = 1592663893301307318L;
private final static long TEMP_AFFICHAGE = 4000;
/**
* Constructeur par initialisation
* #param p_Frame Frame
* #param p_TempsAffichage Temps d'affichage en millisecondes
*/
public SplashScreen()
{
super(new Frame());
JLabel lblImage = new JLabel(new ImageIcon(this.getClass().getResource("/res/ui/splashScreen.jpg")));
Container container = this.getContentPane();
container.add(lblImage, BorderLayout.CENTER);
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = lblImage.getPreferredSize();
this.setLocation(screenSize.width/2 - (labelSize.width/2), screenSize.height/2 - (labelSize.height/2));
this.setVisible(true);
try
{
Thread.sleep(TEMP_AFFICHAGE);
}
catch (InterruptedException ex)
{
ApplicationLogger.getInstance().severe(ex.getLocalizedMessage());
}
finally
{
this.setVisible(false);
}
}
}
Edit This is completely different from the original answer; I'm leaving the original answer below.
It looks like the initial JLabel render is dog slow on OSX - removing all the sleeps still leaves me with a ~2 second pause while java renders the label. So we change the rules.
First we create a JPanel class that takes a buffered image:
class ImgPanel extends JPanel {
private BufferedImage img;
public ImgPanel(BufferedImage img) {
this.img = img;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, null);
}
}
We then change the splash screen constructor like so:
public SplashScreen()
{
BufferedImage img = null;
try {
img = ImageIO.read(this.getClass().getResource("/res/ui/splashScreen.jpg"));
} catch (Exception ex) {
}
ImgPanel panel = new ImgPanel(img);
Container container = this.getContentPane();
container.add(panel);
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation(screenSize.width/2 - (img.getWidth()/2), screenSize.height/2 - (img.getHeight()/2));
this.setVisible(true);
}
This renders the image as soon as the panel appears without a pause.
Note - I've removed the entire sleep code to reduce confusion - the logic would be better captured in a separate SwingWorker to perform the hide of the splash screen and the display of the main screen:
class worker extends SwingWorker<String, Object> {
private final static long TEMP_AFFICHAGE = 4000;
private SplashScreen splash;
private FenetrePrincipale principale;
public worker(SplashScreen splash, FenetrePrincipale principale) {
this.splash = splash;
this.principale = principale;
this.splash.setVisible(true);
}
#Override
public String doInBackground() {
try
{
Thread.sleep(TEMP_AFFICHAGE);
}
catch (InterruptedException ex)
{
ApplicationLogger.getInstance().severe(ex.getLocalizedMessage());
}
return "";
}
#Override
protected void done() {
splash.setVisible(false);
principale.setVisible(true);
}
};
Then the main code looks like:
public static void main(String[] args)
{
SplashScreen splSplashScreen = new SplashScreen();
//Main window
FenetrePrincipale fenetrePrincipale = new FenetrePrincipale();
worker w = new worker(splSplashScreen, fenetrePrincipale);
w.execute();
}
Original answer - putting the thread for sleeping into a SwingWorker is still a good idea, as it would allow you to perform actual work before initialization.
Ok, a simple example of putting the sleep off the gui thread, using your splash code - this code comes after the this.setVisible(true), and replaces the try {} catch {} finally {} clause:
this.setVisible(true);
worker do_work = new worker(this);
do_work.execute();
}
class worker extends SwingWorker<String, Object> {
private SplashScreen parent;
public worker(SplashScreen parent) {
this.parent = parent;
}
#Override
public String doInBackground() {
try
{
Thread.sleep(TEMP_AFFICHAGE);
}
catch (InterruptedException ex)
{
ApplicationLogger.getInstance().severe(ex.getLocalizedMessage());
}
return "";
}
#Override
protected void done() {
parent.setVisible(false);
}
};
I just create a SwingWorker which does a sleep as doWorkInBackground, and once that is concluded, it closes the parent frame, which is the splash screen.
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.
I'll start explaining from the bottom to top, so you will actually understand what I was trying to do, and understand my code better.
I am creating a library, that let's you capture an area, whether if the capture is a gif animation or an image. After capturing is finished, the library will return an object that contains ByteArrayInputStream and util methods like createImage etc.
While reading this, you can have access to the library here: https://github.com/BenBeri/WiseCapturer/
Now this is a dummy example on how my library works:
Your application creates an instance of bootstrap with the capturer class, and begins a capture:
public static void main(String[] args) throws AWTException {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
}
The listener will return CapturedImage which you can use to do whatever you wish to.
Now with this example, this should let you capture twice, once and again after you're done, and once it's done, it will show the 2nd capture in a JFrame window.
Now I am not talking about this JFrame.
The problem only occurs with ScreeenshotCapturer, it will work fine with GifCapturer instance.
The problem
After finishing the first capture, the second capture JFrame transparent window will not come up, I don't see it in the windows toolbar, nor anywhere, but the application still runs.
However, as I said it does work if I use GifCapturer instance.
Now let's debug how my library works:
Bootstrap constructor:
/**
* Bootstrap consturctor, let it bootstrap!
* #param c
* Capturer instance
* #throws AWTException
*/
public Bootstrap(Capturer c) throws AWTException {
this.capturer = c;
}
Now the Capturer class initializes, it's the abstract class, same constructor for all capturers:
public Capturer() throws AWTException {
this.camera = new CaptureCamera(this);
}
This creates a new capture camera, which is where I am having the problem.
The purpose of CaptureCamera is to have the whole JFrame, transparent sized the same as my screen, and contain in it the JPanel that is responsible to do the selection rectangle drawing.
The constructor of it:
public CaptureCamera(Capturer c) throws AWTException {
this.c = c;
this.toolkit = Toolkit.getDefaultToolkit();
this.screen = this.toolkit.getScreenSize();
this.robot = new Robot();
this.selector = new SelectionCamera();
super.setSize(this.screen);
super.setUndecorated(true);
super.setBackground(new Color(255, 255, 255, 1));
// Listeners for area selection
super.addMouseListener(new SelectionAdapter(this, this.selector));
super.addMouseMotionListener(new SelectionMotion(this, this.selector));
super.add(this.selector);
}
Okay, now let's take a look at how the capturing begins.
the beginCapture method in bootstrap:
/**
* Starts capturing the screen, sends back a callback event with the
* captured file.
*
* The system saves a temporary file to send the file.
* #param c
* Callback instance
*/
public void beginCapture(ScreenCaptureCallback c) {
this.capturer.setCallback(c);
this.capturer.beginSelection();
}
setCallback is not really important for this problem, so beginSelection method:
The same for all capturers
#Override
public void beginSelection() {
super.init();
this.setHotkeys();
super.getCamera().startSelection();
}
startSelection method (sorry for the dumb duplicated names with the same meaning ill change later):
/**
* Starts area selection event
* #param c Capturer instance
*/
public void startSelection() {
super.setVisible(true);
}
Okay, this is where it should make the JFrame visible, I've tried printing before and it showed true, but the JFrame didn't show on the second attempt.
Now the frame is visible, and the user can select an area.
once selected, the mouese adapter will execute startCapturing method.
startCapturing in GifCapturer:
#Override
public void startCapturing(final int x, final int y, final int width, final int height) {
this.border = new GifCaptureBorder(x, y, width, height);
this.process = new TimerCaptureProcess(this, x, y, width, height);
Timer timer = new Timer();
timer.schedule(this.process, 0, 600);
}
`startCapturing in ScreenshotCapturer:
#Override
public void startCapturing(int x, int y, int width, int height) {
Robot robot = super.getCamera().getRobot();
BufferedImage image = robot.createScreenCapture(new Rectangle(x, y, width, height));
super.disableSelectionFrame();
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ImageIO.write(image, "png", stream);
super.setCaptureResult(stream);
super.finish();
} catch (IOException e) {
e.printStackTrace();
}
}
Now in GifCapturer the process is longer, because it actually starts a Timer to take screenshots of every frame every 60ms.
To finish capturing a gif, you click on "enter", I used JKeyMaster to detect hotkeys.
after clicking "ENTER", this method will be executed in GifCapturer
public void createGif() {
super.disableSelectionFrame();
AnimatedGifEncoder gif = new AnimatedGifEncoder();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
gif.start(stream);
gif.setDelay(1000);
this.border.updateProgress(10);
for(int i = 0; i < this.frames.size(); i++) {
gif.addFrame(this.frames.get(i));
}
this.border.updateProgress(50);
gif.finish();
super.setCaptureResult(stream);
this.border.updateProgress(100);
super.finish();
this.border.setVisible(false);
this.border = null;
}
This is pretty much it, if I will use GifCapturer twice, everything works fine, but if I will use ScreenshotCapturer twice, JFrame will NOT show up on the second time!
I am not really sure why, could this be a bug in Swing? Maybe because GifCapturer takes longer before it makes the frame visible?
What did I do wrong?
Okay, so from what I understand the problem you are having is with this code...
Basically, the WiseCapturer API allows you to "drag" transparent rectangle over the screen when you call beginCapture...
public static void main(String[] args) throws AWTException {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
}
The problem you're having is when captureEnded is called (for the outer capture), the inner capture process is not stating (and you can't "drag" the transparent selection rectangle)...
This seems to be because you are blocking whenever thread/event queue WiseCapturer is using and the captureEnded event as not been allowed to finish...
If I do something like...
try {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
System.out.println("...");
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
t.start();
}
});
System.out.println("Hello");
} catch (AWTException exp) {
exp.printStackTrace();
}
Which starts a new Thread within the outer captureEnded call, I can get it to work...
Also, not knowing the Thread safety rules for this API, I also used SwingUtilities.invokeLater
try {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
System.out.println("...");
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
}
});
System.out.println("Hello");
} catch (AWTException exp) {
exp.printStackTrace();
}
And had it work...I'm also a little weirded out about why you would do this, but that's just me
I would like to create a program where the Jframe is able to move freely on it's own. Kind of like a translation / transition.
For example,
Click on program to begin.
Jframe spawns at location (0,0).
Automatically move (animate) 100 pixels to the right so that the new coordinates are (100,0).
I know there's the setLocation(x,y) method that sets the initial position once the program runs but is there a way to move the entire Jframe after the program starts?
The basic concept would look something like this...
public class MoveMe01 {
public static void main(String[] args) {
new MoveMe01();
}
public MoveMe01() {
EventQueue.invokeLater(
new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
final JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Use the Force Luke"));
frame.pack();
frame.setLocation(0, 0);
frame.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point location = frame.getLocation();
Point to = new Point(location);
if (to.x < 100) {
to.x += 4;
if (to.x > 100) {
to.x = 100;
}
}
if (to.y < 100) {
to.y += 4;
if (to.y > 100) {
to.y = 100;
}
}
frame.setLocation(to);
if (to.equals(location)) {
((Timer)e.getSource()).stop();
}
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
}
This is a pretty straight, linear animation. You'd be better of investigating one of the many animation engines available for Swing, this will provide you with the ability to change the speed of the animation based on the current frame (doing things like slow-in and slow-out for example)
I would take a look at
Timing Framework
Trident
Universla Tween Engine
Updated with a "variable time" solution
This is basically an example of how you might do a variable time animation. That is, rather then having a fixed movement, you can adjust the time and allow the animation to calculate the movement requirements based on the run time of the animation...
public class MoveMe01 {
public static void main(String[] args) {
new MoveMe01();
}
// How long the animation should run for in milliseconds
private int runTime = 500;
// The start time of the animation...
private long startTime = -1;
public MoveMe01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
final JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Use the Force Luke"));
frame.pack();
frame.setLocation(0, 0);
frame.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (startTime < 0) {
// Start time of the animation...
startTime = System.currentTimeMillis();
}
// The current time
long now = System.currentTimeMillis();
// The difference in time
long dif = now - startTime;
// If we've moved beyond the run time, stop the animation
if (dif > runTime) {
dif = runTime;
((Timer)e.getSource()).stop();
}
// The percentage of time we've been playing...
double progress = (double)dif / (double)runTime;
Point location = frame.getLocation();
Point to = new Point(location);
// Calculate the position as perctange over time...
to.x = (int)Math.round(100 * progress);
to.y = (int)Math.round(100 * progress);
// nb - if the start position wasn't 0x0, then you would need to
// add these to the x/y position above...
System.out.println(to);
frame.setLocation(to);
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
}