使用Java Swing高效地重画线

使用Java Swing高效地重画线,java,swing,jpanel,Java,Swing,Jpanel,我试图找到创建动态java图形应用程序的最有效方法。我想构建一个大屏幕,包含许多不同的部分,所有这些部分都使用不同的线程重新绘制或更新,这样屏幕看起来“生动”。 然而,我最初尝试这样做是可怕的,屏幕变得非常慢,有bug等等-所以我想我需要创建不同的模块(JPanel),每个模块都包含其他图形部分(线、圆等),并且每个不同的JPanel分别被重绘(需要时),而不是整个主面板(或框架) 所以我写了一个小的演示程序-我的程序包含一个窗口,多个面板,包装在我的对象“MyPanel”中-每个这样的MyPa

我试图找到创建动态java图形应用程序的最有效方法。我想构建一个大屏幕,包含许多不同的部分,所有这些部分都使用不同的线程重新绘制或更新,这样屏幕看起来“生动”。 然而,我最初尝试这样做是可怕的,屏幕变得非常慢,有bug等等-所以我想我需要创建不同的模块(JPanel),每个模块都包含其他图形部分(线、圆等),并且每个不同的JPanel分别被重绘(需要时),而不是整个主面板(或框架)

所以我写了一个小的演示程序-我的程序包含一个窗口,多个面板,包装在我的对象“MyPanel”中-每个这样的MyPanel包含几条绘制的线(我有一个Line对象),所有线从左上角开始,具有不同的长度和角度)。每个不同的MyPanel都有不同的线条颜色(请参见此图)

我实例化了几个工作线程,每个线程指定用于一个MyPanel-工作线程等待5秒钟,然后尝试以以下方式重新绘制所有线条:

  • 从JPanel(MyPanel)中删除所有现有线路
  • 创建具有不同角度和长度的新线
  • 通过调用super.repaint()重新绘制JPanel(MyPanel)这就是全部目的,只更新此面板,让它用其所有子部分重新绘制自己,而不是整个程序
然而,一些奇怪的事情发生了:当面板被重新绘制时,每个面板都会以一种可能也包含所有其他MyPanel的方式重新绘制,或者以某种方式镜像主屏幕——这里到底发生了什么还不清楚。此外,面板的所有“背景不透明度”都消失了(请参见此图)

在附加代码之前,让我说它使用空的LayoutManager。我知道就效率、模块化等方面而言,这是一个很大的“禁忌”。然而,我没有选择,因为我需要快速创建一个非常复杂和精确的演示,这只是一个概念证明,所以现在,所有这些缺陷都可以忽略不计。我知道这在设计上很糟糕,这也伤害了我,但这是我能按时完成的唯一方法

下面是代码-发生了什么?并且如果不使用这种方法,我如何有效地重新绘制程序的不同部分?注意,我不能“用背景色重新绘制现有线条”,因为我的主程序中有背景图像

任何帮助都将不胜感激

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * Displays the main windows (this is the "JFrame" object).
 */
public class GUI extends JFrame
{
/**
 * A customized panel which contains several lines with different coordinates, all starting from
 * the top left corner of the panel with coordinates (1,1). The object contains a method which
 * removes all drawn lines from the panel, then redraws lines with different vectors.
 */
public static class MyPanel extends JPanel
{
    private List<Line> _lines;

    private Color _color;

    private int _facet;

    private int _numLines;

    public MyPanel(int facet, int numLines, Color color)
    {
        _facet = facet;
        _color = color;
        _numLines = numLines;
        _lines = new ArrayList<>();

        super.setLayout(null);
        createLines();
    }

    public void createLines()
    {
        for(Line line : _lines)
        {
            remove(line);
        }

        _lines.clear();

        Random r = new Random();

        for(int i = 0; i < _numLines; i++)
        {
            int lengthX = r.nextInt(_facet) + 1;
            int lengthY = r.nextInt(_facet) + 1;

            Line line = new Line(1, 1, 1 + lengthX, 1 + lengthY, 1, _color);

            line.setBounds(1, 1, 1 + lengthX, 1 + lengthY);
            super.add(line);

            _lines.add(line);
        }

        super.repaint();
    }
}

/**
 * Represents a line, drawn with antialiasing at a given start and end coordinates
 * and a given thickness.
 */
public static class Line extends JPanel
{
    private int _startX;
    private int _startY;
    private int _endX;
    private int _endY;

    private float _thickness;
    private Color _color;

    public Line(int startX, int startY, int endX, int endY, float thickness, Color color)
    {
        _startX = startX;
        _startY = startY;
        _endX = endX;
        _endY = endY;

        _thickness = thickness;
        _color = color;
    }

