2

I need to put some JButtons in a very small place, and the problem is that the Nimbus LAF automatically puts some space around them, and as a result the buttons look smaller than they really are.

In the following example program I use a FlowLayout with 0 horizontal and vertical gaps, and I expected the buttons to sit tightly without any space between them. If I comment out the setting of the Nimbus LAF, they behave as expected.

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

public class NimbusSpace {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                buildGUI();
            }
        });
    }

    private static void buildGUI() {
        try {
            UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }

        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
        p.add(createButton("aa"));
        p.add(createButton("bb"));
        p.add(createButton("cc"));

        f.add(p);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static JButton createButton(String text) {
        JButton b = new JButton(text);

//        b.setBorder(null);
//        b.setBorderPainted(false);
//        b.setMargin(new Insets(0,0,0,0));
//        b.putClientProperty("JComponent.sizeVariant", "large");
//        b.putClientProperty("JComponent.sizeVariant", "mini");

//        UIDefaults def = new UIDefaults();
//        def.put("Button.contentMargins", new Insets(0,0,0,0));
//        b.putClientProperty("Nimbus.Overrides", def);

        return b;
    }
}

As you can see in the commented out code in createButton, I tried quite a few things, but they didn't remove the space around the buttons.

EDIT: Based on the discussions in the comments, it seems that it is not possible to remove the space between the rectangular edges of the button and the drawn rounded-rectangle outline. Nimbus reserves these two pixels for the "focus highlight", and probably this cannot be changed without re-implementing a lot of Nimbus functionality.

So I accepted guleryuz's trick: if the buttons are positioned at overlapping and negative positions, they can look bigger. In practice this idea seems to work, but it is not a very clean solution, so if you know a better (and reasonably easily implemented) solution, don't hesitate to answer...

lbalazscs
  • 17,474
  • 7
  • 42
  • 50
  • You mean the buttons should be together like in this for example? http://stackoverflow.com/questions/34782238/connect-link-buttons-graphically-together – hamena314 Jan 27 '16 at 16:11
  • @hamena314 my actual problem is that I have some small buttons in a small place, and this issue makes them look even smaller than they are. My example is only intended to illustrate the problem. Your example looks interesting, but I would like to have regular Nimbus buttons, only bigger-looking. – lbalazscs Jan 27 '16 at 17:36
  • The "spacing" is to leave room for the "focus highlight" – MadProgrammer Jan 27 '16 at 21:38
  • @MadProgrammer You are probably right, the spacing is two pixels, and the focus highlight is also two pixels. If I increase the size with guleryuz's hack by one pixel, the remaining one-pixel highlight looks enough to me, and actually focus highlight is not important for this button at all. – lbalazscs Jan 27 '16 at 22:26
  • guleryuz's "hack" is kind of dangerous as it's not also modifying the size of the component to compensate and could cause a bunch of unexpected and difficult to repeat problems – MadProgrammer Jan 27 '16 at 22:31
  • @MadProgrammer On the other hand, it solved my problem (if you are the one who downvoted after I upvoted, I strongly disagree - it was a useful idea). As I said, I didn't accept his answer yet in the hope that a "proper", robust solution also arrives. So far I didn't see any problems, I am also surprised by that. I also modified the size in the real code, as I explained in the comments to guleryuz's answer. – lbalazscs Jan 27 '16 at 22:55
  • @lbalazscs You've solved one "problem" and left yourself open for numerous more...If you want a more "robust" solution, then change the `JButton`'s `ButtonUI` delegate to do what you want – MadProgrammer Jan 27 '16 at 23:03
  • @MadProgrammer I'm not very good with the UI delegates part of Swing, but I have a feeling that it must be hard, especially if I want the button to look and behave like a normal Nimbus button (OK, without the focus highlight or with a thinner highlight, but it should not be very different). If you know some easy way to do this, then please answer the question... – lbalazscs Jan 27 '16 at 23:32
  • @lbalazscs "it's to hard" is not an excuse for implementing bad hacks which could have unexpected results or consequences over the rest of your program. You're trying to create a feature which is not supported by the current implementation of the API, so you need to goto the appropriate location in the API to change it – MadProgrammer Jan 27 '16 at 23:51

2 Answers2

0

Note that if you set the background color and then call setOpaque(true), you can see that the buttons ARE right up against each other. That's just how Nimbus draws a button; I don't think you can change the space between the rectangular edges of the button and the drawn rounded-rectangle outline.

If space is a premium, you can shrink the size a bit by uncommenting your UIDefaults lines and modifying the contentMargins property (but don't use 0,0,0,0, use something like 2,8,2,8).

FredK
  • 4,094
  • 1
  • 9
  • 11
  • Exactly. The problem is that the buttons look smaller than they really are, we agree on that. But I still hope that there is a solution. Yes, the problem is that space is a premium, I have some small buttons in a small place, and this issue makes them look even smaller than they are. The 2,8,2,8 trick didn't change anything in the real code, I am still trying to understand why. – lbalazscs Jan 27 '16 at 17:57
  • I see now, "Button.contentMargins" influences only the preferred size of the button, but I already set that to a fix and small value in the real code, so this doesn't help me. The problem is, as you put it, the space between the rectangular edges of the button and the drawn rounded-rectangle outline. – lbalazscs Jan 27 '16 at 18:53
0

approach 1:

JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, -4, 0));

approach 2:

    JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
    p.add(createButton("aa", 1));
    p.add(createButton("bb", 2));
    p.add(createButton("cc", 3));

with some modifications in createButton method

private static JButton createButton(String text, final int s) {
    JButton b = new JButton(text){
        @Override
        public void setLocation(int x, int y) {
            super.setLocation(x-(s*4), y);
        }
    };
    return b;
}

approach 3

JPanel p = new JPanel(new MigLayout("ins 0, gap -5","[][][]"));
guleryuz
  • 2,714
  • 1
  • 15
  • 19
  • Very creative trick to put the buttons on the top of the other button, and works in this simple example, but my real issue is different, with a more complex layout, so I still hope that there will be an answer that works in that case as well – lbalazscs Jan 27 '16 at 17:43
  • Oh, man, you are a creative genius! I thought that in the worst case I need to write a complicated layout manager that puts components to crazy negative and overlapping locations, but with this trick I already achieved the look that I wanted. In the real code I also needed to override setSize, and I had to be careful because the layout manager calls setLocation twice, so I keep a flag to adjust only for the first call. I upvoted, but I am not accepting yet - maybe somebody finds a proper, robust solution. – lbalazscs Jan 27 '16 at 21:29
  • i'm working for your accept tonight ;) after you mentioned about layout-manager a lightning remind me my favourite layout manager MigLayout and i have edited my answer – guleryuz Jan 27 '16 at 21:44
  • Well, I heard good things about MigLayout, but I never used it, and at the moment the notation "ins 0, gap -5","[][][]" looks pretty scary to me, so still "approach 2" looks the best. BTW, if you are crazy enough to work at night on issues like this, the real code is an open source-project (Pixelitor), I can explain where exactly is the issue, if you are interested. – lbalazscs Jan 27 '16 at 22:04
  • i downloaded and run Pixelitor, you made a great work, really. – guleryuz Jan 27 '16 at 22:31
  • You can observe your trick in the addZoomButton method at https://github.com/lbalazscs/Pixelitor/blob/master/src/main/java/pixelitor/menus/view/ZoomComponent.java – lbalazscs Jan 27 '16 at 22:45