Is there a way in SWT to export a composite to an image which always has the same size/resolution? The problem is that we have a Dashboard which looks always different when opening on screens with different display size/resolution. The question is now can I export the Dashboard to an image wich has a fixed size and always looks the same no matter on which screen size/resolution it has been created?
For the time being we do it like that but as said it depends on the display it has been created on:
Image image = new Image(Display.getCurrent(), this.content.getBounds().width, this.content.getBounds().height);
ImageLoader loader = new ImageLoader();
FileOutputStream fileOutputStream = new FileOutputStream(file);
GC gc = new GC(image);
this.content.print(gc);
gc.dispose();
loader.data = new ImageData[] { image.getImageData() };
loader.save(fileOutputStream, imageFormat);
fileOutputStream.close();
Is there for example some way to create a virtual screen with a certain resolution, which isn't actually displayed and only used for exporting the Dashboard?
Any help or pointers would be appreciated.
In one of my applications I was creating graphs and charts in SWT. The user was able to export these to an image of a size and format that they specified. My solution was to take the GC of the chart composite and redraw it to a new composite off screen, then export the newly drawn composite.
Here's my class which accomplished this:
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.widgets.Composite;
/**
* The class used for writing an {#link Composite} to an image file
*
* #author David L. Moffett
*
*/
public class CompositeImageWriter
{
/**
* Redraws the composite to the desired size off-screen and then writes that
* composite as an image to the desired location and in the desired format
*
* #param absolutePath
* the absolute path to the desired output file
* #param compositeToDraw
* the composite to be written to file as an image
* #param width
* the desired width in pixels that the composite should be redrawn
* to
* #param height
* the desired height in pixels that the composite should be redrawn
* to
* #param imageType
* an int representing the type of image that should be written
*/
public static void drawComposite(String absolutePath, Composite compositeToDraw, int width,
int height, int imageType)
{
Image image = new Image(compositeToDraw.getDisplay(), width, height);
GC gc = new GC(image);
int originalWidth = compositeToDraw.getBounds().width;
int originalHeight = compositeToDraw.getBounds().height;
compositeToDraw.setSize(width, height);
compositeToDraw.print(gc);
compositeToDraw.setSize(originalWidth, originalHeight);
ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { image.getImageData() };
loader.save(absolutePath, imageType);
image.dispose();
gc.dispose();
}
}
For your case of wanting to always export at a specific size, just replace the width and height arguments with appropriate constants.
Edit 1
I should add that the int imageType argument is the corresponding SWT modifier (for example: SWT.IMAGE_PNG, SWT.IMAGE_JPEG, SWT.IMAGE_BMP, etc...).
Edit 2
I updated the static reference to dynamically get the display from the compositeToDraw. Further, here's an example I put together which uses the CompositeImageWriter which you may be able to use to debug your issue:
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
public class CompositeToWrite extends Composite
{
private int width, height;
private Label l;
public CompositeToWrite(Composite parent, int style)
{
super(parent, style);
this.setLayout(new GridLayout(1, true));
this.addListener(SWT.Resize, new Listener()
{
#Override
public void handleEvent(Event event)
{
updateText();
}
});
Button b = new Button(this, SWT.NONE);
b.setText("Export as image (500, 500)");
b.addListener(SWT.Selection, new Listener()
{
#Override
public void handleEvent(Event event)
{
CompositeImageWriter.drawComposite("./img/output.png", CompositeToWrite.this, 500, 500,
SWT.IMAGE_PNG);
}
});
l = new Label(this, SWT.CENTER);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.verticalAlignment = SWT.CENTER;
l.setLayoutData(gd);
updateText();
}
protected void updateText()
{
width = this.getBounds().width;
height = this.getBounds().height;
l.setText("My label is centered in composite (" + width + ", " + height + ")");
}
}
In the case of this example I create a simple composite that once added to a shell will look something like this:
When I click the button it resizes the composite to 500 x 500 and writes the resized composite to a file. The result is this picture:
I should note that I did notice the composite flicker when the button is clicked, so this may not be happening completely in the background or "off screen" as I initially suggested.
Related
I managed to create a Candlestick Chart using JFreeChart-FX and display it using the fxgraphics2d API. But I am pretty much confused on how to enable any interaction with my chart and need some help to this.
I'd be very grateful for any help in the right direction.
I started with this example to get up my initial Chart and altered it so that it uses my data. Then I use a custom Canvas, which utilizes fxgraphics2d to make the JPanel component accessable as a node for my JavaFX applicaiton.
So I know there is for example a specific PanHandlerFX class, but I am lost to utilize this. As far as I was able to research (e.g. here), I need to add the PanHandlerFX class to the list of availableMouseHandlers of my ChartCanvas. But my canvas does not offer anything like availableMouseHandlers. I feel lost now, since there is so few tutorials and information to find regarding the JFree-FX charts and the documentation does not help me either.
Here is my custom canvas class:
import javafx.scene.canvas.Canvas;
import org.jfree.chart.JFreeChart;
import org.jfree.fx.FXGraphics2D;
import java.awt.geom.Rectangle2D;
public class ChartCanvas extends Canvas {
JFreeChart chart;
private FXGraphics2D graphics2D;
public ChartCanvas(JFreeChart chart) {
this.chart = chart;
this.graphics2D = new FXGraphics2D(getGraphicsContext2D());
// Redraw canvas when size changes.
widthProperty().addListener(e -> draw());
heightProperty().addListener(e -> draw());
}
private void draw() {
double width = getWidth();
double height = getHeight();
getGraphicsContext2D().clearRect(0, 0, width, height);
this.chart.draw(this.graphics2D, new Rectangle2D.Double(0, 0, width, height));
//(this.graphics2D,, new Rectangle2D.Double(0, 0, width, height));
}
}
Here is my custom JFreeChart:
import javafx.collections.ObservableList;
import org.ezstrats.model.chartData.Candlestick;
import org.ezstrats.model.chartData.Exchange;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.HighLowItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.FixedMillisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.ohlc.OHLCSeries;
import org.jfree.data.time.ohlc.OHLCSeriesCollection;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
public class JFreeCandlestickChart extends JPanel {
private static final DateFormat READABLE_TIME_FORMAT = new SimpleDateFormat("kk:mm:ss");
private OHLCSeries ohlcSeries;
private TimeSeries volumeSeries;
private JFreeChart candlestickChart;
public JFreeCandlestickChart(String title) {
ObservableList<Candlestick> candlesticks = Exchange.getCandlesticks();
// Create new chart
candlestickChart = createChart(title, candlesticks);
// Create new chart panel
final ChartPanel chartPanel = new ChartPanel(candlestickChart);
chartPanel.setPreferredSize(new Dimension(832, 468));
chartPanel.getChart().getXYPlot().getDomainAxis().setAutoRange(false);
chartPanel.getChart().getXYPlot().getDomainAxis().setLowerBound(candlesticks.get(candlesticks.size() - 300).getTimestampOpen());
chartPanel.getChart().getXYPlot().getDomainAxis().setUpperBound(candlesticks.get(candlesticks.size() - 1).getTimestampOpen());
// Enable zooming - not workign?! ...
chartPanel.setMouseZoomable(true);
chartPanel.setMouseWheelEnabled(true);
chartPanel.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
// process before
super.mouseDragged(e);
chartPanel.getChart().getXYPlot().getDomainAxis().configure();
// process after
}
});
add(chartPanel, BorderLayout.CENTER);
}
public JFreeChart createChart(String title, ObservableList<Candlestick> candlesticks){
/**
* 1st:
* Creating candlestick subplot
*/
// Create OHLCSeriesCollection as a price dataset for candlestick chart
OHLCSeriesCollection candlestickDataset = new OHLCSeriesCollection();
ohlcSeries = new OHLCSeries("Price");
candlestickDataset.addSeries(ohlcSeries);
// Create candlestick chart priceAxis
NumberAxis priceAxis = new NumberAxis("Price");
priceAxis.setAutoRangeIncludesZero(false);
// Create candlestick chart renderer
CandlestickRenderer candlestickRenderer = new CandlestickRenderer(CandlestickRenderer.WIDTHMETHOD_AVERAGE,
false,
new HighLowItemLabelGenerator(new SimpleDateFormat("kk:mm"), new DecimalFormat("0.00000000")));
// Create candlestickSubplot
XYPlot candlestickSubplot = new XYPlot(candlestickDataset, null, priceAxis, candlestickRenderer);
candlestickSubplot.setBackgroundPaint(Color.white);
/**
* 2nd:
* Creating volume subplot
*/
// creates TimeSeriesCollection as a volume dataset for volume chart
TimeSeriesCollection volumeDataset = new TimeSeriesCollection();
volumeSeries = new TimeSeries("Volume");
volumeDataset.addSeries(volumeSeries);
// Create volume chart volumeAxis
NumberAxis volumeAxis = new NumberAxis("Volume");
volumeAxis.setAutoRangeIncludesZero(true);
// Set to no decimal
volumeAxis.setNumberFormatOverride(new DecimalFormat("0"));
// Create volume chart renderer
XYBarRenderer timeRenderer = new XYBarRenderer();
timeRenderer.setShadowVisible(false);
timeRenderer.setDefaultToolTipGenerator(new StandardXYToolTipGenerator("Volume--> Time={1} Size={2}",
new SimpleDateFormat("kk:mm"), new DecimalFormat("0")));
// Create volumeSubplot
XYPlot volumeSubplot = new XYPlot(volumeDataset, null, volumeAxis, timeRenderer);
volumeSubplot.setBackgroundPaint(Color.white);
/**
* 3rd:
* Adding Candles to this chart
**/
for (Candlestick candle: candlesticks){
addCandleToChart(candle.getTimestampOpen(),
candle.getPriceOpen(),
candle.getPriceHigh(),
candle.getPriceLow(),
candle.getPriceClose(),
candle.getVolumeQuote());
}
/**
* 4th:
* Create chart main plot with two subplots (candlestickSubplot,
* volumeSubplot) and one common dateAxis
*/
// Creating charts common dateAxis
DateAxis dateAxis = new DateAxis("Time");
dateAxis.setDateFormatOverride(new SimpleDateFormat("dd.mm.yy kk:mm"));
//dateAxis.setRange();
// reduce the default left/right margin from 0.05 to 0.02
dateAxis.setLowerMargin(0.02);
dateAxis.setUpperMargin(0.02);
dateAxis.setLabelAngle(0);
// Create mainPlot
CombinedDomainXYPlot mainPlot = new CombinedDomainXYPlot(dateAxis);
mainPlot.setGap(10.0);
mainPlot.add(candlestickSubplot, 4);
mainPlot.add(volumeSubplot, 1);
mainPlot.setOrientation(PlotOrientation.VERTICAL);
mainPlot.setDomainPannable(true);
JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, mainPlot, false);
//chart.removeLegend();
// Einbetten in JScrollPaenl??? um Scrollen zu ermöglichen...
// ChartPanel chartPanel = new ChartPanel(chart);
return chart;
}
/**
* Fill series with data.
*
* #param c opentime
* #param o openprice
* #param h highprice
* #param l lowprice
* #param c closeprice
* #param v volume
*/
private void addCandleToChart(long time, double o, double h, double l, double c, double v) {
// Add bar to the data. Let's repeat the same bar
FixedMillisecond t = new FixedMillisecond(time);
//READABLE_TIME_FORMAT.parse(String.valueOf(time)));
ohlcSeries.add(t, o, h, l, c);
volumeSeries.add(t, v);
}
public void setOhlcSeries(OHLCSeries ohlcSeries) {
this.ohlcSeries = ohlcSeries;
}
public void setVolumeSeries(TimeSeries volumeSeries) {
this.volumeSeries = volumeSeries;
}
public OHLCSeries getOhlcSeries() {
return ohlcSeries;
}
public TimeSeries getVolumeSeries() {
return volumeSeries;
}
public JFreeChart getCandlestickChart() {
return candlestickChart;
}
}
And this is how I print the chart (main.class):
// Switching Views
public void drawNewChart(JFreeChart newChart){
centerChart.getChildren().removeAll();
ChartCanvas chartCanvas = new ChartCanvas(newChart);
centerChart.getChildren().add(chartCanvas);
chartCanvas.widthProperty().bind(centerChart.widthProperty());
chartCanvas.heightProperty().bind(centerChart.heightProperty());
}
As shown here, construct a ChartViewer with your JFreeChart to create an interactive chart. The viewer's enclosed ChartCanvas will manage the PanHandlerFX for you. As a concrete example, add the following line to the example, and drag as described here:
plot.setDomainPannable(true);
Original:
After drag right:
As an aside, you may find the JavaFX Demos helpful in this context.
How to draw a semi do nut chart in jfreechart , For example use this below link, https://www.highcharts.com/demo/pie-semi-circle
This is my code
DefaultPieDataset dataset = new DefaultPieDataset( );
dataset.setValue("Safari-32", new Long( 32) ); dataset.setValue("Chrome-44", new Long( 44) );
dataset.setValue("Apple-24", new Long( 24) );
dataset.setValue("Google-75", new Long( 75) );
dataset.setValue("Michele", new Long( 97) ); dataset.setValue("Jony", new Long( 41) );
JFreeChart chart = ChartFactory.createRingChart("Chart title", dataset, true, false, false);
chart.setBackgroundPaint(Color.WHITE);
chart.setBorderVisible(false);
RingPlot plots = (RingPlot) chart.getPlot();
Font font3 = new Font("Book Antiqua", Font.BOLD, 17);
plots.setShadowPaint(null);
plots.setBackgroundPaint(null);
plots.setOutlineVisible(false);
plots.setLabelOutlinePaint(null);
plots.setLabelBackgroundPaint(Color.WHITE);
plots.setCenterTextMode(CenterTextMode.FIXED);
String te = "334";
plots.setCenterText((String)te); plots.setCenterTextFont(font3);
plots.setLabelGenerator(null); // Remove the labels from chart area
font3 = new Font("Book Antiqua", Font.PLAIN, 10);
LegendTitle legend = chart.getLegend();
legend.setPosition(RectangleEdge.RIGHT); legend.setItemFont(font3);
legend.setBorder(0, 0, 0, 0);
String filename = "D:\\ad\\do nut.jpg";
ChartUtilities.saveChartAsJPEG(new File(filename), chart, 250, 155);
This is my code and this produces a full donut chart. I need a donut of starting angle from 180 degree to 0 degree
Initial
Refresh
It's quite simple to create a semi/half donut in java using jfreechart. The most important thing is the invisible dataset. My favourite aircraft is the F16 Falcon, but my code below doesn't have any military associations. Feel free to reuse and/or adapt the source code.
Description: Example class to demonstrate semi/half-donut (TAGS: java, osgi, jfreechart, version 1.0.19, SWT, #PostConstruct, ChartComposite, Eclipse, E4, PiePlot, RingPlot, Semi, Half, Example, BackgroundImage, Resizing, Layout)
package de.enjo.jfreechart.semi.donut.example.parts;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Objects;
import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.RingPlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.experimental.chart.swt.ChartComposite;
/*
* Example class to demonstrate semi/half-donut with jfreechart version 1.0.19
* (SWT, ChartComposite, Eclipse, E4, jfreechart, PiePlot, RingPlot, Semi, Half, Example)
*
* #note: This example doesn't use the ChartPanel class to avoid an additional Swing-UI Thread
* */
public class SamplePart {
// synchronize ui, i.e. dataset has been changed
#Inject
private UISynchronize uiSync;
// refresh ui job
private final Job refreshJob = new Job("Refresh Job") {
#Override
protected IStatus run(IProgressMonitor monitor) {
uiSync.asyncExec(SamplePart.this::updateUI);
return Status.OK_STATUS;
}
};
// invisible dataset, the most important thing
private final String INVISIBLE = "have_a_look_on_me_if_you_can_xD";
// an awt image
private BufferedImage backgroundImage;
// color white
private org.eclipse.swt.graphics.Color backgroundColor = new org.eclipse.swt.graphics.Color(255, 255, 255);
private java.awt.Color whiteColorAlphaChannel = new java.awt.Color(255, 255, 255, 0);
// swt widget
private ChartComposite chartComposite;
// the colors we need/support
private ColorRegistry colors;
public SamplePart() {
colors = new ColorRegistry();
colors.put("COLOR" + 0, new RGB(0, 0, 255));
colors.put("COLOR" + 1, new RGB(0, 255, 0));
colors.put("COLOR" + 2, new RGB(255, 0, 0));
colors.put("COLOR" + 3, new RGB(0, 255, 255));
colors.put("COLOR" + 4, new RGB(255, 255, 0));
colors.put("COLOR" + 5, new RGB(128, 128, 128));
}
/**
* initializing ui & simulate data change via refresh job (delay 3 seconds)
*
* #note: wait 3 seconds after starting to refresh
*/
#PostConstruct
public void createComposite(Composite parent) {
initializeExample(parent);
refreshJob.schedule(3000);// milliseconds
}
// construct and set all defaults
private void initializeExample(Composite parent) {
parent.setLayout(GridLayoutFactory.fillDefaults().numColumns(1).create());
parent.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
parent.setBackground(backgroundColor); // white
/**
* 1st load background image
*/
try {
// no really military associations
backgroundImage = loadImage();
} catch (Exception e) {
/* ignore , it has to be present */}
/**
* 2nd create composite (swt)
*/
chartComposite = new ChartComposite(parent, SWT.NONE);
chartComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
chartComposite.setDomainZoomable(false);// no zoom needed
chartComposite.setRangeZoomable(false);// no zoom needed
/**
* 3rd create dataset (important thing (...most important thing...*fg))
*
* - don't forget to decrease by the previous value (degree of previous value =>
* array[index-1])
*
* - you need an additional, invisible dataset to complete the pie or ring plot
* up to 100% (360° or 1.0f)
*
* FYI: 0.0f-1.0f <> 0%-100% <> 0°-360°
*/
DefaultPieDataset dataset = new DefaultPieDataset();
// in this example we use a range of 0°-180°
int[] degreeValues = new int[] { 45, 90, 135, 180 };// 45°, 90° etc.
for (int index = 0; index < degreeValues.length; index++) {
if (index == 0) {
dataset.setValue(String.valueOf(index), Math.toRadians(degreeValues[index]));
} else {
dataset.setValue(String.valueOf(index), Math.toRadians(degreeValues[index] - degreeValues[index - 1]));
}
}
// MOST IMPORTANT
// invisible dataset to complete pie chart up to 100%
// you can use any other numbered key here, in my case the key is named:
// have_a_look_on_me_if_you_can_xD (should be unique)
dataset.setValue(INVISIBLE, Math.toRadians(180));// semi => 180°, we have 360° now
/**
* 4th create plot & chart
*/
final RingPlot plot = new RingPlot(dataset);
plot.setOutlineVisible(false);
plot.setLabelGenerator(null);
for (int index = 0; index < degreeValues.length; index++) {
plot.setSectionPaint(String.valueOf((index)), getAWTColor(index));
// section stroke line for better visibility
plot.setSectionOutlinePaint(String.valueOf((index)), new java.awt.Color(213, 54, 0));
}
// MOST IMPORTANT
// invisible section to complete pie chart up to 100%
// you can use any other numbered key here, in my case the key is named:
// have_a_look_on_me_if_you_can_xD (should be unique)
plot.setSectionPaint(INVISIBLE, whiteColorAlphaChannel); // 180° alpha invisible
plot.setSectionOutlinePaint(INVISIBLE, whiteColorAlphaChannel); // 180° alpha invisible
//
plot.setBackgroundImage(backgroundImage);// you can also use a picture of your grandma ^^
plot.setBackgroundImageAlpha(1.0f); // background image without transparent channel
plot.setForegroundAlpha(0.5f); // plots drawing with transparent channel (semi)
plot.setSectionDepth(0.9D);// ring depth/width in double
plot.setCircular(true); // no ellipse
plot.setInnerSeparatorExtension(0.2f);// percent of inner separator strokes
plot.setOuterSeparatorExtension(0.2f);// percent of outer separator strokes
plot.setSectionOutlinesVisible(true);// strokes between datasets
plot.setSeparatorPaint(new java.awt.Color(213, 54, 0)); // stroke paint
plot.setShadowPaint(null);// no shadow drawing needed (i'm always on the bright side of life... :P)
/**
* #note: edit image to correct size and position of AOI (area-of-interest)
* first before use these settings
*
* #note: setBackgroundImageAlignment(0) = resize of image is disabled. Comment
* it out to enable auto resizing (not recommended in this case)
*/
plot.setInteriorGap(0.0D);
plot.setBackgroundImageAlignment(0);
//
final JFreeChart chart = new JFreeChart(null, null, plot, false);
chart.setBackgroundPaint(new java.awt.Color(parent.getBackground().getRed(), parent.getBackground().getGreen(),
parent.getBackground().getBlue()));
/*
* 5th complete initialization
*/
chartComposite.setChart(chart);
}
private java.awt.Color getAWTColor(int index) {
/*
* ensure that dataset size/length does not exceed the color size/length
*/
org.eclipse.swt.graphics.Color color = colors.get("COLOR" + index);
return new java.awt.Color(color.getRed(), color.getGreen(), color.getBlue());
}
// is called by the refresh job
public void updateUI() {
// simulate date change
if (Objects.nonNull(chartComposite) && !chartComposite.isDisposed()) {
chartComposite.setRedraw(false);
DefaultPieDataset dataset = new DefaultPieDataset();
// in this example we use a range 0°-180°, 6 colors are supported
int[] degreeValues = new int[] { 30, 60, 90, 120, 150, 180 };// 30°, 60° etc.
for (int index = 0; index < degreeValues.length; index++) {
if (index == 0) {
dataset.setValue(String.valueOf(index), Math.toRadians(degreeValues[index]));
} else {
dataset.setValue(String.valueOf(index),
Math.toRadians(degreeValues[index] - degreeValues[index - 1]));
}
}
// MOST IMPORTANT
// invisible dataset to complete pie chart up to 100%
// you can use any other numbered key here, in my case the key is named:
// have_a_look_on_me_if_you_can_xD (should be unique)
dataset.setValue(INVISIBLE, Math.toRadians(180));// semi => 180°, we have 360° now
((RingPlot) chartComposite.getChart().getPlot()).setDataset(dataset);
chartComposite.setRedraw(true);
}
}
/*
* ############################# helper area ############################
*/
private BufferedImage loadImage() throws Exception {
/**
* #note: image source:
* https://www.pngarea.com/view/e6f205a3_jet-png-f-16-plane-png-transparent-png/
*
* #note: put this image into the icons directory, named "f16.png" and replace
* transparent background with white background color first
*
* #note: this example has no military associations. I like this aircraft, not
* more :). You can use every other image with white background in this
* example
*/
return getBufferedImage(SamplePart.class.getResourceAsStream("/icons/f16.png"));
}
private BufferedImage getBufferedImage(InputStream inputStream) throws Exception {
byte[] bytes = read(inputStream);
return getBufferedImage(bytes);
}
/*
* load resources without additional plugins, like emf etc.
*/
private byte[] read(InputStream is) throws Exception {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead = 0;
byte[] data = new byte[is.available()];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] bytes = buffer.toByteArray();
buffer.close();
is.close();
return bytes;
}
private BufferedImage getBufferedImage(byte[] bytes) throws Exception {
InputStream is = new ByteArrayInputStream(bytes);
BufferedImage bufferedImage = ImageIO.read(is);
is.close();
return bufferedImage;
}
}
I need a donut of starting angle from 180 degree to 0 degree.
You can start at 180° using the parent PiePlot method setStartAngle(). You can hide the lower half using a transparent color, as shown here, or cover it using one of the approaches shown here. OverlayLayout and transparent white is illustrated below.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.RingPlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
public class RingChartTest {
private PieDataset createDataset() {
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("Safari", 75);
dataset.setValue("Chrome", 60);
dataset.setValue("FireFox", 45);
dataset.setValue("", 180);
return dataset;
}
private JFreeChart createChart(PieDataset dataset) {
JFreeChart chart = ChartFactory.createRingChart(
"Browser Share", dataset, true, false, false);
RingPlot plot = (RingPlot) chart.getPlot();
plot.setStartAngle(180);
plot.setCircular(true);
plot.setSimpleLabels(true);
plot.setSectionDepth(0.5);
plot.setBackgroundPaint(Color.WHITE);
Color invisible = new Color(0xffffffff, true);
plot.setSectionPaint("", invisible);
plot.setSectionOutlinePaint("", invisible);
plot.setShadowPaint(null);
//plot.setLabelGenerator(null);
return chart;
}
public JPanel createDemoPanel() {
JFreeChart jfreechart = createChart(createDataset());
ChartPanel chartPanel = new ChartPanel(jfreechart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 400);
}
};
chartPanel.setLayout(new OverlayLayout(chartPanel));
JLabel label = new JLabel("BrowserShare");
label.setFont(label.getFont().deriveFont(48.0f));
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setAlignmentX(0.5f);
label.setAlignmentY(0.75f);
label.setOpaque(true);
label.setBackground(Color.LIGHT_GRAY);
chartPanel.add(label);
return chartPanel;
}
public static void main(String args[]) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame("Ring Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new RingChartTest().createDemoPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
I have to display a message box on some action, I am able to do that but the message dialog box appears smaller in size.Is there any way to increase the size of the message box in java?
here is my code:
Display.getDefault().syncExec(new Runnable () {
#Override
public void run() {
// Get active window page
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
Shell parent = window.getShell();
MessageBox dialog =
new MessageBox(shell,SWT.RESIZE|SWT.ICON_INFORMATION|SWT.OK);
dialog.setText("Project info");
dialog.setMessage("Project info Text will come here");
int returnCode = dialog.open();
System.out.println("returnCode "+ returnCode);
}
});
You can create your own dialog box. Take a look at the examples here. I've copied the relevant code, in case that link stops working:
public class DialogExample extends Dialog {
public DialogExample(Shell parent) {
super(parent);
}
public String open() {
Shell parent = getParent();
Shell dialog = new Shell(parent, SWT.DIALOG_TRIM
| SWT.APPLICATION_MODAL);
dialog.setSize(100, 100);
dialog.setText("Java Source and Support");
dialog.open();
Display display = parent.getDisplay();
while (!dialog.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
return "After Dialog";
}
public static void main(String[] argv) {
new DialogExample(new Shell());
}
}
As far as i know SWT uses the OS system message box so this means you can only change the title/text and icon type.
But you could use JFace which is an extension to SWT and try to use org.eclipse.jface.dialogs.MessageDialog API.
Here's my version: You don't hardcode your dialog size, rather make it variable on the user's screen size.
I've added my personal helper methods below, and demonstrated their usage.
This would be far more flexible than an OS MessageBox, but you're gonna have to add icons manually (oooooor I think you can even override MessageDialog instead of Dialog - your call)
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.Shell;
/**
*
* #author stackoverflow.com/users/1774643/ggrec
*
*/
public class CustomMessageBox extends Dialog
{
// ==================== 1. Static Fields ========================
/*
* Default ratio values for big dialogs
*/
private static final double DEFAULT_DIALOG_WIDTH_SCREEN_PERCENTAGE = 0.63;
private static final double DEFAULT_DIALOG_HEIGHT_SCREEN_PERCENTAGE = 0.75;
// ==================== Static Helper Methods ====================
/**
* <pre>
* Very useful for dialogs. Resizes the dialog shell to a size proportional
* to the primary monitor bounds.
*
* <b>1920x1080 monitor && 0.63x0.75 ratios => 1400x800 shell</b>
*
* This means 63% of screen's width, and 75% of screen's height.
*
* The advantage of this method is that the dialog will always be proportional
* to the screen, no matter what the screen size is (e.g. big LG flat TV screen,
* or MacOS display).
* </pre>
*
* #param shell Dialog shell (e.g. the 'newShell' object in configureShell API from Dialog)
* #param widthRatio A percentage of current screen's size (i.e. smaller than 1, bigger than 0)
* #param heightRatio
*/
public static void resizeAndCenterShellOnScreen(final Shell shell, final double widthRatio, final double heightRatio)
{
final Display display = shell.getDisplay();
final Monitor primaryMonitor = display.getPrimaryMonitor();
final Rectangle monitorRect = primaryMonitor.getBounds();
// 1.) Resize the Shell
final int newWidth = (int) Math.floor(monitorRect.width * widthRatio);
final int newHeight = (int) Math.floor(monitorRect.height * heightRatio);
shell.setSize(newWidth, newHeight);
centerShellOnScreen(shell);
}
public static void centerShellOnScreen(final Shell shell)
{
final Rectangle shellBounds = shell.getBounds();
final Display display = shell.getDisplay();
final Monitor primaryMonitor = display.getPrimaryMonitor();
final Rectangle monitorRect = primaryMonitor.getBounds();
final int x = monitorRect.x + (monitorRect.width - shellBounds.width) / 2;
final int y = monitorRect.y + (monitorRect.height - shellBounds.height) / 2;
shell.setLocation(x, y);
}
// ==================== 3. Static Methods ====================
public static void main(final String[] args)
{
new CustomMessageBox().open();
}
// ==================== 4. Constructors ====================
public CustomMessageBox()
{
super(Display.getDefault().getActiveShell());
}
// ==================== 5. Creators ====================
#Override
protected Control createDialogArea(final Composite parent)
{
final Composite dialogArea = (Composite) super.createDialogArea(parent);
final Label label = new Label(dialogArea, SWT.NULL);
label.setText("YOLO");
label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
return dialogArea;
}
#Override
protected void configureShell(final Shell newShell)
{
super.configureShell(newShell);
resizeAndCenterShellOnScreen(newShell, DEFAULT_DIALOG_WIDTH_SCREEN_PERCENTAGE, DEFAULT_DIALOG_HEIGHT_SCREEN_PERCENTAGE);
}
}
Cheers.
I'm trying to create this basic photo editing app via java swing. I have my code to work somewhat for when 1 picture is imported; I have 3 views - photo view which displays the photo only, thumbnail view which should display thumbnails of the pictures and split view which should be a combination of photo in BorderLayout.CENTER and thumbnail in BorderLayout.SOUTH. I've put in images and code excerpts as to why this isn't working the way it should. I can't upload any images but hopefully the excerpts provide much detail.
Split View Related Excerpts:
public void changeMode(boolean p, boolean b, boolean s){
/*
* Photo View will display a single PhotoComponent2 in a large area.
*/
isPhoto = p;
if (isPhoto){
//have a child JPanel set as CENTER component of BorderLayout of the JScrollPane (scroll)
childPhoto = new JPanel();
childPhoto.add(displayPhotos.get(getCurrentPhoto()), BorderLayout.CENTER);
System.out.println("in lc photo view class");
}
/*
* Browser View will hold all the images.
*/
isBrowse = b;
if(isBrowse){
//have a child JPanel set as CENTER component of BorderLayout to hold grid of thumbnails within
// JScrollPanel (scroll)
this.removeAll();
childBrowse = new JPanel();
tc2 = new ThumbnailComponent(displayPhotos.get(getCurrentPhoto()));
childBrowse.setLayout(new WrapLayout());
childBrowse.add(tc2);
// for(int i = 0; i < displayThumbs.size(); i++){
// childBrowse.add(displayThumbs.get(i));
// System.out.println(displayThumbs.get(i));
// }
System.out.println("in lc browser view class");
}
/*
* Split View is a combination of Photo and Browser View in that the top half
* is Photo View and the bottom half is Browser View.
*/
isSplit = s;
if(isSplit){
//have a child JPanel in CENTER to hold PhotoComponent plus a child JPanel in SOUTH to hold thumbnails
containsAll = new JPanel();
containsAll.setLayout(new BorderLayout());
containsAll.add(childPhoto, BorderLayout.CENTER);
containsAll.add(childBrowse, BorderLayout.SOUTH);
System.out.println("in lc split view class");
}
}
This is basically all of my problems right now. Currently the thumbnails that are being created are based on the current image. If I go to photo view and and change the image being displayed with my forward/backward buttons and then go back to browser view I get the thumbnail of the respective image. However, I want to be able to create thumbnails for all images being imported and then display it. I tried the for loop (which I've commented out) and that didn't help either. The other code associated with this are my main class that creates the JFrame and the buttons,etc., the photoComponent that has my paintComponent method I use in my thumbnails and lightComponent classes.
MyPhotos3:
view = new JMenu("View");
mbar.add(view);
pv = new JRadioButton("Photo Viewer");
pv.addActionListener(new ActionListener(){ //change status
public void actionPerformed(ActionEvent e){
sbar.setText("Status: By clicking this, you'll be able to view your photos one at a time");
boolean p = true;
boolean b = false;
boolean s = false;
lc.changeMode(p,b,s);
scroll.add(lc.childPhoto);
scroll.setViewportView(lc.childPhoto);
scroll.getViewport().setBackground(Color.BLUE);
scroll.revalidate();
scroll.repaint();
}
});
b = new JRadioButton("Browser");
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){ //change status
sbar.setText("Status: By clicking this, you'll be able to view all your photos as thumbnails");
boolean p = false;
boolean b = true;
boolean s = false;
lc.changeMode(p,b,s);
scroll.setViewportView(lc.childBrowse);
scroll.getViewport().setBackground(Color.BLUE);
scroll.revalidate();
scroll.repaint();
}
});
sm = new JRadioButton("Split Mode");
sm.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){ //change status
sbar.setText("Status: By clicking this, you'll be able to view a single photo with a film strip dimensional view");
boolean p = false;
boolean b = false;
boolean s = true;
lc.changeMode(p,b,s);
scroll.setViewportView(lc.containsAll);
scroll.getViewport().setBackground(Color.BLUE);
scroll.revalidate();
scroll.repaint();
}
});
PhotoComponent:
public PhotoComponent2(boolean f, Image img){
isFlip = f;
init = img;
x = init.getWidth(null);
y = init.getHeight(null);
setPreferredSize(new Dimension (x,y));
bi = new BufferedImage(init.getWidth(null),init.getHeight(null),BufferedImage.TYPE_INT_ARGB);
newIcon = new ImageIcon(bi);
img1 = new JLabel("", newIcon, JLabel.CENTER);
image = img1;
this.add(img1);
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocus(true);
//System.out.println("In constructor");
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(init, 0, 0, null);
this.addMouseListener(this);
this.addMouseMotionListener(this);
//System.out.println("In paintComponent");
Thumbnails:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.JComponent;
public class ThumbnailComponent extends JComponent{
/**
* ThumbnailComponent class is a way to create smaller versions of each photo passed in.
*
* #author Puja Sheth
* #version 1.0 10/16/2014
*/
private static final long serialVersionUID = 1L;
PhotoComponent2 pc;
Image img;
double x;
double y;
int newX;
int newY;
public ThumbnailComponent(PhotoComponent2 input){
pc = input;
img = pc.init;
x = (img.getWidth(null))/(.5);
y = (img.getHeight(null))/(.5);
newX = (int)x;
newY = (int)y;
setPreferredSize(new Dimension (newX,newY));
// add(input);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics gCopy = g.create();
Graphics2D g2d = (Graphics2D)gCopy;
g2d.scale(.5,.5);
pc.paintComponent(g2d);
}
}
Any help would be greatly appreciated!!!!
Won't solve your problem, but a few general comments about your code:
scroll.add(lc.childPhoto);
scroll.setViewportView(lc.childPhoto);
scroll.revalidate();
scroll.repaint();
You should never add a component to a scrollpane. The only line of code you need is:
scroll.setViewportView(lc.childPhoto);
The scrollpane will automatically revalidate() and repaint() itself when the viewport view is changed.
super.paintComponent(g);
g.drawImage(init, 0, 0, null);
this.addMouseListener(this);
this.addMouseMotionListener(this);
Never add listener to a component is a painting method. Painting methods are for painting only. A listener has nothing to do with painting. Also, the painting methods are invoked whenever Swing determines the component needs to be repainted so you will be adding multiple listeners to the component.
In a Java SWT shell window, how do I set its inner size than its whole window frame size?
For instance, if I use shell.setSize(300, 250) this would make the whole window appearing as exactly 300x250. This 300x250 includes the size of the window frame.
How can I set the inner size, that is the content display region of the shell window to 300x250 instead? That's this 300x250 excludes the width of the window frame.
I tried to minus some offset values but the thing is different Operating Systems have different window frame sizes. So having a constant offset would not be accurate.
Thanks.
From your question what I understood is that you want to set the dimension of the Client Area. And in SWT lingo it is defined as a rectangle which describes the area of the receiver which is capable of displaying data (that is, not covered by the "trimmings").
You cannot directly set the dimension of Client Area because there is no API for it. Although you can achieve this by a little hack. In the below sample code I want my client area to be 300 by 250. To achieve this I have used the shell.addShellListener() event listener. When the shell is completely active (see the public void shellActivated(ShellEvent e)) then I calculate the different margins and again set the size of my shell. The calculation and resetting of the shell size gives me the desired shell size.
>>Code:
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
public class MenuTest {
public static void main (String [] args)
{
Display display = new Display ();
final Shell shell = new Shell (display);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
layout.numColumns = 1;
shell.setLayout(layout);
shell.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,true));
final Menu bar = new Menu (shell, SWT.BAR);
shell.setMenuBar (bar);
shell.addShellListener(new ShellListener() {
public void shellIconified(ShellEvent e) {
}
public void shellDeiconified(ShellEvent e) {
}
public void shellDeactivated(ShellEvent e) {
}
public void shellClosed(ShellEvent e) {
System.out.println("Client Area: " + shell.getClientArea());
}
public void shellActivated(ShellEvent e) {
int frameX = shell.getSize().x - shell.getClientArea().width;
int frameY = shell.getSize().y - shell.getClientArea().height;
shell.setSize(300 + frameX, 250 + frameY);
}
});
shell.open ();
while (!shell.isDisposed()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
}
If I get you right you should set the size of the inner component to the needed size and use the method pack() (of the frame).
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
public class SWTClientAreaTest
{
Display display;
Shell shell;
final int DESIRED_CLIENT_AREA_WIDTH = 300;
final int DESIRED_CLIENT_AREA_HEIGHT = 200;
void render()
{
display = Display.getDefault();
shell = new Shell(display, SWT.SHELL_TRIM | SWT.CENTER);
Point shell_size = shell.getSize();
Rectangle client_area = shell.getClientArea();
shell.setSize
(
DESIRED_CLIENT_AREA_WIDTH + shell_size.x - client_area.width,
DESIRED_CLIENT_AREA_HEIGHT + shell_size.y - client_area.height
);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
public static void main(String[] args)
{
SWTClientAreaTest appl = new SWTClientAreaTest();
appl.render();
}
}
Use computeTrim to calculate the bounds that are necessary to display a given client area. The method returns a rectangle that describes the bounds that are needed to provide room for the client area specified in the arguments.
In this example the size of the shell is set so that it is capable to display a client area of 100 x 200 (width x height):
Rectangle bounds = shell.computeTrim(0, 0, 100, 200);
shell.setSize(bounds.width, bounds.height);
This article describes the terms used by SWT for widget dimensions:
https://www.eclipse.org/articles/Article-Understanding-Layouts/Understanding-Layouts.htm