Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Easy Learn Java: Programming Articles, Examples and Tips - Page 378


Previous 1060 Stories (530 Pages, 2 Per Page) Next

VolatileBufferedToolkitImage Strategies

Go to all tips in Swing, AWT

A common question seems to arise often from Java graphics developers about which image type or creation method to use. When exactly should you use VolatileImage? What is BufferedImage appropriate for? What about the old Toolkit images? And when is BufferStrategy more appropriate than one of these image types?

It's a pretty big topic, and the answer (like all truly great answers) is probably "It depends". But there are some general guidelines that can come in handy.

Image Types

First of all, perhaps a short dictionary of image types might help:

  • Toolkit Image: This is the oldest kind of image object in the Java API. These images are created and returned by the old 1.x APIs such as Applet.getImage() and Toolkit.createImage(). These images are created from a pointer to a data source, such as a GIF or JPG file, and return an object of type Image. They are useful for convenient loading and storage of image data for display, but getting at the actual pixel data or manipulating it is not as easy.
  • BufferedImage: This is an image type that was created in the JDK 1.2 API. They were created for easier and more powerful manipulation of the actual pixel data in an image. At first, there was no way to load an image from a data source directly into a BufferedImage; these images were used, instead, to create an arbitrary buffer for pixel data, which you could then write to, read from, or display conveniently. The main way to get actual pixel data into a BufferedImage object at first was through use of rendering operations (after getting a Graphics object for the BufferedImage), or by manually setting the pixel data through methods in BufferedImage, WritableRaster, and DataBuffer. With the advent of the ImageIO API (see below) in JDK 1.4, it became possible to create a BufferedImage object directly from a data source, just like Toolkit images (only these BufferedImage objects are writable, unlike their Toolkit image cousins).
  • VolatileImage: This image type was created in JDK 1.4 as a means of creating and managing accelerated image memory. One of the problems with hardware acceleration for images is that, on some platforms, accelerated memory can be deleted out from under you at any time. This is obviously not what you want for your typical image data. To work around that, the VolatileImage API was created to provide a notification mechanism so that you know when an image must be re-rendered due to data loss. VolatileImage objects are not loaded from image data, but are just created as empty pixel buffers (much as the initial BufferedImage objects were (see above)); to load image data into a VolatileImage, applications must load the image data through some non-Volatile means, get the Graphics object for the VolatileImage, and then copy the data into the Graphics object using drawImage().
  • Managed Images: These image objects are not specific objects or APIs in Java, but are rather a concept of how we accelerate image operations. A "managed image" is one that you create through any of the normal image creation/loading methods and which we try to accelerate for you internally, by creating an accelerated mirror copy of the image data. This type of image can benefit from hardware acceleration without falling prey to the "surface loss" issues mentioned above for VolatileImage. I'll talk more about managed images and hardware acceleration later in the article.

That's it for the basic image types. Now let's talk about how we actually create and use these image objects.

Read the rest here



comments? | Printer Friendly Page  Send to a Friend | Score: 0
Posted by jalex on Sunday, June 26, 2005 (00:00:00) (2447 reads)

What do you Prefer?

Go to all tips in Story by Dr. Kabutz

The Java Specialists' Newsletter [Issue 030] - What do you Prefer?

Author: Herman Lintvelt (Polymorph Systems)

JDK version:

Category: GUI

You can subscribe from our home page: http://www.javaspecialists.co.za (which also hosts all previous issues, available free of charge Smile

With the arrival of my second child, a 4.2kg daughter which we called Nicola Constance Bettina Kabutz, I have been rather busy changing nappies, rocking the child to sleep, and more exhaustingly, helping my 3 year old son cope with life in general. Fortunately for my die-hard supporters out there, Herman Lintvelt (herman@javaspecialists.co.za) stepped in and saved the day. I promise to pull my socks up and get these things done more regularly as soon as life returns to stability.

With regards

Heinz


Recently I've downloaded JDK 1.4 beta 2, and then forgot about it for a while as my struggles with JMF required all my resources. But then, on a cold Worcester (South Africa) evening, while sitting in front of my fireplace with a nice warm fire heating the room, I was thinking about things I prefer. My preferences.

