views:

595

answers:

4
+4  Q: 

SWT and blinking

I need the ability to have a blinking (red, maybe more colors) background for rows in a TableViewer/TreeViewer. What are the best options?

There may be more than one row blinking, the blinking MUST be synchron and I need two blinking modes, fast and slow.

A: 

Have you tried implementing a Thread which will periodically update the backgroundcolor of the blinking rows and requests a redraw of the view?

Sven Lilienthal
So far I haven't tried anything, I'm looking for some inspiration of somebody who already did such a thing.
Mauli
+1  A: 

You should have a construction that resembles something like this:

LinkedList<Row> rows = new LinkedList<Row>();
Thread blinker = null;

public void start() {
    blinker = new Thread() {
        public void run() {
            while(!this.interrupted()) {
                try {
                    synchronized (rows) {
                        for (Row row : rows) {
                            row.setForegroundColor(color1);
                        }
                    }
                    Thread.sleep(500);
                    synchronized (rows) {
                        for (Row row : rows) {
                            row.setForegroundColor(color2);
                        }
                    }
                    Thread.sleep(500);
                } catch (InterruptException e) {
                    break;
                }
            }
        }
    };
    blinker.start();
}

public void stop() {
    if (blinker != null) {
        blinker.interrupt();
    }
}

public void add(Row row) {
    synchronized (rows) {
        if (!rows.contains(row)) {
            rows.add(row);
        }
    }
}

public void remove(Row row) {
    synchronized (rows) {
        rows.remove(row);
    }
}

When the Shell displays, it should call start(). When it disposes, call stop().

Note that I haven't actually tested this; it's some Javaish pseudocode. If you can't set the row color with the suggested setForegroundColor() above, you could perhaps introduce a widget and define a paint() event.

Paul Lammertsma
-1. JTables paint themselves with CellRenderers. And only when repaint is called. And Swing is not ThreadSafe: http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
z5h
and *you* didn't even read the question. This is not about JTables and not about Swing.
zedoo
The OP is referring to `TableViewer`, not `JTables`. Nobody spoke of Swing, SWT is being used here.
Paul Lammertsma
Sorry. SO won't let me change my vote unless your answer is changed. If you make an edit, I can remove my downvote.
z5h
I took your comment into consideration nonetheless, because I don't actually know how rows work in TableViewer. I know you can embed a widget. Thanks, z5h!
Paul Lammertsma
A: 

Howdy, this is a fast hack that shows the idea, improvable in many ways. I show the three classes doing the job. If you want I can provide an exported source plugin ready to install into your eclipse workbench tomorrow. Here are the core classes:

import java.util.TimerTask;

import org.eclipse.jface.resource.ColorDescriptor;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.ui.PlatformUI;

public class Blinker extends LabelProvider implements ITableLabelProvider, IColorProvider  {

    private final TableViewer viewer;


    public Blinker(TableViewer viewer){
     this.viewer = viewer;
    }

    // this is just a lousy way to store blink_on/blink_off...
    private byte state; 

    // there must be a better way to get a color...
    final static Color red = ColorDescriptor.createFrom(new RGB(255,0,0)).createColor(PlatformUI.getWorkbench().getDisplay());
    final static Color green = ColorDescriptor.createFrom(new RGB(0,255,0)).createColor(PlatformUI.getWorkbench().getDisplay());


    private final TimerTask task = new TimerTask(){
     @Override
     public void run() {
      state++;
      PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable(){
       public void run() {
        viewer.refresh();
       }
      });
     }
    };

    private Timer t;

    synchronized byte getState(){
     return state;
    }

    @Override
    public Image getColumnImage(Object element, int columnIndex) {
     return null;
    }

    @Override
    public String getColumnText(Object element, int columnIndex) {
     return ((Element) element).text;
    }

    @Override
    public Color getBackground(Object object) {
     Element element = (Element) object;
     if (element.isBlinking()){
      return getState() % 2 == 0 ? Blinker.red : Blinker.green;
     } else {
      return Blinker.green;
     }
    }

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


    public void start() {
     t = new Timer();
     t.schedule(task, 200, 1000);
    }

    public void stop() {
     t.cancel();
     t = null;
        }

}

This is a sample model class. Blink state is stored within the object, but you might want to improve this by using some sort of Adapter:

package com.example.blinker;

public class Element {

    private boolean blinking;
    public final String text;


    public Element(String string, boolean b) {
     this.text = string;
     this.blinking = b;
    }


    public synchronized boolean isBlinking(){
     return blinking;
    }


    public synchronized void setBlinking(boolean b){
     this.blinking = b;
    }


    public static final Element[] sampledata = new Element[] {
     new Element("Merkur", false),
     new Element("Venus", true),
     new Element("Erde", false),
     new Element("Mars", true),
     new Element("Jupiter", false),
     new Element("Saturn", true),
     new Element("Uranus", false),
     new Element("Neptun", true),
     new Element("Pluto", false),
    };

}

And finally a TableViewer embedded in a View, making use of the two above:

package com.example.blinker.views;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

import com.example.blinker.Blinker;
import com.example.blinker.Element;

public class SampleView extends ViewPart {

    public static final String ID = "com.example.blinker.views.SampleView";

    private TableViewer viewer;
    private Blinker blinker;

    class ViewContentProvider implements IStructuredContentProvider {
     public void inputChanged(Viewer v, Object oldInput, Object newInput) {}
     public void dispose() {}
     public Object[] getElements(Object parent) {
      return Element.sampledata;
     }
    }

    public void createPartControl(Composite parent) {
     viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
     viewer.setContentProvider(new ViewContentProvider());
     blinker = new Blinker(viewer);
     viewer.setLabelProvider(blinker);
     viewer.setInput(new Object());
     blinker.start();
    }

    public void setFocus() {
     viewer.getControl().setFocus();
    }

    public void dispose() {
     blinker.stop();
    }
}
zedoo
+1  A: 

I would do something similar to this. Update the elements that you need to change the colors for at a regular interval. At each update toggle the colors depending on how you want them to flash.

void scheduleColorChange(final Color colors[], final int startIndex, final int changeInterval)
{
  getDisplay().timerExec(changeInterval, new Runnable()
  {
    public void run()
    {
      Object[] elements = getColorChangingElements();
      setColorsForFlashingElements(elements, colors[index%colors.length]);
      getViewer().update(elements);
      scheduleColorChange(colors, startIndex+1, changeInterval)
    }
 });

}

and the have you label provider implement IColorProvider.

Kire Haglin
This allows for choosing which rows should be blinking and on an interval, which seems the most likely desire not all blinking just some. Clean and simple example my favorite of those provided.+ Provides for only updating those elements that blink rather than full refresh+ Uses display thread safe abstractionNote index should be startIndex in the code snippet provided I think
fisherja