Carsten Zerbst's Weblog

Carsten Zerbst's Weblog
  • All
  • PDF
  • NetBeans
  • General
  • Java
  • Developer
Friday Oct 23, 2009

Craftsmann's Guide to Swing Application, JGoodies Binding II

The last blog introduced the concept of JGoodies Binding with the chain from domain model, value model and JComponent specifc view adapter. The examples shown so far used the BasicComponentFactory as convinient way to directly create bounded Swing components. This Blog will show you how to handle the most common binding cases using either the BasicComponentFactory or explicitly creating the binding chain. All examples are based on this domain model.

Check- and Radiobuttons

Check- and Radiobuttons are a standard way to offer selection for on/off and one from many cases. Both cases are supported by the BasicComponentFactory:

ValueModel vm = new PropertyAdapter( model, "on", true );
JCheckBox checkBox = BasicComponentFactory.createCheckBox( vm, "binding to boolean value" );

vm = new PropertyAdapter( model, "oneFromThree", true );
JRadioButton radioButton = BasicComponentFactory.createRadioButton( vm, "A", " possibility A" );
radioButton = BasicComponentFactory.createRadioButton( vm, "B", " possibility B" );
For the radio button you have to provide a value (A and B in the example). When this value is matched by the bound property the button is selecteda and is used when a user selects the button.

Selection in JComboBox and JList

JList and JComboBoxes are typically used to select one item out of a collection. Therefore they handle two variables, one contains the possibilities to select from, one contains the selected item(s). In most cases you know the possible items to choose from in advance and could use simple solution using the SelectionInList class. For the JComboBox this requires 3 three lines of code, the same ways is available for JLists.

ValueModel vm = bena.getValueModel( "selectionInPossibilities" );
SelectionInList selection = new SelectionInList( DomainModel.THREE_POSSIBILITIES, vm );
JComboBox box = BasicComponentFactory.createComboBox( selection );

JSpinner

The JSpinner is pretty similar to a JComboBox, it offers to select one out of many possible values. Using the SpinnerAdapterFactory it is possible to bind it to your domain model. While the JSpinner itself is not restricted to certain value, the binding framework supports only Date and Number items. Usually you provide the minimal, maximal and default value plus the number of steps alongside your value to create a binding:

ValueModel vm = ... ;// type of ValueModel (date, number) has to match created SpinnerModel !!!
SpinnerNumberModel spinnerModel =  SpinnerAdapterFactory.createNumberAdapter(vm, 42, 0,100, 2);
JSpinner levelSpinner = new JSpinner(spinnerModel);
This creates a spinner for a range from 0 to 100, stepwidth 2 and the default value 42.

Changing Collections

Many domain models contain collection style attributes which vary over the time. As discussed in the last blog, attributes have to be bound to work correct with any kind of binding. It is pretty simple to bind the collection style value itself in your domain model:

public class DomainModel {
    private List collection;
	private PropertyChangeSupport chsngeSupport;
	
	public void setCollection( List collection ) {
		Object ov = this.collection;
		this.collection  = collection;
		firePropertyChange("collection", ov, collection);
	}
}	
But in most cases one will not exchange the complete collection but simply add or remove items. As the standard collections (ArrayList, HashSet, ...) do not fire an event in those cases, you find yourself modifiying the collection but as no event is fired no updates happen. If you have a closer look into the Swing APIs you find the ListModel interface, and JGoodies Binding contains the needed ArrayListModel implementation. This is a 1:1 replacement for the standard ArrayList with the added functionality to fire events when the model is changed. Of course you should not provide a setter any more to avoid replacing the complete list. The ArrayListModel could be used directly with the JList. (If you need to support changing the list AND changing the list content have a look at the IndirectListModel).
public class DomainModel {
    private final ListModel changingList = new ArrayListModel();
	
	  public ListModel getChangingList() {
        return changingList;
    }
}
...

JList list = new JList( domainModel.getChangingList());
The same pattern applies for JComboBoxes and JList used to select an instance. By providing an ArrayListModel as variable to contain the possible values both the selection AND the objects to select from are bound variables and could change over the time.

Conclusion

