The Source for Java Technology Collaboration
User: Password:



Shannon Hickey

Shannon Hickey's Blog

Enable Dropping into Empty JTables

Posted by shan_man on January 19, 2006 at 01:46 PM | Comments (12)

So you've created an empty JTable, you've given it a TransferHandler to accept drops, and you've added it to a JScrollPane. But when you launch your application and drag some completely valid data into the table, it rejects you! I'm not kidding; go ahead and try it yourself with this demo (requires build 76 or greater of Mustang). Drag from the component labelled "Drag from here" into the JTable, and you'll see the following:

What's going on? Without peeking at the demo's "Options" menu (which would likely give it away), can you figure it out? How about a hint: The background color of a JTable in the Ocean Look and Feel is supposed to be white. In this demo, I haven't changed it, and yet you aren't seeing that white color. Perhaps there's a connection...Are you ready for a second hint? Using the demo, double click a couple of times on the drag source to have some rows added to the table. Now try dragging again and you'll see that this time you can indeed drop into the table. But, the drop line is only shown when the mouse is over an existing row; if you drag below the existing rows, you'll see something like the following:

After seeing this, have you yet started to wonder if maybe that gray "no-drop" area is not actually a part of the table? If so, you've figured out what's going on! You see, unlike JList and JTree, for some reason JTable is not implemented to be automatically stretched to fill the height of a JScrollPane's viewport; it only takes up as much vertical room as needed for the rows that it contains. As such, when you're dragging over that gray area, you're actually not over the table. This issue has been known for some time under bug number 4310721 (JTable is not stretched to fill a viewport's height). Let's have a look at how this has been resolved in Mustang, and how you can easily work around it in earlier releases.

The behavior of a component in this capacity is controlled by the component's implementation of the getScrollableTracksViewportHeight method, declared in the Scrollable interface. This method tells the viewport whether or not it should force the height of the contained component to match the height of the viewport. JList and JTree, which implement Scrollable, do something intelligent in this method and tell the viewport that they want to be stretched any time their preferred height is smaller than the viewport height. JTable on the other hand, prior to Mustang, always returns false.

Determining this to be something that developers often want to change, we've made it easier to do so in Mustang; it is now very simple to configure JTable to act like the other two components in this regard. Striving to maintain backward compatibility and to not break the previous clearly specified behavior (however poor), we've added a new property to JTable to enable solving this problem: "fillsViewportHeight". By default the property is false, so that JTable acts exactly as it did previously. By setting the property to true, with the method JTable.setFillsViewportHeight(boolean), JTable behaves like lists and trees and is stretched to fill the viewport height when appropriate.

Using the demo again, let's see what this looks like. If you've closed the demo, please launch it again. If you still have it running, please select the "Reset" item from the "Options" menu to reset the state. In the demo, the new "fillsViewportHeight" property can be changed via the "Fill Viewport Height" item in the "Options" menu. Please enable this option now. As you'll see, and as indicated in the following screen shots, the table is now stretched to fill the viewport. This results in two positive things: 1) The white background is now visible; 2) You can now drop anywhere within the viewport.

 

Incidentally, since it's already apparent in the demo and screen shots, let me quickly draw your attention to the solid line indicating the drop location in the JTable. This is also new in Mustang, and the result of using JTable in the INSERT_ROWS drop mode, a subject which I began talking about in my earlier blog entry. There's actually a lot more to say about the new drop modes with respect to JTable, and for that reason I'll leave further discussion on the subject to a future blog entry.

For now, let's conclude with me fulfilling my promise of demonstrating how to make JTable stretch to fill the viewport in pre-Mustang releases. It's extremely simple, with a variation of the following override in a JTable subclass being all that is needed :

public boolean getScrollableTracksViewportHeight() {
    // fetch the table's parent
    Container viewport = getParent();

    // if the parent is not a viewport, calling this isn't useful
    if (!viewport instanceof JViewport) {
        return false;
    }

    // return true if the table's preferred height is smaller
    // than the viewport height, else false
    return getPreferredSize().height < viewport.getHeight();
}

With this code you'll acheive identical results to turning the new property on in Mustang. And there's no need to wait since it's most likely the behavior you want, is extremely easy, and will not interfere when you upgrade in the future. That's the best kind of work-around in my opinion!

That's all I have for today, but please stay tuned. I'm finding it extremely rewarding to communicate with you via this blog and I'm on a roll, with the words just flowing. Potential upcoming topics include the new drop modes as they pertain to JTable, and fancy customization of drop mode indication in JTree - something that was a big hit, and received audience applause at the last JavaOne conference. In fact, I may just have to write that one first, as I'm getting quite excited about it. Until next time, take care!


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Drag&Drop is a very important feature that was left behind. I'm glad you're working on it and making such a good job.

    Posted by: imjames on January 19, 2006 at 09:49 PM

  • These are the little improvements that make a big difference. Thanks for the tip.

    Posted by: arnovdk on January 20, 2006 at 12:49 AM

  • Isn't amazing how a little bit of code can make such a big difference?

    leouser

    Posted by: leouser on January 20, 2006 at 08:45 AM

  • I've got to say, shannon, these blogs rock. I had no idea how much work went into the Drag 'n Drop, or how much functionality is now there. Keep 'em coming! Can't wait to write my next dnd app :)

    Posted by: rbair on January 20, 2006 at 09:14 AM

  • We did this for our Java 1.4 app, and we needed to add something extra so the JTable could gain keyboard focus without any rows. This is necessary to respect CTRL-V pastes from the clipboard. Our fix was to make the table take focus when clicked, which BasicTableUI does not do when there aren't any rows. Here's the code from our table's MouseListener:


    public void mousePressed(MouseEvent e) {
    // ignore this event if necessary
    if(e.isConsumed()
    || !table.isEnabled()
    || !SwingUtilities.isLeftMouseButton(e)) {
    return;
    }

    // if the UI ignores our desparate plea for focus when
    // the table is clicked beyond the last row or last column,
    // we'll try to grab focus anyway so that CTRL-V works
    int row = table.rowAtPoint(e.getPoint());
    int column = table.columnAtPoint(e.getPoint());
    if(row == -1 || column == -1) {
    if (!table.hasFocus() && table.isRequestFocusEnabled()) {
    table.requestFocus();
    }
    }
    }
    Cheers,
    Jesse

    Posted by: jessewilson on February 22, 2006 at 03:05 PM


  • Jesse, I just tried this out and you're right: clicking below the rows in 1.4.2 and 5.0 does not give focus to the table. It's great that you've noticed this and worked around it. The good news is that in 6.0, this problem no longer exists!

    Posted by: shan_man on February 23, 2006 at 12:11 PM

  • Great stuff. Would really be great if you could give a look&feel to the mouse cursor. ;-)


    Setting a JLabel with text or icon and an alpha would really make it a nice touch for drag and drop. The windows DnD really stinks.

    Keep up the great work.

    Regards,

    Posted by: cupofjoe on October 31, 2006 at 06:25 PM


  • cupofjoe: I believe you're referring to the ability to show a visual representation of what you're dragging. This is currently on the table for Java SE 7. RFE number 4816922 (No way to set drag icon: TransferHandler.getVisualRepresentation() is not used).

    Posted by: shan_man on November 22, 2006 at 12:42 PM

  • Hi Shannon

    Is it possible to enable dropping some data into empty non-scrollable JTables? If it is, how can I do that?

    RegardsDanijel

    Posted by: danijelbasic on September 14, 2007 at 04:31 AM

  • Hi danijelbasic: It certainly is possible! JTable accepts drops anywhere inside its bounds. The thing with empty tables is that they're typically given no space by most layout managers. You just need to ensure that the JTable is given the right preferred size and/or that the layout manager gives it some space.

    Posted by: shan_man on September 14, 2007 at 05:58 AM

  • how can we do that in JRE 1.5 it doesnt provide setfil.... method.

    Posted by: vankadia on November 14, 2007 at 01:11 PM

  • vankadia: Please refer to the last code sample in the blog entry. It shows you exactly how to do it in 1.5 without the setFillsViewportHeight method. Thanks!

    Posted by: shan_man on November 20, 2007 at 09:07 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds