tags:

views:

54

answers:

2

I'll try to explain my problem as simply as possible but it's a tricky topic and people who haven't encountered the issue probably won't know what I'm talking about.

I want to use a BorderLayout using west, east, north, south, etc. components that are my "normal" components (JLabels, JButtons, etc.) then I want the center component to be an "image" (that is: pixels). To this end I'm using a BufferedImage and using setIcon on a JLabel that is inside a panel that is part of the "center".

However I want my image/pixels to be "fluid": whenever the user resizes the app, I want to compute the exact size of the JLabel (icon/text gap is set to 0) and then create a new image (pixels that I manipulate directly in a BufferedImage but whatever) that has exactly that size.

Now it does work fine. But only when I resize the main window ("window" as in "one of the window of the operating system) by making it bigger.

It doesn't work when I downsize my main window.

The reason, after a lot of testing, is obviously because the size of my JLabel (in which I did a setIcon( img ) is influencing the computation of the layout manager.

So here comes the billion dollar question: how should I use a BorderLayout (or any other layout) so that I can create a "fluid" rectangle of pixels in the center of my app?

+1  A: 

Answering my own question with an answer that I will not accept even tough it does work...

The problem can be "worked around" by creating a picture a few pixels smaller than the getVisibleRect of the center area.

So in my case I create an ImageIcon from a BufferedImage that is 20 pixels smaller (both in width and height) than the area that will hold it.

What happens then is that because the picture is smaller it doesn't "block"/prevent the layout manager from putting everything at their correct place when downsizing the main window.

So by using such an hack I get the "fluid" behavior I want.

This is however an hack whose level of hackyness cannot be understated and I'm sure there's a very clean way to solve this.

Webinator
@Webinator Glad you called at a hack, perhaps another layout manager could have done it? [SpringLayout][1] perhaps? [1]: http://download.oracle.com/javase/7/docs/api/javax/swing/SpringLayout.html
dr.manhattan
@dr.manhattan: well, I just thought about the issue and realized that this hack could work (and I tried it and it *does* work :) but I'm not happy with it and I'm *sure* there's a clean way to do this with, say, a *BorderLayout*. It's just that I don't know Swing's internals well enough :(
Webinator
+1  A: 

The reason, after a lot of testing, is obviously because the size of my JLabel (in which I did a setIcon( img ) is influencing the computation of the layout manager.

The preferred size of the JLabel is used in the preferred size of the panel, but this size is ignored when you resize the frame, since the CENTER only gets whatever space is left over after the preferred size of the other 4 components is considered.

To this end I'm using a BufferedImage and using setIcon on a JLabel that is inside a panel that is part of the "center".

Sounds to me like it should work.

Create the panel with a BorderLayout. Add the JLabel to the Center of your main panel. Then add a ComponentListener to the panel. Now when the frame is resized the center panel size will be adjusted to take the space available to it. Now that you know the size of the center panel you can recreate the Icon and add it to your JLabel,

This is how you write a SSCCE:

import java.awt.*;
import javax.swing.*;

public class LabelTest2 extends JFrame
{
    public LabelTest2()
    {
        JLabel picture = new JLabel(new ImageIcon("???.jpg"));
        add(picture);
    }

    public static void main(String[] args)
    {
        LabelTest2 frame = new LabelTest2();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}
camickr
@camickr: but that is precisely what doesn't work. When the frame is "upsized", the center panel is correctly adjusted. However when I "downsize" the frame, the JLabel at the center of my main panel refuses to get "smaller" because it is filled with the image (well, I suppose that is the reason and you can look at my answer: if I make on purpose the image inside the JLabel smaller, then the resizing works, even if I downsize it).
Webinator
@webinator, I have never seen it work like this when using a BorderLayout. Post your SSCCE (http://sscce.org) of a JLabel added to the Center of a BorderLayout. The area in the center will shrink/grow as required.
camickr
@camickr: the problem is that apparently doing a *setIcon(...)* on a JLabel means that later on the *getMinimumSize* sent back by that *JLabel* is set to at least the size of the size of the *ImageIcon*...
Webinator
@webinator, yes that is true, but that is only relevant when you do a pack() on the frame. Once the user takes over and manually resizes the frame that information is ignored. The BorderLayout will only paint the icon in whatever space is left over. Post your SSCCE that demonstrates the problem. I've posted my SSCCE that proves it works as I've described. At least it works on XP.
camickr
@camickr: the area in the center does **NOT** grow as required, as explained in my question and as explained in my answer. It is the very reason I'm posting the question here. My money is that it as to do with the minimum size (hence why my hack-response, using a smaller image, works), minimum size which is apparently dependent on the size of the image of the JLabel. You've never seen it, which is also precisely why I started my question stating: *people who haven't encountered the issue probably won't know what I'm talking about*. :)
Webinator
@webinator, which is why you post a SSCCE with your question!!! I believe certain layouts, like the BoxLayout do respect the minimum size, but your question makes no mention of this, only that you are using a BorderLayout. If this is the problem, then reset the minimum size to 0, when you recreate your icon every time the window is resized.
camickr
@camickr: the BorderLayout does respect the minimum size. Most layout do: that is the reason why if you resize any Java app up to 10x10 pixels, you will only basically see part of the first component on screen. This is in a 250 KLOC desktop Java app. I'll write an SSCCEE reproducing the issue tomorrow or so if nobody figures out meanwhile what's going on. Once again: I verified and the JLabel's minimum size is always at least the size of the ImageIcon of that JLabel.
Webinator
@webinator, did you run the code I posted? It does NOT respect the minimum size. You can shrink the frame as small as you want (width wise you can only shrink it as long as there is space for the buttons in the title bar). You will only see the image drawn from the top/left of the image for the space available. If you resize the frame larger than the image then the image becomes centered in the frames window. I don't know how to post code any simpler! I guess I don't understand your problem.
camickr