I am rendering a few charts and I would like to use threading to take advantage of my multiple cores to enhance performance. I am trying to thread the paintComponent function of JFreeChart's ChartPanel. I can get away with it because it renders the image as a buffered image. So I think I only need to be careful about the calls g2 on the swing thread. Here is the function:
Here is my attempt to thread it:PHP Code:/**
* Paints the component by drawing the chart to fill the entire component,
* but allowing for the insets (which will be non-zero if a border has been
* set for this component). To increase performance (at the expense of
* memory), an off-screen buffer image can be used.
*
* @param g the graphics device for drawing on.
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (this.chart == null) {
return;
}
Graphics2D g2 = (Graphics2D) g.create();
// first determine the size of the chart rendering area...
Dimension size = getSize();
Insets insets = getInsets();
Rectangle2D available = new Rectangle2D.Double(insets.left, insets.top,
size.getWidth() - insets.left - insets.right,
size.getHeight() - insets.top - insets.bottom);
// work out if scaling is required...
boolean scale = false;
double drawWidth = available.getWidth();
double drawHeight = available.getHeight();
this.scaleX = 1.0;
this.scaleY = 1.0;
if (drawWidth < this.minimumDrawWidth) {
this.scaleX = drawWidth / this.minimumDrawWidth;
drawWidth = this.minimumDrawWidth;
scale = true;
}
else if (drawWidth > this.maximumDrawWidth) {
this.scaleX = drawWidth / this.maximumDrawWidth;
drawWidth = this.maximumDrawWidth;
scale = true;
}
if (drawHeight < this.minimumDrawHeight) {
this.scaleY = drawHeight / this.minimumDrawHeight;
drawHeight = this.minimumDrawHeight;
scale = true;
}
else if (drawHeight > this.maximumDrawHeight) {
this.scaleY = drawHeight / this.maximumDrawHeight;
drawHeight = this.maximumDrawHeight;
scale = true;
}
Rectangle2D chartArea = new Rectangle2D.Double(0.0, 0.0, drawWidth,
drawHeight);
// are we using the chart buffer?
if (this.useBuffer) {
// do we need to resize the buffer?
if ((this.chartBuffer == null)
|| (this.chartBufferWidth != available.getWidth())
|| (this.chartBufferHeight != available.getHeight())) {
this.chartBufferWidth = (int) available.getWidth();
this.chartBufferHeight = (int) available.getHeight();
GraphicsConfiguration gc = g2.getDeviceConfiguration();
this.chartBuffer = gc.createCompatibleImage(
this.chartBufferWidth, this.chartBufferHeight,
Transparency.TRANSLUCENT);
this.refreshBuffer = true;
}
// do we need to redraw the buffer?
if (this.refreshBuffer) {
this.refreshBuffer = false; // clear the flag
Rectangle2D bufferArea = new Rectangle2D.Double(
0, 0, this.chartBufferWidth, this.chartBufferHeight);
Graphics2D bufferG2 = (Graphics2D)
this.chartBuffer.getGraphics();
Rectangle r = new Rectangle(0, 0, this.chartBufferWidth,
this.chartBufferHeight);
bufferG2.setPaint(getBackground());
bufferG2.fill(r);
if (scale) {
AffineTransform saved = bufferG2.getTransform();
AffineTransform st = AffineTransform.getScaleInstance(
this.scaleX, this.scaleY);
bufferG2.transform(st);
this.chart.draw(bufferG2, chartArea, this.anchor,
this.info);
bufferG2.setTransform(saved);
}
else {
this.chart.draw(bufferG2, bufferArea, this.anchor,
this.info);
}
}
// zap the buffer onto the panel...
g2.drawImage(this.chartBuffer, insets.left, insets.top, this);
}
// or redrawing the chart every time...
else {
AffineTransform saved = g2.getTransform();
g2.translate(insets.left, insets.top);
if (scale) {
AffineTransform st = AffineTransform.getScaleInstance(
this.scaleX, this.scaleY);
g2.transform(st);
}
this.chart.draw(g2, chartArea, this.anchor, this.info);
g2.setTransform(saved);
}
Iterator iterator = this.overlays.iterator();
while (iterator.hasNext()) {
Overlay overlay = (Overlay) iterator.next();
overlay.paintOverlay(g2, this);
}
// redraw the zoom rectangle (if present) - if useBuffer is false,
// we use XOR so we can XOR the rectangle away again without redrawing
// the chart
drawZoomRectangle(g2, !this.useBuffer);
g2.dispose();
this.anchor = null;
this.verticalTraceLine = null;
this.horizontalTraceLine = null;
}
The part that I modified is surrounded by and ...was supposed to produce bold text. However, when I run the application, the charts are blank. I can resize, click on them without crashing / errors, but no charts are drawn. Any idea what's wrong or the proper way to multi-thread the above function?PHP Code:[B] public void paintComponent(Graphics g)
{
final ChartPanel cpf = this;
final Graphics gf = g;
final Graphics2D g2 = (Graphics2D) g.create();
final GraphicsConfiguration gc = g2.getDeviceConfiguration();
initPanel(g);
if(this.useBuffer)
{
new Thread(new Runnable() {
public void run() {
cpf.paintComponen(gf, gc, g2);
}
}).start();
}
else this.paintComponen(g, gc, g2);
}
public void initPanel(Graphics g)
{
super.paintComponent(g);
}[/B]
/**
* Paints the component by drawing the chart to fill the entire component,
* but allowing for the insets (which will be non-zero if a border has been
* set for this component). To increase performance (at the expense of
* memory), an off-screen buffer image can be used.
*
* @param g the graphics device for drawing on.
*/
public void paintComponen(Graphics g, GraphicsConfiguration gc, Graphics2D g2) {
//super.paintComponent(gf);
if (this.chart == null) {
return;
}
// first determine the size of the chart rendering area...
Dimension size = getSize();
Insets insets = getInsets();
Rectangle2D available = new Rectangle2D.Double(insets.left, insets.top,
size.getWidth() - insets.left - insets.right,
size.getHeight() - insets.top - insets.bottom);
// work out if scaling is required...
boolean scale = false;
double drawWidth = available.getWidth();
double drawHeight = available.getHeight();
this.scaleX = 1.0;
this.scaleY = 1.0;
if (drawWidth < this.minimumDrawWidth) {
this.scaleX = drawWidth / this.minimumDrawWidth;
drawWidth = this.minimumDrawWidth;
scale = true;
}
else if (drawWidth > this.maximumDrawWidth) {
this.scaleX = drawWidth / this.maximumDrawWidth;
drawWidth = this.maximumDrawWidth;
scale = true;
}
if (drawHeight < this.minimumDrawHeight) {
this.scaleY = drawHeight / this.minimumDrawHeight;
drawHeight = this.minimumDrawHeight;
scale = true;
}
else if (drawHeight > this.maximumDrawHeight) {
this.scaleY = drawHeight / this.maximumDrawHeight;
drawHeight = this.maximumDrawHeight;
scale = true;
}
Rectangle2D chartArea = new Rectangle2D.Double(0.0, 0.0, drawWidth,
drawHeight);
// are we using the chart buffer?
if (this.useBuffer) {
// do we need to resize the buffer?
if ((this.chartBuffer == null)
|| (this.chartBufferWidth != available.getWidth())
|| (this.chartBufferHeight != available.getHeight())) {
this.chartBufferWidth = (int) available.getWidth();
this.chartBufferHeight = (int) available.getHeight();
this.chartBuffer = gc.createCompatibleImage(
this.chartBufferWidth, this.chartBufferHeight,
Transparency.TRANSLUCENT);
this.refreshBuffer = true;
}
// do we need to redraw the buffer?
if (this.refreshBuffer) {
this.refreshBuffer = false; // clear the flag
Rectangle2D bufferArea = new Rectangle2D.Double(
0, 0, this.chartBufferWidth, this.chartBufferHeight);
Graphics2D bufferG2 = (Graphics2D)
this.chartBuffer.getGraphics();
Rectangle r = new Rectangle(0, 0, this.chartBufferWidth,
this.chartBufferHeight);
bufferG2.setPaint(getBackground());
bufferG2.fill(r);
if (scale) {
AffineTransform saved = bufferG2.getTransform();
AffineTransform st = AffineTransform.getScaleInstance(
this.scaleX, this.scaleY);
bufferG2.transform(st);
this.chart.draw(bufferG2, chartArea, this.anchor,
this.info);
bufferG2.setTransform(saved);
}
else {
this.chart.draw(bufferG2, bufferArea, this.anchor,
this.info);
}
}
// zap the buffer onto the panel...
final Graphics2D g2f = g2;
final Image buffimgfin = this.chartBuffer;
final Insets insetsf = insets;
final ChartPanel thispanelfinal = this;
try {
[B]SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
g2f.drawImage(buffimgfin, insetsf.left, insetsf.top, thispanelfinal);
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}[/B]
}
// or redrawing the chart every time...
else {
AffineTransform saved = g2.getTransform();
g2.translate(insets.left, insets.top);
if (scale) {
AffineTransform st = AffineTransform.getScaleInstance(
this.scaleX, this.scaleY);
g2.transform(st);
}
this.chart.draw(g2, chartArea, this.anchor, this.info);
g2.setTransform(saved);
}
Iterator iterator = this.overlays.iterator();
while (iterator.hasNext()) {
Overlay overlay = (Overlay) iterator.next();
overlay.paintOverlay(g2, this);
}
// redraw the zoom rectangle (if present) - if useBuffer is false,
// we use XOR so we can XOR the rectangle away again without redrawing
// the chart
drawZoomRectangle(g2, !this.useBuffer);
g2.dispose();
this.anchor = null;
this.verticalTraceLine = null;
this.horizontalTraceLine = null;
}



Adv Reply


Bookmarks