JTree : modify apperance regardless of L&F - java

I've got a JTree which I'm trying to modify it so that the actual selection area for any selected node will extend from the very left of the JTree to the very right of the JTree.
Most examples on the web talks about extending BasicTreeUI. From there you just modify the methods that determine selection area, and that's it. However, this will require that the JTree - regardless of which platform it runs on - will use that implementation. I won't really be able to take advantage of the various UI implementations that target specific platforms as I always will be using BasicTreeUI (and not the Metal, Windows or Aquia implementations).
What I ideally would like to be able to do is to take whatever implementation of BasicTreeUI that is currently installed on the JTree and wrap it in a custom wrapper of mine which extends BasicTreeUI. From there I would override all methods and delegate to the wrapped UI, and do my own implementation of a few methods where required to recalculate the node selection area. However, most methods on BasicTreeUI is protected,
so I can really do this.
Not sure how to get around this...any ideas would be welcome!

Perhaps you could override setUI and wrap the provided UI in your custom tree UI, like so:
#Override
public void setUI(TreeUI ui) {
super.setUI(new MyCustomTreeUI(ui));
}
Another option to consider is looking into providing/setting tree UI properties in the global UIManager. I believe that the platform-specific tree UIs will ask the global UIManager for property values and configure themselves accordingly - perhaps you could simply do something like UIManager.put("Tree.selectionWidth", 100).

Related

Accessibility in a custom Swing control which apes a native one?

I have a Swing custom control which serves an almost identical function to a JLabel. It's not accessible by default for people who use assistive technology, like a screen reader. I'm working on the Megamek GitHub Project, and trying to figure out how to associate the PMSimpleLabel class with other objects, as in the JLabel class's setLabelFor method.
The approach taken so far seems to be to more or less ape the JLabel's accessibility implementation. I'm not sure if this is the right way to go about it, there seem to be some elements in the latter I'm not understanding.
The problem turns out to be largely because of the custom components. The AccessibleJComponent class has a fallback mechanism to name controls which don't ohterwise have accessible names, but this is hard-coded to look for a JLabel and not a custom label class.
There are a few work-arounds for this, such as modifying the get/setAccessibleName methods, or switching to using the accessible description instead.
The solution in the long term is probably to use regular Swing components where possible

Programming with a Java MVC approach using NetBeans GUI builder

I've been tasked with making a GUI that essentially takes a bit of user input and does some folder/file manipulation on various drives accessible by the machine the program is being run on. While designing this GUI, I'm starting to realize that MVC will make my life much easier and anyone else who decides to modify code, but I can't really see how this can be done via NetBeans.
I've done a bit of reading up on this topic, and I can't really see any clear cut answers as to whether or not this can be done on NetBeans. Surely it can be done if I programmatically build the GUI, but that somewhat defeats the purpose of why I chose to use NetBeans.
Netbeans is fine to do this.
The key thing to realize is that while all of the basic Swing components are MVC, for the most part you don't interact with them that way. A simple text field has it internal model, but that model isn't your model, the text field is more a primitive.
Your model deals with higher level events (button actions and what not), rather than button presses and arrow moves and mouse clicks.
So, for high level MVC, the primary mechanism of communication is through PropertyChangeListeners. And the basic task of building your app up is wiring the PCLs of the assorted data elements along with their GUI components together.
For example, a simple case is you have a list of items. And that list is rendered on the screen via a JTable, and that table is on a JPanel.
Your list has it's own model, i.e. it's not simply a Java List. It's not a List because standard Java Lists don't support PCL notifications. But your Model would obviously wrap such a List.
Now, the next question is how do you wire up JTable to be associated with your List model.
One, you could subclass JTable and bind it to your Model. Or, more simply, you use the JTable as a primitive, and let the enclosing JPanel manage the interaction between your Model and the JTable.
That means having your JPanel implement PropertyChangeListener, and then, when wiring everything up, you do something like this:
ListModel myModel = new ListModel();
ListPanel myPanel = new ListPanel();
myModel.addPropertyChangeListener(myPanel);
Now, whenever your ListModel is changed, is will notify the ListPanel.
On your ListPanel you can having something like:
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(ListModel.CHANGED)) {
ListModel model = (ListModel) evt.getSource();
DefaultTableModel tm = (DefaultTableModel) listTable.getModel();
tm.setRowCount(0);
for (String s : model.getList()) {
tm.addRow(new Object[]{s});
}
}
}
Now, you can see this simply reloads the entire table model, but you can make your property changes as fine grained as you want. You can also see that if this was some other model (like a Person or something) you can populate individual text fields and whatnot on the panel.
This is a pretty simple GUI, but it shows the fundamentals of how this all wires together. I think a bit of this is lost in the Swing examples which are great for one panel screens but don't scale at all when you start adding other views.
Your JPanels basically become combined VC, as your GUI gains complexity you can factor those kinds of things out, but its works pretty well for reasonable amounts of screens and such.
There are two ways in which Netbeans can help you leverage its codebase: GUI Builder (1) and NB Platform (2).
(1) Netbeans had for a while one of the better drag-n-drop GUI builders in the Java world, codenamed Matisse.
That said, it's been a long time since I worked with it - and I never really liked the generated code, it wasn't very comprehensible (which of course is not the purpose of auto-generated code). For more complex UIs we hand-wrote the layout and the work was bearable, even if not the most pleasant. For simple UIs, I'd try GUI Builder again, for complex UIs with a lot of wired logic, I'd probably still would write it by hand.
To see how the GUI Builder works, take a look at one of the many tutorial videos, e.g. this one:
NetBeans GUI Builder: Adding Components
(2) Netbeans Platform is to Netbeans, what RCP is to Eclipse. A rich set of components developed for an IDE, that can be reused. I briefly looked into NB Platform and we would have used it, if the project didn't change course. Maybe this SO question can shed more light on this aspect: Which Rich Client Platform to use?.
Concerning MVC. There was JSR 296, a generic Swing Application Framework, that looked somewhat promising, but was withdrawn in 2011. That did not stop people to fork it and work on it, as this project shows: Better Swing Application Framework, with a release in mid 2012. Even if you do not use such a framework, please do not put all code in one class (as you mention in you comment), but create a simple model/controller and keep the UI components separate. It does not need to be fancy for a simple app, a minimal MVC-ish separation of concerns might suffice.
I also hit this problem and i found a link which gives a good example how to seperate the controller from the view using the NetBeans GUI builder.
Here is the link.

Localization and L&Fs

I thought it would be nice if I gave the user the ability to choose and switch between "themes" (L&Fs). I'd give him a choice between Java metal (default), System default, and maybe a couple more I'll download from the internet...
My application is also bilingual (you can pick between two languaes to be displayed).
However, it's important for my application to be fully translated. I can handle the simple stuff, naming JLabels, JButtons, titles of frames, etc...
But there are also some predefined components whoose string I cannot manage as easely (e.g. JFileChooser). I was told that I could change them using the UIManager, but that their strings are L&F specific.
Now, regardless to how much fun would be translating my application for each and every L&F, I hope there is some centralised way of controlling those strings.
After all, JFileChoose (e.g.) is the same component, no matter the L&F that is used, right?
It prints text on the same parts of itself, no?
So, there should be something I could access that would grant me "master" control over the text that is printed onto the predefined components, I assume...
Any ideas?
not easy job,
have to read Modifying the Look and Feel
most important is Changing the Look and Feel After Startup
have to accept that you have to override value for Keys into UIManeger too, NOTICE about one of Look and Feel
is possible that different L&F have got various Fonts and Colors for concrete JComponents, multiply by Native OS
in some cases is important if you'll to change Color or ColorUIResources (Font or FontUIResources)
JFileChooser is compound JComponents, you can to extract its members,
best place to start could be this idea,
Nimbus Look and Feel lives with own life

Colouring JTree's TreeNodes

I have a JTree which I give objects that implement the TreeNode interface, and a custom TreeModel to display them (not using DefaultMutableTreeNode). I would like to change the text colour of some nodes. I can't find anything in the docs, except javax.swing.tree.DefaultTreeCellRenderer.setTextNonSelectionColor(Color newColor), but it will change everything indiscriminately, and I only need it for some nodes (specifically, broken links, i.e. nodes whose corresponding files can't be found on the disk, should be greyed out, the rest should be default). Can it be done, and how?
You are close to your answer. What you need to do is Sub Class the DefaultTreeCellRenderer and override a few of the DefaultTreeCellRenderer's methods. Then make sure you tell the tree to use your custom cell renderer.
What you will need to do is have some state variables that indicate whether or not a link is broken, and set the color of the node based on that.
You might also look at org.netbeans.swing.outline, mentioned in this answer. Ordinary extensions of TableCellRenderer and the RenderDataProvider interface make it especially easy to customize the appearance of rows in the tree.

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!
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?

Categories

Resources