Friday, April 16, 2010

SWT Table Images And Transparency

I recently came across a Windows platform issue using images inside an SWT table. A little research turned up this long-standing open SWT bug.

The problem results when you change the background color of a row in a table. I like to alternate colors on the rows in my tables, so I create a LabelProvide like this:


private class PortfolioViewLabelProvider extends LabelProvider implements ITableLabelProvider, ITableColorProvider {

@Override
public Color getBackground(Object element, int columnIndex) {
return null;
}

public Image getColumnImage(Object obj, int index) {
Image retImage = null;
return retImage;
}

public String getColumnText(Object obj, int index) {
String retVal = "";
return retVal;
}

@Override
public Color getForeground(Object element, int columnIndex) {
return null;
}
}


Of course, you would actually want to return some real values in those methods.

Using a JFace TableViewer allows the table to be decorated with the listener via the setLabelProvider method.

Under Linux, SWT uses GTK native widgets for table. An example of one of my tables looks like this:

Make sure your monitor is set up so you see each row is a different shade--the first row is a deep gray, and the second row is black.

The table looks fine and all of the images ( transparent png files ) are correctly displayed. Now look at the same application on Windows 7.

Notice the images have black backgrounds now which is the background of the table. The transparency mask in the png is ignored--annoying and ugly. Look closely at the circled area to see the problem.

Luckily, with a little help from old posts in that bug and some trial and error, I came up with an easy fix that works for Windows and Linux. Using the same label provider as above, we can get the row color during the SWT.EraseItem event and erase the area with the same color used for the row:


topPortfoliosViewer.getTable().addListener(SWT.EraseItem, new Listener() {
@Override
public void handleEvent(Event event) {
event.gc.setBackground(plp.getBackground(event.item.getData(), event.index));
event.gc.fillRectangle(event.getBounds());
}
});


And the result on Windows 7:

The result is how I want it. The images blend in correctly. I'm not sure what the real problem is here--is it Windows or Eclipse? Either way, the fix works for me, and I can continue on with development.

2 comments:

rohin said...

Could you please send me the code snippet of your SWT table, I am also doing something like this.
Also there is no feature to make header colorful in SWT ,then how are you doing this.
Plz reply!

Martin Heitz said...

Great article, solution works fine for me (Eclipse 3.8). Retrieval of the background color was slightly adjusted to "event.gc.setBackground(labelProvider.getBackground(event.item.getData()));"
because I am using a StyledCellLabelProvider.

Thank you and best regards from Black Forrest, Germany,
Martin Heitz