在 Java Swing 应用程序中向 Graphics2D 面板添加新数据
Add new data to Graphics2D panel in a Java Swing application
我正在编写一个 Java Swing 应用程序来处理数据。
我需要添加的功能之一是以图形方式可视化数据。
为此,我想使用 Graphics2D class.
我创建了一个 GUI,集成了我的程序,还有一个使用 Graphics2D 绘制图形的面板 class。
但我的问题是,在从 GUI 选择并加载文件后,我不知道如何调用 drawLine 方法
下面是简短的代码示例,显示了我的问题。
它只包含一个带有 2 个面板的基本 GUI 和一个带有加载选项的菜单来解释我的问题:
在 MyFrame.java 文件中,我在第 87 行添加了注释以准确显示我被卡住的位置。
该应用程序基于 3 个文件:
main:在这里它创建了 GUI 的 MyFrame 实例
Myframe:创建 GUI 和进一步的数据处理
MyPanel:制作一个 Graphics2D 的 Jpanel,以蓝色矩形框作为起始视图。
如果有人能给我一个关于如何从 MyFrame() 构造函数外部调用此 drawLine 方法的提示...
我仍然不完全理解如何在 classes...
之间进行交互的全部要点
这是 GUI 外观的图片:
谢谢你帮我解决这个问题
public class main {
public static void main(String[] args) {
new MyFrame();
}
}
- MyFrame.java:
public class MyFrame extends JFrame {
JTextComponent tc;
String fileName;
MyFrame() {
this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
this.setLayout(null);
this.setBounds(0,0,464,312);
tc = new JTextPane();
tc.setBounds(0,520,450,50);
tc.setPreferredSize(new Dimension(450,50));
JScrollPane sp = new JScrollPane(tc);
JMenuBar mb = new JMenuBar();
JMenu fm = new JMenu("File");
JMenuItem loadItem = new JMenuItem("Load file");
loadItem.addActionListener(e -> {tc.setText("loading"+"\n");
SDprocess();});
fm.add(loadItem);
mb.add(fm);
MyPanel p1 = new MyPanel();
p1.setBounds(0,0,450,200);
p1.setPreferredSize(new Dimension(450,200));
JPanel p2 = new JPanel();
p2.setBounds(0,200,450,50);
p2.setPreferredSize(new Dimension(450,50));
p2.add(sp);
this.setJMenuBar(mb);
this.add(p1);
this.add(p2);
this.setResizable(false);
this.setVisible(true);
}
public void SDprocess() {
File fr = null;
JFileChooser fc = new JFileChooser();
int result = fc.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
fr = fc.getSelectedFile();
fileName=fr.getName();
System.out.println(fileName);
}
try {
Scanner sc = new Scanner(fr);
tc.setText(fileName +" loading\n");
while (sc.hasNextLine()) {
String line = sc.nextLine();
// ...
// rest of code to get the x and y data for drawing
// lines using drawLine(x1,y1,x2,y2) method.
//
// at this point I need to call this drawLine method but how ???
// i just don't know how to call this method from this point and how to
// and update the graphics panel p1 after adding the data....
}
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- MyPanel.java:
public class MyPanel extends JPanel {
Graphics2D g2D;
MyPanel() {
this.setPreferredSize(new Dimension (450,200));
}
public void paint (Graphics g) {
g2D = (Graphics2D) g;
g2D.setStroke(new BasicStroke(1));
g2D.setPaint(Color.blue);
g2D.drawLine(5, 5, 445,5);
g2D.drawLine(445, 5, 445,195);
g2D.drawLine(445, 195, 5,195);
g2D.drawLine(5, 195, 5,5);
}
}
Oracle 有一个有用的教程,Creating a GUI With Swing。跳过 Netbeans 部分。
这是“读取文件”之前修改后的 GUI。
这是“读取文件”后修改后的 GUI。
我创建了一个应用程序模型来保存线段。这个模型传给绘图JPanel
,这样就可以在绘图JPanel
.
的paintComponent
方法中绘制线段了
我清理了你的 GUI。我使用 Swing layout managers 创建了 GUI。我将 JPanels
的创建与 JFrame
的创建分开,以便人们更容易阅读和理解代码。
这是完整的可运行代码。我在 类 内部制作了额外的 类 这样我就可以 post 将这段代码作为一个块。
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
public class ExampleDrawingGUI {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new ExampleDrawingGUI().new MyFrame());
}
public class MyFrame extends JFrame {
private static final long serialVersionUID = 1L;
private ExampleDrawingModel model;
JTextComponent tc;
MyPanel p1;
public MyFrame() {
super("My Frame");
this.model = new ExampleDrawingModel();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setJMenuBar(createMenuBar());
p1 = new MyPanel(model);
this.add(p1, BorderLayout.CENTER);
this.add(createTextPanel(), BorderLayout.SOUTH);
this.pack();
this.setLocationByPlatform(true);
// this.setResizable(false);
this.setVisible(true);
}
private JMenuBar createMenuBar() {
JMenuBar mb = new JMenuBar();
JMenu fm = new JMenu("File");
JMenuItem loadItem = new JMenuItem("Load file");
loadItem.addActionListener(e -> {
tc.setText("loading" + "\n");
model.readFile();
p1.repaint();
});
fm.add(loadItem);
mb.add(fm);
return mb;
}
private JPanel createTextPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
tc = new JTextPane();
tc.setPreferredSize(new Dimension(450, 50));
JScrollPane sp = new JScrollPane(tc);
panel.add(sp, BorderLayout.CENTER);
return panel;
}
public void repaint() {
p1.repaint();
}
}
public class MyPanel extends JPanel {
private static final long serialVersionUID = 1L;
private ExampleDrawingModel model;
public MyPanel(ExampleDrawingModel model) {
this.model = model;
this.setPreferredSize(new Dimension(450, 200));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
paintBorder(g2D);
for (LineSegment line : model.getLines()) {
Point startPoint = line.getStartPoint();
Point endPoint = line.getEndPoint();
g2D.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
}
}
private void paintBorder(Graphics2D g2D) {
int margin = 5;
int x1 = margin;
int x2 = getWidth() - margin;
int y1 = margin;
int y2 = getHeight() - margin;
g2D.setStroke(new BasicStroke(3f));
g2D.setPaint(Color.blue);
g2D.drawLine(x1, y1, x1, y2);
g2D.drawLine(x1, y1, x2, y1);
g2D.drawLine(x2, y1, x2, y2);
g2D.drawLine(x1, y2, x2, y2);
}
}
public class ExampleDrawingModel {
private List<LineSegment> lines;
public ExampleDrawingModel() {
this.lines = new ArrayList<>();
}
public void readFile() {
this.lines.clear();
// Here's where you'd read a file and create a list of lines.
lines.add(new LineSegment(new Point(100, 100), new Point(100, 150)));
}
public List<LineSegment> getLines() {
return lines;
}
}
public class LineSegment {
private final Point startPoint, endPoint;
public LineSegment(Point startPoint, Point endPoint) {
this.startPoint = startPoint;
this.endPoint = endPoint;
}
public Point getStartPoint() {
return startPoint;
}
public Point getEndPoint() {
return endPoint;
}
}
}
首先,您的代码存在一些问题:
class MyFrame extends JFrame {
//....
MyFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null); // !! Good God, no don't do this!
this.setBounds(0, 0, 464, 312); // and don't do this
像瘟疫一样避免空布局和 setBounds,因为这会导致 GUI 非常不灵活,虽然它们在一个平台上看起来不错,但在大多数其他平台或屏幕分辨率上看起来很糟糕,而且很难更新和维护。相反,您需要研究和学习布局管理器,然后嵌套 JPanel,每个 JPanel 都使用自己的布局管理器来创建令人愉悦且复杂的 GUI,这些 GUI 在所有 OS 上看起来都不错。
此外,不要忘记在 添加组件之后和设置可见之前对 JFrame 调用 pack()
,以便布局管理器执行他们的操作。
然后:
class MyPanel extends JPanel {
// ...
Graphics2D g2D; //!! -- no, don't do this
如果您创建一个 Graphics 或 Graphics2D 字段,您很想在绘画方法之外使用它,这是灾难的根源,因为从组件获得的任何 Graphics 都是短暂的,并且这样做有创建脆弱的风险图形或抛出 NullPointerException
public void paint (Graphics g) {
g2D = (Graphics2D) g;
g2D.setStroke(new BasicStroke(1));
g2D.setPaint(Color.blue);
g2D.drawLine(5, 5, 445,5);
g2D.drawLine(445, 5, 445,195);
g2D.drawLine(445, 195, 5,195);
g2D.drawLine(5, 195, 5,5);
}
不要重写 paint 而是重写 paintComponent,因为这风险较小(paint 有更大的责任,你不想搞砸)并且如果需要的话动画更流畅,因为 paintComponent 默认使用双缓冲。
此外,您几乎总是 应该在您自己的重写中调用 super 的绘画方法,因此改为:
@Override
protected void paintComponent(Graphics g) {
// first call the super's method:
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g.create();
现在关于您的实际问题,即在呈现 GUI 之后创建图像和绘图,可能最简单的方法是创建一个 BufferedImage 并在您的 GUI 中使用它绘制。您可以通过调用 Graphics 方法 drawImage(...)
轻松完成此操作。您可以在需要时随时将 BufferedImage 传递到您的绘图 JPanel 中。例如,您的代码可能类似于...
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Foo {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MainPanel mainPanel = new MainPanel();
MyMenu myMenu = new MyMenu();
myMenu.setMyPanel(mainPanel.getMyPanel());
myMenu.setMainPanel(mainPanel);
frame.add(mainPanel);
frame.setJMenuBar(myMenu);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
class MainPanel extends JPanel {
private static final int GAP = 5;
private JTextArea textArea = new JTextArea(4, 40);
private MyPanel myPanel = new MyPanel();
public MainPanel() {
textArea.setFocusable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BorderLayout(GAP, GAP));
add(myPanel);
add(scrollPane, BorderLayout.PAGE_END);
}
public MyPanel getMyPanel() {
return myPanel;
}
public void appendTextAreaText(String text) {
textArea.append(text);
}
public void setBuffImg(BufferedImage bImage) {
myPanel.setBuffImg(bImage);
}
}
class MyMenu extends JMenuBar {
private MainPanel mainPanel;
private MyPanel myPanel;
public MyMenu() {
JMenu fm = new JMenu("File");
JMenuItem loadItem = new JMenuItem("Load file");
loadItem.addActionListener(e -> {
// Emulate reading file here in a background thread
if (myPanel != null) {
int width = MyPanel.MY_WIDTH;
int height = MyPanel.MY_HEIGHT;
BufferedImage bImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = bImg.createGraphics();
// draw with g2 here using data from file
// emulating this:
g2.setColor(Color.RED);
float strokeWidth = (float) (2 + 6 * Math.random());
g2.setStroke(new BasicStroke(strokeWidth));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int x2 = (int) (MyPanel.MY_WIDTH * (1 + Math.random()) / 2);
int y2 = (int) (MyPanel.MY_HEIGHT * (1 + Math.random()) / 2);
g2.drawLine(5, 5, x2, y2);
g2.dispose();
myPanel.setBuffImg(bImg);
if (mainPanel != null) {
mainPanel.appendTextAreaText("adding image \n");
}
}
});
fm.add(loadItem);
add(fm);
}
public void setMyPanel(MyPanel myPanel) {
this.myPanel = myPanel;
}
public void setMainPanel(MainPanel mainPanel) {
this.mainPanel = mainPanel;
}
}
class MyPanel extends JPanel {
private static final int GAP = 5;
public static final int MY_WIDTH = 450;
public static final int MY_HEIGHT = 200;
private BufferedImage bImg = null;
// Graphics2D g2D; //!! -- no, never do this!!
MyPanel() {
// this.setPreferredSize(new Dimension(450, 200));
setBackground(Color.WHITE);
}
// better to override getPreferredSize
@Override
public Dimension getPreferredSize() {
return new Dimension(MY_WIDTH + 2 * GAP, MY_HEIGHT + 2 * GAP);
}
public void setBuffImg(BufferedImage bImg) {
this.bImg = bImg;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
// first call the super's method:
super.paintComponent(g);
if (bImg != null) {
g.drawImage(bImg, GAP, GAP, null);
}
Graphics2D g2D = (Graphics2D) g.create();
g2D.setStroke(new BasicStroke(1));
g2D.setPaint(Color.blue);
Rectangle rect = new Rectangle(GAP, GAP, getWidth() - 2 * GAP, getHeight() - 2 * GAP);
g2D.draw(rect);
}
// Don't override paint but rather paintComponent
// public void paint (Graphics g) {
}
我正在编写一个 Java Swing 应用程序来处理数据。 我需要添加的功能之一是以图形方式可视化数据。 为此,我想使用 Graphics2D class.
我创建了一个 GUI,集成了我的程序,还有一个使用 Graphics2D 绘制图形的面板 class。
但我的问题是,在从 GUI 选择并加载文件后,我不知道如何调用 drawLine 方法
下面是简短的代码示例,显示了我的问题。 它只包含一个带有 2 个面板的基本 GUI 和一个带有加载选项的菜单来解释我的问题:
在 MyFrame.java 文件中,我在第 87 行添加了注释以准确显示我被卡住的位置。
该应用程序基于 3 个文件: main:在这里它创建了 GUI 的 MyFrame 实例 Myframe:创建 GUI 和进一步的数据处理 MyPanel:制作一个 Graphics2D 的 Jpanel,以蓝色矩形框作为起始视图。
如果有人能给我一个关于如何从 MyFrame() 构造函数外部调用此 drawLine 方法的提示...
我仍然不完全理解如何在 classes...
之间进行交互的全部要点这是 GUI 外观的图片:
谢谢你帮我解决这个问题
public class main {
public static void main(String[] args) {
new MyFrame();
}
}
- MyFrame.java:
public class MyFrame extends JFrame {
JTextComponent tc;
String fileName;
MyFrame() {
this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
this.setLayout(null);
this.setBounds(0,0,464,312);
tc = new JTextPane();
tc.setBounds(0,520,450,50);
tc.setPreferredSize(new Dimension(450,50));
JScrollPane sp = new JScrollPane(tc);
JMenuBar mb = new JMenuBar();
JMenu fm = new JMenu("File");
JMenuItem loadItem = new JMenuItem("Load file");
loadItem.addActionListener(e -> {tc.setText("loading"+"\n");
SDprocess();});
fm.add(loadItem);
mb.add(fm);
MyPanel p1 = new MyPanel();
p1.setBounds(0,0,450,200);
p1.setPreferredSize(new Dimension(450,200));
JPanel p2 = new JPanel();
p2.setBounds(0,200,450,50);
p2.setPreferredSize(new Dimension(450,50));
p2.add(sp);
this.setJMenuBar(mb);
this.add(p1);
this.add(p2);
this.setResizable(false);
this.setVisible(true);
}
public void SDprocess() {
File fr = null;
JFileChooser fc = new JFileChooser();
int result = fc.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
fr = fc.getSelectedFile();
fileName=fr.getName();
System.out.println(fileName);
}
try {
Scanner sc = new Scanner(fr);
tc.setText(fileName +" loading\n");
while (sc.hasNextLine()) {
String line = sc.nextLine();
// ...
// rest of code to get the x and y data for drawing
// lines using drawLine(x1,y1,x2,y2) method.
//
// at this point I need to call this drawLine method but how ???
// i just don't know how to call this method from this point and how to
// and update the graphics panel p1 after adding the data....
}
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- MyPanel.java:
public class MyPanel extends JPanel {
Graphics2D g2D;
MyPanel() {
this.setPreferredSize(new Dimension (450,200));
}
public void paint (Graphics g) {
g2D = (Graphics2D) g;
g2D.setStroke(new BasicStroke(1));
g2D.setPaint(Color.blue);
g2D.drawLine(5, 5, 445,5);
g2D.drawLine(445, 5, 445,195);
g2D.drawLine(445, 195, 5,195);
g2D.drawLine(5, 195, 5,5);
}
}
Oracle 有一个有用的教程,Creating a GUI With Swing。跳过 Netbeans 部分。
这是“读取文件”之前修改后的 GUI。
这是“读取文件”后修改后的 GUI。
我创建了一个应用程序模型来保存线段。这个模型传给绘图JPanel
,这样就可以在绘图JPanel
.
paintComponent
方法中绘制线段了
我清理了你的 GUI。我使用 Swing layout managers 创建了 GUI。我将 JPanels
的创建与 JFrame
的创建分开,以便人们更容易阅读和理解代码。
这是完整的可运行代码。我在 类 内部制作了额外的 类 这样我就可以 post 将这段代码作为一个块。
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
public class ExampleDrawingGUI {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new ExampleDrawingGUI().new MyFrame());
}
public class MyFrame extends JFrame {
private static final long serialVersionUID = 1L;
private ExampleDrawingModel model;
JTextComponent tc;
MyPanel p1;
public MyFrame() {
super("My Frame");
this.model = new ExampleDrawingModel();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setJMenuBar(createMenuBar());
p1 = new MyPanel(model);
this.add(p1, BorderLayout.CENTER);
this.add(createTextPanel(), BorderLayout.SOUTH);
this.pack();
this.setLocationByPlatform(true);
// this.setResizable(false);
this.setVisible(true);
}
private JMenuBar createMenuBar() {
JMenuBar mb = new JMenuBar();
JMenu fm = new JMenu("File");
JMenuItem loadItem = new JMenuItem("Load file");
loadItem.addActionListener(e -> {
tc.setText("loading" + "\n");
model.readFile();
p1.repaint();
});
fm.add(loadItem);
mb.add(fm);
return mb;
}
private JPanel createTextPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
tc = new JTextPane();
tc.setPreferredSize(new Dimension(450, 50));
JScrollPane sp = new JScrollPane(tc);
panel.add(sp, BorderLayout.CENTER);
return panel;
}
public void repaint() {
p1.repaint();
}
}
public class MyPanel extends JPanel {
private static final long serialVersionUID = 1L;
private ExampleDrawingModel model;
public MyPanel(ExampleDrawingModel model) {
this.model = model;
this.setPreferredSize(new Dimension(450, 200));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
paintBorder(g2D);
for (LineSegment line : model.getLines()) {
Point startPoint = line.getStartPoint();
Point endPoint = line.getEndPoint();
g2D.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
}
}
private void paintBorder(Graphics2D g2D) {
int margin = 5;
int x1 = margin;
int x2 = getWidth() - margin;
int y1 = margin;
int y2 = getHeight() - margin;
g2D.setStroke(new BasicStroke(3f));
g2D.setPaint(Color.blue);
g2D.drawLine(x1, y1, x1, y2);
g2D.drawLine(x1, y1, x2, y1);
g2D.drawLine(x2, y1, x2, y2);
g2D.drawLine(x1, y2, x2, y2);
}
}
public class ExampleDrawingModel {
private List<LineSegment> lines;
public ExampleDrawingModel() {
this.lines = new ArrayList<>();
}
public void readFile() {
this.lines.clear();
// Here's where you'd read a file and create a list of lines.
lines.add(new LineSegment(new Point(100, 100), new Point(100, 150)));
}
public List<LineSegment> getLines() {
return lines;
}
}
public class LineSegment {
private final Point startPoint, endPoint;
public LineSegment(Point startPoint, Point endPoint) {
this.startPoint = startPoint;
this.endPoint = endPoint;
}
public Point getStartPoint() {
return startPoint;
}
public Point getEndPoint() {
return endPoint;
}
}
}
首先,您的代码存在一些问题:
class MyFrame extends JFrame {
//....
MyFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null); // !! Good God, no don't do this!
this.setBounds(0, 0, 464, 312); // and don't do this
像瘟疫一样避免空布局和 setBounds,因为这会导致 GUI 非常不灵活,虽然它们在一个平台上看起来不错,但在大多数其他平台或屏幕分辨率上看起来很糟糕,而且很难更新和维护。相反,您需要研究和学习布局管理器,然后嵌套 JPanel,每个 JPanel 都使用自己的布局管理器来创建令人愉悦且复杂的 GUI,这些 GUI 在所有 OS 上看起来都不错。
此外,不要忘记在 添加组件之后和设置可见之前对 JFrame 调用 pack()
,以便布局管理器执行他们的操作。
然后:
class MyPanel extends JPanel {
// ...
Graphics2D g2D; //!! -- no, don't do this
如果您创建一个 Graphics 或 Graphics2D 字段,您很想在绘画方法之外使用它,这是灾难的根源,因为从组件获得的任何 Graphics 都是短暂的,并且这样做有创建脆弱的风险图形或抛出 NullPointerException
public void paint (Graphics g) {
g2D = (Graphics2D) g;
g2D.setStroke(new BasicStroke(1));
g2D.setPaint(Color.blue);
g2D.drawLine(5, 5, 445,5);
g2D.drawLine(445, 5, 445,195);
g2D.drawLine(445, 195, 5,195);
g2D.drawLine(5, 195, 5,5);
}
不要重写 paint 而是重写 paintComponent,因为这风险较小(paint 有更大的责任,你不想搞砸)并且如果需要的话动画更流畅,因为 paintComponent 默认使用双缓冲。
此外,您几乎总是 应该在您自己的重写中调用 super 的绘画方法,因此改为:
@Override
protected void paintComponent(Graphics g) {
// first call the super's method:
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g.create();
现在关于您的实际问题,即在呈现 GUI 之后创建图像和绘图,可能最简单的方法是创建一个 BufferedImage 并在您的 GUI 中使用它绘制。您可以通过调用 Graphics 方法 drawImage(...)
轻松完成此操作。您可以在需要时随时将 BufferedImage 传递到您的绘图 JPanel 中。例如,您的代码可能类似于...
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Foo {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MainPanel mainPanel = new MainPanel();
MyMenu myMenu = new MyMenu();
myMenu.setMyPanel(mainPanel.getMyPanel());
myMenu.setMainPanel(mainPanel);
frame.add(mainPanel);
frame.setJMenuBar(myMenu);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
class MainPanel extends JPanel {
private static final int GAP = 5;
private JTextArea textArea = new JTextArea(4, 40);
private MyPanel myPanel = new MyPanel();
public MainPanel() {
textArea.setFocusable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BorderLayout(GAP, GAP));
add(myPanel);
add(scrollPane, BorderLayout.PAGE_END);
}
public MyPanel getMyPanel() {
return myPanel;
}
public void appendTextAreaText(String text) {
textArea.append(text);
}
public void setBuffImg(BufferedImage bImage) {
myPanel.setBuffImg(bImage);
}
}
class MyMenu extends JMenuBar {
private MainPanel mainPanel;
private MyPanel myPanel;
public MyMenu() {
JMenu fm = new JMenu("File");
JMenuItem loadItem = new JMenuItem("Load file");
loadItem.addActionListener(e -> {
// Emulate reading file here in a background thread
if (myPanel != null) {
int width = MyPanel.MY_WIDTH;
int height = MyPanel.MY_HEIGHT;
BufferedImage bImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = bImg.createGraphics();
// draw with g2 here using data from file
// emulating this:
g2.setColor(Color.RED);
float strokeWidth = (float) (2 + 6 * Math.random());
g2.setStroke(new BasicStroke(strokeWidth));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int x2 = (int) (MyPanel.MY_WIDTH * (1 + Math.random()) / 2);
int y2 = (int) (MyPanel.MY_HEIGHT * (1 + Math.random()) / 2);
g2.drawLine(5, 5, x2, y2);
g2.dispose();
myPanel.setBuffImg(bImg);
if (mainPanel != null) {
mainPanel.appendTextAreaText("adding image \n");
}
}
});
fm.add(loadItem);
add(fm);
}
public void setMyPanel(MyPanel myPanel) {
this.myPanel = myPanel;
}
public void setMainPanel(MainPanel mainPanel) {
this.mainPanel = mainPanel;
}
}
class MyPanel extends JPanel {
private static final int GAP = 5;
public static final int MY_WIDTH = 450;
public static final int MY_HEIGHT = 200;
private BufferedImage bImg = null;
// Graphics2D g2D; //!! -- no, never do this!!
MyPanel() {
// this.setPreferredSize(new Dimension(450, 200));
setBackground(Color.WHITE);
}
// better to override getPreferredSize
@Override
public Dimension getPreferredSize() {
return new Dimension(MY_WIDTH + 2 * GAP, MY_HEIGHT + 2 * GAP);
}
public void setBuffImg(BufferedImage bImg) {
this.bImg = bImg;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
// first call the super's method:
super.paintComponent(g);
if (bImg != null) {
g.drawImage(bImg, GAP, GAP, null);
}
Graphics2D g2D = (Graphics2D) g.create();
g2D.setStroke(new BasicStroke(1));
g2D.setPaint(Color.blue);
Rectangle rect = new Rectangle(GAP, GAP, getWidth() - 2 * GAP, getHeight() - 2 * GAP);
g2D.draw(rect);
}
// Don't override paint but rather paintComponent
// public void paint (Graphics g) {
}