This two blogs should cover most cases you need to bind Swing components to your domain model for business style applications. There are more things to detect in JGoodes Binding, e.g. binding of JTables or colour choosers, but based on this blog you'll find them pretty straight forward. And off course the binding framework is not only restricted to bind your domain model to a Swing component, but could be used to bind any bean to another. The PropertyConnector just gets both beans and attribute names and you are done:

DomainModel m1 = ...;
OtherModel m2 = ...;
PropertyConnector( m1, "attrName1", m2, "attrName2");

JGoodies Binding to bind standard Java Beans to Swing components is a mature solution. Other solutions like the Beans Binding efforts are more or less stuck or depend on special annotations.
Please keep three things in mind:

  • The Binding Framework does not care about threads. If you change your domain model outside AWT EDT you use the Swing components not as intended
  • The Binding Framework identifies the bean properties by their name. Mispelling them results in a runtime error
  • The ValueModel does not care about bean properties type. If you bind e.g. a List to a JComponent which expects a String you get a runtime error

Content

Posted at 02:35PM Oct 23, 2009 by Carsten Zerbst in Java  |  Comments[2]

Thursday Oct 15, 2009

Craftsmann's Guide to Swing Application, JGoodies Binding I

According to the common Model View Controller (MVC) Pattern, applications with a GUI have three different parts:

Model
This contains the data needed by the application. In SWING applications is usually a Java Bean or POJO. Called Domain Model in Binding Documentation
View
This contains all view components of the application like JTextFields, JList or JTables
Controller
This part contains the code implement the behaviour
In most applications all parts are connected to form the typical triangle:

spacer

In SWING application the model part is typically implemented using a Java Bean or POJO, the view part is implemented using the components provided by SWING or based on the SWING framework. But as of today there is no solution shipped with Java which is used to bind the model to the view and vice versa.

If you have a close look many application use a simple copy and paste solution, the data is copied from the bean into the SWING components and later on copied back from those into the bean (e.g. when a user presses the Save button). But this approach has it's limits, especially if the data has it's own life dictated by other source or you want to validate the user input. That's where a real binding is needed, a solution to bind the Model and View components together and automatically update one if a change in the other occurs.

There is life outside the SWING world, e.g. the scripting language Tcl/Tk knows a special bind command for nearly two decades, and so does JavaFX. But as of today there is no solution available in the Java core language for the binding. There have been efforts under their way in JSR 295 Beans Binding to standardize such a binding. Unfortunately these efforts failed, the Beans Binding JSR did not come to an end (like the SWING Application Framework) and in the end multiple forks exists which try to create a usuble Beans Binding.

As with many real world problems in the SWING area you find a solution by Karsten Lentzsch, he offers the JGoodies Binding framework, a full featured solution to bind typicall SWING components like JTextFields, JComboBoxes etc. to models.

JGoodies Binding

The JGoodies Binding is available from JGoodies, currently in version 2.0.6. In case you are still bound to Java 1.4.2 (yes, there a still such companies) you could use version 1.5 from archive.

The idea behind JGoodies Binding is that of an universal model access to the data found in the domain model. The universal model access is called a Value Model. On top of the Value Model are a number of view adaptors which are used to cast the Value Model into the appropriate form to couple with a Swing component like a JTextField or JList.

spacer

Model Requirements

To keep the Model via the Value Model to the Swing component in synch, one needs to ensure that every change in the model is propagated to the view layer and vice versa. Unlike simple POJOs this neccesitates bound properties in the data model. The difference between a simple Java Bean property and a bound property is, that a change to a bound property is signaled to every interested listener by firing a PropertyChangeEvent.

With the simple P(lain) O(ld) J(ava) O(bject) approach, a typical model is implemented like the following Bean

public class Customer {

    private String name;
   
    public String getName() {
        return name;
    }
   
    public void setName(String name) {
        this.name = name;
    }
}

But for binding other components need to follow changes in to attributes. According to the Java Beans this is achieved by bounded values, which fire an PropertyChangeEvent to interested listeners. This necessitates a bean implementation like this:

public class Customer {
    private final ExtendedPropertyChangeSupport propChangeSupport = 
                  new ExtendedPropertyChangeSupport(this);

    private String name;
   
    // methods needed to add, remove listeners
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propChangeSupport.addPropertyChangeListener( listener);
    }
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propChangeSupport.removePropertyChangeListener(listener);
    }
    public void addPropertyChangeListener(String propertyName,
                                      PropertyChangeListener listener) {
        propChangeSupport.removePropertyChangeListener(propertyName, listener);
    }
    public void removePropertyChangeListener(String propertyName,
                                         PropertyChangeListener listener) {
        propChangeSupport.removePropertyChangeListener(propertyName, listener);
    }
   
    // getter as used
    public String getName() {
        return name;
    }

    // Setter fires a PropertyChangeEvent using the property change support
    public void setName(String name) {
        String oldValue = this.name;
        this.name = name;
        propChangeSupport.firePropertyChange("name", oldValue, name);
    }
}

Every change to the name attribute in the bean triggers firing a PropertyChangeEvent. Implementing the creation of the PropertyChangeEvent and sending it to all registered PropertyChangeListeners is pretty simple, but in most cases simply use the existing implementation in com.jgoodies.binding.beans.ExtendedPropertyChangeSupport or java.beans.PropertyChangeSupport and delegate the task. All you need to do is to enhance your setters to keep the old value and call the property change support.

Simple Binding

Binding a Swing component to such a bound property is simple. As first step you create a ValueModel which encapsulates your Bean, then use the BasicComponentFactory to create an already bound Swing Component:

ValueModel vm = new PropertyAdapter(cust, "name", true);
JTextField text =BasicComponentFactory.createTextField(vm);

With just this two lines, you get a Swing component which is bound to your model property. Every time the model property changes, the contents of the JTextField is updated and vice vera. You do not have copy the value from bean to Swing back and forth, everything is handled automatically by the JGoodies Binding.

The ValueModel is the generic glue between a Java Bean Property and any kind of View Adapter. There are two ways to create a Value Model in JGoodies Bindings. One way is to create the ValueModel directly using the PropertyAdapter. It gets the encapsulated bean and the name of the desired property as input. In most cases you want to have bidirectional update support, so you add the additional true to the constructor:

 ValueModel vm = new PropertyAdapter(cust, "name", true);
When you use a wrong property name, you get an error at runtime, so real production code should use static identifiers. Unlike template engines like JSP or Freemarker the property name do not support chained identifiers !

If you use many properties from the same domain model, it could be usefull to use the BeanAdapeter. This registers only on PropertyChangeListener instead one per adapted property:

BeanAdapter bad = new BeanAdapter( cust);
ValueModel vm1 = bad.getValueModel("name");
ValueModel vm2 = bad.getValueModel("surname");

There are several possibilities to connect the ValueModel to a Swing component. The most convinient way is to use the BasicComponentFactory. It has many convinience function to directly create an already bound JComponent. Typicall cases are :

  • Bind a JCheckBox to a boolean value
  • Bind a JTextField to an integer/long value
  • Bind a JLabel to a string value
  • Bind a JPasswordField to a string value
  • Bind a JTextField to a string value
  • ...

The next Blog demonstrates how to handle the more complex cases using JGoodies Binding like lists, comboboxes, attributes with differences between representation (e.g. String) and model type (e.g. java.util.Date).

Content

Posted at 11:47PM Oct 15, 2009 by Carsten Zerbst in Java  | 

Saturday Oct 03, 2009

Craftsmann's Guide to Swing Application, Form Layout II

In the previous entry I presented the first steps in designing a typical business style form. As result we had a sketch of the form with the entries and labels arranged in a grid:
spacer

If you have a look at the layouts available in SWING, there is only one candidate, which is more or less able to create such a GUI: the GridBagLayout. The GridBagLayout is very flexible and after long experience and even more tinkering around you could create nearly every layout with it. BUT it takes a tremendous time and frustration tolerance to get there. As a start look at Totally Gridbag.

So please let me introduce Karsten Lentzsch's JGoodies Forms. This layout framework offers all you need to create forms and button bars in time and with a superb quality. With the form layout you define a design grid for rows and columns in terms of width/height, alignment and resizing behavior. The definition is done using a human readable description (or domain specific language to use that buzzword). After you defined that grid you place your components. It is even possible to override the global grid definition on a per component base.

spacer

