简体   繁体   English

Swing中的多线程渲染

[英]Multithreaded rendering in swing

I am just toying around with the idea of creating a multithreaded renderer in swing for my java2d games where each thread is responsible for rendering its own swingcomponent and came up with a simple program to try and and achieve this. 我只是想为我的java2d游戏在swing中创建一个多线程渲染器的想法,每个线程负责渲染自己的swingComponent,并提出了一个简单的程序来尝试并实现这一目标。

*I am aware that Thread.sleep is not the preferred method but it has worked without a hitch on my single-threaded renderings that use active rendering, I haven't tested with a swingtimer but to my knowledge Thread.sleep sleeps the calling thread so that cannot be the issue. *我知道Thread.sleep不是首选方法,但是它在使用主动渲染的单线程渲染上没有任何问题,我没有用swingtimer进行过测试,但据我所知Thread.sleep使调用线程休眠所以这不是问题。

( Problem ) The program creates four panels in four threads with a bouncing ball in each but only the first created thread ever does anything, the others are simply not started at all (verifiable with sysout in run methods). 问题 )该程序在四个线程中创建四个面板,每个线程中都有一个弹跳球,但是只有第一个创建的线程才能执行任何操作,其他线程根本无法启动(可以在run方法中使用sysout进行验证)。 So only one thread does the rendering, the others are never given a chance to run, the sysout: System.out.println("Ballbouncer: " + this + " running."); 因此,只有一个线程进行渲染,而其他线程则永远都没有机会运行,即sysout: System.out.println("Ballbouncer: " + this + " running."); confirms this and so does the visual (image added). 确认这一点,视觉效果(添加的图像)也一样。

BallBouncer (runnable) BallBouncer(可运行)

public class BallBouncer implements Runnable {
private ColoredPanel ballContainer;
private List<Ellipse2D.Double> balls;
public static final Random rnd = new Random();
private double speedX, speedY;

public BallBouncer(ColoredPanel container) {
    this.ballContainer = container;
    this.balls = new ArrayList<>();
    balls.add(container.getBall());
    this.speedX = 10 * rnd.nextDouble() - 5;
    this.speedY = 10 * rnd.nextDouble() - 5;
}

public BallBouncer(List<ColoredPanel> containers) {
    for (ColoredPanel p : containers) {
        new BallBouncer(p).run();
    }
}

@Override
public void run() {
    while (true) {
        System.out.println("Ballbouncer: " + this + " running.");
        moveBall();
        ballContainer.repaint();
        try {
            Thread.sleep(15);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private void moveBall() {
    for (Ellipse2D.Double ball : balls) {
        ball.x += speedX;
        ball.y += speedY;

        if (ball.x < 0
                || ball.x + ball.getWidth() > ballContainer.getWidth()) {
            speedX *= -1;
        }
        if (ball.y < 0
                || ball.y + ball.getHeight() > ballContainer.getHeight()) {
            speedY *= -1;
        }
    }


}

Container 容器

public class ColoredPanel extends JPanel {
private Ellipse2D.Double circle;

public ColoredPanel(Color color) {
    circle = new Ellipse2D.Double(0, 0, 10, 10);
    setBackground(color);
}

public Ellipse2D.Double getCircle() {
    return circle;
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();
    g2d.setColor(getBackground().darker());
    g2d.fill(circle);
}

@Override
@Transient
public Dimension getPreferredSize() {
    return new Dimension(400, 400);
}

public Double getBall() {
    return getCircle();
}

Main 主要

public class ColoredPanelContainer extends JPanel {

private List<ColoredPanel> panels = new ArrayList<>();

public ColoredPanelContainer() {
    setUpPanels();
    setBackground(Color.black);
}

private void setUpPanels() {
    for (int i = 0; i < 4; i++) {
        Color color = new Color(BallBouncer.rnd.nextInt(256),
                BallBouncer.rnd.nextInt(256), BallBouncer.rnd.nextInt(256));
        panels.add(new ColoredPanel(color));
    }
    for (int i = 0; i < 4; i++) {
        add(panels.get(i));
    }
}

@Override
@Transient
public Dimension getPreferredSize() {
    return new Dimension(1000, 1000);
}

public List<ColoredPanel> getPanels() {
    return panels;
}

public static void main(String[] args) {
    JFrame frame = new JFrame();
    ColoredPanelContainer container = new ColoredPanelContainer();
    frame.getContentPane().add(container);
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    new BallBouncer(container.getPanels());
}
}

Notice the ball only bouncing in the left panel (first started thread), the others are stationary at all times. 请注意,球仅在左侧面板上弹跳(第一个启动的线程),其他球始终保持静止。 在此处输入图片说明

You're doing this: 您正在执行此操作:

public BallBouncer(List<ColoredPanel> containers) {
    for (ColoredPanel p : containers) {
        new BallBouncer(p).run();
    }
}

Which is not the proper way to start a thread. 这不是启动线程的正确方法。 All you're doing is running the run method directly and sequentially . 您要做的就是直接并按顺序运行run方法。 That means that the code runs in that loop in the same thread that calls the constructor. 这意味着代码在调用构造函数的线程中在该循环中运行。

You should read this tutorial. 您应该阅读本教程。 It explains how to use threads in Swing. 它说明了如何在Swing中使用线程。 Namely, how to use javax.swing.SwingWorker and SwingUtilities.invoke* . 即,如何使用javax.swing.SwingWorkerSwingUtilities.invoke* There is also this tutorial , which explains how to use the Swing Timer class. 还有本教程 ,它说明了如何使用Swing Timer类。

And, just for further education about threads: Here are ways to start threads in java when you're not using swing . 并且,只是为了进一步了解线程: 以下是当您不使用swing时在Java中启动线程的方法 You do not want to use these examples when you're writing a Swing application 在编写Swing应用程序时,您不想使用这些示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM