Java Coding Problems

This is a new forum that can be used to discuss anything that's not directly related to JPatch.

Java Coding Problems

Postby dcuny » Sat Aug 29, 2009 10:15 pm

I'm having some problems coding an application in Java. The idea is pretty simple: load a graphic, alter it, and display the results. It works fine under Windows, but doesn't render the image in Linux.

The main class is essentially:
Code: Select all
   public static void main(String[] args) {
      

      // load an image
      BufferedImage image = null;
      try {
          image = ImageIO.read(new File("images/bluescreen.png"));
      } catch (IOException e) {
         System.out.println("Unable to load image file");
         System.exit(0);
      }      

      GPanel panel = new GPanel(image);
      
      // create a new frame
      JFrame frame = new JFrame();
      
      // set size to image
      frame.setSize(100, 100);
      
      // set content to panel
      frame.setContentPane(panel);
      
      frame.setVisible(true);      
   }

The GPanel class extends JPanel to render the image:
Code: Select all
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;


@SuppressWarnings("serial")
public class GPanel extends JPanel {

   BufferedImage image;
   
   GPanel(BufferedImage image) {
      // set the image
      this.image = image;
   }
   
   @Override public void paint(Graphics g) {
        // draw the image
        g.drawImage(this.image, 0, 0, null);
   }
   
}
I'm aware that Java doesn't always load an image when expected, but it baffles me why this works under Windows. :(
dcuny
 
Posts: 2902
Joined: Fri May 21, 2004 6:07 am

Re: Java Coding Problems

Postby sascha » Mon Aug 31, 2009 12:43 pm

Perhaps it's a problem with the layout manager:
Try to set the size of the GPanel explicitly (and disable the JFrame's layout-manager), or make it return the image's dimension in it's getPreferredSize() method as a hint to the layout manager (or simply call GPanel.setPreferredSize() with the image's dimension)
You could also use a JLabel(new ImageIcon(image)) instead of your GPlanel.
Hope that helps :)
sascha
Site Admin
 
Posts: 2792
Joined: Thu May 20, 2004 9:16 am
Location: Austria

Re: Java Coding Problems

Postby dcuny » Mon Aug 31, 2009 3:38 pm

sascha wrote:Perhaps it's a problem with the layout manager

I'll give it a try, but I don't think that's it. I can get it to render a rectangle in the window, although it doesn't repaint as often as I'd expect it to. :?

Sometimes Java drives me crazy...
dcuny
 
Posts: 2902
Joined: Fri May 21, 2004 6:07 am

Re: Java Coding Problems

Postby sascha » Mon Aug 31, 2009 7:20 pm

Ok, wait a sec!

This kind of thing works just fine, under Windows, OSX, and Linux - believe me, I've written about 100 test applications that do just that: updating an image and drawing it.