    public void paint(Graphics g)
    {
        Graphics2D g2d = (Graphics2D)g;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.setColor(_color);
        g2d.setStroke(new BasicStroke(_thickness));
        g2d.drawLine(_startX, _startY, _endX, _endY);
    }
}

/**
 * Stores all "MyPanel" panels of the GUI.
 * The "MyPanels" are rectangular panels containing lines of the same color
 * (different color across different panels).
 */
public List<MyPanel> panels;

public GUI()
{
    setSize(800, 800);
    setLayout(null);
    setTitle("Y U no work??");

    panels = new ArrayList<>();

    // The starting positions (x,y) of the "MyPanel"s. All panels are squares of
    // height = 300 and width = 300.
    int[][] coords = {{1, 1}, {100, 100}, {200, 100}, {50, 300}, {300, 300}, 
                      {0, 400}, {300, 400}, {350, 250}, {370, 390}};

    // The colors of the lines, drawn in the panels.
    Color[] colors = {Color.RED, Color.GREEN, Color.BLUE, Color.ORANGE, Color.CYAN,
                      Color.MAGENTA, Color.YELLOW, Color.PINK, Color.darkGray};


    for(int i = 0; i < colors.length; i++)
    {
        MyPanel panel = new MyPanel(300, 50, colors[i]);
        panel.setBackground(new Color(0, 0, 0, 0));
        // Set the *exact* start coordinates and width/height (null layout manager).
        panel.setBounds(coords[i][0], coords[i][1], 300, 300);
        add(panel);
        panels.add(panel);
    }
}

/**
 * A runnable used to instantiate a thread which waits for 5 seconds then redraws
 * the lines of a given "MyPanel".
 */
public static class Actioner implements Runnable
{
    private MyPanel _panel;

    public Actioner(MyPanel panel)
    {
        _panel = panel;
    }

    public void run()
    {
        while(true)
        {
            try
            {
                Thread.sleep(5000);
            }
            catch(Exception e) {}

            _panel.createLines();
        }
    }
}

public static void main(String[] args)
{
    GUI GUI = new GUI();

    EventQueue.invokeLater(() ->
    {
        GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GUI.setVisible(true);
    });

    // Create all operating threads (one per "MyPanel").
    for(MyPanel panel : GUI.panels)
    {
        new Thread(new Actioner(panel)).start();
    }
}
import java.awt.BasicStroke;
导入java.awt.Color;
导入java.awt.EventQueue;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.RenderingHints;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.Random;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
/**
*显示主窗口(这是“JFrame”对象)。
*/
公共类GUI扩展JFrame
{
/**
*一个自定义面板,其中包含多条具有不同坐标的线,所有线都从
*带有坐标(1,1)的面板左上角。该对象包含一个
*从面板中删除所有绘制的线,然后使用不同的矢量重新绘制线。
*/
公共静态类MyPanel扩展了JPanel
{
私有列表行;
私人色彩(u色),;
私人内部方面;
私人互联网;
公共MyPanel(整数面、整数线、彩色)
{
_小面=小面;
_颜色=颜色;
_numLines=numLines;
_行=新的ArrayList();
super.setLayout(空);
createLines();
}
公共void createLines()
{
对于(行:_行)
{
删除(行);
}
_行。清除();
随机r=新随机();
对于(int i=0;i<\u numLines;i++)
{
int lengthX=r.nextInt(_facet)+1;
int longlent=r.nextInt(_facet)+1;
线条=新线(1,1,1+长度,1+长度,1,_颜色);
线.立根(1,1,1+长度x,1+长度);
super.add(行);
_行。添加(行);
}
super.repaint();
}
}
/**
*表示在给定起点和终点坐标处使用抗锯齿绘制的线
*和给定的厚度。
*/
公共静态类行扩展了JPanel
{
私人int_startX;
私人国际机场;
私人互联网(endX);
私人国际;
专用浮子厚度;
私人色彩(u色),;
公共线(int startX、int startY、int endX、int endY、浮动厚度、颜色)
{
_startX=startX;
_startY=startY;
_endX=endX;
_endY=endY;
_厚度=厚度;
_颜色=颜色;
}
公共空间涂料(图g)
{
Graphics2D g2d=(Graphics2D)g;
g2d.setRenderingHint(renderingHits.KEY\u抗锯齿,renderingHits.VALUE\u抗锯齿\u开启);
g2d.setColor(_color);
g2d.设定行程(新基本行程(_厚度));
g2d.抽绳(_startX,_startY,_endX,_endY);
}
}
/**
*存储GUI的所有“MyPanel”面板。
*“MyPanels”是包含相同颜色线条的矩形面板
*(不同面板的颜色不同)。
*/
公开名单小组;
公共图形用户界面()
{
设置大小(800800);
setLayout(空);
片名(“你没有工作吗?”);
panels=newarraylist();
//“MyPanel”s的起始位置(x,y)。所有面板均为正方形
//高度=300,宽度=300。
int[][]coords={{1,1},{100100},{200100},{50300},{300300},
{0, 400}, {300, 400}, {350, 250}, {370, 390}};
//在面板中绘制的线条的颜色。
Color[]colors={Color.RED,Color.GREEN,Color.BLUE,Color.ORANGE,Color.CYAN,
Color.洋红,Color.YELLOW,Color.PINK,Color.darkGray};
for(int i=0;ipublic void paint(Graphics g)
{
    Graphics2D g2d = (Graphics2D)g;

    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g2d.setColor(_color);
    g2d.setStroke(new BasicStroke(_thickness));
    g2d.drawLine(_startX, _startY, _endX, _endY);
}
protected void paintComponent(Graphics g)
{
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g.create();

    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g2d.setColor(_color);
    g2d.setStroke(new BasicStroke(_thickness));
    g2d.drawLine(_startX, _startY, _endX, _endY);

    g2d.dispose();
}
panel.setBackground(new Color(0, 0, 0, 0));
panel.setOpaque(false);
public void run()
{
    while(true)
    {
        try
        {
            Thread.sleep(5000);
        }
        catch(Exception e) {}

        _panel.createLines();
    }
}