4

I'm attempting to create a custom JButton that has interchangeable skin components. Using CardLayout as the switching mechanism, I'm having difficulty with the JComponent (i.e. skin component) laying flush across the JButton.


For instance,

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public final class SkinsDemo {

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

    private static void createAndShowGUI(){
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new FlowLayout());
        frame.add(new JSkinnableButton());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static final class JSkinnableButton extends JButton{
        private static final long serialVersionUID = -5167346969674067012L;

        protected JSkinnableButton(){
            super();
            setLayout(new CardLayout()); // for interchangeability 
            add(new JSkinComponent(), "Skin");
        }
    }

    private static final class JSkinComponent extends JComponent{
        private static final long serialVersionUID = 2172542865655802012L;

        protected JSkinComponent(){
            super();
            setOpaque(true);
            setLayout(new FlowLayout()); // need layout manager
            setBackground(Color.CYAN);
            add(new JLabel("Skin"));
        }

        @Override
        protected void paintComponent(Graphics g){
            Graphics gCopy = g.create();
            gCopy.setColor(getBackground());
            gCopy.fillRect(0, 0, getWidth(), getHeight());
            gCopy.dispose();
        }
    }
}

enter image description here


That's a really crude example, but I think it conveys my intentions clearly.

And this JButton will be listening for property change events from a domain object and will update it's display accordingly.

mre
  • 43,520
  • 33
  • 120
  • 170
  • back from the ends, `1)` are you want to fill with Color.CYAN whole JButton `2)` by using LayoutManager, `3)` how much skins you want to.., `4)` skin depends of JButton Events ??? – mKorbel Nov 21 '11 at 14:36
  • @mKorbel, I want the background of the `JComponent` to fill the entire `JButton` and by using the `CardLayout` manager, I want to be able to easily switch between 3 different skins, which are changed upon receiving a `PropertyChangeEvent`. – mre Nov 21 '11 at 14:43
  • Why not just change the `Icon` or, less conveniently, the `ButtonUI`? – trashgod Nov 21 '11 at 15:51
  • @trashgod that would be easy, I think that (@mre) knows that, maybe ??? basically ??? same question as I post http://stackoverflow.com/questions/8197261/jtable-how-to-change-background-color, change paint(), paintComponent at Runtime, without fileckering and another side effect from un-correct usage of CustomPaint for compound JComponent, to find the correct (and then) simple way, I think – mKorbel Nov 21 '11 at 16:58

1 Answers1

2

There's space being taken up in your JSkinnableButton by the button's margin and border.

protected JSkinnableButton(){
    super();
    setLayout(new CardLayout()); // for interchangeability
    setMargin(new Insets(0,0,0,0));
    setBorder(BorderFactory.createEmptyBorder());
    add(new JSkinComponent(), "Skin");
}

Now, the border in particular, is a part of what makes a button look like a button, but I assume you've already got a plan for that...

Rob I
  • 5,627
  • 2
  • 21
  • 28