Images
[Framework practical 7 of 7]


We now have a perfectly decent little application, however, there are a few of things we could do to improve it.


Firstly, we could resize the frame so that it showed the whole of the image whatever its size.

The code to do this isn't especially hard; you just setSize to something appropriate in the Analyst's paint method. But what to set it to?

All Image objects have getWidth and getHeight methods that take in an ImageObserver. The best ImageObserver is the frame itself, so you can get the width of the image, thus:

int width = image.getWidth(this);

And height similarly. You can then use these to set the Analyst's height and width. Remember, you may also want to use Insets, as we saw in the lecture.


Secondly, you may find that your images flicker quite a lot when displayed.

To be honest you'd rarely draw an image directly onto a frame: they're not really set up for it. You may find it better to make a java.awt.Canvas object as an instance variable within Analyst, and add it to the frame using Analyst's inherited add method just below where you set up the menu etc. You can then draw on this in paint. Canvas is a chunk of screen for drawing on. It will resize with the Analyst frame and you shouldn't need to resize it.

   public void paint (Graphics g) {
      Image image = store.getDataAsImage();
      Graphics gc = canvas.getGraphics();
      // Resize Analyst here if we want.
      gc.drawImage(image, 0, 0, this);
         // note x and y now relative to canvas so no insets needed.
   }


Thirdly, we might want to wait to display an image until we've read a proper one in.

At the moment the application shows a black square because we set the data array in Storage up thus:

double data[][] = new double[300][300];

This fills it with zeros (primitive types have a default value of zero; objects have a default value of null, i.e. "not set up"). This was because in earlier practicals we weren't reading data in, and I didn't want it throwing a whole bunch of "not set up" exceptions if your code went wrong. However, now we're reading data in, we could do this:

double data[][] = null;

leaving the array not set up until the user uses the "Open..." MenuItem, thereby calling setData with a suitable data array. If we did this, we could then do the following to our getDataAsImage method:

   public Image getDataAsImage() {
      if (data != null) {
         // Our Image making code.
         return image;
      } else {
         return null;
      }
   }

And in our Analyst's paint method, this:

   public void paint (Graphics g) {
      Image image = store.getDataAsImage();
      if (image != null) {
         // Resize here if we want.
         // drawImage
      }
   }

i.e. don't do anything if the image == null, which it will be if store.getDataAsImage has returned null because the data array is null.

(if you do this, you might like to add the lines:

   if (data == null) {
      data = new double[300][300];
   } else {
      data = new double[data.length][data[0].length];
   }

to the top of your setRandomData method, so it still works if there's no data set up.)


Finally, you might like to try and link all your practical code with the code from the first assessment.

You've got code to do lots of jobs. It would be nice if you could could read some data in (or had a menu item to generate some random data if you didn't have any), and then run your first assignment process over the data and see the result. We'll leave that for you to play with, but feel free to talk it through with us. In the meantime, here's a version of the IO class (IO.java) that reads in image files like gifs and jpgs and writes these formats as well, along with a satellite image of an important and mysterious continent to manipulate (sat.jpg), should you be interested.