1

Simple question, is there a way to create a sort of "button group" (no, not this), where two or more buttons are connected together. If you look at JTabbedPanes, for example, on a mac system you get this:

tab buttons

This is exactly what I'd like to have with a set of buttons. Pushing two or more buttons together, like seen in this post, does not work as the border layouts conflict and is also uneven:

buttons pushed together

I have been searching around for a while on anything like this but I haven't been able to find anything. Now, I do understand that I could create a whole new component from scratch, but I was wondering if there was a better way to do this.

I tried screwing around with JTabbedPanes, but these "tabs" are not buttons in the traditional sense that give you full capabilities. They are heavily restricted and in addition overall JTabbedPane is not a viable cross platform tool as I just want the look-and-feel displayed by mac.

Are there any solutions to this?

Community
  • 1
  • 1
Code Doggo
  • 2,146
  • 6
  • 33
  • 58
  • There is no component in Swing which does, the tab rendering under Mac OS is provided by the Look And Feel delegate (from Apple). You'd have to make you're own – MadProgrammer Jan 14 '16 at 05:24
  • @MadProgrammer The look-and-feel on mac isn't something I need completely, I just need the ability to stick buttons together like shown in the JTabbedPane. Could you point in me the direction of where I could figure out the tab rendering? – Code Doggo Jan 14 '16 at 05:26
  • Nothing I know of. You'd probably end up creating the border yourself aound some JToggleButtons in a tight layout – Jan Jan 14 '16 at 05:27
  • @Jan Alright thanks. I was thinking i'd have to write my own component for it. I was just curious if there was an **easier** option out there. – Code Doggo Jan 14 '16 at 05:28
  • 1
    So adding a bunch off buttons to `JPanel` using a `FlowLayout` isn't what you're after? – MadProgrammer Jan 14 '16 at 05:28
  • @MadProgrammer No, I want to render them together like exactly what is shown in the JTabbedPane. @Jan mentioned `JToggleButtons`, but I want just regular `JButtons` for this purpose. I am thinking I am gonna have to make my own component after all. – Code Doggo Jan 14 '16 at 05:31
  • 2
    Just remember, `JTabbedPane` renders differently on different systems, so using it as the base example might not be what you want to do, but I understand what you seem to be trying to achieve ;) – MadProgrammer Jan 14 '16 at 05:32
  • @MadProgrammer Haha yeah, that is why I mentioned JTabbedPane not being a viable option for cross platform use. Anyways, ill get cracking now and see what I can come up with. I'll post back here when I think I have a working solution for anyone else who might benefit from it. – Code Doggo Jan 14 '16 at 05:34
  • JMenu with JSeparators in the JMenuBar added to container (JPanel) directly (not JFrame.setMenuBar), for listening to use - XxxMenuListeners – mKorbel Jan 14 '16 at 08:36

1 Answers1

2

As @MadProgrammer says, here is an example of adding a bunch off buttons to JPanel using a FlowLayout:

screenshot

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

public class StickButtonsTest {
  private JComponent makeUI() {
    JPanel p = new JPanel();
    p.setBorder(BorderFactory.createEmptyBorder(10, 5, 0, 5));
    p.add(makeToggleButtonBar());
    return p;
  }
  private static AbstractButton makeButton(String title) {
    AbstractButton b = new JToggleButton(title) {
      @Override protected void fireStateChanged() {
        ButtonModel model = getModel();
        if (model.isSelected()) {
          setForeground(Color.ORANGE.brighter());
        } else {
          setForeground(Color.WHITE);
        }
        super.fireStateChanged();
      }
    };
    b.setHorizontalTextPosition(SwingConstants.CENTER);
    b.setBorder(BorderFactory.createEmptyBorder());
    b.setContentAreaFilled(false);
    b.setFocusPainted(false);
    b.setForeground(Color.WHITE);
    b.setBackground(new Color(0x00AEF3));
    b.setIcon(new ToggleButtonBarCellIcon());
    return b;
  }
  private static JPanel makeToggleButtonBar() {
    ButtonGroup bg = new ButtonGroup();
    JPanel p = new JPanel(new GridLayout(1, 0, 0, 0));
    for (AbstractButton b: Arrays.asList(
        makeButton("left"), makeButton("c1"),
        makeButton("c2"), makeButton("right"))) {
      bg.add(b);
      p.add(b);
    }
    return p;
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new StickButtonsTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
  public static void createAndShowGUI() {
  }
}

//http://ateraimemo.com/Swing/ToggleButtonBar.html
class ToggleButtonBarCellIcon implements Icon {
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    Container parent = c.getParent();
    if (!(parent instanceof JPanel)) {
      return;
    }
    int gap = 3;
    int r = 8;
    int w = c.getWidth();
    int h = c.getHeight() - 1;

    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    Path2D.Float p = new Path2D.Float();

    if (c == parent.getComponent(0)) {
      //:first-child
      p.moveTo(x, y + r);
      p.quadTo(x, y, x + r, y);
      p.lineTo(x + w, y);
      p.lineTo(x + w, y + h);
      p.lineTo(x + r, y + h);
      p.quadTo(x, y + h, x, y + h - r);
    } else if (c == parent.getComponent(parent.getComponentCount() - 1)) {
      //:last-child
      w--;
      p.moveTo(x, y);
      p.lineTo(x + w - r, y);
      p.quadTo(x + w, y, x + w, y + r);
      p.lineTo(x + w, y + h - r);
      p.quadTo(x + w, y + h, x + w - r, y + h);
      p.lineTo(x, y + h);
      p.moveTo(x, y + gap);
      p.lineTo(x, y + h - gap);
    } else {
      p.moveTo(x, y);
      p.lineTo(x + w, y);
      p.lineTo(x + w, y + h);
      p.lineTo(x, y + h);
      p.moveTo(x, y + gap);
      p.lineTo(x, y + h - gap);
    }
    p.closePath();

    Color ssc = new Color(1f, 1f, 1f, .2f);
    Color bgc = new Color(0f, 0f, 0f, .2f);
    if (c instanceof AbstractButton) {
      ButtonModel m = ((AbstractButton) c).getModel();
      if (m.isSelected() || m.isRollover()) {
        ssc = new Color(1f, 1f, 1f, .4f);
        bgc = new Color(1f, 1f, 1f, .1f);
      }
    }

    Area area = new Area(p);
    g2.setPaint(c.getBackground());
    g2.fill(area);
    g2.setPaint(new GradientPaint(x, y, ssc, x, y + h, bgc, true));
    g2.fill(area);
    g2.setPaint(new Color(0f, 0f, 0f, .5f));
    g2.draw(p);

    g2.dispose();
  }
  @Override public int getIconWidth() {
    return 60;
  }
  @Override public int getIconHeight() {
    return 24;
  }
}
aterai
  • 9,658
  • 4
  • 35
  • 44