Insets for custom Synth look and feel - java

I'm implementing a custom Look & Feel using Synth for my application - basically providing custom versions of SynthStyle, SynthPainter and SynthStyleFactory.
I am not using any XML, i.e. everything is done through the Java API. In general this is working just fine.
The best way to set appropriate insets is however proving a little tricky. I can see various options:
Override getInsets for SynthStyle to return specific insets for each Region
Apply a border to components using SynthStyle.installDefaults
Set all insets to (0,0,0,0) and compensate in the painting methods
Create new ComponentUI delegates
What would be the best approach and why?

Did you come to a decision on this yet? Here's my opinion on things...
Overriding getInsets() looks like a nice solution if you have a simple style with a small number of contexts. It should help keep insets consistent throughout your GUI with only one point of change needed.
Applying an empty border to components seems a little hackish for this purpose. If you need to apply a custom border to a component then you might inadvertently remove the empty border unless you override the setBorder() methods to use a compound border.
Setting all insets to 0 is unnecessary since they start at 0 already... I would be very scared at the thought of rewriting paint methods! That's generally done for adding finishing touches to components, not re-defining their entire boundaries.
I'm not entirely sure how creating a new ComponentUI would help, since that's mainly to do with sizing and painting (like the above).
I would try out option 1 first since it will have a global effect on your application, and then start working out what exceptions and contexts you want to put into it.

Related

What is the point of overriding the getInsets() method?

I'm looking at the documentation for javax.swing.JComponent, and this method stuck out to me because I am currently trying to create a subclass of this type. Is there any point in overriding the getInsets()? What is the purpose of this method when we already have getPreferredSize()?
getInsets defines space which can be taken up by extra content, like borders, which is, generally, added to the preferredSize and offsets the position (translates) of the Graphics context, to ensure that the actual content is painted instead the insets.
Personally, unless you intend to prevent anybody from modifying the state of the components borders or are thinking for providing margins of some sort, I'd leave it alone (and not override it)

Java: GridBagConstraints - best way to pad components

So I'm working on a GridBagLayout UI right now. I'm trying to space my components out just right, and in all my research I've found four different tools that seem to affect the spacing between components and their overall positioning. I'm just seeking clarity on the best way to use each of these. I may be new at Java, but I'm very OCD about having finite control over my layouts, so I'm trying to figure out how to fine tune component positioning.
I understand the syntax for all of these, just looking for advice on how to use them properly. I also understand that once they're declared, they affect every component that follows them in the code until they are "reset" by declaring them again.
weight(x,y) - this one I'm having a real hard time understanding it's actual effect. Does it add padding before or after the cell? Or does it just move around the contents in the cell?
ipad(x,y) - seems to add padding only after the object in the cell (to the right/bottom). Is that correct?
insets - seems to be a great, precise tool for this. Are there rules that govern when it is appropriate to use it? Best practices, etc?
anchor - ties a component to the top/bottom/left/right/center of the cell. Mostly interested how this method interacts with the others I listed here. How does where the component is anchored affect the padding generated by the three methods above.
Thanks so much.

How to make all tooltips semi-transparent in Java?

