Using threads to paint panel in java
我正在编写一个包含许多不同视图的程序。 其中一个是相当图形密集型(它显示一个互连的图形)。 其他人只是展示小而复杂的图表。
我发现主视图的绘制时间很长(甚至只绘制当前可见的区域),并且在绘制时,界面的其余部分变得非常慢。
我的问题是,我可以创建一个新线程来处理绘画 - 如果是这样,它会导致性能提升,我怀疑它不会。 我尝试过以下方法:
创建一个抽象类ThreadPaintablePanel,我的复杂视图继承自。
1 2 3 4 5 6 7 8 9 10 11 12 |
然后在我复杂的视图中,我的
重写的
谢谢
你不能让任何线程,但事件发送线程(EDT)触摸GUI。让其他线程弄乱GUI会导致麻烦和异常。您可以使用多线程多缓冲技术。它涉及两个步骤:
为了并行化复杂的绘图例程,您可以简单地将整个"视图"划分为补丁,让一个线程将一个补丁绘制到一个图像中。这是一个使用Java处理图像的教程。
获得图像后,可以覆盖
为了避免不必要的工作,请确保最初执行第一步,然后仅在视图更改后执行,否则只需再次绘制先前计算的结果。此外,如果可以缩小视图内部在帧之间发生更改的区域,请尝试仅更新部分修补程序。
让我们假设您的视图至少与最佳线程数一样高,因此我们可以垂直分区视图。另外,让我们假设绘制任何像素所需的工作量与其他像素相同,因此我们可以为每个补丁使用相同的大小。这两个假设使事情变得容易多了。
代码如下。如果您不需要计算机执行任何其他操作,则可以将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | // 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, ...); } } |
我想你想要做的是绘制到非UI线程中的缓冲区(所以你管理的那个),并在完成时(在UI线程中)复制缓冲区。