Some things to keep in mind (sorry if they sound obvious, but judging from my own experience, my own code often fails because of obvious things):
  • Be sure that the image you update and the one you paint are the same instance (watch out for new keywords where they shouldn't be)
  • For reasons I do not fully understand yet, repaint() calls to the topmost container (most likely a JFrame) do not always repaint all its children. To be on the safe side, call repaint() on your component (e.g. your GPanel object)
  • When writiing directly to the data-buffer of a BufferedImage (e.g. the byte[] or int[] array containing the actual pixel data), be sure to acquire it with something like
    Code: Select all
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    int[] framebuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
    and *not* image.getData().getDataBuffer()... which returns just a copy of the actual buffer (this one kept me puzzling for quite some hours)
    This is not important if you use Java2D drawing commands on the graphics object obtained by image.createGraphics()
  • When using Swing containers, you should actually override paintComponent(Graphics g), not paint(), and call super.paintComponent() within it, but this is not really important in this case.
  • Component.repaint() does not actually repaint the component. What this method does is scheduling a repaint event on the EventQueue, the actual painting is performed on the ETD (Event-Dispatching-Thread) at some later point in time.
    If you are sure that you are on the ETD, e.g. while processing an even - you can check this by calling SwingUtilities.isEventDispatchThread() - and you need to repaint *now*, you can also call one of the paintImmediately methods.
    Long story short: Be aware that all painting is done on the ETD - regardless which thread calls repaint() - so don't block the ETD, otherwise no repainting will be done whatsoever.
  • Once a swing component is showing, don't call any method on it from any other thread than the ETD (there are exceptions, like repaint()). Use EventQueue.invokeLater(Runnable runnable) to schedule your run() method to be invoked on the ETD at some time in the future (i.e. after all pending requests on the ETD have been processed). There's also an invokeAndWait() method which blocks until your code has been executed on the ETD, this might solve the problem in your case (firing repaint() 100 times does not mean that Swing will actually repaint() 100 times, as it can collapse pending repaint events).
  • Sometimes (this usually just happens with short test code), calling swing methods from the the constructor or main() method won't work, exactly because the methods are being called from the wrong thread (i.e. not the ETD) or the component is not yet ready.
    Call e.g. frame.setVisible() true after you've done the layout (e.g. adding children to the JFrame), and make sure that any drawing code that updates that frame is executed on the ETD afterwards. See above

I hope this helps, if you're really stuck feel free to send me your code.

I know that AWTs multithreaded architecture is difficult to understand at first. But keep in mind that your applications main thread is not the tread on which AWT (and for that matter Swing) runs, they run on the ETD. You don't need to worry about threads though, even JPatch is single-threaded. This works because it only constructs the GUI on the main thread and eventually calls something like frame.setVisible(). This is the last method the main tread executes!
Everythings else JPatch does it does as a response to AWT events (key-strokes, mouse-motion, etc.), and as these events are processed on the ETD, JPatch essentially runs on the ETD too, so I don't have to worry about any threading issues with Swing/AWT. This is how most Java GUI appliactions are written. Special care is only needed for e.g. background-tasks, that are performed on a different thread.
sascha
Site Admin
 
Posts: 2792
Joined: Thu May 20, 2004 9:16 am
Location: Austria

Re: Java Coding Problems

Postby dcuny » Tue Sep 01, 2009 5:38 am

The "not on the Main thread" looked like the most probable, but I'm still not making any progress. It might have something to do with my NVidia drivers, since I occasionally get grey windows of death: :roll:
GreyDesktopOfDeath.png

Anyway, here's a link to the zip file.
dcuny
 
Posts: 2902
Joined: Fri May 21, 2004 6:07 am

Re: Java Coding Problems

Postby sascha » Thu Sep 03, 2009 9:42 am

I've started it, and it displays an image :|
What is it supposed to do, or what does it not do on your machine respectively?
sascha
Site Admin
 
Posts: 2792
Joined: Thu May 20, 2004 9:16 am
Location: Austria

Re: Java Coding Problems

Postby dcuny » Thu Sep 03, 2009 9:28 pm

That's how it works under Windows, too. But under my Ubuntu system, it doesn't display an image. What OS did you run it under?

I'm guessing that it's a display driver issue with my video card not playing nice, because I occasionally get the sort of "grey screens" that I posted from other applications as well. I guess I can code the application under Windows, and just hope that it works for other people. :?
dcuny
 
Posts: 2902
Joined: Fri May 21, 2004 6:07 am

Re: Java Coding Problems

Postby sascha » Fri Sep 04, 2009 12:11 am

I've tried it on Ubuntu 9.04 with the nvidia drivers, which shouldn't make a lot of a difference since this doesn't use GL but only X11.

Which JVM did you use? Did you turn on the java2d OpenGl pipeline?

I've spotted a few odd things in your code though:

In GPanel, the cast to Graphics2D isn't necessary, neither is setting the clip region (both should do no harm, but read on below)
In Greenscreen we have more serious problems:
1st: Once a component is visible, don't do anything with it from outside the EDT - but that's just what you do:
You set it visible and then change the content pane from your main thread (which is not the EDT).
Reversing that order should fix it: Set the content pane, then make it visible.
2nd: I've never seen it this way, and I'm not sure this will work. In Java 1.4 and earlier you'd do something like
frame.getContentPane().add(panel), while in 1.5 and later you can also do frame.add(panel)
I'm not sure if it's save to *replace* the JFrame's content-pane (and what it will do to layout managers) - this might behave differently under different Java versions.

I guess it's either a threading issue (1) or somehow related to 2, producing inconsistent results under different Java versions.

So my suggestion is to do the following:
1. panel.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()); // make the panel as large as the image, or rather hint this info to the layout-manager
2. frame.add(panel); // add the panel to the frame
3. frame.pack(); // set the size of the frame so that all components will fit into it
4. frame.setVisible(true); make it visible

