【问题标题】:Custom JButton paintComponent Method Modifies Shape Visually? Not Actual Button Shape?自定义 JButton paintComponent 方法可视化修改形状?不是实际的按钮形状?
【发布时间】:2014-02-02 12:31:48
【问题描述】:

我正在尝试创建一个包含地图的应用程序 (Java)。每个县或州,都需要有自己的 mouseover、mouseClicked 方法等。

我尝试这样做的方法是在扩展 JButton 的自定义类中覆盖paintComponent 和paintBorder 方法。代码和结果截图:

public class CustomButton extends JButton implements MouseListener {


 private Polygon shape;
 private boolean isMouseOver;
 private Color buttonColor = new Color(100,100,100);


    public CustomButton (Polygon shape,Color buttonColor) {
        //this.setText(text);
        this.buttonColor = buttonColor;
        this.shape = shape;
        setContentAreaFilled(false);
        addMouseListener(this);
    }


    @Override
    public Dimension getPreferredSize() {
        return (new Dimension(120, 120));
    }

    // Hit detection
    public boolean contains(int x, int y) {
        return shape.contains(x, y);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);


        if (isMouseOver && isEnabled()) { 
            g.setColor(new Color(buttonColor.getRed()+50,buttonColor.getGreen()+50,buttonColor.getBlue()+50));
        }else{
            g.setColor(buttonColor);    
        }
        g.fillPolygon(shape); 


    }

    protected void paintBorder(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.setStroke(new BasicStroke(2));

        if (isMouseOver && isEnabled()) {            
            g2d.setColor(new Color(buttonColor.getRed()-50,buttonColor.getGreen()-50,buttonColor.getBlue()-50));             
        }else{
        g2d.setColor(new Color(buttonColor.getRed()-100,buttonColor.getGreen()-100,buttonColor.getBlue()-100));
        }
        g2d.drawPolygon(shape);

    }

结果:

我想要实现的目标(在 Paint 中编辑):

我认为这是因为即使我重写了paintComponent 方法。这 只修改 JButton 内绘制的内容?所以 JButton 的边界 保持矩形?有没有办法来解决这个问题?还是我应该努力实现这一目标 以完全不同的方式?

任何帮助都会很棒!我什至看过在 OpenGL 中对此进行编程。我非常 小经验!而且它会永远消失!

非常感谢

提姆

【问题讨论】:

    标签: java swing jbutton paintcomponent


    【解决方案1】:

    使用 OverlayLayout 怎么样:http://java-swing-tips.blogspot.jp/2012/12/combine-five-jbuttons-to-make.html

    import java.awt.*;
    import javax.swing.*;
    
    public class CompoundButtonTest {
      public JComponent makeUI() {
        JPanel p = new JPanel();
        p.add(new JButton("JButton"));
        p.add(makeCompoundButton(120, 80));
        return p;
      }
      private static JComponent makeCompoundButton(int w, int h) {
        final Dimension d = new Dimension(w, h);
        JPanel p = new JPanel() {
          @Override public Dimension getPreferredSize() {
            return d;
          }
        };
        p.setLayout(new OverlayLayout(p));
        p.add(new CustomButton(TriangleType.A, d, new Color(0x6464C8)));
        p.add(new CustomButton(TriangleType.B, d, new Color(0x64C864)));
        return p;
      }
      public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
          @Override public void run() {
            createAndShowGUI();
          }
        });
      }
      public static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new CompoundButtonTest().makeUI());
        f.setSize(320, 240);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }
    
    enum TriangleType {A, B}
    
    class CustomButton extends JButton {
      private final Color buttonColor;
      private final TriangleType type;
      private final Dimension dim;
      private Shape shape;
      private int stroke = 3;
      public CustomButton(TriangleType type, Dimension d, Color color) {
        super();
        this.type = type;
        this.dim = d;
        this.buttonColor = color;
        setContentAreaFilled(false);
        setBorder(BorderFactory.createEmptyBorder());
        setIcon(new Icon() {
          @Override public void paintIcon(Component c, Graphics g, int x, int y) {
            Graphics2D g2 = (Graphics2D)g.create();
            if(getModel().isArmed()) {
              g2.setColor(buttonColor.darker());
            } else if(isRolloverEnabled() && getModel().isRollover()) {
              g2.setColor(buttonColor.brighter());
            } else {
              g2.setColor(buttonColor);
            }
            g2.translate(x, y);
            g2.fill(shape);
            g2.setColor(buttonColor.darker());
            g2.setStroke(new BasicStroke((float)stroke));
            g2.draw(shape);
            g2.dispose();
          }
          @Override public int getIconWidth()  {
            return dim.width;
          }
          @Override public int getIconHeight() {
            return dim.height;
          }
        });
      }
      private Rectangle rect;
      @Override public void paintComponent(Graphics g) {
        Rectangle r = getBounds();
        if(!r.equals(rect)) {
          int v = 8;
          int s = stroke/2;
          int w = r.width  - s;
          int h = r.height - s;
          if(TriangleType.A==type) {
            w -= v;
            h -= v;
            shape = new Polygon(new int[] {s,w,s}, new int[] {s,s,h}, 3);
          } else {
            w -= s;
            h -= s;
            shape = new Polygon(new int[] {w,w,v}, new int[] {v,h,h}, 3);
          }
          rect = r;
        }
        super.paintComponent(g);
      }
      @Override public boolean contains(int x, int y) {
        return shape.contains(x, y);
      }
    }
    

    【讨论】:

      【解决方案2】:

      我认为您不能(轻松地)使用多个组件来做到这一点。

      相反,您应该只使用一个包含地图图像的 JLabel。然后,您需要创建一个要在地图顶部绘制的形状列表,以表示您所在国家/州的轮廓。所以你需要

      1. 覆盖标签的paintComponent() 方法以在地图上绘制每个Shape。
      2. 实现您的 MouseListener 代码,您遍历形状列表以确定鼠标当前正在使用哪个形状。

      【讨论】:

        【解决方案3】:

        您可以在 null LayoutManager 的帮助下实现这一点:

        1. 删除getPreferredSize() 方法。
        2. 将空布局设置为按钮容器 (setLayout(null);)。
        3. 为您的按钮设置相同的边界,例如下一个:

          b1.setBounds(0,0,80,80); b2.setBounds(0,0,80,80);

        对于实现按钮单击,您需要使用ActionListener 而不是MouseListener

        【讨论】:

          猜你喜欢
          • 2016-07-27
          • 1970-01-01
          • 2023-03-25
          • 2012-12-01
          • 2016-08-16
          • 1970-01-01
          • 1970-01-01
          • 2020-08-19
          相关资源
          最近更新 更多