The complete code to create the form you designed using the JGoodies Form Layout is in the code snippet below:
public JPanel createComponent() {

        FormLayout layout = new FormLayout(
                "4dlu,right:max(50dlu;pref), 4dlu, 75dlu:grow, 4dlu, pref,4dlu",
                "4dlu,pref,3dlu,pref,3dlu,pref,fill:4dlu:grow" ); // rows

        PanelBuilder builder = new PanelBuilder( layout );
        CellConstraints cc = new CellConstraints();

        int row = 2;
        JLabel label = new JLabel("Label 1:");
        builder.add( label, cc.xy( 2, row ) );

        JTextField field1 = new JTextField();
        builder.add( field1, cc.xyw( 4, row, 3 ) );

        row += 2;
        builder.addLabel( "Longer Label :", cc.xy( 2, row ) );

        JTextField field2 = new JTextField();
        builder.add( field2, cc.xyw( 4, row, 3 ) );

        row += 2;
        builder.addLabel( "Label 3:", cc.xy( 2, row ) );

        JTextField field3 = new JTextField();
        builder.add( field3, cc.xy( 4, row ) );

        JButton select = new JButton( "..." );
        builder.add( select, cc.xy( 6, row ) );

        return builder.getPanel();

    }

Define the Layout

In the first lines you define the global grid of your form, in this case with the column specification 4dlu,right:max(50dlu;pref), 4dlu, 75dlu:grow, 4dlu, pref,4dlu and the row specification 4dlu,pref,3dlu,pref,3dlu,pref,fill:4dlu:grow.

Human readable ??

Yes, I think so, but just after some explanation. Each column and row is specified with a string separated from the next one using the comma (,). Each specification may have up to three parts which are separated using the colon (:), the alignment, the width and the resizing behavior. A definition like 4dlu reads as

  • no alignment specified (default to fill for columns, vertically center for rows)
  • width is 4dlu
  • no resizing

You may know pixels, centimeters and points, but dlu ? Using pixels or centimeters to define a size is possible in form layout as well, but they definitively have a drawback. A pixel is not a fixed size, as the resolution of the display varies. And most forms do contain a lot off text and the size of the text is defined e.g. in the systems preferences. What looks good on your screen will look pretty bad if someone uses a different font size. Therefore forms layout offers the display unit as unit to define fixed sizes. The display unit is calculated on the users computer based on his font size, so all widths defined in dlu are relatively to the users font. You may know this from the em size available in LaTeX and HTML. Therefore the first 4dlu defines a column which has a width of 4 display units.

Fixed size defined in dlu or pixels are easy, but forms layout offers more. Using min or pref you could specify the size to be the minimum or preferred size of all components placed in that row or column. This is used to specify the height of all rows containing labels and entries.

As you could see in the definition of the second column, there are even possibilities to have a bound on the resulting size. The column specification right:max(50dlu;pref) results in a width defined by the largest label, but using 50 dlu as upper bound. If your labels are longer, they are truncated and your layout is not corrupted.

Depending on your needs the size off the columns and rows may either be constant or uses additional space if the user resizes the gui. This behaviour is given using the grow keyword, so in the example the width of the entries is enlarged with the size off the frame.

The user documentation of JGoodies Form Layout explains all these possibilities in depth, this article should be enough for a start.

Place the components

After you defined the FormLayout, there are two more layout specific lines in the example:

 PanelBuilder builder = new PanelBuilder( layout );
 CellConstraints cc = new CellConstraints();
With the first one you create a PanelBuilder which is more or less a convenience class used to minimize the code you type. The second one is an object you could use to define the cell in which you place a component. Existing components like the first label are simply added to the design grid using the cell location in x (column) and y (row). Both column and row count start with 1 !.

The design grid has more columns as you expected, as the last line sports both a text entry and button. Therefore the first both entries have to span three columns. This is simply described using the xyw(idth) method of the CellConstraint.

As you could see with the second row, the builder already has a convinience method to create and place a label with one shot.

After you put all your components into the layout, you could asked the builder to return the created panel and you are done.

There is of course much more available in forms layout than demonstrated in this small example. E.g. you could define groups of columns and rows which always have the same width or height. Or you define special growing behavior where additional space is divided in an arbitrary ratio. And if you run into a problem, e.g. by placing components into the wrong cell or using an inappropriate layout description. Forms layout has already a simple help build in, the FormDebugPanel. Using

 PanelBuilder builder = new PanelBuilder( layout, new FormDebugPanel() );
will give you red lines painted on your form so you could see your design grid.

spacer

Résumé

Using Karsten Lentzsch's JGoodies Form Layout enables you to design forms in no term. The resulting forms are independant off the screen solution (as long as you use dlu !) and resize like you like and not like You Know Who (GridBagLayout). An alternative to Form Layout is the MiG Layout, but I never used it so far.

Posted at 10:34PM Oct 03, 2009 by Carsten Zerbst in Java  |  Comments[1]

Craftsmann's Guide to Swing Application, Form Layout I

No matter whether your application will consist of multiple pages or a simple dialog style GUI, user interaction is typically done by one or more forms. Theses forms are made from several labels and active components like text fields, buttons or sliders. This is the primary interface your users are going to see and have to work with. Given that the type and number off attributes to edit is already known, you have several task to be done BEFORE you open your editor:

  • Decide the optimal form to display/edit the attribute. Do you better use a textfield, combobox or a slide ?
  • Decide whether to layout the elements onto one or more forms. If you have a large number of attributes, perhaps multiple forms are a better choice ?
  • Decide how to layout the elements on a form. Think about logical groups and avoid random sprinkles all over your form
  • Using a design grid for rows and columns helps a lot

As experience with mine and other people application tell me, don't do this alone unless you are a real user experience crack. It is typically better to show your sketches other colleagues. If you already have working code, then its typically to late, so please use either a sheet of paper for you first ideas.

If drawing does not match your style use GUI mock up tool like Pencil, but paper is typically faster. And please refrain from creating "art". The mantra off business style applications is to not surprise you users. Every label, every text field should have it's place just where a user expects it to be. Your form may look a bit boring, but this is better then user searching around for the right entries. And boring is not the same as ugly.

If you are in need for good examples have look at applications made by Apple or some GNOME application like Evolution. A look at the Apple Human Interface Guidelines is usefull as well.

spacer

After you and your colleagues and you are satisfied, DO NOT open your editor. Now take your sketch and draw the design grid into the sketch. Then decide the width/height, alignment and resize behaviour for the rows and columns.

spacer

Content

Posted at 08:31PM Oct 03, 2009 by Carsten Zerbst in Java  | 

Sunday Sep 27, 2009

Craftsmann's Guide to Swing Application, Introduction

I was asked by a colleague off mine to help him create a simple application. He just starts creating rich client application and needs someone to shepard him through the scrub off Swing application development until he finds his own way to the meadows. After some meetings filled with discussion and pair-programming, I decided to write down some of my ideas how to create small to medium sized Swing applications.

The applications in mind are typical business style application with one to several forms to create or edit data. If you need to create a filthy rich applications you may find some sensible hints for the structure of you application as well, but then you have to consult other guys like Chet Haase or Romain Guy for the eye candy.

There will be several articles each dedicated to the different disciplines needed to build an application:

  • Form Layout, how to effectively layout forms Part 1, Part 2
  • Binding, how to bind the Forms with Beans, Part 1 Part 2
  • Validation, how to validate the Beans and give feedback
  • Actions, how to handle actions in your application

The articles are based on my experience and make heavy use of the libraries offered by Karsten Lentzsch.

Posted at 10:31PM Sep 27, 2009 by Carsten Zerbst in Java  |  Comments[1]

Thursday May 22, 2008

Extract U3D from PDF

Starting with PDF 1.6 the Adobe Reader supports real 3D models in the U3D format. The embedding of U3D files into a PDF document is more or less covered, but so far there is no tool to extract U3D from PDFs.

The following code is based on Bruno Lowagies iText library, a real nice Java library to create and modify PDF files. It searches through the PDF objects from a file and puts all found U3D streams into files.

import com.lowagie.text.pdf.PRIndirectReference;
import com.lowagie.text.pdf.PRStream;
import com.lowagie.text.pdf.PdfName;
import com.lowagie.text.pdf.PdfObject;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Logger;

/**
 *
 * @author cz
 */
public class ExtractU3D {

    private static final Logger log = Logger.getLogger(ExtractU3D.class);
    public static final String PDF_NAME_3D = "3D";
    public static final String PDF_NAME_U3D = "U3D";

