2015-11-18 32 views
0

我有一个带有两个按钮的Jframe:'A'和'B'。点击按钮'A'应该在JPanel中显示大写字母A.仅在鼠标悬停时,画布内的任何'A'字母都应以红色显示。当鼠标离开时,文字颜色应该变回黑色。只改变鼠标悬停字母的颜色

我已经为此编码,它只能使用一次。字母'A'变成红色,但不会变回黑色。此外,它不会为多个“A的

代码工作的JFrame中:

import java.awt.BorderLayout; 
import java.awt.GridLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class DrawFrame extends JFrame{ 
    private final int WIDTH = 500; 
    private final int HEIGHT = 300; 

    private GUIModel model; 

    private JButton number1; 
    private JButton number2; 

    private JPanel numberPanel; 
    private DrawPanel graphicsPanel; 

    public DrawFrame() 
    { 
     this.model = new GUIModel(" "); 

     createSelectionPanel(); 
     createGraphicsPanel(); 

     this.setSize(WIDTH, HEIGHT); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     this.setVisible(true); 
    } 

    private void createSelectionPanel() 
    { 
     numberPanel = new JPanel(); 

     ButtonListener listener = new ButtonListener(); 

     number1 = new JButton("A"); 
     number1.addActionListener(listener); 

     number2 = new JButton("B"); 
     number2.addActionListener(listener); 

     numberPanel.setLayout(new GridLayout(2,2)); 
     numberPanel.add(number1); 
     numberPanel.add(number2); 

     this.add(numberPanel, BorderLayout.WEST); 
    } 

    private void createGraphicsPanel() 
    { 
     //instantiate drawing panel 
     graphicsPanel = new DrawPanel(WIDTH, HEIGHT, model); 
     //add drawing panel to right 
     add(graphicsPanel); 
    } 

    private class ButtonListener implements ActionListener { 
     @Override 
     public void actionPerformed(ActionEvent event) { 
      model.setDisplayString(event.getActionCommand()); 
     } 
    } 

    //creates a drawing frame 
    public static void main(String[] args) 
    { 
     DrawFrame draw = new DrawFrame(); 
    } 
} 

代码的JPanel:

import javax.swing.JPanel; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.FontMetrics; 
import java.awt.Graphics; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionListener; 
import java.util.ArrayList; 
import java.util.List; 

public class DrawPanel extends JPanel{ 
    private static final long serialVersionUID = 3443814601865936618L; 

    private Font font = new Font("Default", Font.BOLD, 30); 

    private static final Color DEFAULT_TEXT_COLOR = Color.BLACK; 
    private static final Color HOVER_TEXT_COLOR = Color.RED; 
    private Color color = DEFAULT_TEXT_COLOR; 

    private List<GUIModel> numberList = new ArrayList<GUIModel>(); 
    private GUIModel model; 
    boolean mouseHover = false; 

    public DrawPanel(int width, int height, GUIModel model){ 
     this.setPreferredSize(new Dimension(width, height)); 
     this.model = model; 

     //set white background for drawing panel 
     setBackground(Color.WHITE); 

     //add mouse listeners 
     MouseHandler mouseHandler = new MouseHandler(); 
     this.addMouseListener(mouseHandler); 
     this.addMouseMotionListener(mouseHandler); 
    } 

    void checkForHover(MouseEvent event) { 
     FontMetrics metrics = getFontMetrics(font); 

     Graphics g = getGraphics(); 
     Rectangle textBounds = metrics.getStringBounds("A", g).getBounds(); 
     g.dispose(); 

     int index = 0; 
     while (index < numberList.size()) { 
      Double x = numberList.get(index).getCoordinate().getX(); 
      Double y = numberList.get(index).getCoordinate().getY(); 

      textBounds.translate(x.intValue(), y.intValue()); 

      if (textBounds.contains(event.getPoint())) { 
       color = HOVER_TEXT_COLOR; 
      } 
      else { 
       color = DEFAULT_TEXT_COLOR; 
      } 
      index++; 
     } 
     repaint(textBounds); 
    } 

    @Override 
    public void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     g.setFont(font); 
     g.setColor(color); 

     int index = 0; 
     while (index < numberList.size()) { 
      Double x = numberList.get(index).getCoordinate().getX(); 
      Double y = numberList.get(index).getCoordinate().getY(); 
      String display = numberList.get(index).getDisplayString(); 
      g.drawString(display, x.intValue(), y.intValue()); 
      index++; 
     } 

