Main | May 2007 »

April 30, 2007

JFC/Swing musings (repost)

I am not a JFC/Swing expert. But here are some musings about JFC/Swing development. Resposting from my personal page.

JFC/Swing musings

  • Learn how to use javax.swing.AbstractAction.
  • Never extend JFrame. Use JPanel or JComponent instead. Think components for IDE's etc.
  • If you create throwaway layout code.. you will throw it away.
  • new ActionListener() { actionPerformed() { someMethod(); }} is not a good idea. I don't like Microsoft's delegates either. Use AbstractAction if it makes sense. If you have a lot of inner classes, it will probably increase your blood pressure and reduce code reuse.
  • Don't extend JButton because "it's not good enough". The programmer, and not the API, is usually the problem.
  • Don't add "pretty colors and stuff" to Swing components without testing them on Macs or Mac users will hate you for it.
  • Support the keyboard. Add mnemonics and shortcuts. Solve component focus problems.
  • Understand that the "everything off by default" mentality of Swing is 50% design and 50% "boring technical reasons". The Flash 9 plugin just came out on Linux. Cross platform code cause all kinds of boring problems. Try image tiles on the Direct X and OS X OpenGL pipeline as an example.
  • To hide a window on a Mac you hit Command-W. Quit is Command-Q. The about dialog must be implemented through a custom Apple API. Learn the .app format. On Windows you should use a .exe wrapper. If you have seven javaw processes running, which one is the Swing application that just crashed ?
  • Make sure that "lazy loading" is not a case of lazy developer. Users loathe software that gets a heart attack if you press the wrong key. Listen for the users frantic ESC ESC ESC commands.
  • My mom presses the shutdown button. I rip out the power cable. Lost or corrupt data should be thing of the past. Most of my data is in a PostgreSQL database. Good IO code is a skill set on its own.
  • A user should always be able to turn off your custom Look and Feel code. Otherwise your application will not be future-compatible. Think Vista, Leopard, high DPI LCD/Plasma.
  • Use Eclipse and learn how to refactor code. It is like the old search/replace but much better, global and undoable. Netbeans is fun for creating component prototypes. The latest GUI builder is pretty nice. It does suffer from the old Layout-Used-Not-In-JDK syndrome (Sun, IBM, Borland - I am looking in your general direction)
  • Thinking in bitmaps and pixels might bite you in the ass later. Test on multiple DPI settings and check any custom fonts. Some Linux distributions have really funky fonts. Resolution independent vector images is probably the future, but support is scarce. Also note that Photoshop (bitmap/vector) is more popular than Illustrator (vector) for creative work. There are fewer vector monkeys than bitmap monkeys.
  • Try to understand property listeners. They are so boring that you forget how to use them properly.
  • Standardize on one text encoding. I try to use UTF8. Line breaks is still an issue. Try CR in Unix perl. Understand this if your application does IO pipes and runtime commands.
  • Check your Swing data models. Incorrect sorting, bad threading and generally being a dumbass can cause data corruption. This is not a Swing problem, but rather that an inexperienced developer (like myself) is given plenty of ways to shoot himself in the foot. Often system A works fine.. but when connected to systems B and C (developed six months later) you end up in trouble.
  • Badly written IO and threading code might not manifest itself in the same way on different platforms. A bad UI routine might look good on your platform.
  • Some people believe that "intelligent design" should be used in software development. I am more of a.. let's see what just crawled out of the primordial ooze kind of a guy. Evolution followed up by learning (refactoring). Instead of writing pretty code I write horrible code. If you have never written horrible code, how do you know what "good" code looks like ? Take pride in creating the most horrible piece of garbage the world have ever seen and then making it much worse. I know this is not very professional, but there are so many wrappers around wrappers around wrappers out there that it drives me to do this. How many layers of indirection do we need exactly ?
  • Try not to copy/paste code. I know about the management problem relating to deadlines and such, but copy/pasted code often results in a "rewrite from scratch".
  • "XML will solve everything" ? Most web developers use CSS for layout. The only layout code done in XML is the basic layout. Left, right, middle, top, bottom,box1-2-3, add script, bold, address, abbr etc. Global layout stuff usually ends up in a CSS file. Please understand that Microsoft XAML, Mozilla XUL and Adobe Apollo are huge frameworks. It ain't "simple". Lock-in and version dependencies are going to to be a bitch.
  • Don't listen to "experts". Listen to people who have created something and that can give you a zip file or a URL. There are so many people advocating that Hello World-type applications should be written using the Netbeans or Eclipse framework. Come on already...
  • Nuclear powered aircraft carriers SUCK at driving on land. Therefore.. BikeFramework will rule the seas !! Understand what you are creating. Is it a mountain bike or a Space Shuttle ?
  • UI threading is hard. I have my own way of doing it.. but I don't want to make it public since I am very talented in the arts of IllegalThreadStateException's and JVM crashing.
    More information on Swing threading.
    http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
    http://foxtrot.sourceforge.net/docs/index.php
    http://spin.sourceforge.net/
    http://java.sun.com/docs/books/tutorial/uiswing/TOC.html

April 26, 2007

Downtime