    public static void main(String[] args) throws Exception {
        BasicConfigurator.configure();

        Option helpO = new Option("h", "help", false, "display help");
        Option logO = OptionBuilder.withLongOpt("log").hasArg().withDescription(
                "url for log4j.properties file, e.g. file:./log4j.properties").withValueSeparator('=').create("log");
        Option fileO = OptionBuilder.withArgName("f").withLongOpt("file").hasArg().isRequired(
                true).withDescription("the name of the PDF file").create("f");
        Options options = new Options();
        options.addOption(helpO);
        options.addOption(fileO);
        options.addOption(logO);

        // create the parser

        CommandLine line = null;

        try {
            CommandLineParser parser = new PosixParser();
            line = parser.parse(options, args);
        } catch (ParseException exp) {

            // oops, something went wrong
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp("ExtractU3D", options);

            System.exit(66);
        }

        if (line.hasOption("h")) {
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp("ExtractU3D", options);
            System.exit(0);
        }

        if (line.hasOption("log")) {

            try {
                URL propsURL = new URL(line.getOptionValue("log"));
                PropertyConfigurator.configure(propsURL);
                log.info("using log4j configuration from " + propsURL.toExternalForm());
            } catch (MalformedURLException ex) {
                System.err.println("invalid properties url " + line.getOptionValue("log"));
                System.err.println("use standard configuration");
                BasicConfigurator.resetConfiguration();

            }
        }

        String pdfFileName = line.getOptionValue("f");
        File pdfFileIn = new File(pdfFileName);

        if (!(pdfFileIn.isFile())) {
            System.err.println("could not find file '" + pdfFileIn.getAbsolutePath() + "'");

            System.exit(66);
        }

        if (!(pdfFileIn.canRead())) {
            System.err.println("unable to read file '" + pdfFileIn + "'");

            System.exit(66);
        }

        FileInputStream fis = new FileInputStream(pdfFileIn);

        PdfReader reader = new PdfReader(fis);

        int numExport = 0;

        for (int i = 0; i < reader.getXrefSize(); i++) {
            PdfObject pdfobj = reader.getPdfObject(i);

            log.info("pdfObj " + pdfobj);
            if (pdfobj == null || !pdfobj.isStream()) {
                continue;
            }
            PdfStream stream = (PdfStream) pdfobj;

            log.info("  length " + stream.getRawLength());
            log.info("  keys " + stream.getKeys());
            log.info("  class " + stream.getClass());

            for (Iterator it = stream.getKeys().iterator(); it.hasNext();) {
                PdfName name = (PdfName) it.next();

                PdfObject pdobj = stream.get(name);
                log.info("      " + PdfName.decodeName(name.toString()) + "\t\t: pdobj " + pdobj + ", " + pdobj.getClass());

                if (pdobj instanceof PRIndirectReference) {

                    PRIndirectReference inref = (PRIndirectReference) pdobj;

                    log.info("    indirect type " + inref.type());
                    if (PRIndirectReference.STREAM == inref.type()) {
                        log.info("#bytes " + inref.getBytes().length);
                    }
                }

            }

            PdfObject pdfsubtype = stream.get(PdfName.SUBTYPE);
            log.info("  subtype " + pdfsubtype);



            if (PDF_NAME_U3D.equals(PdfName.decodeName(pdfsubtype.toString()))) {
                byte[] u3d = PdfReader.getStreamBytesRaw((PRStream) stream);
                File out = new File("extract" + ( numExport++)  + ".u3d");
                log.info("extracting " + u3d.length + " bytes U3D to " + out);

                FileOutputStream fos = new FileOutputStream(out);
                fos.write(u3d);
                fos.close();
            }

        }
    }
}

Posted at 10:51PM May 22, 2008 by Carsten Zerbst in PDF  | 

Tuesday Mar 25, 2008

Schliemann Tutorial

I wrote a full blown Tutorial on the Netbeans WIKI how to extend the Netbeans IDE to support a new language. The tutorial explains the Generic Language Support (codename Schliemann) using ISO 10303 Part21 (STEP Physical File) as example. spacer

Posted at 05:22PM Mar 25, 2008 by Carsten Zerbst in NetBeans  | 

Friday Sep 16, 2005

Using JTree with SwingWorker

Often the datasource for JTrees are not that fast and data is only retrieved when a certain node is opened. If the retrieval of children takes longer than several tenth of seconds the GUI does not feel snappy.

Now take the

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.