I've managed to make semi-transparent tooltips using UIManager and creating Colors with 4 parameters:
UIManager.put("ToolTip.background",new Color(0x40,0x51,0x67,0x40));
But there's a problem - well, two in fact: the first tooltip that appears on the screen always ignores the transparency, and - unfortunately - same goes for tooltips outside of the window frame. From what I can understand (and judging from the only piece of information I could find), this is because some of the tooltips are heavyweight rather than lightweight and that's why their ignore my color setting for some reason. While I could manage to keep my stuff with tooltips far enough from the border, it seems like a cheap way to solve this problem and it still doesn't cover the first tooltip appearing white for some reason.
So, a clueless newbie asks: is there a simple way to make heavyweight tooltips transparent without making my own classes extending PopupFactory and Popup? If there isn't, do you have any tips on what I should change if I decide to create new classes and replace default PopupFactory with:
PopupFactory.setSharedInstance(new MyPopupFactory());
Also, out of sheer curiosity and since it concerns tooltips: why does this...
UIManager.put("ToolTip.background",new Color(0x40,0x51,0x67);
...replace both ToolTip.background and ToolTip.backgroundInactive, while when I use ColorUIResource I have to write two separate commands:
UIManager.put("ToolTip.background",new ColorUIResource(0x60,0x6a,0x76));
UIManager.put("ToolTip.backgroundInactive",new ColorUIResource(0x60,0x6a,0x76));
I know that my questions might have turned out a bit chaotic, but any advices would be greatly appreciated.
Transparency not working as expected with a heavyweight component is normal - window transparency, although supported by some platforms, is not supported directly by swing.
You can make use of com.sun.awt.AWTUtilities (not portable to other VM's obviously) to make windows transparent (see this article: https://today.java.net/pub/a/today/2008/03/18/translucent-and-shaped-swing-windows.html).
Take a look at the JRE source code of PopupFactory. You could call setPopupType(2) to make the factory prefer heavyweight popups. The method is not visible, so you will need to call it using reflection. Thats a hack you can't be sure it will work in future obviously.
Since Swing doesn't support it through its standard API, the most sensible choice would probably be to not use transparency effects where they are not supported. Possibly don't use transparency at all, if you desire a uniform look.

Suggestion for implementing a drawing program - UML designer

This program will have an infinite canvas (ie as long as the user scrolls, it becomes bigger) with a tiled background image, and you can drag and drop blocks and draw arrows between blocks. Obviously I won't use a layout manager for placing blocks and lines, since they will be absolutely positioned (any link on this, possibily with a snapping feature?). The problem arises with blocks and lines. Basically I'll have two options:
Using a simple layout for each building block. This is the simplest and clearest approach, but does it scale well when you have hundreds of objects? This may not be uncommon, just imagine a database with 50 tables and dozens of relationships
Drawing everything with primitives (rectangles, bitmaps, etc). This seems too complicated (especially things like text padding and alignment) but may be more scalable if you have a large number of objects. Also there won't be any event handler
Please give me some hints based on your experience. I have never drawn with Java before - well I did something rather basic with PHP and on Android. Here is a simple preview
DISCLAIMER
You are not forced to answer this. I am looking for someone who did something like this before, what's the use of writing I can check an open source project? Do you know how difficult it is to understand someone else's code? I'm talking about implementations details here... Moreover, there is no guarantee that he's right. This project is just for study and will be funny, I don't want to sell it or anything and I don't need your authorization to start it.
Measuring and drawing text isn't such a pain, since java has built in classes for doing that. you may want to take a look at the 2D Text Tutorial for more information. In fact, I did some text drawing computations with a different graphics engine which is much more primitive, and in the end it was rather easy (at least for the single-line drawing, for going multiline see the previous link).
For the infinite canvas problem, that's also something I always wanted to be able to do. A quick search here at stackoverflow gives this which sounds nice, althought I'm not sure I like it. What you can do, is use the way GIMP has a scroll area that can extend as you move - catch the click of the middle mouse button for marking the initial intention to move the viewport. Then, when the mouse is dragged (while the button is clicked) move the viewport of the jscrollpane by the offset between the initial click and the current position. If we moved outside the bounds of the canvas, then you should simply enlarge the canvas.
In case you are still afraid of some of the manual drawing, you can actually have a JPanel as your canvas, with a fixed layout. Then you can override it's paint method for drawing the connectors, while having child components (such as buttongs and text areas) for other interaction (and each component may override it's own paint method in case it wants to have a custom-painted rect).
In my last drawing test in java, I made an application for drawing bezier curves (which are basically curves made of several control points). It was a JPanel with overidden paint method that drew the curve itself, and buttons with custom painting placed on the location of the control points. Clicking on the control point actually was clicking on a button, so it was easy to detect the matching control point (since each button had one control point associated with it). This is bad in terms of efficiency (manual hit detection may be faster) but it was easy in terms of programming.
Anyway, This idea can be extended by having one child JPanel for each class rectangle - this will provide easy click detection and custom painting, while the parent will draw the connectors.
So in short - go for nested JPanels with custom drawing, so that you can also place "on-canvas" widgets (and use real swing widgets such as text labels to do some ready drawing) while also having custom drawing (by overriding the paint method of the panels). Note that the con of this method is that some swing look-and-feel's may interfere with your drawing, so may need to mess a bit with that (as far as I remember, the metal and nimbus look-and-feel's were ok, and they are both cross-platform).

Java Nimbus LAF with transparent text fields

I have an application that uses disabled JTextFields in several places which are intended to be transparent - allowing the background to show through instead of the text field's normal background.
When running the new Nimbus LAF these fields are opaque (despite setting setOpaque(false)), and my UI is broken. It's as if the LAF is ignoring the opaque property. Setting a background color explicitly is both difficult in several places, and less than optimal due to background images actually doesn't work - it still paints it's LAF default background over the top, leaving a border-like appearance (the splash screen below has the background explicitly set to match the image).
Any ideas on how I can get Nimbus to not paint the background for a JTextField?
Note: I need a JTextField, rather than a JLabel, because I need the thread-safe setText(), and wrapping capability.
Note: My fallback position is to continue using the system LAF, but Nimbus does look substantially better.
See example images below.
Conclusions
The surprise at this behavior is due to a misinterpretation of what setOpaque() is meant to do - from the Nimbus bug report:
This is a problem the the orginal design of Swing and how it has been confusing for years. The issue is setOpaque(false) has had a side effect in exiting LAFs which is that of hiding the background which is not really what it is ment for. It is ment to say that the component my have transparent parts and swing should paint the parent component behind it.
It's unfortunate that the Nimbus components also appear not to honor setBackground(null) which would otherwise be the recommended way to stop the background painting. Setting a fully transparent background seems unintuitive to me.
In my opinion, setOpaque()/isOpaque() is a faulty public API choice which should have been only:
public boolean isFullyOpaque();
I say this, because isOpaque()==true is a contract with Swing that the component subclass will take responsibility for painting it's entire background - which means the parent can skip painting that region if it wants (which is an important performance enhancement). Something external cannot directly change this contract (legitimately), whose fulfillment may be coded into the component.
So the opacity of the component should not have been settable using setOpaque(). Instead something like setBackground(null) should cause many components to "not have a background" and therefore become not fully opaque. By way of example, in an ideal world most components should have an isOpaque() that looks like this:
public boolean isOpaque() { return (background!=null); }
I ran into this same issue last week using JTextPane. The setOpaque() method works as expected when using any look and feel other than nimbus. Apparently, the nimbus look and feel changes the behaviour we have come to expect with setOpaque() for many Components. Depending on how you look at it, it can be considered a bug. Check the comments on this sun bugid:
nimbus opaque bug
The workaround that worked for me was:
myPane.setOpaque(false); // added by OP
myPane.setBorder(BorderFactory.createEmptyBorder());
myPane.setBackground(new Color(0,0,0,0));
Note from OP: I also had to ensure setOpaque(false) for JTextField so that the parent background was painted - just wanted to mention this for others who follow in case they had experimented with setOpaque(true), as I had.
Hey there Software Monkey.
mmhh what about installing UI's subclasses replacement that actually respect the setOpaque behavior.
I think it is something like setUI or something like that.
You could grab the source code of the nimbus and see what's broken there ( if it is there ) , subclass it and install the "fixed" one.
Yours sound quite intersting, do you have any screenshot we can see?
From the javadoc
public void setBackground(Color bg)
Sets the background color of this component. The background color is
used only if the component is opaque,
and only by subclasses of JComponent
or ComponentUI implementations. Direct
subclasses of JComponent must override
paintComponent to honor this property.
It is up to the look and feel to honor this property, some may choose
to ignore it.
I think the question is how to interpret "opaque" and "background".
For a JTextfield there is the question: "what visible parts are the background?". I'd define "background" as the parts of the bounding rectangle, that are not drawn by the component.
For a "round" button, e.g., this will be the corners outside the circle.
Therefor I'd say a JTextfield has no visible background! It has a rectangular shape and what you are the taking as background is not the field's background but the field's canvas.
Rebuttal from OP
This is an interesting enough idea to be worth responding to in the answer for future viewers (as opposed to in comments).
I have to disagree. I would argue that the part of the component outside the border is not part of the component - it's outside the component. A field with rounded corners is, of necessity, non-opaque, in that it cannot be responsible for painting it's entire rectangular region - this is a side-effect of all components being rectangular in dimensions.
I think this consideration makes the argument for the existing (and misunderstood) meaning of isOpaque(). It also makes my argument that setOpaque() should not exist and that setBackground(null) should cause the component to not paint a background.
I would put forth that the background of a text field is indeed the color of the region inside it's borders, and I don't think you will find very many people to dispute that as an intuitive conclusion - therefore having background apply to that region obeys the rule of least surprise for the API user.

Categories

Resources