Doing all those things in this order should ensure that your frame and panel are set up correctly under any circumstances.

There's actually a third thing that could go wrong:
In your code, you don't set the panel size, so I guess it's 0/0, but your setClip tells it to actually paint outside the panel, which doesn't sound like a save way of doing it.

If this still doesn't help, I'm afraid I'm running out of ideas too.
sascha
Site Admin
 
Posts: 2792
Joined: Thu May 20, 2004 9:16 am
Location: Austria

Re: Java Coding Problems

Postby dcuny » Fri Sep 04, 2009 2:05 am

sascha wrote:I've tried it on Ubuntu 9.04 with the nvidia drivers, which shouldn't make a lot of a difference since this doesn't use GL but only X11.

I'm suggesting it mainly because I've had some odd behaviors (like the screenshot above), which usually come about when Ubuntu decides a window is being unresponsive.

Which JVM did you use?

Code: Select all
java version "1.6.0_0"
OpenJDK Runtime Environment (IcedTea6 1.4.1) (6b14-1.4.1-0ubuntu11)
OpenJDK Server VM (build 14.0-b08, mixed mode)


Did you turn on the java2d OpenGl pipeline?

I don't know how to turn on the OpenGL pipeline, so I guess the answer is "no."

In GPanel, the cast to Graphics2D isn't necessary, neither is setting the clip region

I added these in later when comparing this to some code which worked. The original code had neither.

1st: Once a component is visible, don't do anything with it from outside the EDT - but that's just what you do:
You set it visible and then change the content pane from your main thread (which is not the EDT).

I fiddled with moving that line around to see if it would make a difference. It was originally after the setContent call.

2nd: I've never seen it this way, and I'm not sure this will work. In Java 1.4 and earlier you'd do something like
frame.getContentPane().add(panel), while in 1.5 and later you can also do frame.add(panel)

I think I've done this safely in other applications. It didn't seem to make a difference.

