Compound JTree Node allowing events to pass through to objects underneath
I went through the answer by #Jakub Zaverka ,which was pretty lucid.But what I could not understand is where is the code to create tree nodes (JTree ,food,sports,colors).
Could someone explain how the nodes are created.
If I create a Node extending JPanel having a JButton and JLabel as fields ,can I set the node using the constructor of JTree which would be rendered and edited by the same custom renderer and editor.
The default JTree constructor "Returns a JTree with a sample model." To get the sample model, the constructor invokes the protected method getDefaultTreeModel(), which returns a sample model that is "Used primarily for beanbuilders to show something interesting." The values you see are contained in the source. A related example is seen here.
I have a JTree that stores "ShipmentItem"s and the .toString() on them shows the quantity, then the name of the ShipmentItem. At some point I change the quantity of multiple items at once but the toString() doesn't refresh until I've actually clicked on that particular tree node. I don't want to have to extend JTree to use 'Property Fired' I just want to be able to refresh it so that it shows the update.
I tried jtree.setModel(tree.getModel()) this didn't seem to work at all.
When you change something to your TreeModel (which you do by adjusting the ShipmentItem objects) you must make sure your TreeModel fires the correct event. This will cause the JTree to repaint the correct part. If you for example started from the DefaultTreeModel, your extension should call nodeChanged when the object of the node has changed.
Note: you do not have to adjust the toString method for correct rendering. The concept you are looking for is a TreeCellRenderer (check the Swing tutorial for more information)
I am implementing comboboxes in an application where IceFaces forms are being built dynamically. There are no xhtmls around, we put together everything from Java code. This works nice so far, but I am stucked at HtmlSelectOneListbox. In my code I create one that appears on the form as well correctly, but I don't know how to add the SelectItems to it.
HtmlSelectOneListbox combo = new HtmlSelectOneListbox();
combo.setId(id);
combo.setDisabled(readOnlyWindow);
/* parent is the UIComponent instance around us*/
parent.getChildren().add(combo);
I can create instances of SelectItems or even SelectItemsTag but the combo has no methods to set them. It has only a setValue/setValueExpression and with that I could set my value binding expression to the object representing #{bean.value}. But the selectitems property should be set not on the listbox but its nested f:selectItems that I don't know how to create.
I think UISelectItem and/or UISelectItems objects should be added as children of HtmlSelectOneListbox in a similar way you add combo to the parent component.
I am designing a web application testing tool with integrated webbrowser in Java, to implement the browser i used the HTMLEditorKit of JeditorPane which provides bare minimum functionality which is ok for me.
Now I wanna detect all the html elements such as buttons, lists, dropdownList, textfields etc. and record the behaviour of these elements when user interacts with them.(e.g. User types in textboxes of webpage)
I tried using actionListeners on the JeditorPane to detect events of adding components with no positive result.All the eventsListeners for JeditorPane will not work on the html elements such as textbox(webpage form) displayed in it.
Is there any way i can detect and listen to action of the html elememts(especially web form) rendered in JeditorPane which is dynamically loaded when i supply url.
To render such elements (let's name them controls) EditorKit uses ComponentView and extensions. On paint() ComponentView creates a container - inner class Invalidator. The Invalidator actually contains control from Element attributes.
So after paint() is done you can get list of children of your JEditorPane. I think the list will contains the Invalidators only. And ask each Invalidator about inner component. Thus you'll have list of actual controls created in the JEditorPane.
Then you can add any listeners depending on the component type to register any activity.
On each document change event (insert/delete/update) you should recheck changhes in the list after the next paint() and update your data accordingly.
I'm writing a custom swing component (something completely new, but think JTree or JList). I'm trying to follow the general design of JTree, JTable, JList etc for consistency (I've also seen various poor 3rd party components abandon the separable model and/or renderer approach).
So, I have a model full of nodes, the component itself and a renderer. At some point the node has to be turned into text and displayed by a renderer. I'm not clear on the best way to do this:
Pass the node itself (as Object) to the renderer, and let the renderer decide how to display it.
This is how JList does it.
Requires a customised renderer just to change the text.
Allows great flexibility in how to display the node (doesn't even have to be text).
Pass the node itself (as Object) to the renderer, but have a convertValueToText() method in the component class.
This is how JTree does it.
Renderers can be just as flexibile as before - don't have to use this method.
Have to override component to change the text transformation.
As above, but delegate convertValueTotext() to the model.
This is how JXTable does it.
The model is probably the best place for this method - and it's easier to override there.
I don't want to have to customise the renderer just to change the text, but I'd like to be able to customise the renderer to do more than display a model-displayed string (else why bother with renderers). I really don't like the fact that JXTable uses reflection to look for convertValueToText() in the model - this smells of bad magic to me.
Can anyone shed any light on this oft-neglected part of Swing?
SOLUTION
What I ended up doing was this:
Add a method to the model which returns a string for the given node. Importantly, this can be null to indicate that the renderer should know what to do or that we simply can't provide anything useful.
The component has the same method, and passes the call on to the model. This is important for view-model separation. The renderer calls this method, so it doesn't talk to the model directly.
The default renderer calls the above method and if it's not null, it uses it, otherwise it can call toString on the value, or provide a default, or whatever.
This leaves developers a choice when they want to override the displayed value
- Override the method with a non-null return value knowing that the default renderer will display this text.
- Provide a custom renderer which is passed the actual node object so it can do "clever" things if it needs to.
I'm quite happy with it - it "feels" right, it works, and it's easy to use.
Thanks for your perspectives!
Good question. This is not specific to Swing, but a philosophical question about the difference between a model and a view.
In general, is converting objects into text the job of the model or the view? My purist head says that actually you want a hierarchy of views - one to convert object model to text, and one to display the text. You might even want more than two - for instance, object-to-text, text-to-document-structure, document-structure-to-HTML, and then CSS to present to the user.
However, pragmatism says this may get too hard to remember and maintain. So in your circumstance I would suggest: think about how likely it is you'll ever want to extract non-text data from the model. If it is not very likely, then put the equivalent of convertValueToText in the model.
Otherwise, allow the component to either use a renderer, if it is given one, or else take the object value and convert it to text internally.
This allows maximum flexibility and probably makes things feel most natural to the users of the API. I believe this is the JTable model though I haven't used Swing for a long time.
AFAIK neither JList nor JTree require the renderer to render text. The renderer gets passed the data object and return a JComponent which gets positioned as a child in Tree/List itself and then rendered.
I would go with this. A renderer for text would simply return a JLabel. If you want to be able to change the way, the text is constructed pass a Formatter to the TextRender, and you are done.
Stephan
If you had to write your own component do it as simple as possible. In a lot of cases if you need a custom renderer then you don't care about interpretation by component or model. Model holds your data. And in this case is also custom written. From my point of view the good choice is based on first option. Provide DefaultRenderer which implements AbstractRenderer and add there all methods like toText(Object o) and so on. Then allow me to decide whether I want to use default functionality or I prefer to wrote my own. Do you really need custom component? To make it works correctly it is a LOT of work. Is this component worth all this?