gpt4 book ai didi

Java(图形2D): triangle drawn by created Graphics2D not visible until second repaint

转载 作者:行者123 更新时间:2023-12-01 20:16:06 25 4
gpt4 key购买 nike

我有以下最少的代码来绘制带箭头的线:

package gui;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;

import javax.swing.JPanel;

public class StateBtn extends JPanel {

private static final long serialVersionUID = -431114028667352251L;

@Override
protected void paintComponent(Graphics g) {

super.paintComponent(g);

// enable antialiasing
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);


// draw the arrow
Line2D.Double line = new Line2D.Double(0, getHeight()/2, 20, getHeight()/2);
drawArrowHead(g2, line);
g2.draw(line);

// If I call repaint() here (like in my answer below), it works

}

private void drawArrowHead(Graphics2D g2d, Line2D.Double line) {
AffineTransform tx = new AffineTransform();

tx.setToIdentity();
double angle = Math.atan2(line.y2-line.y1, line.x2-line.x1);
tx.translate(line.x2, line.y2);
tx.rotate((angle-Math.PI/2d));

Polygon arrowHead = new Polygon();
arrowHead.addPoint(0,5);
arrowHead.addPoint(-5,-5);
arrowHead.addPoint(5,-5);

Graphics2D g = (Graphics2D) g2d.create();
g.setTransform(tx);
g.fill(arrowHead);
g.dispose();
}

}

它是这样创建的:

package gui;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Main extends JFrame {

private static final long serialVersionUID = 4085389089535850911L;
private JPanel contentPane;

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setSize(500, 500);
setLocation(0, 0);

contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);

StateBtn stateBtn = new StateBtn();
stateBtn.setBounds(200,200,35,35);
contentPane.add(stateBtn);
}
}

线条绘制正确,但箭头不可见,直到我调用 repaint()。问题是该元素是可拖动的,因此每次位置更改时我都必须调用 repaint() 两次。这将使代码更加复杂并且 GUI 会变得滞后。

为什么箭头不能和线画在一起?真的没有人可以帮助我吗?

最佳答案

您尚未发布真实的MCVE ,所以不可能知道你可能做错了什么,但是不需要你在答案中使用的拼凑,你可以在paintComponent中重新调用repaint()。如果您仍然需要您自己的代码方面的帮助,那么请发布有效的 MCVE,我们可以在不修改的情况下编译和运行代码。有关 MCVE 含义的示例,请阅读 MCVE link并查看我在下面的答案中发布的示例 MCVE。

话虽如此,请理解,通常 Swing 图形是被动的,这意味着您可以让程序根据事件更改其状态,然后调用 repaint() ,这建议 到 Swing 重绘管理器来调用重绘。无法保证绘制会发生,因为已“堆积”的重绘请求(由于短时间内调用许多请求而备份)可能会被忽略。

因此,对于您的情况,我们可以使用您的代码并对其进行修改以查看其工作原理。假设我给我的 JPanel 一个 MouseAdapter —— 一个既是 MouseListener 又是 MouseMotionListener 的类,在这个适配器中我只需设置两个 Point 实例字段, p0 —— 代表鼠标最初按下的位置, p1 —— 代表鼠标按下的位置拖动或释放。我可以设置这些字段,然后调用 repaint,并让我的绘画方法使用 p0 和 p1 来绘制我的箭头。所以鼠标适配器可能看起来像这样:

private class MyMouse extends MouseAdapter {
private boolean settingMouse = false;

@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
p0 = e.getPoint();
p1 = null;
settingMouse = true; // drawing a new arrow
repaint();
}

@Override
public void mouseReleased(MouseEvent e) {
setP1(e);
settingMouse = false; // no longer drawing the new arrow
}

@Override
public void mouseDragged(MouseEvent e) {
setP1(e);
}

private void setP1(MouseEvent e) {
if (settingMouse) {
p1 = e.getPoint();
repaint();
}
}
}

