Skip to main content

JTreeTable: Ability to fix the tree column while scrolling.

15 replies [Last post]
siva
Offline
Joined: 2003-07-15

Usually, a lot of times when we present data, the first
column gives the context of the column and the rest of the columns are attributes of that instance. For example, if I am showing the details of a part, the first column will be the part number and the rest of the columns will be it's attributes. In such cases, the UI requirement is that the user should be able to see the context information at all times. So, if I am presenting my data in a JTreeTable, I should be able to fix the first column, which is the tree column and scroll only the remaining columns.

I am not sure if there is an out-of-the-box solution for this even if the data is presented in JTable (One way to do it might be to display in two separate tables, one fixed and the other with both horizontal and vertical scrollbar and handle the vertical scrollbar events such that both tables are in synch). However, since in case of a JTreeTable the tree is part of the component, it should provide such behavior out-of-the-box. Not sure how complicated or easier this would be to code, but this is definitely a must-have feature.

Any thoughts?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
evickroy
Offline
Joined: 2004-07-23

> the simple answer is: no - it's not even working on a
> JNTable :-(
> (see f.i. issues #141-jdnc, #142-jdnc).

Ok. No problem. It's a wish-list item anyway, so we'll just put it on hold until some future phase. ;)

> With all the trickery involved in JXTreeTable to show
> the hierarchical
> column halfway decent, I wouldn't expect a fixed
> hierarchical column to
> work at all - now the tree is in the "locked row
> table" and the "rest
> table" is just a simple table without a hierarchical
> column. Didn't
> track where the NPE comes into play, though.
I can imagine the huge complexity. We've consistently wowed the users with the TreeTable in our current project, so the TreeTable seems somewhat of a miracle in itself. I was just giving the row header lock a try to see if it worked since you guys have pulled off a few miracles already. ;)

If I haven't said it recently, kudos to you all!

Thanks
Erik

Kleopatra

Erik,

forgot to comment:
>
> This sounds suspiciously like the fault of the GroupableTableHeader
> screwing up the renderer, so I don't want to point fingers.

definitely not - it's the same with the "normal" headers on TreeTable
(as you can see when running the visuals of JNTreeTableUnitTest as an
application - just added a method to expose the quirk).

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Kleopatra

jdnc-interest@javadesktop.org wrote:
> Sorry to revive this old post, but I was wondering if any
> knew if the locking feature currently works on a JNTreeTable?

the simple answer is: no - it's not even working on a JNTable :-(
(see f.i. issues #141-jdnc, #142-jdnc).

With all the trickery involved in JXTreeTable to show the hierarchical
column halfway decent, I wouldn't expect a fixed hierarchical column to
work at all - now the tree is in the "locked row table" and the "rest
table" is just a simple table without a hierarchical column. Didn't
track where the NPE comes into play, though.

Primitive types are a different story (it's a core problem - if we call
it a problem?): prior to 1.5 - without autoboxing - primitive types
weren't allowed as values, so no tableModel returned int.class as
columnClass, so there was no need/possibility to register renderers for
them.

But I'm surprised that the renderer lookup mechanism (in core JTable)
doesn't come up with the DefaultTableCellRenderer if it doesn't find an
appropriate registration. Hmm ... getSuperClass(int.class) is null, so
the recursive getDefaultRenderer(class) returns with a null and
getRenderer doesn't jump in to return at least the default. Looks like a
bug to me.

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

dhall
Offline
Joined: 2006-02-17

>> Hmm ... getSuperClass(int.class) is null, so the recursive getDefaultRenderer(class) returns with a null and getRenderer doesn't jump in to return at least the default. Looks like a bug to me.

I came to the same conclusion in the same place in JTable: its one of the deep corners that got a little dusty in theory (it's been a problem longer than 1.5 & autoboxing, but in practice, who returns things like Integer.TYPE from getColumnClass()??). We're exposing the problem when we start generating column class information from metadata, and (based on autoboxing) conflating int and Integer.

It's an easy enough fix in JTable, but where does the ripple extend?

Dave

kleopatra
Offline
Joined: 2003-06-11

>
> I came to the same conclusion in the same place in
> JTable: its one of the deep corners that got a little
> dusty in theory (it's been a problem longer than 1.5
> & autoboxing, but in practice, who returns things
> like Integer.TYPE from getColumnClass()??).

exactly - and there is even more dust: interfaces and arrays aren't found correctly in the lookup.

> We're
> exposing the problem when we start generating column
> class information from metadata, and (based on
> autoboxing) conflating int and Integer.
>
> It's an easy enough fix in JTable, but where does the
> ripple extend?
>

hmm ... the "where" is the question, don't know the answer. As to the "what" we can tweak JXTable in two places:

- change getCellRenderer to always return a renderer != null. though it's undocumented, that's what every client of JTable I've ever seen expects.

- register the specialized renderers (Numbers mostly) with the primitives' type as well (that's what Richard is doing in the binding branch)

Then we'll see where the we are going :-)

There'll probably be a similar issue with editors, didn't look into it, though.

What do you think?

Jeanette

dhall
Offline
Joined: 2006-02-17

I think the bug exists in JTable -- and should be fixed there, if possible. I don't think using JXTable to hide the basic problem is the best solution.

My concern with that would be the associated ripple, but now that I think about it, what's the worst that can happen(*) if something that's never worked before starts working on a subsequent release?

Dave

(*) I know -- extremely bad question in most movies

rameshgupta
Offline
Joined: 2004-06-04

> Usually, a lot of times when we present data, the first
> column gives the context of the column and the rest
> of the columns are attributes of that instance. For
> example, if I am showing the details of a part, the
> first column will be the part number and the rest of
> the columns will be it's attributes. In such cases,
> the UI requirement is that the user should be able to
> see the context information at all times. So, if I am
> presenting my data in a JTreeTable, I should be able
> to fix the first column, which is the tree column and
> scroll only the remaining columns.
>
> I am not sure if there is an out-of-the-box solution
> for this even if the data is presented in JTable (One
> way to do it might be to display in two separate
> tables, one fixed and the other with both horizontal
> and vertical scrollbar and handle the vertical
> scrollbar events such that both tables are in synch).
> However, since in case of a JTreeTable the tree is
> part of the component, it should provide such
> behavior out-of-the-box. Not sure how complicated or
> easier this would be to code, but this is definitely
> a must-have feature.
>
> Any thoughts?

It is quite complicated. The solution involves partitioning the table column model into two table column models, with the first column model containing only the first column, and the second containing the rest. You then need to create two tables that share the same data model, and assign one of the two column models to one table, and the other column model to the other table. Then, put the main table in a scrollpane, and put the table containing the first column in the scrollpane's row header part. You will also have to create a JTableHeader for the first column, and put that in the top-left corner of the scrollpane.

Of course, if you were using JNTable, this feature is available out of the box, but not for JTable or JXTable. Please see JNTable.setRowHeaderLocked() for how you can do this with Swing/X components.

In your case, you want to split the table, but not lock the first column (as JNTable does) because that would prevent you from expanding/collapsing nodes in the first column.

You probably also want the first column to be resizable. If so, you might choose to use a JSplitPane instead of cramming the row header table inside the original scrollpane's row header. So, you would have a JSplitPane, whose right pane would contain the main table wrapped inside a JScrollPane as usual, and the left pane would contain the other table wrapped inside a separate JScrollPane.

Hope this helps.

Ramesh

siva
Offline
Joined: 2003-07-15

Ramesh, what you are saying seems to be a bit too complicated for me and I would try that approach as a last resort. In the meanwhile, I was trying to make use of the JNTable and pass it the TableModel from the JXTreeTable.

There were a couple of issues with this approach.

1. JNTable' JNTable(JTable) constructor is protected. As a result, I can't pass the column model along with the data model in the JNTable(TableModeL) constructor. However, since the JXTreeTable has a special cell renderer/editor for the hierarchical column, it's not found by the JNTable's private JXTable when it creates the defaultCellRenderers/Editors.

2. So, then I changed the code such that, after creating
the JNTable, I explicitly set the columnModel. With this
approach, I do see the nodes in the first column. However,
there seems to be some weird behavior when I collapse/expand the node. Note sure which this happens
but probably because I abandoned the original JTreeTable
which might be doing something extra.

3. After this, now if I try to lock the row header, then
I run into the 1st issue for the row header table that's
implicilty created. I think when the row header table is
being created, it should get the columnModel of the first
column as well. The code

rowHeaderTable = new JXTable(jxtable.getModel());

only passes the model and not the column information.

Given the fact that JNTable implements fixing the row header and JXTreeTable implements the tree behavior of a table, I am thinking that it should be possible to glue these two and get the behavior I am looking for instead of writing my own code.

What do you think?

rameshgupta
Offline
Joined: 2004-06-04

> Ramesh, what you are saying seems to be a bit too
> complicated for me and I would try that approach as a
> last resort.

It's complicated, but not too much :-)

> In the meanwhile, I was trying to make
> use of the JNTable and pass it the TableModel from
> the JXTreeTable.
[snip]

I'll take a look at your code and respond a little later on your approach.

>
> Given the fact that JNTable implements fixing the row
> header and JXTreeTable implements the tree behavior
> of a table, I am thinking that it should be possible
> to glue these two and get the behavior I am looking
> for instead of writing my own code.
>
> What do you think?

It is definitely possible to fuse the two parts together -- That was the gist of my message this morning on how you can go about implementing it.

You could file an RFE, and then wait until we get around to it. Or, you could file an RFE, take ownership of the RFE, file a JCA, and start working on an implementation along the lines I suggested earlier.

If you choose the latter route, I will continue to work closely with you as I have all along -- perhaps even more closely -- and we'd all be happy sooner :-)

What do you think?

Ramesh

siva
Offline
Joined: 2003-07-15

I searched on the web as well for how to fix colums in the table and the solution I found on codeguru.com and a bunch of other places are pretty much the same. Making using of the rowheader of the scrollpane.

I also looked at the JNTable implementation and it seems to be assuming that only one column will be fixed which is not true.

Anyway, after looking at the Swing code as well on how the column expansion works, I was able to make the first column of the JTreeTable fixed and expandable within the same scrollpane (I didn't like the idea of puttting it in a splitpane, as the UI doesn't look good) by adding a mouseinput listeners to the corresponding tableheader.

However, I feel that this whole approach of splitting up the original model into two separate tables is not a clean solution as many functionalities implemented by the JTable have to be recoded to make both tables to look like one (for example, when a JTable is dragged, I think it creates a HTML table for it. Now, since there are two separate tables in this fixed column solution, dragging has to be handled such that the columns from both tables are glued together).

Unfortunately I am in a position where I can not sign JCA or any other documents. However, I can passively contribute by providing feedback and what I have done to the various JDNC components.

rameshgupta
Offline
Joined: 2004-06-04

> I searched on the web as well for how to fix colums
> in the table and the solution I found on codeguru.com
> and a bunch of other places are pretty much the same.
> Making using of the rowheader of the scrollpane.
>
> I also looked at the JNTable implementation and it
> seems to be assuming that only one column will be
> fixed which is not true.

Sure, that was a simplifying assumption to get *something* out. I am working on (among other things) a more general column freezing and scrollpane splitting solution.

>
> Anyway, after looking at the Swing code as well on
> how the column expansion works, I was able to make
> the first column of the JTreeTable fixed and
> expandable within the same scrollpane (I didn't like
> the idea of puttting it in a splitpane, as the UI
> doesn't look good) by adding a mouseinput listeners
> to the corresponding tableheader.
>
> However, I feel that this whole approach of splitting
> up the original model into two separate tables is not
> a clean solution as many functionalities implemented
> by the JTable have to be recoded to make both tables
> to look like one (for example, when a JTable is
> dragged, I think it creates a HTML table for it. Now,
> since there are two separate tables in this fixed
> column solution, dragging has to be handled such that
> the columns from both tables are glued together).

Yes, this is messy code that Swing developers have to write. However, we plan to make this clean and painless for JDNC developers who use JNTable instead of JXTable.

>
> Unfortunately I am in a position where I can not sign
> JCA or any other documents. However, I can passively
> contribute by providing feedback and what I have done
> to the various JDNC components.

That would be fine, as long as you don't share code with us that might cause controversy over ownership later on, or pass along ideas that your company considers proprietary trade secrets and such :-)

Ramesh

evickroy
Offline
Joined: 2004-07-23

Sorry to revive this old post, but I was wondering if any knew if the locking feature currently works on a JNTreeTable?

We are getting an exception when we try and lock the row header in a JNTreeTable. Here is the exception:

[code]
setting row header locked

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.JTable.prepareRenderer(JTable.java:3919)
at org.jdesktop.swingx.JXTable.prepareRenderer(Unknown Source)
at com.birosoft.liquid.LiquidTableUI.paintCell(LiquidTableUI.java:298)
at com.birosoft.liquid.LiquidTableUI.paintCells(LiquidTableUI.java:190)
at com.birosoft.liquid.LiquidTableUI.paint(LiquidTableUI.java:101)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:142)
[/code]

It seems odd that the renderer would be null. This sounds suspiciously like the fault of the GroupableTableHeader screwing up the renderer, so I don't want to point fingers. I'm just curious if the locking currently works on a JNTreeTable while I'm digging into the exception more. Does anyone know off the top of their head?

Thanks
Erik

dhall
Offline
Joined: 2006-02-17

I had a similar problem with a binding demo where I specified the type of a database as 'int' rather than 'Integer'. Does your TableModel/TableColumnModel return any of the primitive types in response to getColumnClass() ??

Dave

rbair
Offline
Joined: 2003-07-08

> I had a similar problem with a binding demo where I
> specified the type of a database as 'int' rather than
> 'Integer'. Does your TableModel/TableColumnModel
> return any of the primitive types in response to
> getColumnClass() ??

I had a similar prob as well. I ended up adding int.class/double.class etc to the list of available renderers. I haven't commited this code, as it was in the binding branch.

Richard

evickroy
Offline
Joined: 2004-07-23

Thanks for the responses. That definitely could be the case, although, I don't understand why it would work fine when we don't try to lock the row header. One item on the user's "wish list" was to make the tree column locked, so we tried it on an existing screen that works fine without it. Let me do some more digging...

Thanks!
Erik