 |
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 Digg DZone Furl 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
|