Home » Eclipse Projects » Standard Widget Toolkit (SWT) » GC operations not propagated to viewport on OS X
GC operations not propagated to viewport on OS X [message #1058858] |
Wed, 15 May 2013 08:31  |
Eclipse User |
|
|
|
I'm developing an Eclipse plug-in on OS X Lion. It has a view with a live histogram and a slider beside it, which regulates the quantity visualized by the histogram. In technical detail, I've got a Scale and a Canvas in a ViewPart and I repeatedly paint the live histogram on the Canvas (from a scheduled task that uses Display#asyncExec). To improve performance I use a single instance of GC across all repaints. Everything works well until the user engages the Scale slider with a mouse-down: as long as the mouse is down, the Canvas is not getting updated at all.
If I use a new GC for each histogram update and dispose it at the end of the update, the Canvas refreshes properly, but in this case performance is severely hampered by the overhead of CG construction/disposal.
Is there an unspecified requirement to dispose the GC in order to guarantee its operations are flushed to the viewport?
Is there a way to keep both the performance and proper refreshing of the Canvas?
BTW On Windows this problem is not manifested.
|
|
| | |
Re: GC operations not propagated to viewport on OS X [message #1059052 is a reply to message #1059022] |
Thu, 16 May 2013 08:39   |
Eclipse User |
|
|
|
Yep there may be an issue of mac,but what i was suggesting should work there too.
i am suggesting on similar lines as below
import org.eclipse.swt.widgets.Composite;
public class UpdateCanvasSnippet extends Composite
{
class ScaleModel
{
private int value;
public ScaleModel(int value)
{
this.value = value;
}
public ScaleModel()
{
this.value = 20;
}
public int getValue()
{
return value;
}
}
private ScaleModel scaleModel = new ScaleModel();
/**
* Create the composite.
*
* @param parent
* @param style
*/
public UpdateCanvasSnippet(Composite parent, int style)
{
super(parent, style);
setLayout(new GridLayout(1, false));
final Scale scale = new Scale(this, SWT.NONE);
GridData gd_scale = new GridData(GridData.FILL_HORIZONTAL);
scale.setLayoutData(gd_scale);
scale.setMinimum(20);
scale.setMaximum(100);
final Canvas canvas = new Canvas(this, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
canvas.setLayoutData(new GridData(GridData.FILL_BOTH));
scale.addSelectionListener(new SelectionListener()
{
@Override
public void widgetSelected(SelectionEvent e)
{
final int selection = scale.getSelection();
Thread thread = new Thread(new Runnable()
{
@Override
public void run()
{
//Actual logic to calculate
scaleModel = new ScaleModel(selection);
Display.getDefault().syncExec(new Runnable()
{
@Override
public void run()
{
canvas.redraw();
}
});
}
});
thread.start();
}
@Override
public void widgetDefaultSelected(SelectionEvent e)
{
// TODO Auto-generated method stub
}
});
canvas.addPaintListener(new PaintListener()
{
@Override
public void paintControl(PaintEvent e)
{
e.gc.setLineWidth(5);
e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_RED));
e.gc.drawRectangle(e.width / 2 - scaleModel.getValue()/2,
e.height / 2 - scaleModel.getValue()/2, scaleModel.getValue(),
scaleModel.getValue());;
}
});
}
@Override
protected void checkSubclass()
{
// Disable the check that prevents subclassing of SWT components
}
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.DOUBLE_BUFFERED);
shell.setLayout(new FillLayout());
UpdateCanvasSnippet testSWTDesigner = new UpdateCanvasSnippet(shell, SWT.None);
shell.setSize(600, 400);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
you perform your operations and update a model which in turn is used by the paint even to draw. all you have to do is update the model and call canvas.redraw()
Note this call can be inside display.asyncExec too. like in your case you perform operations and update the model and call canvas.redraw inside display.syncExec or asyncExec as per your requirement.
EDIT: Updated the snippet as per your scenario.you can test this on mac,if this works then your code also should work.
[Updated on: Thu, 16 May 2013 10:33] by Moderator
|
|
|
Re: GC operations not propagated to viewport on OS X [message #1059130 is a reply to message #1059052] |
Thu, 16 May 2013 17:45   |
Eclipse User |
|
|
|
Thanks for the snippet; you beat me to it I have adapted it to better reflect my issues. I have added more canvases (i have more histograms like that), so the performance becomes more critical. The line in code that says "draw(gc)" is commented out; if we uncomment it and comment "canvas.redraw()" above it, we can compare the two behaviors. Indeed, on my Mac the canvas.redraw() technique works much better. In my real code I was using notifyListeners(SWT.Paint), which is worse than redraw. I am now working on the redraw technique.
import static java.lang.Math.sin;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.swt.layout.GridData.FILL_HORIZONTAL;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
public class UpdateCanvasSnippet extends Composite
{
static final Display display = new Display();
static final ScheduledExecutorService sched = newSingleThreadScheduledExecutor();
double phi, phase;
GC gc;
public UpdateCanvasSnippet(Composite parent, int style) {
super(parent, style);
setLayout(new GridLayout(1, false));
final Scale scale = new Scale(this, SWT.NONE);
final GridData gd_scale = new GridData(FILL_HORIZONTAL);
scale.setLayoutData(gd_scale);
scale.setMinimum(100);
scale.setMaximum(600);
final Canvas canvas = new Canvas(this, SWT.NONE);
gc = new GC(canvas);
canvas.setLayoutData(new GridData(GridData.FILL_BOTH));
sched.scheduleAtFixedRate(new Runnable() { public void run() {
display.asyncExec(new Runnable() { public void run() {
phi = System.currentTimeMillis();
if (!canvas.isDisposed())
canvas.redraw();
// draw(gc);
}});
}}, 0, 10, MILLISECONDS);
scale.addSelectionListener(new SelectionAdapter() {
@Override public void widgetSelected(SelectionEvent e) {
phase = scale.getSelection();
}
});
canvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) {
draw(e.gc);
}});
}
void draw(GC gc) {
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
final Rectangle area = gc.getClipping();
gc.fillRectangle(area);
for (int x = 0; x < area.width; x++)
gc.drawLine(x, 0, x, (int) (area.height/2 - 30*sin((phi/20-phase-x)/10d)));
}
public static void main(String[] args) throws InterruptedException {
final Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.DOUBLE_BUFFERED);
shell.setLayout(new GridLayout(3,false));
for (int i = 0; i < 9; i++) {
final Composite c = new UpdateCanvasSnippet(shell, SWT.None);
gridData().grab(true, true).applyTo(c);
}
shell.setSize(1000, 800);
shell.open();
while (!shell.isDisposed()) if (!display.readAndDispatch()) display.sleep();
sched.shutdown();
sched.awaitTermination(1, SECONDS);
display.dispose();
}
static GridDataFactory gridData() { return GridDataFactory.fillDefaults(); }
@Override protected void checkSubclass() { }
}
|
|
|
Re: GC operations not propagated to viewport on OS X [message #1059166 is a reply to message #1059130] |
Fri, 17 May 2013 02:06   |
Eclipse User |
|
|
|
A small change in your snippet and no performance issue should happen.
import static java.lang.Math.sin;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.swt.layout.GridData.FILL_HORIZONTAL;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
public class UpdateCanvasSnippet extends Composite
{
static final Display display = new Display();
static final ScheduledExecutorService sched = newSingleThreadScheduledExecutor();
double phi, phase;
GC gc;
public UpdateCanvasSnippet(Composite parent, int style)
{
super(parent, style);
setLayout(new GridLayout(1, false));
final Scale scale = new Scale(this, SWT.NONE);
final GridData gd_scale = new GridData(FILL_HORIZONTAL);
scale.setLayoutData(gd_scale);
scale.setMinimum(100);
scale.setMaximum(600);
final Canvas canvas = new Canvas(this, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
// gc = new GC(canvas);
canvas.setLayoutData(new GridData(GridData.FILL_BOTH));
sched.scheduleAtFixedRate(new Runnable()
{
public void run()
{
display.asyncExec(new Runnable()
{
public void run()
{
phi = System.currentTimeMillis();
if (!canvas.isDisposed())
canvas.redraw();
// draw(gc);
}
});
}
}, 0, 10, MILLISECONDS);
scale.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
phase = scale.getSelection();
}
});
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
draw(e.gc);
}
});
}
void draw(GC gc)
{
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
final Rectangle area = gc.getClipping();
gc.fillRectangle(area);
for (int x = 0; x < area.width; x++)
gc.drawLine(x, 0, x, (int) (area.height / 2 - 30 * sin((phi / 20 - phase - x) / 10d)));
}
public static void main(String[] args) throws InterruptedException
{
final Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.DOUBLE_BUFFERED);
shell.setLayout(new GridLayout(3, false));
for (int i = 0; i < 9; i++)
{
final Composite c = new UpdateCanvasSnippet(shell, SWT.None);
gridData().grab(true, true).applyTo(c);
}
shell.setSize(1000, 800);
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
sched.shutdown();
sched.awaitTermination(1, SECONDS);
display.dispose();
}
static GridDataFactory gridData()
{
return GridDataFactory.fillDefaults();
}
@Override
protected void checkSubclass()
{
}
}
just create the canvas using following styles
Canvas canvas = new Canvas(this, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
first one tells the canvas that you dont have your own background,second one tell it to draw on an image first and then draw it to the canvas.which increases the drawing performance.By the way this can be also done in the paint event by first drawing on an image and then drawing that to gc.
refer to canvas section and various others in the snippets page of SWT
http://www.eclipse.org/swt/snippets/
The issue here is not canvas.redraw or notifyListeners(SWT.Paint)(in your case this call was useless)
The issue is creating your own gc and drawing,all major paint operations should be performed in the paint event and only when it is unavoidable or a minor paint operation is required should you use the creating gc and drawing method.
many things are taken care of in the paint event, which would fail in GC method,in your case it is not visible due to periodic updates.
There can be some other ways to achieve this more efficiently like creating a GC using an empty image and drawing on it and on each paint event drawing the image on the canvas.but in this case finding the size of the image will be tricky.
|
|
| | |
Re: GC operations not propagated to viewport on OS X [message #1059225 is a reply to message #1059207] |
Fri, 17 May 2013 07:46   |
Eclipse User |
|
|
|
Thanks, I'll keep in mind to always study the complete inheritance chain of each component class that I'm working with.
The cause of my issues on Mac is demonstrated with the updated snippet below. Even with NO_BACKGROUND the entire Canvas is being cleared out with grey on each repaint. The key method that demonstrates this is drawRect, which draws a blue rectangle only on first invocation. The rectangle immediately disappears from the Canvas even though it is in the area unaffected by any other draw operations.
On my production app I have a lot of expensive-to-draw static content like meter scales, chart title, etc, which for performance reasons I must not redraw each time. If I rely on my own GC, the content is untouched, but whenever a repaint event comes in, everything is erased.
import static java.lang.Math.sin;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.swt.layout.GridData.FILL;
import static org.eclipse.swt.layout.GridData.FILL_HORIZONTAL;
// type imports elided
public class UpdateCanvasSnippet extends Composite
{
static final Display display = new Display();
static final ScheduledExecutorService sched = newSingleThreadScheduledExecutor();
double phi, phase;
boolean rectDrawn;
public UpdateCanvasSnippet(Composite parent, int style) {
super(parent, style);
setLayout(new GridLayout(1, false));
final Scale scale = new Scale(this, SWT.NONE);
final GridData gd_scale = new GridData(FILL_HORIZONTAL);
scale.setLayoutData(gd_scale);
scale.setMinimum(100);
scale.setMaximum(600);
final Canvas canvas = new Canvas(this, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
canvas.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
gridData().align(FILL, FILL).grab(true, true).applyTo(canvas);
sched.scheduleAtFixedRate(new Runnable() { public void run() {
display.asyncExec(new Runnable() { public void run() {
phi = System.currentTimeMillis();
if (!canvas.isDisposed())
canvas.redraw();
}});
}}, 0, 10, MILLISECONDS);
scale.addSelectionListener(new SelectionAdapter() {
@Override public void widgetSelected(SelectionEvent e) {
phase = scale.getSelection();
}
});
canvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) {
draw(e.gc);
}});
}
void drawRect(GC gc) {
if (rectDrawn) return;
gc.setForeground(display.getSystemColor(SWT.COLOR_BLUE));
final Rectangle area = gc.getClipping();
gc.drawRectangle(0, area.height-51, 50, 50);
rectDrawn = true;
}
void draw(GC gc) {
drawRect(gc);
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
final Rectangle area = gc.getClipping();
for (int x = 0; x < area.width; x++)
gc.drawLine(x, 0, x, (int) (area.height/2 - 30*sin((phi/20-phase-x)/10d)));
}
public static void main(String[] args) throws InterruptedException {
final Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.DOUBLE_BUFFERED);
shell.setLayout(new GridLayout(3,false));
for (int i = 0; i < 9; i++) {
final Composite c = new UpdateCanvasSnippet(shell, SWT.None);
gridData().grab(true, true).applyTo(c);
}
shell.setSize(1000, 800);
shell.open();
while (!shell.isDisposed()) if (!display.readAndDispatch()) display.sleep();
sched.shutdown();
sched.awaitTermination(1, SECONDS);
display.dispose();
}
static GridDataFactory gridData() { return GridDataFactory.fillDefaults(); }
@Override protected void checkSubclass() { }
}
|
|
|
Re: GC operations not propagated to viewport on OS X [message #1059242 is a reply to message #1059225] |
Fri, 17 May 2013 09:00   |
Eclipse User |
|
|
|
This is exactly where you will use GC method to draw the static content, the trick being you will create the GC using an empty image, you will draw whatever you want on this and on paint you will first draw this image and then your normal paint operations.
The above case only work when the static content is on non painted region.so you have to define a clipping region in which only
your dynamic content will be painted.
Another way is to draw the whole thing on an empty image and on paint event draw this image.
import static java.lang.Math.sin;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.swt.layout.GridData.FILL;
import static org.eclipse.swt.layout.GridData.FILL_HORIZONTAL;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
// type imports elided
public class UpdateCanvasSnippet extends Composite
{
static final Display display = new Display();
static final ScheduledExecutorService sched = newSingleThreadScheduledExecutor();
double phi, phase;
boolean rectDrawn;
Image drawable = null;
private Canvas canvas;
public UpdateCanvasSnippet(Composite parent, int style)
{
super(parent, style);
setLayout(new GridLayout(1, false));
final Scale scale = new Scale(this, SWT.NONE);
final GridData gd_scale = new GridData(FILL_HORIZONTAL);
scale.setLayoutData(gd_scale);
scale.setMinimum(100);
scale.setMaximum(600);
canvas = new Canvas(this, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
// canvas.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
gridData().align(FILL, FILL).grab(true, true).applyTo(canvas);
sched.scheduleAtFixedRate(new Runnable()
{
public void run()
{
display.asyncExec(new Runnable()
{
public void run()
{
phi = System.currentTimeMillis();
paintImage(canvas);
if (!canvas.isDisposed())
canvas.redraw();
}
});
}
}, 0, 10, MILLISECONDS);
scale.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
phase = scale.getSelection();
}
});
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
draw(e.gc);
}
});
}
private void paintImage(final Canvas canvas)
{
if (rectDrawn)
return;
if (drawable != null)
{
drawable.dispose();
}
if (!canvas.isDisposed())
{
drawable = new Image(display, canvas.getBounds().width, canvas.getBounds().height);
final GC gc = new GC(drawable);
drawRect(gc);
gc.dispose();
}
rectDrawn = true;
}
void drawRect(GC gc)
{
gc.setForeground(display.getSystemColor(SWT.COLOR_BLUE));
final Rectangle area = gc.getClipping();
gc.drawRectangle(0, area.height - 51, 50, 50);
}
void draw(GC gc)
{
if (drawable == null)
{
paintImage(canvas);
}
gc.drawImage(drawable, 0, 0);
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
final Rectangle area = gc.getClipping();
for (int x = 0; x < area.width; x++)
gc.drawLine(x, 0, x, (int) (area.height / 2 - 30 * sin((phi / 20 - phase - x) / 10d)));
}
public static void main(String[] args) throws InterruptedException
{
final Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.DOUBLE_BUFFERED);
shell.setLayout(new GridLayout(3, false));
for (int i = 0; i < 9; i++)
{
final Composite c = new UpdateCanvasSnippet(shell, SWT.None);
gridData().grab(true, true).applyTo(c);
}
shell.setSize(1000, 800);
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
sched.shutdown();
sched.awaitTermination(1, SECONDS);
display.dispose();
}
static GridDataFactory gridData()
{
return GridDataFactory.fillDefaults();
}
@Override
protected void checkSubclass()
{
}
}
Note:you have take lot of care about image and GC dispose, also resize events should accordingly compensated.
|
|
| | | |
Re: GC operations not propagated to viewport on OS X [message #1059448 is a reply to message #1059388] |
Sat, 18 May 2013 13:04   |
Eclipse User |
|
|
|
After reworkng my code, now I've got a problem on Windows: I redraw and update the parent composite which contains all histograms, but nothing happens. The documentation clearly states that the whole bounds of the control will be redrawn.
It only works if I redraw each individual histogram. I am trying to measure the refresh time in order to adapt the refresh rate to it, but if each histogram redraws on its own, I can't easily measure the time to redraw the whole window.
It was easy to reproduce this in our snippet. On Cocoa this works as expected.
import static java.lang.Math.sin;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.swt.layout.GridData.FILL;
public class UpdateCanvasSnippet extends Composite
{
static final Display display = new Display();
static final ScheduledExecutorService sched = newSingleThreadScheduledExecutor();
static double phi, phase;
boolean rectDrawn;
Image drawable;
private Canvas canvas;
public UpdateCanvasSnippet(Composite parent, int style)
{
super(parent, style);
setLayout(new GridLayout(1, false));
canvas = new Canvas(this, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
gridData().align(FILL, FILL).grab(true, true).applyTo(canvas);
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
draw(e.gc);
}
});
canvas.addListener(SWT.Resize, new Listener()
{
public void handleEvent(Event event)
{
paintImage();
}
});
}
void paintImage()
{
if (drawable != null)
drawable.dispose();
drawable = new Image(display, canvas.getBounds().width, canvas.getBounds().height);
final GC gc = new GC(drawable);
gc.setForeground(display.getSystemColor(SWT.COLOR_BLUE));
final Rectangle area = gc.getClipping();
gc.drawRectangle(0, area.height - 51, 50, 50);
gc.dispose();
}
void draw(GC gc)
{
if (drawable == null)
paintImage();
gc.drawImage(drawable, 0, 0);
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
final Rectangle area = gc.getClipping();
for (int x = 0; x < area.width; x++)
gc.drawLine(x, 0, x, (int) (area.height / 2 - 30 * sin((phi / 20 - phase - x) / 10d)));
}
public static void main(String[] args) throws InterruptedException
{
final Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.DOUBLE_BUFFERED);
shell.setLayout(new GridLayout(3, true));
final Scale scale = new Scale(shell, SWT.NONE);
gridData().align(GridData.FILL, GridData.FILL).applyTo(scale);
scale.setMinimum(100);
scale.setMaximum(200);
scale.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
phase = scale.getSelection();
}
});
for (int i = 0; i < 8; i++)
{
final Composite c = new UpdateCanvasSnippet(shell, SWT.None);
gridData().grab(true, true).applyTo(c);
}
sched.scheduleAtFixedRate(new Runnable()
{
public void run()
{
display.asyncExec(new Runnable()
{
public void run()
{
if (shell.isDisposed())
return;
phi = System.currentTimeMillis();
shell.redraw();
shell.update();
}
});
}
}, 0, 10, MILLISECONDS);
shell.setSize(1000, 800);
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
sched.shutdown();
sched.awaitTermination(1, SECONDS);
display.dispose();
}
static GridDataFactory gridData()
{
return GridDataFactory.fillDefaults();
}
@Override
protected void checkSubclass()
{
}
}
|
|
|
Re: GC operations not propagated to viewport on OS X [message #1059641 is a reply to message #1059448] |
Tue, 21 May 2013 01:17   |
Eclipse User |
|
|
|
I dont think refresh call will propagate to children,i may be wrong.
mean while you can do this.
import static java.lang.Math.sin;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.swt.layout.GridData.FILL;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
public class UpdateCanvasSnippet extends Composite
{
static final Display display = new Display();
static final ScheduledExecutorService sched = newSingleThreadScheduledExecutor();
static double phi, phase;
boolean rectDrawn;
Image drawable;
private Canvas canvas;
public UpdateCanvasSnippet(Composite parent, int style)
{
super(parent, style);
parent.addPaintListener(new PaintListener()
{
@Override
public void paintControl(PaintEvent e)
{
canvas.redraw();
}
});
setLayout(new GridLayout(1, false));
canvas = new Canvas(this, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
gridData().align(FILL, FILL).grab(true, true).applyTo(canvas);
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
draw(e.gc);
}
});
canvas.addListener(SWT.Resize, new Listener()
{
public void handleEvent(Event event)
{
paintImage();
}
});
}
void paintImage()
{
if (drawable != null)
drawable.dispose();
drawable = new Image(display, canvas.getBounds().width, canvas.getBounds().height);
final GC gc = new GC(drawable);
gc.setForeground(display.getSystemColor(SWT.COLOR_BLUE));
final Rectangle area = gc.getClipping();
gc.drawRectangle(0, area.height - 51, 50, 50);
gc.dispose();
}
void draw(GC gc)
{
if (drawable == null)
paintImage();
gc.drawImage(drawable, 0, 0);
gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
final Rectangle area = gc.getClipping();
for (int x = 0; x < area.width; x++)
gc.drawLine(x, 0, x, (int) (area.height / 2 - 30 * sin((phi / 20 - phase - x) / 10d)));
}
public static void main(String[] args) throws InterruptedException
{
final Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new GridLayout(3, true));
final Scale scale = new Scale(shell, SWT.NONE);
gridData().align(GridData.FILL, GridData.FILL).applyTo(scale);
scale.setMinimum(100);
scale.setMaximum(200);
scale.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
phase = scale.getSelection();
}
});
for (int i = 0; i < 8; i++)
{
final Composite c = new UpdateCanvasSnippet(shell, SWT.None);
gridData().grab(true, true).applyTo(c);
}
sched.scheduleAtFixedRate(new Runnable()
{
public void run()
{
display.asyncExec(new Runnable()
{
public void run()
{
if (shell.isDisposed())
return;
phi = System.currentTimeMillis();
shell.redraw();
}
});
}
}, 0, 10, MILLISECONDS);
shell.setSize(1000, 800);
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
sched.shutdown();
sched.awaitTermination(1, SECONDS);
display.dispose();
}
static GridDataFactory gridData()
{
return GridDataFactory.fillDefaults();
}
@Override
protected void checkSubclass()
{
}
}
Also explore Draw2D and GEF,that may solve lots of your problems, instead of extensive custom drawing.
[Updated on: Tue, 21 May 2013 01:22] by Moderator
|
|
|
Re: GC operations not propagated to viewport on OS X [message #1060064 is a reply to message #1059641] |
Wed, 22 May 2013 15:37  |
Eclipse User |
|
|
|
I see: catch a paint request and issue a redraw on children. In the meantime I found out that the other overload, namely redraw(int, int, int, int, boolean), does cascade to the children, but is awkward to use because the canvas bounds must be calculated just to pass the "obvious" values which the simple redraw() assumes.
I will take your suggestion to study higher-level APIs seriousy; I do think I'm working at a too low level right now.
Thank you for all the help.
|
|
|
Goto Forum:
Current Time: Wed Jul 23 07:42:57 EDT 2025
Powered by FUDForum. Page generated in 0.31207 seconds
|