当前位置: 首页 > 面试题库 >

使用线程在Java中绘制面板

冯枫
2023-03-14
问题内容

我正在编写一个具有许多不同视图的程序。其中之一是图形密集型(显示互连的图形)。其他人只显示较小但复杂的图表。

我发现主视图的绘制时间很长(甚至只是绘制当前可见的区域),并且在绘制时,界面的其余部分变得很慢。

我的问题是,我可以创建一个新线程来处理绘画吗?如果是这样,是否会导致性能提高,我怀疑它不会。我尝试了以下方法:

创建一个抽象类ThreadPaintablePanel,我的复杂视图将继承该类。

public abstract class ThreadPaintablePanel extends JPanel{
 private Thread painter;
 public abstract void paintThread(Graphics g);

 protected void callPaintThread(Graphics g){
   if(painter != null){
     painter.interrupt();
   }
   painter = new Thread(new PaintRunnable(this, g));
   painter.start();
 }
}

在我的复杂观点中,我的paintComponent方法很简单:super.callPaintThread(g);

被覆盖的paintThread方法包含我所有的绘画代码。但是,这导致未上漆的面板。我是否错过了明显的事情?

谢谢


问题答案:

除了事件分发线程(EDT),您不能让任何线程接触GUI。让其他线程与GUI混乱会导致麻烦和异常。您可以采用多线程多缓冲技术。它涉及两个步骤:

  1. 为了并行化复杂的绘制例程,您可以简单地将整个“视图”划分为小块,然后让一个线程将一个小块绘制为一张图像。这是有关使用Java处理图像的教程。

  2. 获得图像后,可以通过将相应补丁的图像拼接在一起,来覆盖paintComponent并使用Graphics.drawImage方法让EDT显示完整视图或部分视图。

为了避免不必要的工作,请确保先执行第一步,然后再更改视图后再html" target="_blank">执行,否则只需再次绘制先前计算的结果即可。此外,如果可以缩小视图内部在框架之间更改的区域的范围,请尝试仅更新部分补丁。

让我们假设您的视图至少与最佳线程数一样高,因此我们可以垂直划分视图。另外,我们假设绘制任何像素所需的工作量与其他像素差不多,因此我们可以为每个色块使用相同的大小。这两个假设使事情变得容易得多。

代码如下。如果您不需要计算机执行任何其他操作,则可以设置nThreads内核数。请注意,该代码还将伪代码用于“ parallel
for”,在此处进行了说明:

// let multiple threads write all patches
public BufferedImage[] writePatches(...)
{
    // Given data:
    const int nThreads = ...;         // the amount of threads that you want
    Rectangle viewBox = ...;        // The view rectangle

    // Immediate data:
    Dimension viewSize = viewBox.getSize();
    int defaultPatchHeight = (int)ceil((float)viewSize.height / nThreads);
    int lastPatchHeight = viewSize.height - (nThreads-1) * defaultPatchHeight;

    // The actual "buffer" is a set of images
    BufferedImage[] images = new BufferedImage[nThreads];

    // ...

    // pseudocode for parallel processing of a for loop
    parallel-for (nThreads, threadId)
    {
        // the starting point and size of this thread's patch
        // handle boundary (last) patch
        int w = viewBox.width;
        int h = threadId == nThread-1 ? lastPatchHeight : defaultPatchHeight;                
        int x = viewBox.x;
        int y = viewBox.y + threadId * defaultPatchHeight;

        BufferedImage patch = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = off_Image.createGraphics();

        // use g to draw to patch image here
        // better yet: Re-use existing patches and only update the parts that changed.

        images[threadId] = patch;
    }
    return images;
}

// ...

// override paintComponent
@Override
void paintComponent(Graphics gg)
{
    Graphics2D g = (Graphics2D) gg;
    // ...

    // stitch all images together (you can also just display only some images here)
    for (int threadId = 0; threadId < nThreads; ++threadId)
    {
        int w = viewBox.width;
        int h = threadId == nThread-1 ? lastPatchHeight : defaultPatchHeight;                
        int x = viewBox.x;
        int y = viewBox.y + threadId * defaultPatchHeight;

        // use pre-computed images here
        BufferedImage patch = images[threadId];
        g.drawImage(patch, x, y, ...);
    }
}


 类似资料:
  • 所以我在只用线绘制形状时遇到了一个大问题。假设我从屏幕中间的一个点开始画一条线,然后以100个像素的距离向前画,角度为0,然后我用角度72度画另一条相同长度的线,以此类推,直到360度。它应该给我一个完美的五边形,一条线结束,另一条线从那个点开始,但是线在末端不相交,它非常适合角度为0/90/180/270的正方形,但我需要让它适用于每个形状,甚至是圆。我用这个东西来计算: 其中_cosinuse

  • 问题内容: 我正在用Piccolo编写一个交互式applet,并且需要在其中包含高斯曲线(又称正态分布图)。 我想象任何一种Java实现都足够,但是我找不到。理想情况下,我想传递一组值并将图表绘制在面板,图像对象或可以嵌入在applet中的任何对象中。 在让我自己动手编写代码之前,有人知道做这件事的有用代码吗? 欢迎使用其他语言的实现,只要它们易于移植到Java中即可。 问题答案: 不知道它是否有

  • 问题内容: 我正在尝试用Java绘制曲线。一个简单的以(X,Y)开始,(X,Y)结束和曲线量的贝塞尔曲线就足够了。 我找不到在Swing中执行此操作的方法。如果不在Swing中,我可以使用一些简单的数学方法吗?我将如何在Swing中实现它? 编辑:我知道如何通过重写paint(Graphics g)方法绘制形状和线条。 问题答案: 您可以使用Java 2D Object Path2D.Double

  • 问题内容: 我已经使用样条插值法来平滑时间序列,并且还想在绘图中添加一条水平线。但是似乎有一个我无法控制的问题。任何帮助都会非常有帮助。这是我所拥有的: 问题似乎与我对水平线图的使用有关。 问题答案: 您是正确的,我认为这使您失望。您将要重用原始的x轴变量,并使用另一个包含变量的相同长度的numpy数组对其进行绘制。 希望可以解决问题!

  • 我使用样条插值来平滑时间序列,还想在图中添加一条水平线。但是似乎有一个问题超出了我的控制范围。任何帮助都会很有帮助。这是我所拥有的: 问题似乎在于我使用进行水平线绘制。

  • 问题内容: 我试图在bufferedimage上绘制水平和垂直线。它最终应该看起来像一个网格单元。但是,当我运行代码时,我只看到两行:最左边的行和最上面的行(即,从0,0到0,图像的高度和从0,0到图像的宽度,0的一行),这里是代码段: 和覆盖的绘制方法: 所有这些都在扩展了JPanel的名为RobotMaze的类中。任何帮助表示赞赏。 问题答案: