Don’t forget the attachment

November 17, 2010

I’m rarely wowed by UIs these days, but Gmail impressed me today. I was writing up an email, with the intent of attaching a document. Of course, by the time I finished writing the email, I had forgotten to actually attach the document. But Gmail informed me of this mistake when I pressed send:

I wonder if they can figure out a way to warn me even before I press send?

Advertisements

Time for a new keyboard

June 13, 2010

The keyboard is an absolutely fundamental piece of equipment for us software developers. I’ve always used stock keyboards, but my fingers are in need of a keyboard designed for intense and constant use. There have been plenty of web articles on choosing the right keyboard but I’m specifically interested in satisfying a few specific needs (listed in priority order):

  1. Minimal stress on my fingers. When I’m really going at it, my pinkies can end up soar, which ends up slowing me down. Not to mention I don’t want to end up with carpal tunnel!
  2. 1st class support for Mac. I want a keyboard designed to be used with a Mac.
  3. Can’t be distracting. I don’t mind a keyboard with a bit of noise, but it can’t be loud enough that it distracts me or those working around me.

The keyboards that appear to meet my criteria are unfortunately not physically available in any stores to try out, which makes it a bit difficult because they aren’t cheap! So I’m throwing the question out there to here about the keyboard that you love and use every day. Here are a few keyboards that I’m interested in:

Matias Tactile Pro Keyboard

Matias OS X Keyboard

Das Keyboard, Model S (silent)

What do you think?

If you’ve ever extended BasicTableUI, you may have struggled a bit with it’s inability to hook into the cell rendering process. JTable has the prepareRenderer method through which you can inject yourself into the cell painting pipeline. BasicTableUI, however, has no such mechanism.

Why would we even need this capability from a BasicTableUI? In ITunesTableUI, for example, I install a special border on the containing JScrollPane, which paints the row striping (the subject of a future blog entry). In order for the striping to show through, each renderer must be non-opaque (transparent). By default, renderers are opaque, which results in a table that looks like this:

iTunesTable-bad
We have a couple of options to work around this. First, we could simply grab each of the default renderers and make it non-opaque. This isn’t a great solution, though, because there’s no easy way to get a list of all these renderers — we’d end up harding coding a set into our UI delegate. And if downstream consumers added their own renderers, they’d be responsible for making sure they were non-opaque.

The second (and better) option, is to create a custom CellRendererPane that essentially gives us a prepareRenderer method. CellRendererPane is the class used to stamp out each table cell onto the screen. The renderer for the cell is prepared, and then added to the CellRendererPane, which manually invokes paintComponent. Overriding paintComponent gives us the hook into the cell painting process that we’re looking for. Here’s what the custom CellRendererPane looks like:

    /**
     * Creates a custom {@link CellRendererPane} that sets the renderer component to 
     * be non-opaque if the associated row isn't selected. This custom 
     * {@code CellRendererPane} is needed because a table UI delegate has no prepare
     * renderer like {@link JTable} has.
     */
    private CellRendererPane createCustomCellRendererPane() {
        return new CellRendererPane() {
            @Override
            public void paintComponent(Graphics graphics, Component component, 
                                       Container container, int x, int y, int w, int h, 
                                       boolean shouldValidate) {
                // figure out what row we're rendering a cell for.
                int rowAtPoint = table.rowAtPoint(new Point(x, y));
                boolean isSelected = table.isRowSelected(rowAtPoint);
                // if the component to render is a JComponent, add our tweaks.
                if (component instanceof JComponent) {
                    JComponent jcomponent = (JComponent) component;
                    jcomponent.setOpaque(isSelected);
                }

                super.paintComponent(graphics, component, container, x, y, w, h,
                    shouldValidate);
            }
        };
    }

Here’s how we create and install this custom CellRendererPane in our extension of BasicTableUI:

CustomTableUI extends BasicTableUI {
    // ...
    @Override
    public void installUI(JComponent c) {
        super.installUI(c);

        table.remove(rendererPane);
        rendererPane = createCustomCellRendererPane();
        table.add(rendererPane);
        
        // ...
    }
}

and that lets us make all our non-selected cells non-opaque!

iTunesTable-good

iPhone to the rescue

December 22, 2008

no_power1
I was one of the poor saps in southern New Hampshire who lost his power in the recent ice storm – me and 430,000 NH residents! Not only did I lose my power, but it wasn’t restored for a week – that’s a painfully long time to be disconnected.

Fortunately for me, I could stay connected with my relatively new and shiny iPhone. I think I would have gone stir crazy without it. This unusual event made the $70 monthly fee seem oh-so worth it!

Yet another blog

April 22, 2008

At the risk of being left¬†completely¬†in the 20th century, I’ve finally broken down and started a blog. Mainly because I want a place to post sample code and screen shots from my upcoming Java One presentation (Simply Sweet Apps with Glazed Lists).

Other than for my immediate content sharing needs, you’ll probably find sexy UI stuff here, mostly in Java – so if your into that kinda thing, stay tuned.