How to create a ButtonGroup with connected buttons in Java?
Asked Answered
E

2

8

I am currently trying to create a group of toggle-buttons that are similar to the one's used in the formatter preferences of Eclipse:

Formatter preferences of Eclipse

Currently I have attempted this in the following way:

public class Exercise extends JFrame {

    private String[] buttonNames = {"A", "B", "C", "D", "E"};

    Exercise() {
        final JPanel topPanel = new JPanel();
        topPanel.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        int tabCount = 0;
        final ButtonGroup topButtonGroup = new ButtonGroup();
        for (String buttonName : buttonNames) {
            JToggleButton tabButton = new JToggleButton(buttonName);
            topButtonGroup.add(tabButton);
            c.fill = GridBagConstraints.HORIZONTAL;
            c.insets = new Insets(0, -6, 0, -7); // Questionable line
            c.gridx = tabCount;
            c.gridy = 0;
            topPanel.add(tabButton, c);
            tabCount++;
        }
        this.add(topPanel);
        this.setVisible(true);
        this.pack();
    }

    public static void main(String[] args) {
        new Exercise();
    }
}

The result is as follows:

Result without spacing

I have a couple of concerns with my code. First, I do not understand why I have to make the insets negative. According to Oracle's tutorial, "[b]y default, each component has no external padding." Hence, shouldn't there be no spaces by default? Without the negative insets, the result looks like follows:

Result without setting negative insets

Second, I would like to have the toggle button darken instead of turn blue with toggled "on". Is there any easy way do this through Java Swing? Finally, is there any better approach in general? I am curious to know how Eclipse managed to get the toggle-buttons to look as if they are perfectly connected.

Update

I have tried using a BoxLayout as recommended. Unfortunately, this did not seem to fix the problem. The result is almost identical to the picture above. Here is the modified constructor:

Exercise() {
    final JPanel topPanel = new JPanel();
    topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
    final ButtonGroup topButtonGroup = new ButtonGroup();
    for (String buttonName : buttonNames) {
        JToggleButton tabButton = new JToggleButton(buttonName);
    //    tabButton.setBorder(BorderFactory.createBevelBorder(
    //              BevelBorder.RAISED, Color.LIGHT_GRAY, Color.DARK_GRAY));
        topButtonGroup.add(tabButton);
        topPanel.add(tabButton);
    }
    this.add(topPanel);
    this.setVisible(true);
    this.pack();
}

Interestingly enough when I tried adding a border as commented out above, the extra spacing between the buttons somehow disappeared. The result is as below:

With BoxLayout

As much as possible I would like to keep the general look of the button as before but have the edges be more rectangular so that the toggle-buttons will look more connected.

Epizoic answered 23/1, 2014 at 13:58 Comment(2)
I don't use Eclipse but that picture seems to be a tabbed pane's header with a custom Look and Feel. It looks like Seaglass pretty much.Linnell
Thank you for your comment, it indirectly helped me find the solution.Epizoic
E
4

It seems that I have made an embarrassing mistake. I tried dic19's suggestion of using Seaglass' look and feel together with a JTabbedPane and I got almost exactly what I wanted:

Tabbed Pane with Seaglass

But then I realised that the default look and feel for the JTabbedPane was exactly what I wanted:

Default look and feel

The code I used is similar to that used in the JTabbedPane tutorial by Oracle:

public class SeaGlassExercise {

    public static void initWindow() {
        JFrame frame = new JFrame("Application Name");
        CustomTabbedPane content = new CustomTabbedPane();
        frame.setContentPane(content);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLocationByPlatform(true);
//        try {
//            UIManager.setLookAndFeel(
//        "com.seaglasslookandfeel.SeaGlassLookAndFeel");
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        SwingUtilities.updateComponentTreeUI(frame);
        frame.pack();
        frame.setVisible(true);
    }

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

}

class CustomTabbedPane extends JPanel {

    public CustomTabbedPane() {
        super(new GridLayout(1, 1));
        JTabbedPane tabbedPane = new JTabbedPane();
        JComponent panel1 = makeTextPanel("Panel #1");
        tabbedPane.addTab("AAA", panel1);
        JComponent panel2 = makeTextPanel("Panel #2");
        tabbedPane.addTab("BBB", panel2);
        JComponent panel3 = makeTextPanel("Panel #3");
        tabbedPane.addTab("CCC", panel3);
        JComponent panel4 = makeTextPanel("Panel #4");
        tabbedPane.addTab("DDD", panel4);
        add(tabbedPane);
        tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
    }

    protected JComponent makeTextPanel(String text) {
        JPanel panel = new JPanel();
        JLabel filler = new JLabel(text);
        filler.setHorizontalAlignment(JLabel.CENTER);
        panel.setLayout(new GridLayout(1, 1));
        panel.add(filler);
        return panel;
    }
}

Although I knew that Java Swing's default platform-dependent look and feel was different across various platforms, I never imagined that the JTabbedPane would look so different from what was shown on the tutorial:

Oracle's image for JTabbedPane

Epizoic answered 26/1, 2014 at 3:54 Comment(1)
Personally I think the entire swing UI default look is extremely ugly. If you're working on a Mac, then swing will default to using the Aqua Look and Feel, which is what Apple made, and includes all the "standard" buttons, toggles, and yes, tabbed panes that Apple made.Fyrd
E
5

You can use a layout like BoxLayout to eliminate the space. GridBagLayout isn't the only layout out there. Recommended reading: http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html

You can also call JButton functions like setBorder() and setBackground() to achieve the effects you mentioned. As always, the API is your best friend: http://docs.oracle.com/javase/7/docs/api/

Epigeous answered 23/1, 2014 at 14:1 Comment(1)
Thank you for the advice but I am still having some problems as updated in my question above.Epizoic
E
4

It seems that I have made an embarrassing mistake. I tried dic19's suggestion of using Seaglass' look and feel together with a JTabbedPane and I got almost exactly what I wanted:

Tabbed Pane with Seaglass

But then I realised that the default look and feel for the JTabbedPane was exactly what I wanted:

Default look and feel

The code I used is similar to that used in the JTabbedPane tutorial by Oracle:

public class SeaGlassExercise {

    public static void initWindow() {
        JFrame frame = new JFrame("Application Name");
        CustomTabbedPane content = new CustomTabbedPane();
        frame.setContentPane(content);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLocationByPlatform(true);
//        try {
//            UIManager.setLookAndFeel(
//        "com.seaglasslookandfeel.SeaGlassLookAndFeel");
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        SwingUtilities.updateComponentTreeUI(frame);
        frame.pack();
        frame.setVisible(true);
    }

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

}

class CustomTabbedPane extends JPanel {

    public CustomTabbedPane() {
        super(new GridLayout(1, 1));
        JTabbedPane tabbedPane = new JTabbedPane();
        JComponent panel1 = makeTextPanel("Panel #1");
        tabbedPane.addTab("AAA", panel1);
        JComponent panel2 = makeTextPanel("Panel #2");
        tabbedPane.addTab("BBB", panel2);
        JComponent panel3 = makeTextPanel("Panel #3");
        tabbedPane.addTab("CCC", panel3);
        JComponent panel4 = makeTextPanel("Panel #4");
        tabbedPane.addTab("DDD", panel4);
        add(tabbedPane);
        tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
    }

    protected JComponent makeTextPanel(String text) {
        JPanel panel = new JPanel();
        JLabel filler = new JLabel(text);
        filler.setHorizontalAlignment(JLabel.CENTER);
        panel.setLayout(new GridLayout(1, 1));
        panel.add(filler);
        return panel;
    }
}

Although I knew that Java Swing's default platform-dependent look and feel was different across various platforms, I never imagined that the JTabbedPane would look so different from what was shown on the tutorial:

Oracle's image for JTabbedPane

Epizoic answered 26/1, 2014 at 3:54 Comment(1)
Personally I think the entire swing UI default look is extremely ugly. If you're working on a Mac, then swing will default to using the Aqua Look and Feel, which is what Apple made, and includes all the "standard" buttons, toggles, and yes, tabbed panes that Apple made.Fyrd

© 2022 - 2024 — McMap. All rights reserved.