How can I dynamically alter the Java LAF UIDefaults? - java

I'm working on cusomizing a Swing application by dynamically altering the UIDefaults. The end goal is to alter many of them (colors, fonts, sizes, borders, etc) and save the result on a per user basis. While it may give the application some non-standard looks, the client asketh and the client shall receive.
The only problem I'm running into is that GUI will only update ONCE. The first time I change a ui property everthing is great, subsequent changes don't affect anything.
// called from the EDT
// uiKeyName points to some ColorUIResource
UIManager.getDefaults().put(uiKeyName, <<color from color picker>>);
SwingUtilties.updateComponentTreeUI(rootWindow);
It works once, but never again. Ideas?

When you put the new color (for example) in the table, is it a Color object, or a ColorUIResource? As I understand it, the new value will only be taken up if the current value is null or an instance of UIResource. Thus, if you insert a plain old Color object, any subsequent changes you make will be ignored.
Also, as the linked doc page suggests, this may only help with the font and foreground/background colors; when it comes to changing things like borders and margins, you may be out of luck. This is not what Swing's Pluggable LookAndFeels were designed for. Maybe you could interest the client in a Synth-based LAF?

Related

JTextPane: What's the renderer of/for setCharacterAttributes?

I have a JTextPane in my application and I prepare some styles for various words/letters. These styles are applied via setCharacterAttributes. Now I plan to style the background of some styles: If a style defines a background (say gray) and I want to soften the corners (round corners with ie. 3px).
Is there a way to add a special renderer that is used within setCharacterAttributes? Or, do you recommend HighlightPainter added via pane.getHighlighter().addHighlight(...)?
Ok, Your question is not very clear, but if I understand correctly, you intend to customize the default behaviour of the background properties on characters. You describes 2 approaches, and one is probably much easier than the other one.
1) Based on Character attributes (complex one) : You need to define your behaviour by overriding the paint method in javax.swing.text.GlyphView. Then, you will need to change the ViewFactory of your EditorKit to make it take your change into account. I would not recommend this approach.
2) Based on Highlights (easier one) : You need to define a new javax.swing.text.Highlighter.HighlightPainter that paints the round borders as you wish. Then you need to find every set of text where a background is set. You remove the background and add your custom highlighter instead. You can optimize the process, but I think you already got this part.

Get foreground (font) in a particular JTable cell

There are many answers to how to set the font (use renderer), but I want to get this font. The reason why is for unit-testing: test for the renderer doing its job OK.
The human eye can see whether a component for a given cell is rendered with a red foreground, but how can we do this programmatically?
later Just a word about my comment "get hold of the screen real estate". That's not quite it: each one of these table cells contains something... but what? And is it possible to reference it? It almost seems that each one is the "ghost" of the component (the same one) used successively to render each individual cell. Obviously I don't really know about the "architecture" of the representation of a JTable. Would be interesting to find out... although I suspect strongly that these "ghosts" (or whatever) are inaccessible.
Use the JTable.prepareRenderer(...) method.
This method will return the Component that will be used to do the rendering of the cell. So you can then invoke the getForeground() method on the Component.

Apache Batik: How to force JSVGComponent view to update when SVG Dom modified

Using Apache Batik,
Trying to get the JSVGComponent to update (repaint) after adding a new svg element to the DOM. I know about ALWAYS_DYNAMIC, and that is set. The new element(s) are successfully added to the document, but the only way I can get the component to repaint is to resize the view. Upon resize, the new elements pop (appear) into place. I have also tried to add the elements via a Runnable using the UpdateManager and the RunnableQueue. Again, the elements are successfully added, but don't appear until the component is resized (by resizing the housing frame). I have also tried invoking the repaint via a RunQ Runnable, but that also does not work (tho the repaint is actually called).
I think I may have to actually go into the GVT bridge, but I'd sure rather not.
Help extraordinarily appreciated. Thx.
Almost same problem for me : I had to dynamically modifiy the background of boxes (polygon node).
According to MelodyBibi, it works with setSVGDocument(doc); but the SVG flashes during refresh. It's not very appreciable.
My (better) solution is to call
svgCanvas.getCanvasGraphicsNode().fireGraphicsNodeChangeCompleted();
after modifying the DOM model using polygonElement.setAttribute("fill", "red"); on the appropriate Node.
I also added JSVGCanvas.ALWAYS_DYNAMIC before the first loading of the document.
Now my SVG refreshes in realtime, without blinking.
Hoping this will help you.
You can do
svgCanvas.setDocument(doc);
It's works for an JSVGCanvas, may be it will works for you.
You can also try method :
setSVGDocument(doc);
I found this :
There are two common causes for this. The first is that the JSVGCanvas doesn’t know it’s a dynamic document. Normally Batik detects this by looking for script elements but when you modify the document from Java it can’t tell. So call myJSVGCanvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC); before loading the document (with setURI, setDocument, setSVGDocument, etc.).
The second common reason is that the changes aren’t made in the UpdateManager ’s thread. You can run code in the UpdateManager ’s thread with the following: UpdateManager um = JSVGCanvas.getUpdateManager(); um.getUpdateRunnableQueue().invokeLater(Runnable); NOTE: The update manager only becomes available after the first rendering completes. You can be notified when this happens by registering a GVTTreeRendererListener.
But i don't try this yet.

Tracking data offset of data in a table to retrieve the previous/next subset on table scroll

I am writing a browser based application using GWT and making use of websql (yes, I know it is deprecated). I have created a custom table widget (based on FlexTable) and enabled it to scroll with the help of some CSS trickery. What I am striving to achieve (without much success) is that when the user scrolls to the start/end of the current data in the table, an event is fired and the next subset of X rows is returned from the websql DB and replaces the data currently in the table. In order for this to work, I need to keep track of the data offset in the table widget so that I can pass this to the query and use the limit and offset functions of SQL to return the required data. However, I just cannot seem to get the logic right to implement the data offset tracker within the widget. Another complication is that I need the table to be able to scroll 'into the past' (so to speak), so that it can retrieve data from before the initial start point when the table loads.
I have been at this for a number of days now and just cannot seem to get it right. So I was wondering/hoping that someone might be able to point me in the right direction (PLEASE!).
Thanks in advance
Tim
I am not sure why this is causing a problem.
int page = 0;
// when you hit the bottom
page++;
loadData(page);
// when you hit the top
if (page > 0) {
page--;
loadData(page);
}
Tim I think it is not a good idea controlling the scroll with CSS trickery.
I have done something similar soon and controlling all the logic (pagination, scroll positions,...).
What I suggest to use is a gwt's scrollPanel, a HasData widget (like a cellList) your custom AbstractCell (class which is rendered for each row of your list) and asyncDataProvider ( which gives you the onRangeChange handler for asking to your server when the range data display has changed).
You can force/fire that event when in scrollPanel.addScrollHandler detects you are arriving to the end.
If you want to see all of this in action have a look into (click on source code): http://gwt.googleusercontent.com/samples/Showcase/Showcase.html#!CwCellList
EDIT [according comment below]:
A. If you want to override the data (in the example is X+X+X...) with the new retrieved just maintain always the same range of data displayed [display.setVisibleRange(0, newPageSize);], and start from 0 when you render the new data (on your RangeChange listener).
B. If you need to have control over up and down scrolls instead of taking advantage of the used events internally on the cellList (basically onRangeChange), you can create your custom events and fire them (this option could be easier for your colleagues for understanding everything). And do not worry about controlling up and down scrolls, inside the ShowMorePagerPanel.java you can see a simple example of knowing up and down controls.
Anyway, I did not explain more detailed because I did not see you very convinced to use CellList approach (and I was using my tablet :D ).
If you change your mind, just let me know and I write for you a proper example step by step (this part could be tricky, so if you are lost it is normal ;) ).

JTree nodes' rendering and font changes

I have a problem with rendering nodes in JTree. When node's font is changed and node's text gets wider that way then node's text is cut and end of text replaced with dots.
How to tell the JTree then that it should widen area to render tho whole node.
Thank you for help
You can use custom renderer and set to the component (JLabel) something like this
final Dimension size = label.getPreferredSize();
label.setMinimumSize(size);
label.setPreferredSize(size);
or just set text like this
setText("<html>" +valueText+"</html>")
Sounds like the trigger of the font change happens under the feet of the tree: internally, the ui delegate does lots of size caching which must be updated on any change which effects the cached sizes. That's done automatically on changes to the treeModel, to relevant expansion state and some visual changes to the tree itself.
So the basic question is: what triggers the change of the font? If it's some change of the model/nodes, the model implementation is incorrect in not firing an appropriate TreeModelEvent, the obvious solution would be to fix that :-) If it's something outside the model, the solution depends on the details of your context, nothing generally applicable.
Size caching
The JTree uses a renderer to render nodes. The renderer is the same renderer for all OSs, so the differnt lookings are inside ComponentUIs. JTree uses by default a JLabel to paint nodes, so its the JLabel's size wo guides us to cut the text using ....
Lets make a short excourse: Swing has differen LookAndFeels for different Operation Systems, they are detached from the components in UI-Classes like the BasicLabelUI (and this is the source of your problem). BasicLabelUI caches the size of the label to prevent recalculation if no changes has made. So BasicLabelUI did not clear the cache of theese old size values. BasicLabelUI do clear the cache if he gets informed about any changes.
The question is, why does the BasicLabelUI did not get informed about changes? Well, if you modify/expand/rename the Tree programatically you must tell the ComponentUI to drop that cache!
You lucky, you do not need to write much code because a genius already wrote something for you, the creators of the TreeUI-class Rob Davis and Scott Violet wrote startEditingAtPath and stopEditing.
Example
TreeUI ui = tree.getUI();
for (TreePath treePath : selectionPaths) {
ui.startEditingAtPath(tree, treePath);
}
tree.setSelectionPaths(selectionPaths);
tree.expandPath(expandPaths.getSelectionPath());
ui.stopEditing(layer);
Call your TreeModel's reload()

Categories

Resources