Archive

Tag Archives: programming

SpanTable = JTable + Cell span

While Swing provides a wide range of ready made components that cover a wide range of use cases most of the time if you find yourself needing something more you have to resort to writing it from scratch. After a couple of afternoons of searching the web for a decent open source solution I gave up and started looking for a tutorial that would help me understand the concepts underneath JTable and help me extend it to allow cell spanning. I found this tutorial which builds a fully functional JTable with cells that can span multiple columns. This was a nice start but I needed a little more.

Concepts

Adopting the division of cells from the above mentioned tutorial, there are 4 types of cells: hidden, visible, spanned and logical cells.

  • Visible cell – a cell that gets rendered
  • Hidden cells – a cell not rendered because it is spanned by another cell
  • Spanned cells – a cell which spans atleast 2 columns or rows (thereby hiding other cells)
  • Logical cells – every cell is a logical cell, a logical cell is used to query the model

A model holds information that the table displays, using an UI component, including the information about visible and hidden cells and cell spans. A custom UI object filters out the hidden cells to display only the visible ones.

Implementation

Span table class diagram

Span table and its dependencies

A SpanModel implementation

DefaultSpanModel is a basic implementation of the SpanModel interface. It uses java.util.Maps to store information about cell spans and hidden cells.

public class DefaultSpanModel extends ForwardingTableModel implements SpanModel {
    // decorated model
    private Map<Integer, Map<Integer, Integer>> rowSpans;
    private Map<Integer, Map<Integer, Integer>> columnSpans;
    private Map<Integer, Map<Integer, Cell>>    hiddenCells;

    /**
     * Constructs a new <code>DefaultSpanModel</code> backed by the supplied
     * <code>model</code>.
     *
     * @param model to be extended
     */
    public DefaultSpanModel(TableModel model) {
        super(model);

        Factory hashMapFactory = new Factory() {
            public Map<Integer, Integer> create() {
                return new HashMap<Integer, Integer>();
            }
        };

        rowSpans = MapUtils.lazyMap(new HashMap<Integer, Map<Integer, Integer>>(), hashMapFactory);
        columnSpans = MapUtils.lazyMap(new HashMap<Integer, Map<Integer, Integer>>(), hashMapFactory);
        hiddenCells = MapUtils.lazyMap(new HashMap<Integer, Map<Integer, Cell>>(), new Factory() {
            public Object create() {
                return new HashMap<Integer, Cell>();
            }
        });
    }

    // ...
}

Keep in mind that this is not the most efficient implementation as after the first rendering you’ll have (2 *(# of rows) + (# of columns)) of map instances but it does simplify the implementation of functionality and should keep rendering time independent of the number of spanned cells. Its a start :-) .

The most important trick to it is the custom UI object that filters hidden cells and only displays the visible ones. (Swing components delegate their rendering to utility UI objects to facilitate flexible look and feel as the above tutorial explains). This can be a bit of a problem to the generality of the solution. Because to render the span table you need a custom UI object but if someone changes the UI object then you don’t render the span table correctly. The good news is that most of the look and feels don’t change the rendering of tables (mostly only headers). As a precaution I set the UI object in the contructor and ignore any other UI component setting.

public class SpanTable extends JTable {
    private boolean isSpanModel;

    public SpanTable(TableModel model) {
        super(model);
        // the table UI has to be set to <code>SpanTableUI</code>
        this.setUI(new SpanTableUI());
    }

    @Override
    public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
        if (isSpanModel) {
            // if the model is a span model, we have to check if the cell is spanned or not
            // and expand the area of the cell to reflect it
            Rectangle cellRect = super.getCellRect(row, column, includeSpacing);

            for (int i = 1, n = ((SpanModel) getModel()).getRowSpan(row, column); i < n; i++) {
                // expand the area of the visible cell
                cellRect.height += getRowHeight(row + i);
            }

            for (int i = 1, n = ((SpanModel) getModel()).getColumnSpan(row, column); i < n; i++) {
                // expand the area of the visible cell
                cellRect.width += getColumnModel().getColumn(column + i).getWidth();
            }

            return cellRect;
        }

        return super.getCellRect(row, column, includeSpacing);
    }

    @Override
    public void setUI(TableUI ui) { }

    @Override
    public void setModel(TableModel dataModel) {
        isSpanModel = dataModel instanceof SpanModel;
        super.setModel(dataModel);
    }

    @Override
    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
        // only needed for correct repaint behavior
        super.changeSelection(rowIndex, columnIndex, toggle, extend);
        repaint();
    }

    @Override
    public int columnAtPoint(Point point) {
        if(isSpanModel) {
           int row = super.rowAtPoint(point);
           int column = super.columnAtPoint(point);

           // return the column of the hiding cell
           return ((SpanModel) getModel()).getVisibleCell(row, column).getColumn();
        }

        return super.columnAtPoint(point);
    }

    @Override
    public int rowAtPoint(Point point) {
        if(isSpanModel) {
           int row = super.rowAtPoint(point);
           int column = super.columnAtPoint(point);

           // return the row of the hiding cell
           return ((SpanModel) getModel()).getVisibleCell(row, column).getRow();
        }

        return super.rowAtPoint(point);
    }
}

The most importat thing here is the expansion of the spanned cell rectangle in getCellRect().

Here is a simple usage example:

// DATA
String[][] data = new String[][] {
    {"a1", "a2", "a3", "a4"},
    {"b1", "b2", "b3", "b4"},
    {"c1", "c2", "c3", "c4"},
    {"d1", "d2", "d3", "d4"},
    {"e1", "e2", "e3", "e4"}
};

// SPAN TABLE INITIALIZATION
DefaultTableModel model = new DefaultTableModel(data, new String[] { "1", "2", "3", "4" });
DefaultSpanModel spanModel = new DefaultSpanModel(model);

aFrame.getContentPane().add(new JScrollPane(new SpanTable(spanModel)), BorderLayout.CENTER);

spanModel.setColumnSpan(0, 0, 3);
spanModel.setRowSpan(1, 1, 2);
spanModel.setColumnSpan(1, 1, 2);
spanModel.setRowSpan(2, 0, 3);

This is the final result:

A table with 3 spanned cells

A table with 3 spanned cells

A cell spanning 3 columns (edit)

A cell spanning 3 columns (edit)

A cell spanning 2 columns and 2 rows (edit)

A cell spanning 2 columns and 2 rows (edit)

A cell spanning 3 rows (edit)

A cell spanning 3 rows (edit)


Span table

Span table

Resources

source code

each, select, reject, collect, detect, inject, include?, compact – translated into Java

I have compiled this little cheat sheet for those who like working with arrays in Ruby but not just for Ruby’s expressivness as a language but mostly for the idioms behind it. If you like the way Ruby (and also Smalltalk and others, but I like Ruby the best :-) ) handles arrays but you cannot use Ruby in your projects directly — CollectionUtils from the Apache Commons-Collections library (version 3.0 and above) can maybe be the answer you are looking for. For the price of added Java’s verbosity (compared to Ruby) you can find yourself on familiar ground with your Java collections.

Cheat sheet

each

[1, 2, 3, 4].each { |x| print x }
# >> 1
# >> 2
# >> 3
# >> 4

one possibility how to translate Ruby’s each to Java

List<Integer> i = Arrays.asList(1,2,3,4);
CollectionUtils.forAllDo(i, new Closure() {
    public void execute(Object i) {
        System.out.println(i);
    }
});

select

[1, 2, 3, 4].select { |x| x % 2 == 0 }
# >> [2, 4]

one possibility how to translate Ruby’s select to Java

List<Integer> i = Arrays.asList(1,2,3,4);
System.out.println(CollectionUtils.select(i, new Predicate() {
    public boolean evaluate(Object o) {
        return (Integer)o % 2 == 0;
    }
}));

reject

digits = (1..10).to_a
digits.reject { |x| i < 5 }
# >> [5, 6, 7, 8, 9, 10]

one possibility how to translate Ruby’s reject to Java

List<Integer> i = new ArrayList<Integer>(10);
for (int j = 1; j <= 10; j++) {
    i.add(j);
}
System.out.println(CollectionUtils.selectRejected(i, new Predicate() {
    public boolean evaluate(Object o) {
        return (Integer)o < 5;
    }
}));

collect

[1, 2, 3].collect { |x| x + 1 }
# >> [2, 3, 4]

one possibility how to translate Ruby’s collect to Java

List<Integer> i = Arrays.asList(1,2,3);
System.out.println(CollectionUtils.collect(i, new Transformer() {
    public Object transform(Object input) {
        return (Integer)input + 1;
    }
}));

detect

(1..100).to_a.detect { |i| i % 5 == 0 and i % 7 == 0 }
# >> 35

one possibility how to translate Ruby’s detect to Java

List<Integer> i = new ArrayList<Integer>(100);
for (int j = 1; j <= 100; j++) {
    i.add(j);
}
System.out.println(CollectionUtils.find(i, new Predicate() {
    public boolean evaluate(Object o) {
        return (Integer)o % 5 == 0 && (Integer)o % 7 == 0;
    }
}));

inject

[1, 2, 3, 4, 5].inject(0) { |sum, x| sum += x }
# >> 15

Translating inject is a little tricky because of the anonymous classes involved and the final value retrieval. Here is one possible way how to translate Ruby’s inject to Java. Probably not the best way to do it but still a working solution :-)

List<Integer> i = new ArrayList<Integer>(5);
for (int j = 1; j <= 5; j++) {
    i.add(j);
}
CollectionUtils.transform(i, new Transformer() {
    int sum = 0;
    public Object transform(Object input) {
        sum += (Integer)input;
        return sum;
    }
});
System.out.println(i.get(i.size() - 1));

update: A better solution, as Daniel suggested, would be to use Closure instead of a Transformer with combination with CollectionUtils#forAllDo()

// lets use an inner class to do the work:
private static class SumAccumulator implements Closure {
    private int sum;

    public void execute(Object o) {
        sum += (Integer)o;
    }

    public int getSum() {
        return sum;
    }
}

// then the sum accumulation would look something like this:
SumAccumulator accumulator = new SumAccumulator();
CollectionUtils.forAllDo(i, accumulator);
System.out.println(accumulator.getSum());

include?

digits = (1..10).to_a
digits.include? 5
# >> true

one possibility how to translate Ruby’s include? to Java

List<Integer> i = new ArrayList<Integer>(100);
    for (int j = 1; j <= 10; j++) {
        i.add(j);
    }
System.out.println(CollectionUtils.exists(i, PredicateUtils.identityPredicate(5)));

compact

["a", null, "b", null, "c", null].compact
# >> ["a", "b", "c"]

one possibility how to translate Ruby’s compact to Java

List<String> s = new ArrayList<String>();
s.add("a");
s.add(null);
s.add("b");
s.add(null);
s.add("c");
CollectionUtils.filter(s, PredicateUtils.notNullPredicate());
System.out.println(s);

As you can see the added finger typing with ‘translated’ Ruby into Java is in orders of hundreds of percent for small examples like these. But these constructs should stay unchanged and the more business logic you have the more efficient they will get. The added bonus is in being able to work with Java collections in somewhat familiar way to Ruby’s array. You could even make your own List interface implementation with each(), select(), reject(), collect(), detect(), inject(), include(), compact() methods added to the mix. And you could end up with something like this:

class MyList extends ArrayList {
    public void each(Closure closure) {
        CollectionUtils.forAllDo(this, closure);
    }