然后在我的绘画代码中,我将使用您的代码,进行修改以使其使用我的 p0 和 p1 点:

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

if (p0 != null && p1 != null) {
Line2D.Double line = new Line2D.Double(p0.x, p0.y, p1.x, p1.y);

drawArrowHead(g2, line);
g2.draw(line);
}

}

整个 shebang 看起来像这样:

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class StateBtn extends JPanel {
// constants to size the JPanel
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final int AH_SIZE = 5; // size of arrow head -- avoid "magic"
// numbers!

// our start and end Points for the arrow
private Point p0 = null;
private Point p1 = null;

public StateBtn() {
// create and add a label to tell the user what to do
JLabel label = new JLabel("Click Mouse and Drag");
label.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 42));
label.setForeground(new Color(0, 0, 0, 50));
setLayout(new GridBagLayout());
add(label); // add it to the center

// create our MouseAdapater and use it as both MouseListener and
// MouseMotionListener
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

// only do this if there are points to draw!
if (p0 != null && p1 != null) {
Line2D.Double line = new Line2D.Double(p0.x, p0.y, p1.x, p1.y);

drawArrowHead(g2, line);
g2.draw(line);
}

}

private void drawArrowHead(Graphics2D g2d, Line2D.Double line) {
AffineTransform tx = new AffineTransform();

tx.setToIdentity();
double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
tx.translate(line.x2, line.y2);
tx.rotate((angle - Math.PI / 2d));

Polygon arrowHead = new Polygon();
arrowHead.addPoint(0, AH_SIZE); // again avoid "magic" numbers
arrowHead.addPoint(-AH_SIZE, -AH_SIZE);
arrowHead.addPoint(AH_SIZE, -AH_SIZE);

Graphics2D g = (Graphics2D) g2d.create();
g.setTransform(tx);
g.fill(arrowHead);
g.dispose(); // we created this, so we can dispose of it
// we should **NOT** dispose of g2d since the JVM gave us that
}

@Override
public Dimension getPreferredSize() {
// size our JPanel
return new Dimension(PREF_W, PREF_H);
}

private class MyMouse extends MouseAdapter {
private boolean settingMouse = false;

@Override
public void mousePressed(MouseEvent e) {
// if we press the wrong mouse button, exit
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
p0 = e.getPoint(); // set the start point
p1 = null; // clear the end point
settingMouse = true; // tell mouse listener we're creating a new arrow
repaint(); // suggest a repaint
}

@Override
public void mouseReleased(MouseEvent e) {
setP1(e);
settingMouse = false; // no longer drawing the new arrow
}

@Override
public void mouseDragged(MouseEvent e) {
setP1(e);
}

private void setP1(MouseEvent e) {
if (settingMouse) {
p1 = e.getPoint(); // set the end point
repaint(); // and paint!
}
}
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}

private static void createAndShowGui() {
StateBtn mainPanel = new StateBtn();
JFrame frame = new JFrame("StateBtn");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

这段代码就是我的 MCVE 示例的意思。实际上,对于一个像样的 MCVE 来说它有点大,但也足够了。请编译并运行代码以查看其是否有效。如果这对您没有帮助,如果您仍然必须在重绘调用中使用拼凑,那么我强烈建议您创建自己的 MCVE 并将其与您的问题一起发布,然后向我发表评论,以便我可以看到它。

顺便说一句,有人质疑是否可以像在 drawArrowHead(...) 方法中那样创建一个新的 Graphics 对象,是的,这不仅可以,而且是首选方法在处理 AffineTransforms 时要做的事情,因为这样您就不必担心变换可能对可能共享原始 Graphics 对象的边框和子组件产生的下游影响。同样,这也没关系,只要您遵循处理您自己创建的 Graphics 对象的规则,而不是处理JVM 给您的 Graphics 对象

关于Java(图形2D): triangle drawn by created Graphics2D not visible until second repaint,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45787031/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com