How do I solve problems in my screenshot-taking application? - java

I wrote a GUI-based Java program that takes 25 screenshots per second and saves them at a user-defined location.
It works pretty well except that it has two problems:
The mouse cursor is missing from the images and I know it will be because BufferedImages do not contain cursor information in them. They have to be added programatically.
The thread that takes screenshots is a daemon thread. So if I close the application, the thread is killed and the PNG image that was being written gets corrupted. I want to avoid that.
Here are the images of my application:
The award-winning, intuitive GUI:
The high-definition images captured look like this:
As you can see from the image the cursor information is being displayed in the console using MouseInfo's static methods.
Please let me know how to solve the above mentioned two problems.
After solving the problem, the images now look like this:

The mouse cursor is missing from the images and I know it will be
because BufferedImages do not contain cursor information in them. They
have to be added programatically.
That is correct, you have to add the cursor afterwards. The reason for this is that a screenshot taken with the Robot class never contains the cursor. Not really because "the BufferedImage doesn't contain mouse info". A BufferedImage is a class that contains a raster of pixels.
The thread that takes screenshots is a daemon thread. So if I close
the application, the thread is killed and the PNG image that was being
written gets corrupted. I want to avoid that.
Simply, in the screenshot thread, use a flag that indicates wether it should continue or not. Keep taking screenshots as long as that boolean is set to true. Make sure to make it non-deamon. So, when you close the application, set the flag to false.
Probably the most easy way to do this is to add a WindowListener:
yourFrame.addWindowListener(new WindowAdapter()
{
public void windowClosed(WindowEvent e)
{
screenshotThread.stopTakingScreenshots(); // This methods set the flag
}
}
Also notice that you are not taking the time it takes to make and save a screenshot in count. You use a fixed sleep of 40 milliseconds, but let's say that it takes 4 milliseconds to take and save the screenshot, then you should sleep for only 36 milliseconds. To time how long it takes to make the screenshot, use System.currentTimeMillis(); before and after your takeShot() method and make the difference.

Related

Ensure that AWT Canvas is drawn on-screen before doing something else

In my application I NEED to make sure that Canvas is actually appeared on the screen before going for the next step. The reason is that I need to retrieve an AWT Drawable - i.e. the native window surface of that canvas. And that drawable would be invalid if the canvas is not visible, even if it has the flag "visible" set to true.
The problem Im having is that I can't be sure when Java actually decides to display it.
I even made a code to actually delay after Canvas constructor, but what happens is that it is displayed AFTER the delay has expired.
canvas3d = new Canvas3d();
System.err.println("Before sleep");
try
{
Thread.sleep(3000);
}
catch (Exception e) {}
System.err.println("After sleep");
canvas3d.Init();
This is odd, because the drawing and rendering of elements should be handled by a completely separate thread, and my main thread sleeping should theoretically give it enough time to process the stuff. But it still waits for some reason.
Adding Repaint() or revalidate() doesn't help.
The problem with this is that sometimes, the canvas gets displayed before the Init() gets to the point that it needs it to be visible. But other times - it doesn't get displayed before that.
Can I somehow FORCE the application to display the element before I'm doing anything else? Or can I somehow retrieve if the canvas is displayed at the moment or not? Because checking Canvas.visible is pointless - whether it's true or false, it doesn't mean that it's actually displayed or hidden in that precise moment during runtime. It's just a flag showing that it's supposed to be displayed, but oh, oopsie, Java just can't guarantee that it actually is!
It seems that I can use canvas.isShowing() to test if it's actually visible on the screen. At least by checking that parameter I got the result I wanted (so far).
I am still not certain if that's enough and if there's something more that can go wrong on the low level, particularly if I try to access the surface during X11 rendering pipeline where AWT has already completely "displayed" the component but X11 hasn't yet finished drawing it on the screen.
That's one concern.
But for now, it seems to be the best answer I can come up with.

Any way to delay PaintComponent?

I've read through lots of the threads on paintComponent here, most of which making the point that it either is never or almost never necessary (or possible) to choose when paintComponent is called.
In my program, however, sometimes (only sometimes) paintComponent gets called before some of the objects it needs to paint have finished initializing or even sometimes before they've been created, triggering warnings- JOptionPane pop-ups, which surprisingly do not show any of the text they were hard-coded to display in their "message" area. I've read in other places that it's something to do with the EDT, and I've looked into some parts of that but I'm just getting confused. If the main purpose of the EDT is to update the gui, and by default pretty much everything will run in the EDT, then could I tell the program to run all the initialization and update functions in a different thread(s), which I somehow forcibly make run before the EDT runs?
What I'd ideally like to have happen is for paintComponent to wait until a certain point in my code to be run (after a bunch of update functions, regardless of what happens to the screen. After it does get called, it is followed by a pause in which relatively little is going on ( I had been using Thread.sleep() inside a while loop ) and which lasts until the user clicks something - at which point all the necessary functions are run again, followed by paintComponent afterwards, then the sleep() while loop, etc.
From what I understand, I think what I want isn't really possible, so my question is: Do you guys have any ideas of how to get around this?
EDIT:
So essentially the program is a college course planner, intended to make it easier for someone to plan out by semester all the courses they have to take before graduation, move those courses around (if possible), and see how all the courses are connected (prerequisites and such). When the program starts, it loads the list of necessary courses from a text file, then loads info about each course from a bunch of individual text files, and arranges them according to their prerequisites. Courses with no prerequisites go in the first semester, courses whose prerequisites have all been added to the first semester get added to the second, and so on until all the courses have been added. When paintComponent runs, it calls a function that assume all of each course's prerequisites exist on the schedule, and if it finds otherwise, it throws an error and displays a JOptionPane message box. When this happens during a normal run of the program (like if I manually add a course before adding its prerequisites), that all works and displays correctly. But sometimes that message box pops up when only some of the courses have been loaded (meaning control is still in the main constructor) and when it does so, the actual string message doesn't show up - only the actual pane, title and ok button do. Heres the line where I display the error box, so you can know that I'm not trying to display a string variable which has the potential of being empty.
JOptionPane.showMessageDialog(this,
"Course couldn't be loaded, partially >loaded\ncourses have been removed.",
"Error",
JOptionPane.OK_OPTION);
It is the "Course couldn't...been removed." part that doesn't get displayed. This is the only JOptionPane I display with the title "Error".
This post mentioned what sounds like the same thing happening, except I'm not using any of the things that poster had to fix. So possibly it's irrelevant but I'll add it just in case. JOptionPane.showMessageDialog() shows but without any message?
But to step back a bit, because that box popped up before all the courses had been added, it means that paintComponent was somehow called in the middle of the relevant JPanel's constructor, before a bunch of things had been initialized. I added a bunch of println() statements to make sure that that is true. Is it normal for that to happen, and if so, is there a way to fix it without simply using Andrew Thompson's advice?
After thinking though it a bit, I think that because the project is 3200 lines long and relies to a huge extent on text files, I'm really not sure how to ( or if I can) make a SSCCE for it..
If any specific pieces would be helpful I'll gladly add those but if this problem isn't clearly some standard issue I'm getting wrong, then I'll just add that flag and keep looking for bugs.
Thanks for your help
Declare a flag as a class attribute. Check it in the paint method. Change it at the end of the initialization.
class XandYandZ extends JComponent {
boolean initializationFinished = false;
public XandYandZ() {
// long initialisation..
initializationFinished = true;
}
public void paintComponent(Graphics g) {
if (!initializationFinished) return;
// .. paint ..

SwingWorker locks GUI on (unsuccessful) JLabel Icon updating

Ok im really struggling with unlocking my GUI which is locked due to separate SwingWorker thread. Basically what my program does: Initializes webcam, and then grabs single frame and displays it as JLabel icon (doing single grab+display on Button click is ease, however i have immense difficulties in doing such operation consecutively in order to do some image processing). I am aiming to obtain such result:
Grab frame -> process it -> display as ImageIcon of Jlabel > ... repeat Grab frame >...
I need results while webcam is streaming, therefore i used SwingWorker publish and process. In my code "processing part" is not included as it is not necessary since i cant even obtain proper continuous frame grabbing. Generally my background thread will never finish unless cancelled (well thats the assumption as i want to process images as fast as possible with maximum frames per second - unless i should do it other way? - i guess separate thread for single frame grab&process would be bad idea due to fact that im aiming to get 10+ FPS). I know my SwingWorker thread works, since i made tests of saving consecutive images to C:\, and it did work, but my GUI is locked anyway, but at least i know that thread is running and grabbing frames.
Generally i have 2 problems:
no JLabel icon update
Locked GUI
My SwingWorker code:
private class FrameStream extends SwingWorker<Void, BufferedImage> {
#Override
protected Void doInBackground() throws InterruptedException{
BufferedImage processedImage = null;
while (!isCancelled()) {
processedImage = getPIC_COLOR(player);
publish(processedImage);
Thread.sleep(5000); // i made such delay to check whether program is not "choking" with data, but its not the case, without this delay everthing is the same
}
return null;
}
#Override
protected void process(List<BufferedImage> mystuff) {
Iterator it = mystuff.iterator();
while (it.hasNext()) {
img_field.setIcon(new ImageIcon(mystuff.get(mystuff.size()-1)));
}
}
#Override
protected void done() {
infoBAR.setText("FINISHED");
}
}
I am so desperate that i rewritten my code completely basing on tutorials example: Flipper as you can see it is ridiculously similar. All my previous efforts also locked gui so tried the 'tutorial way', nonetheless it did not work, which is a pity. Im in a dead end because i have no clue how to fix that. Im desperate for help since as you can see it seems exactly the same as the tutorial one, maybe something other causes issues: MY FULL CODE
Please help, i'm unable to solve it by myself.
One thing that looks a little different to me is your process method. Rather than specifying the last image, you might wish to iterate through all images like so:
#Override
protected void process(List<BufferedImage> mystuff) {
for (BufferedImage bImage : mystuff) {
img_field.setIcon(new ImageIcon(bImage));
}
}
I'm not sure if this will make a significant difference, but I believe that this is how process should be written. Another thought -- if the BufferedImages are large you may wish to create the ImageIcon in the background thread and publish the ImageIcon rather than the BufferedImage.
Nothing stands out as an issue. Steps I would suggest to further debug.
Instead of using a loop and the process method, just pull one frame and set the Icon once. You need to get that working before you try to make it loop. Your application should be able to set the icon that fact that it doesn't highlights a problem.
Second, because your GUI is locking up, there is something still happening on the EDT. Try, running a profiler or adding System.out.println in your code to find what is running while the GUI is locked.
Last, make sure you don't need to be repainting, revalidating the Label's container to make the image visible.
hmmmm, if I read your last post about this issue, there are maybe lots of possible mistakes (and I see your code), that's nothing to do with SwingWorker, another example just replace change Color for JButton#setBackground() with your Icon or ImageIcon
Have you tried to set the label to observe the image icon?
icon.setImageObserver(label);

Add image URL to bitmap image in listfield

I have 50/100 image url with specific text, i add them in vector, add listfield with callback,
I am downloading the image every time with a function call UrlToImage I am facing problem, the list is too slow , download icon showing on the top right side of simulator.
UrlToImage img = new UrlToImage(imageUrl);
bit = img.getbitmap();
pic = new BitmapField(bit);
g.drawBitmap(xpos, y+10, bit.getWidth(), bit.getHeight(), bit, DrawStyle.LEFT,0);
Can't scroll smoothly throughout the list.
Any idea, comments.
Your formatting is all messed up, but if I understand you correctly, you're downloading upon every callback?
One way to avoid that is create a thread that kicks off when the screen is needed, and asynchronously do the downloads (once each!) and stick the images in a cache. Then the drawListRow callback just pulls from the cache.
It appears as though your code is executing inside the paint method. This all occurs on the UI thread (meaning that you block the UI, make a request, wait for a response, set the image, and then draw the image, every time a paint occurs). Seeing as a request can take about 3 seconds, your UI will freeze for that long.
What you should be doing it fetching your image in the constructor of your class, set an instance variable of your class, and then g.drawBitmap with that instance variable.
In short, the only code in your paint method should be the g.drawBitmap, in order to prevent the choppy scrolling.

How to use a delay in a swing application

I am building a swing application. At some point, I have to start an "animation":
...
jpanel1.setBackground(Color.Black);
Delay(milli)
jpanel1.setBackground(Color.White);
...
and so on.
The gui itself and all the logic behind it work.It is just this time depended color-changing that does not. I have read, that swing is not thread safe, but all the examples I found showed me how to start another thread (for example in the background) but never how to stop the current swing-gui thread.
Edit:
The application should work as following:
configuration files are read, jframe is set up.
some simple questions are beeing asked
a dialogue is opened, which explains the animation.
after the user clicked "ok" the animation - some color flashing - is started. the color and the delay between the color-changing is depended on the configuration
another dialogue is opened and the programm continues -> new jpanel inside the jframe, buttons and so on.
the online thing that does not work are the delays between the color-changing. I understand now why it does not work and I am trying to build a timer, which activates a actionlister, which then changes the color and stops the timer... it just seems so much work for a simple delay... and I have to reorganize the entire animation in the application.
Take a look at: https://timingframework.dev.java.net/
and the samples that come in http://filthyrichclients.org/
They provide some very good information on how animation work and using the Timer framework. You'll have a good understanding of how it works.
I did a sample animation here with Swing after reading those:
count down demo app http://img580.imageshack.us/img580/742/capturadepantalla201004wd.png
Java application featuring blog.stackoverflow.com page ( click on image to see the demo video )
But I'm not even sure what is what you want to achieve.
EDIT
I read about the timing framework to understand better what is all about, but I actually didn't use it ( it is useful to create animations with no linear times - ie no every second as mine, but things like 1, 5, 3, 2 seconds )
The code I'm using in the demo above is exactly this:
final Timer imageTimer = new Timer();
imageTimer.schedule( new TimerTask() {
public void run() {
changeImage();
}
}, 0, 10000 ); //<-- every 10 seconds.
The animation for the "stackoverflowing" and the count down use a similar approach.
You do not want to stop the GUI thread, even if you want to have a flashing effect. This is because other basic actions, like repainting when the GUI is hidden by other windows, will be stalled. Take a look at Timer. It will allow you to have an event fired on an interval and you can handle that, in the GUI thread, in your actionPerformed method.
You will want to use the javax.swing.Timer class and not the java.util.Timer class.
The later is preferred when you need general timing the former is preferred for UI updating/changes.
See http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html
You may also want to look at https://timingframework.dev.java.net/.
Do the timer on another thread and when the timer goes off it can send an update message for the animation to draw the next frame.
Another consideration is the delay itself. Don't pick a fixed delay-interval. Old games used to do that and they become unplayable on faster computers. Instead what the newer games do is use the speed of the current CPU to figure out how many update events they need a second at runtime, call it a 'delay-factor', and is set when the program starts up. . The timer uses the delay factor so the animation displays correctly even on machines of different clock-speed.

Categories