    public MyList select(Predicate predicate) {
        return MyList(CollectionUtils.select(this, predicate));
    }

    // ... and so on ... you get the idea
}

Block

Ruby code block are chunks of code surrounded by do and end keywords (or single line block with curly braces). Blocks can take arguments. The arguments are declared surrounding variable names by pipe symbols. They can be associated with method calls and evaluated using yield. Passing arguments is accomplished by passing arguments to yield. Any method can be called with a block as an implicit argument. So for example:

# implicit block evaluation
def m1
  yield
end

# passing arguments to implicit block
def m2( param )
  yield param
end

# assigning a name to an implicit block
def m3( param, &block )
  block.call param
end

m1 { puts 'hello' }
# => "hello"

m2( 'hello' ) { |x| puts x }
# => "hello"

m3( 'hello' ) do |x|
  3.times { puts x }
end
# => "hello"
# => "hello"
# => "hello"

In the above example we can see how are blocks associated with method calls and how are blocks evaluated inside a method. In the m3 method call we can see how multi line blocks are associated with method calls.

Q: Whoa! Where is the yield in m3, hmm? And what is the meaning of the ampersand before the parameter block?

You got me :) The yield is replaced by block.call because we supplied a name for the block being associated (and a very unimaginative one: block) and thanks to that by the time the block gets to the method body it’s no longer a block. It’s actually a Proc. In m1 and m2 the block is anonymous and we evaluate it by calling yield. If we want to give a name to the block (by putting an ampersand before the name of the methods last parameter) we get a reference to it wrapped in a Proc object. And to evaluate a Proc you need to call it’s call method.

The m3 example is interesting in another way also. It shows how blocks handle scope of variables. The block sees the variables in the context (scope) it was declared in. The block { puts x } sees the variable x declared outside of its scope and therefore can print it. And blocks are generous and can provide that kind of scope transcending service to anyone — but only if they go through a self sacrifice and change into a Proc!

Proc

A Proc can be created by associating a block to the call of Proc.new (actually associating a block with any method call does the trick). Proc is a block associated with a context. So for example if we have a local variable say foo and we use it in a block and send the block to a method which automatically converts the block to a Proc then the formally local variable foo can be accessed in the new scope of the method. Pretty cool, huh?

def bar
  yield( 10 )
  puts var # bam! this throws an error
end

var = 1
bar { |value| var = value }
# => 10
# => NameError: undefined local variable or method `var' for main:Object
#            from (irb):3:in `bar'
#            from (irb):6

In the above example we declare a method bar which cannot access the variable var which is defined later in the scope but using a block we can assign a value to it without being able to access it directly (hence the NameError). Since the start of a method (or class) definition opens a new context we cannot assign the value of var in a method and see it change in the outer scope without the cool goodness of Procs. So only an “insane” person would try something like this:

var = 1
def bar
  var = 10
end
bar
puts var
# => 1

And expect var to be 10.

Lambda

Lambda is a Kernel method (so we should write it with a lowercase l – lambda) a call to which is equivalent to Proc.new. Except that a lambda returns a Proc which checks the number of parameters passed when called. If the number of parameters is wrong you get a warning.

l = lambda {|x| 3.times {puts x}}
l.call "hi","you"
# => (irb):2: warning: multiple values for a block parameter (2 for 1)
# => "hi"
# => "you"
# => "hi"
# => "you"
# => "hi"
# => "you"

Lambda vs Proc

From Wikipedia

Both Proc.new and lambda in this example are ways to create a closure, but semantics of the closures thus created are different with respect to the return statement.

def foo
  f = Proc.new { return "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo"
end

def bar
  f = lambda { return "return from lambda" }
  f.call # control does not leave bar here
  return "return from bar"
end

puts foo # prints "return from foo from inside proc"
puts bar # prints "return from bar"

Follow

Get every new post delivered to your Inbox.