1. panel.setPreferredSize(new Dimension(image.getWidth(), image.getHeight());

I originally had some debugging code in the panel which would render a rectangle. Since the rectangle was rendering, I was fairly certain this wasn't the problem. This didn't change the behavior. :(

Doing all those things in this order should ensure that your frame and panel are set up correctly under any circumstances.

Nope. :(

In your code, you don't set the panel size, so I guess it's 0/0, but your setClip tells it to actually paint outside the panel, which doesn't sound like a save way of doing it.

Hrm... Still no luck.

There's something fundamentally wrong here. I've reduced the code down to pretty much nothing, and I'm not even getting the panel to paint at all. I'm going to trawl through the Internet and see if I can find some simple example, and work from there.

Thanks!
dcuny
 
Posts: 2902
Joined: Fri May 21, 2004 6:07 am

Re: Java Coding Problems

Postby sascha » Fri Sep 04, 2009 7:27 am

java version "1.6.0_0"
OpenJDK Runtime Environment (IcedTea6 1.4.1) (6b14-1.4.1-0ubuntu11)

I've tried it with OpenJDK too now (the same version, seems to be the default in Ubuntu 9.04) - and it works.

To be on the save side, use the Sun JVM as a reference. You can install in in Ubuntu too, the packages are called "sun-java6-jdk", etc.
1. panel.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()); // make the panel as large as the image, or rather hint this info to the layout-manager
2. frame.add(panel); // add the panel to the frame
3. frame.pack(); // set the size of the frame so that all components will fit into it
4. frame.setVisible(true); make it visible

This does not work? Are you 100% sure?

Ah, and you should add a frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); so that your program exits after you close it's window. Otherwise, after starting it a few times you'll have several JVMs waiting in the background (you'll see them in Eclipsed DEBUG perspective and can only close them from there.)

A last thing you could try: If you use an older graphics card, turn off the "effects" (i.e. compiz) - you can do this in the Appearance settings, or simply disable it by typing "metacity --replace" in a shell. I've had troubles with JPatch's OpenGL displays on the notebook at work (5 years old, ATI mobility) when compiz was running. It never made any troubles with "standard" AWT though, so it's a long shot.

Edit:
Ok, here's how I'd do it:
Code: Select all
import java.awt.*;
import java.io.*;

import javax.imageio.*;
import javax.swing.*;

public class ImageTest {

   public static void main(String[] args) throws IOException {
      final Image image = ImageIO.read(new File("test.jpg"));
      final ImagePanel imagePanel = new ImagePanel(image);
      final JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(imagePanel);
      frame.pack();
      frame.setVisible(true);
   }

   @SuppressWarnings("serial")
   final static class ImagePanel extends JComponent {
      final Image image;
      
      public ImagePanel(final Image image) {
         this.image = image;
         setPreferredSize(new Dimension(image.getWidth(null), image.getHeight(null)));
      }
      
      @Override
      public void paintComponent(Graphics g) {
         super.paintComponent(g); // fill background if applicable
         g.drawImage(image, 0, 0, null);
      }
   }
}

I refuse to believe that this would not work :D
Could you compile and run that for me?
sascha
Site Admin
 
Posts: 2792
Joined: Thu May 20, 2004 9:16 am
Location: Austria

Re: Java Coding Problems

Postby dcuny » Fri Sep 04, 2009 4:15 pm

sascha wrote:This does not work? Are you 100% sure?

I'll try it again. :)

-Ah, and you should add a frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); so that your program exits after you close it's window. Otherwise, after starting it a few times you'll have several JVMs waiting in the background (you'll see them in Eclipsed DEBUG perspective and can only close them from there.)

I added that, too. At one point, I had fiddled with the code and gotten a picture to render. But it didn't repeat when I ran the code again, so it makes me suspicious of the JVM or the video card. The same code should create the same results, so perhaps not closing the window properly had a cumulative effect on the debug environment in Eclipse. I've had similar odd effects when working on OpenGL in Java and Eclipse which only cleared up when I rebooted the machine. :|

A last thing you could try: If you use an older graphics card, turn off the "effects" (i.e. compiz) - you can do this in the Appearance settings, or simply disable it by typing "metacity --replace" in a shell. I've had troubles with JPatch's OpenGL displays on the notebook at work (5 years old, ATI mobility) when compiz was running. It never made any troubles with "standard" AWT though, so it's a long shot.

I'll try this when I get back from work today.

I refuse to believe that this would not work :D
Could you compile and run that for me?

I'll let you know! Thanks again! :D
dcuny
 
Posts: 2902
Joined: Fri May 21, 2004 6:07 am

Re: Java Coding Problems

Postby sascha » Fri Sep 04, 2009 7:30 pm

The same code should create the same results

This isn't necessarily true for race conditions or other threading related bugs. And not exiting from the JVM could (very) theoretically lead to other issues, like running out of VRAM because it never gets freed, etc.

Anyway, let me know whether my code snipplet works or not.
sascha
Site Admin
 
Posts: 2792
Joined: Thu May 20, 2004 9:16 am
Location: Austria

Re: Java Coding Problems

Postby sascha » Sun Sep 06, 2009 5:17 pm

:idea: :?:
sascha
Site Admin
 
Posts: 2792
Joined: Thu May 20, 2004 9:16 am
Location: Austria

Re: Java Coding Problems

Postby dcuny » Mon Sep 07, 2009 6:27 pm

Sorry, I've had very little free time over the last couple of days. My vacation is almost over, so I should be able to test this out in a day or so. :(
dcuny
 
Posts: 2902
Joined: Fri May 21, 2004 6:07 am

Re: Java Coding Problems

Postby sascha » Tue Sep 08, 2009 9:29 am

Don't worry, I was just practicing my communicate solely via emoticons skills ;-)
sascha
Site Admin
 
Posts: 2792
Joined: Thu May 20, 2004 9:16 am
Location: Austria

Next

Return to Off topic

Who is online

Users browsing this forum: No registered users and 1 guest

cron