You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SWT Canvas绘制多矩形触发Graphic is disposed错误排查求助

SWT "Graphic is disposed" Error When Drawing Multiple Rectangles on Canvas

Let's break down why you're hitting this error and fix it step by step:

Root Causes of the Error

Looking at your error stack trace and code, there are three critical issues causing the Graphic is disposed exception:

  1. You're manually disposing the framework-managed GC
    In every paintControl method, you call e.gc.dispose(). The GC passed via PaintEvent is created and owned by the SWT framework—you never need to dispose it yourself. When you do, the framework tries to use this already-released GC later, triggering the disposed error.

  2. You're adding duplicate PaintListeners and disposing the Canvas
    Your timer task adds a new PaintListener to canvas2 every second, and inside each listener you call canvas2.dispose(). Once canvas2 is disposed, any subsequent paint events (triggered by the framework or your code) will try to access a destroyed component, leading to errors.

  3. Inefficient and error-prone drawing logic
    Adding new listeners for each rectangle is not how SWT drawing works. You should maintain a collection of drawing data, then render all elements in a single listener when a redraw is triggered.

Fixed Code Implementation

Here's how to adjust your code to resolve these issues:

First, add an inner class to store rectangle data (position, size, color) and a list to track all rectangles you want to draw:

public class MainWindow implements Runnable {
    // Inner class to hold rectangle drawing details
    private static class RectangleInfo {
        int x;
        int y;
        int width;
        int height;
        Color color;

        public RectangleInfo(int x, int y, int width, int height, Color color) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.color = color;
        }
    }

    private List<RectangleInfo> rectangles = new ArrayList<>();
    // ... rest of your class variables

Next, update your canvas2 PaintListener to render all rectangles from the list (only add this listener once, not in the timer):

canvas2.addPaintListener(new PaintListener() {
    public void paintControl(PaintEvent e) {
        // Render every rectangle in our list
        for (RectangleInfo rect : rectangles) {
            e.gc.setBackground(rect.color);
            e.gc.fillRectangle(rect.x, rect.y, rect.width, rect.height); // Fill the rectangle
            e.gc.setForeground(rect.color);
            e.gc.drawRectangle(rect.x, rect.y, rect.width, rect.height); // Draw border (optional)
        }
        // DO NOT call e.gc.dispose() here!
    }
});

Then, rewrite your timer runnable to add rectangle data to the list and trigger a redraw, instead of adding new listeners:

final Runnable run = new Runnable() {
    private int counter = 0;
    @Override
    public void run() {
        // Move the image
        lblNewLabel.setLocation(lblNewLabel.getLocation().x + 1, lblNewLabel.getLocation().y);
        // Update composite_1 size
        composite_1.setSize(composite_1.getSize().x + 1, 282);
        composite_1.setBackground(green);

        int random = (int) (Math.random() * 10);
        Color rectColor = red; // Default color

        switch (random) {
            case 0:
                rectColor = red;
                break;
            case 1:
                rectColor = gray;
                break;
            case 2:
                rectColor = darkBlue;
                break;
            default:
                // Skip drawing for other random values
                display.timerExec(1000, this);
                return;
        }

        // Add new rectangle data to our list
        rectangles.add(new RectangleInfo(composite_1.getSize().x, 0, 5, 15, rectColor));
        // Trigger canvas2 to redraw with the new rectangle
        canvas2.redraw();

        System.out.print(random);
        display.timerExec(1000, this);
    }
};

Finally, remove the unnecessary redrawCanvas method (it disposes a GC incorrectly) and all instances of e.gc.dispose() and canvas2.dispose() from your code.

Key SWT Drawing Best Practices

  • Never dispose the GC from PaintEvent: SWT manages this resource—let it handle cleanup.
  • Use a single PaintListener: Maintain drawing data in a collection, then render all elements in one place.
  • Trigger redraws with redraw(): Instead of adding new listeners, update your data and call redraw() to tell SWT to repaint the component.
  • Avoid disposing components while they're in use: Only dispose a component when you're completely done with it (e.g., when the shell closes).

内容的提问来源于stack exchange,提问作者Duseop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:07:17