Do not worry, I won't carry on being philosophical. It actually reminded me of the new Preferences API in JDK1.4, so I put away the red wine, and pulled out my laptop. And was I pleasantly surprised.

The Preferences API

The guys at Sun has seen the need for handling preferences in a somewhat better and easier to use way than using Properties or implementing a complex preference subsystem that saves it to a database or some other backing store. So they created the Preferences API.

Using this API starts with the Preferences class in the java.util.prefs package. This class represents a preference node in some kind of preference hierarchy. Such a node can have child nodes, as well as key-value pairs belonging to it (similar to Windows Registry). The 4 important static methods of Preferences are:

// return system preference-node for package that O belongs to
Preferences systemNodeForPackage(Object 0);
// return root node of system preferences
Preferences systemRoot();
// return system preference-node for package that O belongs to
Preferences userNodeForPackage(Object O);
// return root node of user preferences
Preferences userRoot();
Some explanation is probably needed. The preference data gets saved in two tree-like structures in an implementation specific way. The JDK for Windows version saves it in the Windows Registry, but it is possible to create one's own implementation that might for example use a database. The one tree is used to store user-specific preferences (each user on a system will have a seperate tree), and the other tree stores system preferences. (The definition of user and system depends on the preferences implementation. In the Windows JDK version it maps to Windows users and system-wide preferences.) Each node in this tree can be represented by a Preferences object.

However, if you're like me you do not like theory too much (and that's what javadocs are for), so let us explore this API with an example: a "Cross-platform Registry Editor".


Cross-platform Registry Editor

The idea of this Java tool is to be able to view and edit preferences saved via the Preferences API, no matter on what platform it is executed (i.e. the backing store used is transparent to the user).

Preference Nodes

We implement the class PreferencesEditor as a JDialog, and it must contain a JTree to present the preferences trees (user and/or system), and a JTable to display and edit the actual preference values. We need the following inner classes: PrefTreeNode to represent a preference node in the JTree, PrefTableModel to handle the display and editing of preference values in the table, and PrefTreeSelectionListener to update the JTable with the currently selected preference node.

I list the code for PreferenceEditor with discussions in between the code.

//add all other necessary imports here
import java.util.prefs.Preferences;
import java.util.prefs.BackingStoreException;

public class PreferencesEditor extends JDialog {
  JTree prefTree;
  JTable editTable;

  /**
   * Creates PreferencesEditor dialog that show all System and
   * User preferences.
   * @param owner owner JFrame
   * @param title title of dialog
   */
  public PreferencesEditor(JFrame owner, String title){
    this(owner, title, null, true, null, true);
  }

  /**
   * @param owner owner JFrame
   * @param title title of dialog
   * @param userObj the package to which this object belongs is
   * used as the root-node of the User preferences tree (if
   * userObj is null, then the rootnode of all user preferences
   * will be used)
   * @boolean showUserPrefs if true, then show user preferences
   * @param systemObj the package to which this object belongs is
   * used as the root-node of the System preferences tree (if
   * systemObj is null, then the rootnode of all system
   * preferences will be used)
   * @param showSystemPrefs if true, then show system preferences
   */ 
  public PreferencesEditor(JFrame owner, String title,
      Object userObj, boolean showUserPrefs, Object systemObj,
      boolean showSystemPrefs) {
    super(owner, title);
    getContentPane().setLayout(new BorderLayout(5,5));
    setSize(640,480);
    createTree(userObj, showUserPrefs, systemObj, showSystemPrefs);
    editTable = new JTable();
    createSplitPane();
    createButtonPanel();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }

As mentioned in the code comments, there are two constructors: one give access to all the system and user preferences, and one can be used to only display/edit a specified subset of the preferences. Let's first look at the createTree(...), createUserNode(...) and createSystemRootNode(...) methods to see how this is done:

  private void createTree(Object userObj, boolean showUserPrefs, Object systemObj, boolean showSystemPrefs){
    DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Preferences");
    if (showUserPrefs) {
      rootNode.add(createUserRootNode(userObj));
    }
    if (showSystemPrefs) {
      rootNode.add(createSystemRootNode(systemObj));
    }
    DefaultTreeModel model = new DefaultTreeModel(rootNode);
    prefTree = new JTree(model);
    prefTree.addTreeSelectionListener(new PrefTreeSelectionListener());
  }
  private MutableTreeNode createSystemRootNode(Object obj) {
    try {
      PrefTreeNode systemRoot;
      if (obj==null) {
        systemRoot = new PrefTreeNode(Preferences.systemRoot());
      } else {
        systemRoot = new PrefTreeNode(Preferences.systemNodeForPackage(obj));
      }
      return systemRoot;
    } catch (BackingStoreException e) {
      e.printStackTrace();
      return new DefaultMutableTreeNode("No System Preferences!");
    }
  }
  private MutableTreeNode createUserRootNode(Object obj) {
    try {
      PrefTreeNode userRoot;
      if (obj==null) {
        userRoot = new PrefTreeNode(Preferences.userRoot());
      } else {
        userRoot = new PrefTreeNode(Preferences.userNodeForPackage(obj));
      }
      return userRoot;
    } catch (BackingStoreException e) {
      e.printStackTrace();
      return new DefaultMutableTreeNode("No User Preferences!");
    }
  }
If the user specify a userObj (and showUserPrefs=true), then Preferences.userNodeForPackage(userObj) gets called in creteUserRootNode. This will return a Preferences object that represents the preferences node that maps to the package structure of userObj. If this preference node does not yet exist in the backing store, it gets created. For example, if I call createUserNode(new com.polymorph.MyClass()), then the preference node "com/polymorph" will be returned, and its parent node will be "com" (in the user preference tree). If the user pass null as parameter, then Preferences.userRoot() gets called, which return the root node of the user preferences tree (for the current user). The same goes for createSystemRootNode and the system preferences.

Of course we need a way of representing a preference node in a JTree, and this is what the PrefTreeNode inner class is for.

  class PrefTreeNode extends DefaultMutableTreeNode {
    Preferences pref;
    String nodeName;
    String[] childrenNames;

    public PrefTreeNode(Preferences pref) throws BackingStoreException {
      this.pref = pref;
      childrenNames = pref.childrenNames();
    }
    public Preferences getPrefObject(){
      return pref;
    }
    public boolean isLeaf(){
      return ((childrenNames==null)||(childrenNames.length == 0));
    }
    public int getChildCount(){
      return childrenNames.length;
    }
    public TreeNode getChildAt(int childIndex){
      if(childIndex < childrenNames.length){
        try {
          PrefTreeNode child = new PrefTreeNode(pref.node(childrenNames[childIndex]));
          return child;
        } catch (BackingStoreException e) {
          e.printStackTrace();
          return new DefaultMutableTreeNode("Problem Child!");
        }
      }
      return null;
    }
    public String toString(){
      String name = pref.name();
      if ((name == null)||("".equals(name))){ //if root node
        name = "System Preferences";
        if (pref.isUserNode()) name = "User Preferences";
      }
      return name;
    }
  }
This inner class decorates a Preferences object to be used as a MutableTreeNode in a JTree. All the child preferences nodes of this object are accessed via the pref.childrenNames() call, and stored in a String array. This array is then used to calculate the number of children nodes, whether this is a leaf node, etc. getChildAt gets a specific child node, mainly via the pref.node(childrenNames[childIndex]) call. Preferences.node("nodeString") returns a Preferencesobject for the node specified by "nodeString". It can specify a node relative to the current one, ex. "child1", which will return a child preference node (as we use it in getChildAt), or an absolute path can be specified, ex. "/com/polymorph/UI" will return a node "UI", with parent node "polymorph".

Preference Key-Value pairs

OK, our editor is now able to handle the nodes in the user and/or system preferences hierarchy, but how to we actually access the preference values? Well, the Preferences API allows us to save preferences in our custom defined preferences structure in a very similar way as we would in a Hashmap: we put key-value pairs in the preferences node, where the key is a specific preference setting name, and the value can either be a String, int, long, boolean, float, double or byte[]. Once you have a Preferences object, you can just call put("keyStr", "valueStr"), or putLong("keyStr", 123l), etc. And you can retrieve these values via the get("keyStr", "defaultStr"), or getLong("keyStr", 233 /*defaultVal*/), etc. methods. Note that for every get method, a default value must be supplied. This forces you to think about default values for when the preferences cannot be loaded from the backing store, thus allowing your application to continue even though preferences could not be loaded.

In our editor example, we access these key-value pairs in a JTable, and we need the PrefTableModel to do this:

  class PrefTableModel extends AbstractTableModel {
    Preferences pref;
    String[] keys;
    public PrefTableModel(Preferences pref){
      this.pref = pref;
      try {
        keys = pref.keys();
      } catch (BackingStoreException e) {
        System.out.println("Could not get keys for Preference node: "+pref.name());
        e.printStackTrace();
        keys = new String[0];
      }
    }
    public String getColumnName(int column) {
      switch(column){
      case 0: return "Key";
      case 1: return "Value";
      default: return "-";
      }
    }
    public boolean isCellEditable(int rowIndex, int columnIndex) {
      switch(columnIndex) {
      case 0: return false;
      case 1: return true;
      default: return false;
      }
    }
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
      pref.put(keys[rowIndex], aValue.toString());
      try {
        pref.sync(); //make sure the backing store is synchronized with latest update
      } catch (BackingStoreException e) {
        System.out.println("Error synchronizing backStore with updated value");
        e.printStackTrace();
      }
    }
    public Object getValueAt(int row, int column){
      String key = keys[row];
      if (column==0) return key;
      Object value = pref.get(key, "(Unknown)");
      return value;
    }
    public int getColumnCount(){
      return 2;
    }
    public int getRowCount(){
      return keys.length;
    }
  }
In the PrefTableModel constructor, pref.keys returns all the key-names stored in the pref node. These key-names are then used in getValueAt to get the value of either a key or value-column cell. If we want the value of a Value-column cell, we get it as a String via the pref.get(key, "Unknown") call (default value="Unknown"), as the Preferences API unfortunately does not seem to allow us to retrieve it as an Object. Thus all values are presented as String in the table, but this should not be a problem, as it seems that these values are saved as Strings anyway in the backing store. getLong, getBoolean, etc. tries and interpret the saved string-value as a long, boolean, etc.

Only the Value-column cells are editable, and the setValueAt method uses pref.put(key-name, aValue) to update the edited value. It also calls pref.sync() that forces any updates to be synchronized with the backing store.

How do we connect this table model to the preference tree? Well, the PreferencesEditor constructor creates a JTable object (editTable), and then we use the PrefTreeSelectionListener inner class to update the table model of this table.

  class PrefTreeSelectionListener implements TreeSelectionListener{
    public void valueChanged(TreeSelectionEvent e) {
      try {
        PrefTreeNode node = (PrefTreeNode)e.getPath().getLastPathComponent();
        Preferences pref = node.getPrefObject();
        editTable.setModel(new PrefTableModel(pref));
      } catch (ClassCastException ce) {
        System.out.println("Node not PrefTreeNode!");
        editTable.setModel(new DefaultTableModel());
      }
    }
  }
The createTree method adds an instance of PrefTreeSelectionListener to the JTree as a listener.

All that now remains to be defined are the createSplitPane() and createButtonPanel methods, and none of them contains any surprises:

  private void createSplitPane(){
    JSplitPane splitPane = new JSplitPane();
    splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
    splitPane.setOneTouchExpandable(true);
    splitPane.setLeftComponent(new JScrollPane(prefTree));
    splitPane.setRightComponent(new JScrollPane(editTable));
    getContentPane().add(splitPane, BorderLayout.CENTER);
  }
  private void createButtonPanel(){
    JPanel buttonPanel = new JPanel(new BorderLayout(5,5));
    JButton closeButton = new JButton("Close");
    closeButton.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e) {
        System.exit(0);
      }
    });
    buttonPanel.add(closeButton, BorderLayout.EAST);
    getContentPane().add(buttonPanel, BorderLayout.SOUTH);
  }
} //end of PreferencesEditor

And that's how easy it is to implement a simple, yet usable, cross-platform registry editor. Already my mind is spinning with ideas on how to improve on this, like adding functionality to be able to modify the preference trees and making use of the Preferences API export/import capabilities (yhep, you can actually export preferences to XML files, and also import these files). A whole new preferable world is opening up...


Copyright 2000-2004 Maximum Solutions, South Africa

Reprint Rights. Copyright subsists in all the material included in this email, but you may freely share the entire email with anyone you feel may be interested, and you may reprint excerpts both online and offline provided that you acknowledge the source as follows: This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