     if (model.getCoordinate() != null) { 
      Point p = model.getCoordinate();    
      g.drawString(model.getDisplayString(), p.x, p.y); 
      GUIModel number = new GUIModel(); 
      number.setCoordinate(p); 
      number.setDisplayString(model.getDisplayString()); 
      numberList.add(number); 
     } 
    } 

    //class to handle all mouse events 
    private class MouseHandler extends MouseAdapter implements MouseMotionListener 
    { 
     @Override 
     public void mousePressed(MouseEvent event) 
     { 
      model.setCoordinate(event.getPoint()); 
     } 

     @Override 
     public void mouseReleased(MouseEvent event) 
     { 
      DrawPanel.this.repaint(); 
     } 

     @Override 
     public void mouseEntered(MouseEvent event) { 
      checkForHover(event); 
     } 

     @Override 
     public void mouseMoved(MouseEvent event) { 
      checkForHover(event); 
     } 
    } 
} 

代码GUIModel:

import java.awt.Point; 

public class GUIModel { 
    private String displayString; 
    private Point coordinate; 

    public GUIModel() {} 

    public GUIModel(String displayString) { 
     this.displayString = displayString; 
    } 
    public void setDisplayString(String displayString) { 
     this.displayString = displayString; 
    } 

    public String getDisplayString() { 
     return displayString; 
    } 

    public Point getCoordinate() { 
     return coordinate; 
    } 

    public void setCoordinate(int x, int y) { 
     this.coordinate = new Point(x, y); 
    } 

    public void setCoordinate(Point coordinate) { 
     this.coordinate = coordinate; 
    } 
} 

任何帮助非常感谢。谢谢!

+0

'图形G =的getGraphics();'是一个坏主意,并应避免,你也不应该在它上面调用'dispose',因为你没有创建它。你可以使用'FontMetrics#stringWidth','FontMetrics.getHeight()'和'FontMetrics#getAscent'代替 – MadProgrammer

+0

在你的'paintComponent'方法中创建一个新模型是一个坏主意,因为可以调用任何数量的paintComponent'原因,它应该放在'mouseClicked'中 – MadProgrammer

回答

3

有几个误解。

  • Graphics#drawString不会在X/Y位置绘制文本,使X/Y是String的左上角,而是在X/Y轴是字体的基线,这意味着大部分文字都在y位置上方绘制,详情请参阅Font Concepts。这意味着当你尝试计算文本的Rectangle时,它实际上低于你绘制它的地方。相反,您需要使用y + ascent才能正确定位文本。
  • paintComponent可以随时调用,原因有很多,其中许多是您无法控制的。为此,paintComponent应仅用于绘制组件的当前状态,不应更新或修改组件的状态。因此,在该方法内添加新的GUIModel是错误的事情,而应将其添加到MouseListenermouseClicked事件中。
  • 你依靠GUIModel变量。您应该创建一个模型,只有当你真正需要它

