Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should dynamic colors in SWT be allocated and disposed?

Tags:

java

colors

swt

I sometimes need to generate colors dynamically in SWT. Take an example of a view that displays scores between 0-1 in different colors from red-green. There may be other similar views with different colors:

class ScoreView {
    private Canvas canvas;
    private List<Item> items = new ArrayList<Item>();

    public ScoreView(Composite parent) {
        canvas = new Canvas(parent, SWT.NONE);

        canvas.addPaintListener(new PaintListener() {
            public void paintControl(PaintEvent event) {
                GC gc = event.gc;

                int x = 0;
                for(Item item:items) {
                    int shade = (int)(item.getScore() * 255.0);

                    Color color = new Color(Display.getCurrent(), shade, 255-shade, 0);
                    gc.setBackground(color);
                    gc.fillRectangle(x, 0, 50, 50);
                    x += 50;
                }
            }
        });
    }

    public void setItems(List<Item> items) {
        this.items = items;
        canvas.redraw();
    }
}

In SWT, you should always free resources. From http://www.eclipse.org/articles/Article-SWT-Color-Model/swt-color-model.htm:

Colors contain OS resources that must be allocated and freed. For this reason, it is necessary to dispose every color that you have created.

So what's the best way to dispose of the colors?

From http://www.eclipse.org/articles/swt-design-2/swt-design-2.html:

If you are using graphics resources in a widget - for example, widget.setFont(font) - it is often best to clean these up when the widget they are used in is disposed, so you can hook a dispose listener on the widget...

So I can keep track of every color I've allocated and dispose them in a DisposeListener on the canvas or the shell. But from the same link:

The operating system frees all of a program's resources when the program exits. Why not just rely on this? Operating system resources are not infinite. If your program doesn't free up resources as they are no longer needed, it can run out of resources. It can also cause other programs to run out of resources. So waiting until the program exits to free up resources is generally a bad idea.

It looks like I haven't gained anything because even though the colors are disposed, they would have been disposed anyway on exit (the view lasts the lifetime of the program).

I take it I can't dispose of colors directly in the PaintListener because they are still being used by the GC while they are being shown, so would I have to remember what colors are being used and dispose them in the next paint call if they haven't been used again in that call?

If I manage that, there's still another problem if there are only a few colors available. Because of the order that colors are allocated in, I could render many shades of red, then run out of colors, and not be able to display any shade of green. So in that case, would it be better to pre-allocate a range of colors that I might need at the beginning of the program (like a palette)? How many should I allocate and in what order? That would mean never disposing of these colors.

Also, is there any way to know how many colors are available at any time? Do other running programs take away the number of colors available?

like image 570
fgb Avatar asked Jan 16 '23 00:01

fgb


1 Answers

Eclipse RCP handles this through the global ColorRegistry.

By using it, you avoid resource pre-allocation on application startup. When you need a resource, you query the global registry for it. If it's not available, you allocate and register it with the global registry.

private static final String SHADE = "shadedcolor";

Color color = null;
if (!JFaceResources.getColorRegistry().hasValueFor(SHADE)) {
    color = new Color(Display.getCurrent(), shade, 255-shade, 0);
    JFaceResources.getColorRegistry().put(SHADE, color);
} else {
    color = JFaceResources.getColorRegistry().get(SHADE);
}

The resource will be deallocated on application exit.

like image 111
tkotisis Avatar answered Jan 28 '23 14:01

tkotisis