Java and Sun are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Maximum Solutions is independent of Sun Microsystems, Inc.

21032 bytes more | comments? | Printer Friendly Page  Send to a Friend | Score: 0
Posted by jalex on Saturday, June 25, 2005 (00:00:00) (2364 reads)

Previous 1060 Stories (530 Pages, 2 Per Page) Next

530| 529| 528| 527| 526| 525| 524| 523| 522| 521| 520| 519| 518| 517| 516| 515| 514| 513| 512| 511| 510| 509| 508| 507| 506| 505| 504| 503| 502| 501| 500| 499| 498| 497| 496| 495| 494| 493| 492| 491| 490| 489| 488| 487| 486| 485| 484| 483| 482| 481| 480| 479| 478| 477| 476| 475| 474| 473| 472| 471| 470| 469| 468| 467| 466| 465| 464| 463| 462| 461| 460| 459| 458| 457| 456| 455| 454| 453| 452| 451| 450| 449| 448| 447| 446| 445| 444| 443| 442| 441| 440| 439| 438| 437| 436| 435| 434| 433| 432| 431| 430| 429| 428| 427| 426| 425| 424| 423| 422| 421| 420| 419| 418| 417| 416| 415| 414| 413| 412| 411| 410| 409| 408| 407| 406| 405| 404| 403| 402| 401| 400| 399| 398| 397| 396| 395| 394| 393| 392| 391| 390| 389| 388| 387| 386| 385| 384| 383| 382| 381| 380| 379|
378
| 377| 376| 375| 374| 373| 372| 371| 370| 369| 368| 367| 366| 365| 364| 363| 362| 361| 360| 359| 358| 357| 356| 355| 354| 353| 352| 351| 350| 349| 348| 347| 346| 345| 344| 343| 342| 341| 340| 339| 338| 337| 336| 335| 334| 333| 332| 331| 330| 329| 328| 327| 326| 325| 324| 323| 322| 321| 320| 319| 318| 317| 316| 315| 314| 313| 312| 311| 310| 309| 308| 307| 306| 305| 304| 303| 302| 301| 300| 299| 298| 297| 296| 295| 294| 293| 292| 291| 290| 289| 288| 287| 286| 285| 284| 283| 282| 281| 280| 279| 278| 277| 276| 275| 274| 273| 272| 271| 270| 269| 268| 267| 266| 265| 264| 263| 262| 261| 260| 259| 258| 257| 256| 255| 254| 253| 252| 251| 250| 249| 248| 247| 246| 245| 244| 243| 242| 241| 240| 239| 238| 237| 236| 235| 234| 233| 232| 231| 230| 229| 228| 227| 226| 225| 224| 223| 222| 221| 220| 219| 218| 217| 216| 215| 214| 213| 212| 211| 210| 209| 208| 207| 206| 205| 204| 203| 202| 201| 200| 199| 198| 197| 196| 195| 194| 193| 192| 191| 190| 189| 188| 187| 186| 185| 184| 183| 182| 181| 180| 179| 178| 177| 176| 175| 174| 173| 172| 171| 170| 169| 168| 167| 166| 165| 164| 163| 162| 161| 160| 159| 158| 157| 156| 155| 154| 153| 152| 151| 150| 149| 148| 147| 146| 145| 144| 143| 142| 141| 140| 139| 138| 137| 136| 135| 134| 133| 132| 131| 130| 129| 128| 127| 126| 125| 124| 123| 122| 121| 120| 119| 118| 117| 116| 115| 114| 113| 112| 111| 110| 109| 108| 107| 106| 105| 104| 103| 102| 101| 100| 99| 98| 97| 96| 95| 94| 93| 92| 91| 90| 89| 88| 87| 86| 85| 84| 83| 82| 81| 80| 79| 78| 77| 76| 75| 74| 73| 72| 71| 70| 69| 68| 67| 66| 65| 64| 63| 62| 61| 60| 59| 58| 57| 56| 55| 54| 53| 52| 51| 50| 49| 48| 47| 46| 45| 44| 43| 42| 41| 40| 39| 38| 37| 36| 35| 34| 33| 32| 31| 30| 29| 28| 27| 26| 25| 24| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1|


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy