如何摆脱不同位置的油漆和涂料立即

问题描述 投票:0回答:1

我正在研究任意形状的按钮。第一阶段成功了,因为按钮出现在预期的位置.第二阶段失败了,因为从doClick调用的paintImmediately油漆到一个完全不同的位置.我尝试了几种方法来使用AffineTransform,但无法计算出正确的位置。

任何提示是感激的。

我试过的是这样的--Buttonclass:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;

import javax.swing.JButton;
import javax.swing.SwingUtilities;


public class MyCircleButton extends JButton implements MouseListener {
   public MyCircleButton(String text, double xCenter, double yCenter, double rOuter, double rInner,
         double start, double extend) {
      super(text);
      this.text     = text;
      this.xCenter  = xCenter;
      this.yCenter  = yCenter;
      this.xOffset  = xCenter - rOuter;
      this.yOffset  = yCenter - rOuter;
      this.rOuter   = rOuter;
      this.rInner   = rInner;
      this.angStart = start;
      this.angSize  = extend;
      int fontSize = (int) (rOuter * 0.15);

      this.font = new Font("Arial", Font.BOLD, fontSize);
      this.addMouseListener(this);
      calcShape();
      calcText();
   }


   @Override
   public boolean contains(int x, int y) {
      return shape.contains(x, y);
   }


   @Override
   public void doClick(int pressTime) {
      model.setPressed(true);
      Component c = SwingUtilities.getRoot(this);
      Graphics  g = c.getGraphics();
      Rectangle r = shape.getBounds();

      if (g != null) {
         Graphics2D      g2 = (Graphics2D) g;
         Point           p  = SwingUtilities.convertPoint(this, new Point(0, 0), getParent());
         AffineTransform t  = new AffineTransform();

         t.setToTranslation(p.getX(), p.getY());
         //         t.setToTranslation(xText, yText);
         //         t.setToTranslation(xCenter, yCenter);
         //         g2.getTransform().concatenate(t);
         g2.setTransform(t);
         paint(g);
      }
      try {
         Thread.currentThread().sleep(pressTime);
      } catch (InterruptedException ie) {
      }
      model.setPressed(false);
   }


   @Override
   public int getHeight() {
      return shape.getBounds().height;
   }


   @Override
   public int getWidth() {
      return shape.getBounds().width;
   }


   @Override
   public int getX() {
      return shape.getBounds().x;
   }


   @Override
   public int getY() {
      return shape.getBounds().y;
   }


   @Override
   public void mouseClicked(MouseEvent me) {
      System.out.println("mouse clicked CIRCLE-BUTTON<" + text + "> at " + me.getX() + "/" + me.getY());
      doClick(50);
   }


   @Override
   public void mouseEntered(MouseEvent me) {
   }


   @Override
   public void mouseExited(MouseEvent me) {
   }


   @Override
   public void mousePressed(MouseEvent me) {
   }


   @Override
   public void mouseReleased(MouseEvent me) {
   }


   @Override
   public void paint(Graphics g) {
      Graphics2D  g2        = (Graphics2D) g;
      Shape       oldClip   = g2.getClip();
      Paint       oldPaint  = g2.getPaint();
      Stroke      oldStroke = g2.getStroke();
      Font        oldFont   = g2.getFont();
      FontMetrics fm        = g2.getFontMetrics(font);
      Rectangle2D tb        = fm.getStringBounds(text, g2);

      g2.setClip(this.shape);
      if (getModel().isArmed() || getModel().isPressed())
         g2.setPaint(Color.RED);
      else
         g2.setPaint(Color.GREEN);
      g2.fill(shape);
      g2.setStroke(new BasicStroke(4));
      g2.setPaint(Color.WHITE);
      g2.draw(shape);

      g2.setPaint(Color.BLACK);
      g2.setFont(font);
      g2.drawString(text, (int) (xText + 2 - tb.getWidth() / 2), (int) (yText + 2 + fm.getAscent() * 0.35));
      g2.setPaint(Color.WHITE);
      g2.drawString(text, (int) (xText - tb.getWidth() / 2), (int) (yText + fm.getAscent() * 0.35));

      g2.setFont(oldFont);
      g2.setStroke(oldStroke);
      g2.setPaint(oldPaint);
      g2.setClip(oldClip);
   }


   protected void calcShape() {
      Arc2D     a        = new Arc2D.Double(xOffset, yOffset, 2 * rOuter, 2 * rOuter, angStart, angSize,
            Arc2D.PIE);
      Ellipse2D e        = new Ellipse2D.Double(xOffset + rOuter - rInner, yOffset + rOuter - rInner,
            2 * rInner, 2 * rInner);
      Area      resShape = new Area(a);

      resShape.subtract(new Area(e));
      this.shape = resShape;
   }


   protected void calcText() {
      double angle = angStart + angSize / 2;
      double r     = rInner + (rOuter - rInner) / 2;
      double xOff  = r * Math.sin(Math.toRadians(90 + angle));
      double yOff  = r * Math.cos(Math.toRadians(90 + angle));

      xText = xCenter + (Math.abs(xOff) > 0.1 ? xOff : 0);
      yText = yCenter + (Math.abs(yOff) > 0.1 ? yOff : 0);
   }


   private double xCenter;
   private double yCenter;
   private double xOffset;
   private double yOffset;
   private double rOuter;
   private double rInner;
   private double angStart;
   private double angSize;
   private double xText;
   private double yText;
   private String text;
   private Shape  shape;
   private Font   font;
}

Buttonclass: 和Pane class:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class TestCirclePane extends JPanel {
   public TestCirclePane(int w, int h) {
      diameter = (int) (0.9 * (w < h ? w : h));
      Dimension s = new Dimension(w, h);

      xCenter = w / 2;
      yCenter = h / 2;
      setMinimumSize(s);
      setPreferredSize(s);
      setLayout(null);
      createComponents(this);
   }


   @Override
   public void paintChildren(Graphics g) {
      for (Component c : getComponents()) {
         if (c instanceof MyCircleButton)
            ((MyCircleButton) c).paint(g);
      }
   }


   protected void createComponents(JPanel p) {
      double r   = diameter / 2;
      double w   = r * 0.66;
      double r3o = r;
      double r3i = r - w * 0.5;

      add(new MyCircleButton("B0", xCenter, yCenter, r3o, r3i, 135, 90));
      add(new MyCircleButton("B1", xCenter, yCenter, r3o, r3i, 45, 90));
      add(new MyCircleButton("B2", xCenter, yCenter, r3o, r3i, -45, 90));
      add(new MyCircleButton("B3", xCenter, yCenter, r3o, r3i, 225, 90));
   }


   @Override
   protected void paintComponent(Graphics arg0) {
      super.paintComponent(arg0);
      Graphics2D g2       = (Graphics2D) arg0;
      Dimension  d        = getSize();
      Paint      oldPaint = g2.getPaint();

      g2.setPaint(Color.WHITE);
      g2.fill3DRect(0, 0, d.width, d.height, true);
      g2.setPaint(Color.LIGHT_GRAY);
      g2.drawLine(0, yCenter, d.width, yCenter);
      g2.drawLine(xCenter, 0, xCenter, d.height);
      g2.setPaint(oldPaint);
   }


   public static void createWindow() {
      JFrame frame  = new JFrame("Test - CircleButton");
      JPanel client = new JPanel();

      client.setLayout(new BorderLayout());
      client.add(placeHolder("top"), BorderLayout.NORTH);
      client.add(placeHolder("bottom"), BorderLayout.SOUTH);
      client.add(placeHolder("left"), BorderLayout.WEST);
      client.add(placeHolder("right"), BorderLayout.EAST);
      client.add(new TestCirclePane(800, 600), BorderLayout.CENTER);

      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(client);
      frame.pack();
      frame.setVisible(true);
   }


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


   public static JComponent placeHolder(String s) {
      JLabel l = new JLabel(s);

      l.setPreferredSize(new Dimension(300, 300));

      return l;
   }


   private int               xCenter;
   private int               yCenter;
   private int               diameter;
   private static final long serialVersionUID = 1L;
}
java swing jbutton paint
1个回答
0
投票

