我有一个带有两个按钮的 Jframe:“A”和“B”。单击按钮“A”应在 JPanel 中显示大写字母 A。仅当鼠标悬停时, Canvas 内的任何“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;
}
}
任何帮助将不胜感激。谢谢!
最佳答案
存在一些误解。
Graphics#drawString
不会在 x/y 位置绘制文本,因此 x/y 是String
的左上角,而是,x/y 位置是字体的基线,这意味着大部分文本绘制在 y 位置上方,请参阅 Font Concepts更多细节。这意味着当您尝试计算文本的矩形
时,它实际上低于您绘制它的位置。相反,您需要使用 y + ascent 来使文本正确定位。paintComponent
可以出于多种原因随时调用,其中许多原因是您无法控制的。为此,paintComponent
应该只用于绘制组件的当前状态,并且永远不应该更新或修改组件的状态。因此,在方法中添加新的GUIModel
是错误的做法,而应该将其添加到MouseListener
的mouseClicked
事件中。- 您非常依赖
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;
}
}
}
关于java - 仅更改鼠标悬停时字母的颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33772839/