Some services will be offline over the next 48 hours. Cleaning house.

April 23, 2007

Darkstar sample code

PaintableApp.java - Lanch PaintableApp. Download SDK.

package com.teppefall.ds.demo;

import java.awt.Dimension;
import com.teppefall.ds.Application;

public class PaintableApp extends Application {

	public PaintableApp(String args[]) {
		super("Paintable", args, new Dimension(600, 600));
		getApplicationFrame().getContentPane().add(new Paintable());
		showApplication();
	}

	public static void main(String[] args) {
		Application.launch(PaintableApp.class, args);
	}

}

April 19, 2007

Teppefall DSI

Inspired by the Adobe Apollo project and Bruce Eckel's article about Java user interfaces, I have created the Darkstar Installer or DSI for short.

DSI is a 2,5Mb Web Start compatible runtime based on the Darkstar application framework, the Park assembly framework, parts of the Tango icon set and the Substance look and feel. DSI looks the same on all platforms and is free for commercial and non-commercial use as long as the application is distributed through Web Start. If you ZIP/DMG the application or sell it on a CD/DVD you must buy a license.

Now you can use Fabric for layout, Surface for Java 2D and DSI for deployment. The key feature here is that applications can be launched with DSI on the web and without DSI on the desktop. You don't need to write a "web" or "desktop" application. Just write one application and be done with it. I should point out that UI state, storage and offline functionality is still being worked on and will be available in the beta phase. You can create your own Web Start logic in the mean time.

DSI is currently in alpha and everything is therefore not up to spec. You can test it here.

http://jnlp.labs.teppefall.com/

DSI usage:
java -jar dsi.jar com.teppefall.massive.Massive http://teppefall.com
java –cp dsi.jar com.teppefall.ds.runtime.DSI com.teppefall.massive.Massive http://teppefall.com
http://jnlp.labs.teppefall.com/app/Massive?class=com.teppefall.massive.Massive&mime=jnlp

Fabric 2.0.1

Fabric's documentation is really bad. Some may say “non-existent“ is a better description. Well, here is a simple paper describing the technology.

Design

Fabric is based on JavaBeans XML aka “Long-Term Persistence for JavaBeans”. The serialization format created by Sun to store Java Bean data in XML. Instead of using a custom parser and reading the elements into a data structure, I decided to use XSLT transformation and XMLDecoder to create a runtime object. Some may say this is insane and I sort of agree. It is nuts and I know of no other implementation like it. I did it because I wanted to learn XSLT and because I believe automated derivative data is the future, rather than huge parsers with plenty of vendor lock in. Just look at web browsers and the eternal bitch fest that is CSS layout. Internet Explorer still lags behind everyone else and because of this no one bothers to create standard compliant code. Validate Google's HTML if you do not believe me.

Ironically some people probably ignore Fabric because they are worried about being locked into a technology created by a tiny company that might be gone tomorrow. Fabric has in fact been designed from the ground up to overcome this. This is how it works.

This is the default view – home.jfc:

<jfc>
    <component class="com.teppefall.park.runtime.ParkDesktop"/>
</jfc>

This is transformed into this:

<?xml version="1.0" encoding="utf-8"?>
 <java version="1.4.2" class="java.beans.XMLDecoder">
 <!--
   This file was automatically generated by Teppefall Fabric.
   http://www.teppefall.com
   -->
 <object id="self" class="com.teppefall.park.runtime.jfc.JFCPanel">
 <object idref="self">
 <void property="title">
 <string/>
 </void>
 </object>
 <void method="add">
 <object class="com.teppefall.park.runtime.ParkDesktop"/>
 </void>
 </object>
 </java>

JFCPanel extends AssemblyAdapter which implements Assembly. All these classes are available in the source folder.

You can access this view either by using the entire Fabric SDK (now you are dependent on me):

add(new Park(“home.jfc”));

Or just the runtime part (now you have access to all the source code):

Assembly assembly = Importer.decode(getClass(), “home.xml”); // this is the transformed data
Jpanel root = assembly.getPanel();
JmenuBar menu = assembly.getMenuBar();
JpopupMenu popup = assembly.getPopupMenu();

If you follow a simple pattern – MyPanel.java + MyPanel.xml – you can also do this.

Assembly assembly = Importer.decode(getClass());

There is nothing magical about the importer.

public static Assembly decode(Class owner) {
    return decode(owner, Console.self(owner) + ".xml");
}
public static Assembly decode(Class owner, String resource) {
    InputStream xml = owner.getResourceAsStream(resource);
    if(xml == null) {
       Console.warn(Importer.class, "Resource not found \"" + resource + "\"");
    }
    XMLDecoder decoder = new XMLDecoder(xml);
    Assembly assembly = (Assembly)decoder.readObject();
    return assembly;
}

Fabric is a prototype tool

But it can be used directly in an application. Since there is no standardized data and event binding available today this technology should only be used in small web applications. Fabric JFC (the format, not the application) is designed as a lightweight alternative to Adobe Apollo, Microsoft XAML and Mozilla XUL. Some seriously suggest to people that they should use the Eclipse or NetBeans application framework to create Java web applications. This is the equivalent of buying an 18 wheeler for a one mile paper route.

Yeah, but this is a toy right ?

Fabric has been really brutal to developers up to now. Doing recursive programming in XSLT is hard and very few people have probably even attempted to create their own transformers. Because of this I have spent a lot of time creating a powerful syntax that I have simply named JFC after Java Foundation Classes. It is simple to understand and very powerful.

<jfc title="Java Hut">
 <popupmenu>
 <menuitem text="PAL"/>
 <menuitem text="NTSC"/>
 <menuitem text="320x240"/>
 <menuitem text="640x480"/>
 <menuitem text="800x600"/>
 <menuitem text="Custom"/>
 <separator/>
 <menuitem text="Frames per second"/>
 </popupmenu>
 <layout class="java.awt.BorderLayout">
 <layout class="java.awt.BorderLayout" constraint="Center">
 <component class="com.teppefall.ds.render2d.Darkstar" name="renderer" constraint="Center"/>
 <gridlayout columns="3" rows="1" constraint="South">
 <component class="javax.swing.JPanel">
 </component>
 <layout class="java.awt.FlowLayout">
 <component class="javax.swing.JButton" name="capture">
 <property name="text" value="Capture"/>
 </component>
 </layout>
 <layout class="java.awt.FlowLayout">
 <property name="alignment" value="2" type="int"/>
 <component class="javax.swing.JLabel" name="effects">
 <property name="text" value="Effects"/>
 </component>
 <component class="javax.swing.JToggleButton" name="one">
 <property name="text" value="1"/>
 </component>
 <component class="javax.swing.JToggleButton" name="two">
 <property name="text" value="2"/>
 </component>
 </layout>
 </gridlayout>
 </layout>
 <component class="javax.swing.JScrollPane" constraint="South">
 <property name="verticalScrollBarPolicy" value="21" type="int"/>
 <property name="horizontalScrollBarPolicy" value="31" type="int"/>
 <property name="viewportView" type="Component">
 <component class="javax.swing.JList" name="images">
 <property name="cellRenderer" type="Object" value="com.teppefall.park.runtime.MyImageItemRenderer"/>
 <property name="selectionMode" value="1" type="int"/>
 <property name="layoutOrientation" value="2" type="int"/>
 <property name="visibleRowCount" value="1" type="int"/>
 <property name="fixedCellWidth" value="80" type="int"/>
 <property name="fixedCellHeight" value="80" type="int"/>
 <property name="selectionMode" value="2" type="int"/>
 <property name="listData" type="Vector">
 <vector>
 <item>Hello World !</item><item>Hello World !</item>
 </vector>
 </property>
 </component>
 </property>
 </component>
 </layout>
 </jfc>

Fabric JFC

Copyright 2007 Teppefall

<jfc
   title=””
   height=””
   width=””
 >
 <component, layout, gridlayout
   name=””
   class=””
   action=””
   constraint=””
   text=””
   enabled=””
   mnemonic=””
   icon=””
   focus=””
 >
 <gridlayout
   rows=””
   columns=””
 >
 <property
   name=””
   value=””
   type=”boolean|byte|char|short|double|float|int|long|Hashtable|Vector|Component|Object|Color|Dimension|Rectangle|Point|Icon|Tree”
 >
 <action, 
   name=””
   class=””
 >
 <menubar, popupmmenu>
 <menu, menuitem
   name=””
   action=””
   text=””
   enabled=””
   mnemonic=””
   icon=””
 >
 <menuitem
   type=”radiobutton|checkbox”
 >
 <separator>
 <vector>
 <hashtable>
 <item
   name=””
   value=””
 >
   
package com.teppefall.park.runtime;
/**
   * (c) Teppefall
   * http://teppefall.com
   *
   * Assembly.java
   * Mar 3, 2004
   */
import java.io.Serializable;
import java.util.Hashtable;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JMenuBar;
import javax.swing.JPopupMenu;
import javax.swing.JPanel;

public interface Assembly extends Serializable {
   
    void parkInitialize();
    void parkShutdown();
    void parkInstruction(String instruction);
    void parkBinder(String listener);
    void parkParameter(String data);
    void add(JComponent component);
   
    JPanel getPanel();
    JMenuBar getMenuBar();
    JPopupMenu getPopupMenu();
    ActionListener getActionListener();
    String getIcon();
    String getTitle();
    String getStatus();
    Dimension getSize();

    void setIcon(String icon);
    void setTitle(String title);
    void setUsingStatus(boolean usingStatus);
    boolean isUsingStatus();
    void setAttributes(Hashtable attributes);
    void setAttribute(String name, Object value);
    Object getAttribute(String name);
    Hashtable getAttributes();
}

Further reading

http://java.sun.com/products/jfc/tsc/articles/persistence/
http://java.sun.com/products/jfc/tsc/articles/persistence2/
http://java.sun.com/products/jfc/tsc/articles/persistence3/

http://java.sun.com/products/jfc/tsc/articles/persistence3/javabeans.dtd

Paintrhelpr

Fabric 2.01

Download here | More info | Buy licenses .

Next generation Teppefall software

Coming soon to Teppefall Link.