不知道这是否会有帮助,但这里有我的两点意见。

  1. 不要覆盖 paintChildren(…). JPanel会自动重新绘制任何添加到面板上的组件,不要覆盖paint(...)。

  2. 不要覆盖paint(...)。自定义绘画是通过重写 paintComponent(…) 而你需要调用 super.paintComponent(…) 否则你可能会出现绘画伪影。

  3. 不要覆盖 getX(getY() 这些方法是用来控制组件在面板上的位置,我猜你不应该覆盖getWidth()和getHeight()。

  4. 我也猜测你不应该覆盖getWidth()和getHeight()。我想你应该覆盖的是 getPreferredSize() 方法来控制组件的大小。

  5. 如果你要使用null布局,那么你的代码要负责设置面板上每个组件的大小位置。

  6. 不要在你的绘制方法中进行翻译。组件的绘制应该总是相对于(0,0)进行。这个位置决定了组件在面板上的位置。

  7. 不要在doClick()方法中调用Thread.sleep()。Thread.sleep()会导致EDT进入睡眠状态,这意味着GUI无法重新绘制自己。不知道为什么你还需要覆盖这个方法。


0
投票

所以这就是变体,可以用。首先是Button类,然后是Pane类

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;

import javax.swing.JButton;
import javax.swing.SwingUtilities;


public class MyCircleButton extends JButton implements MouseListener {
   public MyCircleButton(String text, double xCenter, double yCenter, double rOuter, double rInner,
         double start, double extend) {
      super(text);
      this.xCenter  = xCenter;
      this.yCenter  = yCenter;
      this.xOffset  = xCenter - rOuter;
      this.yOffset  = yCenter - rOuter;
      this.rOuter   = rOuter;
      this.rInner   = rInner;
      this.angStart = start;
      this.angSize  = extend;
      int fontSize = (int) ((rOuter - rInner) * 0.5);

      setFont(new Font("Arial", Font.BOLD, fontSize));
      this.addMouseListener(this);
      setBorderPainted(false);
      setContentAreaFilled(false);
      calcShape();
      calcText();
   }


   @Override
   public boolean contains(int x, int y) {
      return shape.contains(x, y);
   }


   @Override
   public int getHeight() {
      return shape.getBounds().height;
   }


   @Override
   public int getWidth() {
      return shape.getBounds().width;
   }


   @Override
   public int getX() {
      return shape.getBounds().x;
   }


   @Override
   public int getY() {
      return shape.getBounds().y;
   }


   @Override
   public void mouseClicked(MouseEvent me) {
   }


   @Override
   public void mouseEntered(MouseEvent me) {
   }


   @Override
   public void mouseExited(MouseEvent me) {
   }


   @Override
   public void mousePressed(MouseEvent me) {
      model.setArmed(true);
      model.setPressed(true);
      paintImmediately();
   }


   @Override
   public void mouseReleased(MouseEvent me) {
      model.setArmed(false);
      model.setPressed(false);
      paintImmediately();
   }


   @Override
   public void paintComponent(Graphics g) {
      Graphics2D      g2        = (Graphics2D) g;
      Paint           oldPaint  = g2.getPaint();
      Stroke          oldStroke = g2.getStroke();
      Font            oldFont   = g2.getFont();
      AffineTransform oldTrans  = g2.getTransform();
      FontMetrics     fm        = g2.getFontMetrics(getFont());
      Rectangle2D     tb        = fm.getStringBounds(getText(), g2);
      AffineTransform t         = new AffineTransform();

      t.setToTranslation(-1 * shape.getBounds().getX(), -1 * shape.getBounds().getY());
      t.concatenate(oldTrans);
      g2.setTransform(t);
      if (getModel().isArmed() || getModel().isPressed())
         g2.setPaint(Color.RED);
      else
         g2.setPaint(Color.GREEN);
      g2.fill(shape);
      g2.setStroke(new BasicStroke(4));
      g2.setPaint(Color.WHITE);
      g2.draw(shape);

      g2.setPaint(Color.BLACK);
      g2.setFont(getFont());
      g2.drawString(getText(), (int) (xText + 2 - tb.getWidth() / 2),
            (int) (yText + 2 + fm.getAscent() * 0.35));
      g2.setPaint(Color.WHITE);
      g2.drawString(getText(), (int) (xText - tb.getWidth() / 2), (int) (yText + fm.getAscent() * 0.35));
      g2.setFont(oldFont);
      g2.setStroke(oldStroke);
      g2.setPaint(oldPaint);
   }


   protected void calcShape() {
      Arc2D     a        = new Arc2D.Double(xOffset, yOffset, 2 * rOuter, 2 * rOuter, angStart, angSize,
            Arc2D.PIE);
      Ellipse2D e        = new Ellipse2D.Double(xOffset + rOuter - rInner, yOffset + rOuter - rInner,
            2 * rInner, 2 * rInner);
      Area      resShape = new Area(a);

      resShape.subtract(new Area(e));
      this.shape = resShape;
   }


   protected void calcText() {
      double angle = angStart + angSize / 2;
      double r     = rInner + (rOuter - rInner) / 2;
      double xOff  = r * Math.sin(Math.toRadians(90 + angle));
      double yOff  = r * Math.cos(Math.toRadians(90 + angle));

      xText = xCenter + (Math.abs(xOff) > 0.1 ? xOff : 0);
      yText = yCenter + (Math.abs(yOff) > 0.1 ? yOff : 0);
   }


   protected void paintImmediately() {
      Component       c  = SwingUtilities.getRoot(this);
      Graphics        g  = c.getGraphics();
      Graphics2D      g2 = (Graphics2D) g;
      Point           p  = SwingUtilities.convertPoint(this, new Point(0, 0), c);
      AffineTransform oT = g2.getTransform();
      AffineTransform t  = new AffineTransform();

      t.setToTranslation(p.getX(), p.getY());
      g2.setTransform(t);
      paintComponent(g);
      g2.setTransform(oT);
   }


   private double xCenter;
   private double yCenter;
   private double xOffset;
   private double yOffset;
   private double rOuter;
   private double rInner;
   private double angStart;
   private double angSize;
   private double xText;
   private double yText;
   private Shape  shape;
}

现在是Pane类:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class TestCirclePane extends JPanel {
   public TestCirclePane(int w, int h) {
      diameter = (int) (0.9 * (w < h ? w : h));
      Dimension s = new Dimension(w, h);

      xCenter = w / 2;
      yCenter = h / 2;
      setMinimumSize(s);
      setPreferredSize(s);
      setLayout(null);
      createComponents(this);
   }


   protected void createComponents(JPanel p) {
      double r   = diameter / 2;
      double w   = r * 0.66;
      double r3o = r;
      double r3i = r - w * 0.5;

      add(new MyCircleButton("B0", xCenter, yCenter, r3o, r3i, 135, 90));
      add(new MyCircleButton("B1", xCenter, yCenter, r3o, r3i, 45, 90));
      add(new MyCircleButton("B2", xCenter, yCenter, r3o, r3i, -45, 90));
      add(new MyCircleButton("B3", xCenter, yCenter, r3o, r3i, 225, 90));
   }


   @Override
   protected void paintComponent(Graphics arg0) {
      super.paintComponent(arg0);
      Graphics2D g2       = (Graphics2D) arg0;
      Dimension  d        = getSize();
      Paint      oldPaint = g2.getPaint();

      g2.setPaint(Color.WHITE);
      g2.fill3DRect(0, 0, d.width, d.height, true);
      g2.setPaint(Color.LIGHT_GRAY);
      g2.drawLine(0, yCenter, d.width, yCenter);
      g2.drawLine(xCenter, 0, xCenter, d.height);
      g2.setPaint(oldPaint);
   }


   public static void createWindow() {
      JFrame frame  = new JFrame("Test - CircleButton");
      JPanel client = new JPanel();

      client.setLayout(new BorderLayout());
      client.add(placeHolder("top"), BorderLayout.NORTH);
      client.add(placeHolder("bottom"), BorderLayout.SOUTH);
      client.add(placeHolder("left"), BorderLayout.WEST);
      client.add(placeHolder("right"), BorderLayout.EAST);
      client.add(new TestCirclePane(800, 600), BorderLayout.CENTER);

      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(client);
      frame.pack();
      frame.setVisible(true);
   }


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


   public static JComponent placeHolder(String s) {
      JLabel l = new JLabel(s);

      l.setPreferredSize(new Dimension(300, 300));

      return l;
   }


   private int               xCenter;
   private int               yCenter;
   private int               diameter;
   private static final long serialVersionUID = 1L;
}

由于这个形状的按钮并不像一个普通的按钮 我需要添加一个鼠标监听器 为了给鼠标点击提供视觉反馈,我使用了以下方法 mousePressed()mouseReleased().但当我的 paintComponent() 被从油漆链外调用,我意识到,它不知道自己(按钮)的来源。

所以我想,在我的 paintImmediately里面是有buttons paint概念的。因此,我准备了环境,就像superclass在正常的油漆操作上会做的那样。那么,我以为superclass会做什么呢?不知道--只是一个猜测。

所以,如果你认为我的编码是错误的,请告诉我,如何做得更好。


0
投票

我终于找到了窍门=:O

我把创建形状的工作从面板移到了Layoutmanager中,这样就可以设置按钮的大小和位置,现在可以正常工作了。没有重载位置或大小获取器,也没有paintImmediately :)

谢谢你的帮助。

© www.soinside.com 2019 - 2024. All rights reserved.