Custom swing component - Turning a node into text
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!
Asked by: John940 | Posted: 21-01-2022
Answer 1
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.
Answered by: Ryan684 | Posted: 22-02-2022Answer 2
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
Answer 3
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?
Answered by: Michelle801 | Posted: 22-02-2022Similar questions
java - What is a component
I listen to the podcast java posse, on this there is often discussion about components (note components are not (clearly) objects). They lament the fact that Java does not have components, and contrast with .NET that does. Components apparently makes developing applications (not just GUI apps) easier.
I can figure from the discussion certain qualities that a component has, its something to-do with decoupling (s...
java - Is there a free (LGPL< BSD, etc. ) RDF editor component for swing?
I look for a JComponenet based RDF editor which I could embed in my application?
It does'n need to be fancy .
Thanks in advance.
java - How to return actual cell component bounds in a JTable?
I have a custom renderer in a JTable to display JCheckboxes for booleans. However, this causes a slight issue because when the user clicks in the table cell, but not in the checkbox, the checkbox is still checked.
Is there a way I can return the bounds of the actual JCheckbox that is rendered by the JTable at a particular point so I can determine if ...
java - Facelets custom component doesn't set attribute after submit
I am having a problem with custom components in facelets. The first time that the page is rendered, the attributes are set properly on the component class. When a form is submitted however, the attributes are not set.
Here is the class that I am using to test this.
public class TestEcho extends UIData
{
/** Logger. */
private static Log log = LogFactory.getLog(TestEcho.class);
private...
class - Calling methods of "parent" component in Java
I have the following situation I think would be best to show in sample program code. I have a Java class that extends JPanel. In this class are two objects which are two more JPanels. In one of the JPanel objects is a JTable object. I added a listener to this JTable that detects a double click. When it detects a double click, I want to fire a method in t...
How to tell if my Java component is in an Applet?
I have a Component which I am using both in a standalone Java application as well as in a Java applet. How can I figure out from within the Component whether my component is in an applet?
Also, once I figure out that I'm running in an Applet, how can I get access to the Applet?
java - Post a KeyEvent to the focused component
What is the best way to post a Button Press to a component? I tried using the Robot class and it works, normally. However, this class has some problems under some Linux platforms, so I wonder what is the best Java-only way to post an event to a component.
In this particular case, I want to post backspace events to a JTextField when I press a button.
EDIT: I've used the Robot class after all. I fi...
java - Making a component less sensitive to Dragging in Swing
A JComponent of mine is firing a mouseDragged event too vigorously. When the user is trying to click, it interprets is as a drag even if the mouse has only moved 1 pixel.
How would I add a rule for a particular component that amounted to:
Do not consider it a drag event unless
the mouse has moved 10 pixels from the
point at which is was pressed down.
java - What is the best way to unit test a EJB3 component without having to deploy the component
I would like to have a JUnit (or other) system where the enterprise beans can be tested in a mock environment so that all resources/beans and so on are injected locally. The enterprise beans should not have to accomplish this. All kinds of injection should be supported.
I would like to have a maven plugin for this so that the tests can be run from a maven build.
Transactions are not necessary during...
java - How do I use a base class or interface with a grid or loop component in Tapestry 5?
I have a concrete class A that extends BaseA and implements InterfaceA. I want to loop through a list of A using either the base class or interface as the looping variable. Trying something like this:
<t:loop source="listOfA" value="propertyOfTypeBaseA">
${propertyOfTypeBaseA.someField}
</t:loop>
gives me an error "Could not find a coercion from type A to BaseA". The sam...
Still can't find your answer? Check out these amazing Java communities for help...
Java Reddit Community | Java Help Reddit Community | Dev.to Java Community | Java Discord | Java Programmers (Facebook) | Java developers (Facebook)