概念,这个例子地址最上面提到的问题

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.FontMetrics; 
import java.awt.Graphics; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionListener; 
import java.util.ArrayList; 
import java.util.List; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class DrawFrame extends JFrame { 

    private final int WIDTH = 500; 
    private final int HEIGHT = 300; 

// private GUIModel model; 
    private JButton number1; 
    private JButton number2; 

    private JPanel numberPanel; 
    private DrawPanel graphicsPanel; 

    public DrawFrame() { 
//  this.model = new GUIModel(" "); 

     createSelectionPanel(); 
     createGraphicsPanel(); 

     this.setSize(WIDTH, HEIGHT); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     this.setVisible(true); 
    } 

    private void createSelectionPanel() { 
     numberPanel = new JPanel(); 

     ButtonListener listener = new ButtonListener(); 

     number1 = new JButton("A"); 
     number1.addActionListener(listener); 

     number2 = new JButton("B"); 
     number2.addActionListener(listener); 

     numberPanel.setLayout(new GridLayout(2, 2)); 
     numberPanel.add(number1); 
     numberPanel.add(number2); 

     this.add(numberPanel, BorderLayout.WEST); 
    } 

    private void createGraphicsPanel() { 
     //instantiate drawing panel 
     graphicsPanel = new DrawPanel(WIDTH, HEIGHT); 
     //add drawing panel to right 
     add(graphicsPanel); 
    } 

    private class ButtonListener implements ActionListener { 

     @Override 
     public void actionPerformed(ActionEvent event) { 
      graphicsPanel.setDisplayString(event.getActionCommand()); 
     } 
    } 

    //creates a drawing frame 
    public static void main(String[] args) { 
     DrawFrame draw = new DrawFrame(); 
    } 

    public static class DrawPanel extends JPanel { 

     private static final long serialVersionUID = 3443814601865936618L; 

     private Font font = new Font("Default", Font.BOLD, 30); 

     private static final Color DEFAULT_TEXT_COLOR = Color.BLACK; 
     private static final Color HOVER_TEXT_COLOR = Color.RED; 
     private Color color = DEFAULT_TEXT_COLOR; 

     private List<GUIModel> numberList = new ArrayList<GUIModel>(); 
     boolean mouseHover = false; 

     private String displayString; 
     private GUIModel hoverModel; 

     public DrawPanel(int width, int height) { 
      this.setPreferredSize(new Dimension(width, height)); 

      //set white background for drawing panel 
      setBackground(Color.WHITE); 

      //add mouse listeners 
      MouseHandler mouseHandler = new MouseHandler(); 
      this.addMouseListener(mouseHandler); 
      this.addMouseMotionListener(mouseHandler); 
     } 

     protected Rectangle getBounds(GUIModel model) { 
      FontMetrics metrics = getFontMetrics(font); 
      Double x = model.getCoordinate().getX(); 
      Double y = model.getCoordinate().getY(); 

      Rectangle textBounds = new Rectangle(
        x.intValue(), 
        y.intValue(), 
        metrics.stringWidth(model.getDisplayString()), 
        metrics.getHeight()); 
      return textBounds; 
     } 

     void checkForHover(MouseEvent event) { 

      Rectangle textBounds = null; 
      if (hoverModel != null) { 
       textBounds = getBounds(hoverModel); 
      } 
      hoverModel = null; 
      if (textBounds != null) { 
       repaint(textBounds); 
      } 
      for (GUIModel model : numberList) { 

       textBounds = getBounds(model); 

       if (textBounds.contains(event.getPoint())) { 
        hoverModel = model; 
        repaint(textBounds); 
        break; 
       } 
      } 
     } 

     @Override 
     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      g.setFont(font); 
      g.setColor(DEFAULT_TEXT_COLOR); 

      FontMetrics fm = g.getFontMetrics(); 
      for (GUIModel model : numberList) { 
       if (model != hoverModel) { 
        Double x = model.getCoordinate().getX(); 
        Double y = model.getCoordinate().getY(); 
        String display = model.getDisplayString(); 
        g.drawString(display, x.intValue(), y.intValue() + fm.getAscent()); 
       } 
      } 
      if (hoverModel != null) { 
       g.setColor(HOVER_TEXT_COLOR); 
       Double x = hoverModel.getCoordinate().getX(); 
       Double y = hoverModel.getCoordinate().getY(); 
       String display = hoverModel.getDisplayString(); 
       g.drawString(display, x.intValue(), y.intValue() + fm.getAscent()); 
      } 

//   if (model.getCoordinate() != null) { 
//    Point p = model.getCoordinate(); 
//    g.drawString(model.getDisplayString(), p.x, p.y); 
////    GUIModel number = new GUIModel(); 
////    number.setCoordinate(p); 
////    number.setDisplayString(model.getDisplayString()); 
////    numberList.add(number); 
//   } 
     } 

     public void setDisplayString(String text) { 
      displayString = text; 
     } 

     //class to handle all mouse events 
     private class MouseHandler extends MouseAdapter implements MouseMotionListener { 

      @Override 
      public void mouseClicked(MouseEvent e) { 
       GUIModel model = new GUIModel(displayString); 
       model.setCoordinate(e.getPoint()); 
       numberList.add(model); 
       repaint(); 
      } 

      @Override 
      public void mouseMoved(MouseEvent event) { 
       checkForHover(event); 
      } 
     } 
    } 

    public static class GUIModel { 

     private String displayString; 
     private Point coordinate; 

     public GUIModel() { 
     } 

     public GUIModel(String displayString) { 
      this.displayString = displayString; 
     } 

     public void setDisplayString(String displayString) { 
      this.displayString = displayString; 
     } 

     public String getDisplayString() { 
      return displayString; 
     } 

     public Point getCoordinate() { 
      return coordinate; 
     } 

     public void setCoordinate(int x, int y) { 
      this.coordinate = new Point(x, y); 
     } 

     public void setCoordinate(Point coordinate) { 
      this.coordinate = coordinate; 
     } 
    } 
}