I have implemented a custom view in my Eclipse plugin project, where I want to display different graphs, which are selected by the user. I have no problem with creating a custom view, using org.eclipse.swt.graphics.GC and drawing the required parts but I would like to implement the following:
Inside the custom view I want to have some fixed area on the bounds of the view, where I can display the coordinate system (x- and y-axis with the corresponding labeling), which is fixed. Between these bounds I would like to display the graph, which is changing dynamically, depending on user selection.
So what I need is a custom view, that is built like the following:
Inside the grey area on the left and on the bottom I want to have the coordinate system axes (shown red) and inside the white area I want to draw the graph.
How do I create such an area inside my view? It should just be a filed, without any translations or scales, just a independend area, like a view inside a view...
#Override
public void init(IViewSite site) throws PartInitException {
super.init(site);
}
#Override
public void createPartControl(Composite parent) {
canvas = new Canvas(parent, SWT.NONE);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
drawCoordinateSystem(e);
drawGraph(e);
});
public void drawCoordinateSystem(PaintEvent e) {
// 1. create area inside view
// 2. draw coordinate system
}
public void drawGraph() {
// 3. draw graph
}
I know how to solve point 2 and 3. But I don't know, how to create such an area inside my view.
I would appreciate any help!
I would suggest that you add multiple controls and handle drawing for different cases in a different way.
For example, instead of having just one monolithic Canvas that draws everything from graph to coordinates, to helpful labels. Add a bunch of label controls on top for showing coordinates, add a parent, or labels for coordinate systems etc.
Your createPartControl should look something like below:
Composite topBar = new Composite(parent, SWT.None);
topBar.setLayout(new GridLayout(3, false));
Label title = new Label(topBar, SWT.NONE);
title.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
Label x = new Label(topBar, SWT.NONE);
Label y = new Label(topBar, SWT.NONE);
Composite graphArea = new Composite(parent, SWT.NONE);
graphArea.setLayout(new GridLayout(2, false));
Canvas xAxis = new Canvas(graphArea, SWT.NONE);
GridData gd = new GridData(GridData.CENTER, GridData.FILL, false, true);
gd.widthHint = 10;
xAxis.setLayoutData(gd);
xAxis.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
drawXAxis();
}
});
Canvas graph = new Canvas(graphArea, SWT.NONE);
graph.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
drawGraph(e);
}
});
Label emptySpace = new Label(graphArea, SWT.NONE);
Canvas yAxis = new Canvas(graphArea, SWT.NONE);
GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
gd.heightHint = 10;
xAxis.setLayoutData(gd);
yAxis.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
drawYAxis();
}
});
You should draw everything in Your paintListener, if Your graph changes just redraw area of graph for example:
Rectangle rect = getGraphBoundries(); //you must implement this method
canvas.redraw(rect.x, rect.y, rect.width, rect.height, true);
this will redraw graph area. To avoid unnecessary computing of axes area in in paintListener paintEvent's gc has area that need to be redrawn called clipping. You can write condition like this:
public void paintControl(PaintEvent e) {
...
if(drawGraph(e.gc.getClipping().intersects(getGraphBoundries())) {
drawGraph(e);
}
...
}
Related
I'm sadly far from being an expert in SWT and RCP, but I really tried my best here... I can't figure out how to configure the widgets to get this layout (just a Photoshopped screen, never worked this way):
This is what I get if I set the column number of the GridLayout to 2:
Here is the Refresh and the Blacklist button in the wrong row, but at least everything is visible...
And this is what I get if I set the column number of the GridLayout to 3:
This is total messed up... Most of the widgets are pushed outside the visible area. DatePicker, Refresh, Whitelist and the Calculate buttons are not visible, they are somewhere outside on the right.
This is the codepart for this screen area:
resultingProductsGroup = new Group(propProdGroup, SWT.NONE);
final GridData gd_resultingProductsGroup = new GridData(SWT.FILL,
SWT.CENTER, true, false);
gd_resultingProductsGroup.widthHint = 240;
resultingProductsGroup.setLayoutData(gd_resultingProductsGroup);
resultingProductsGroup.setText("Resulting products");
final GridLayout gridLayout_4 = new GridLayout();
gridLayout_4.numColumns = 2;
resultingProductsGroup.setLayout(gridLayout_4);
Label refDateLabel = new Label(resultingProductsGroup, SWT.NONE);
refDateLabel.setText("Reference date:");
refDateInput = new DateInput(resultingProductsGroup, SWT.BORDER);
refDateInput.setLayoutData(new GridData());
refDateInput.setValue(new Date());
calculateProductsButton1 = new Button(resultingProductsGroup, SWT.NONE);
setupImageButton(calculateProductsButton1, Images.getButtonRefresh());
calculateProductsButton1.setLayoutData(new GridData());
GridDataFactory.swtDefaults().hint(18, 18).applyTo(
calculateProductsButton1);
resultingProductsTable = new TableListWidget<Product>(
resultingProductsGroup, SWT.BORDER, ListWidgetMode.MULTI);
resultingProductsTable.setLinesVisible(true);
resultingProductsTable.setHeaderVisible(true);
final GridData rpTableProperty = new GridData(SWT.FILL, SWT.FILL, true,
true, 3, 1);
resultingProductsTable.setLayoutData(rpTableProperty);
GridDataFactory.swtDefaults().hint(230, 240).applyTo(
resultingProductsTable);
setupResultingProductsTableColumns();
resultingProductsTable.sortByComparator(new Comparator<Product>() {
#Override
public int compare(Product o1, Product o2) {
return o1.getPartNum().getExternalId().compareTo(
o2.getPartNum().getExternalId());
}
});
resultingProductsTable.addOpenListener(new IOpenListener() {
#Override
public void open(OpenEvent event) {
doResultingProductsTableOpen();
}
});
calculateProductsButton2 = new Button(resultingProductsGroup, SWT.NONE);
calculateProductsButton2.setText("Calculate");
whitelistAddButton = new Button(resultingProductsGroup, SWT.NONE);
whitelistAddButton.setText("Whitelist");
whitelistAddButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
doAddToWhitelist();
}
});
blacklistAddButton = new Button(resultingProductsGroup, SWT.NONE);
blacklistAddButton.setText("Blacklist");
blacklistAddButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
doAddToBlacklist();
}
});
What am I not seeing here? I'm stuck with this GUI bug for over 2 days now... Please, help me :)
You could design the whole composite with one GridLayout and 3 columns, while using horizontal span of 3 on the table. That doesn't give you the desired mocked up screen though, because reference date controls and buttons at the bottom would be aligned in columns.
Try instead using 3 composites
reference date: row layout
table: fill layout
button list: row layout
I am creating a legend view and inside the shell is supposed to have a rectangle followed by a label describing the color. I was able to get the view to work using just a normal composite but the legend continues beyond the screen and no way of see it without making the window larger. I am trying to use a scrolledComposite view for my shell but when I execute the program, nothing appears.
public void createPartControl(Composite parent)
{
display = parent.getDisplay();
parent.setLayout(new FillLayout());
sc = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL);
LegendView.composite = new Composite(sc, SWT.NONE);
RowLayout layout = new RowLayout();
layout.wrap = true;
layout.spacing = 5;
composite.setLayout(layout);
}
public static void addRectangle(String legendMessage)
{
final String propId = legendMessage;
final String[] s = propId.split(",");
if (display != null)
{
display.syncExec(new Runnable()
{
#Override
public void run()
{
// Creating the color using the RBG values
final Color color =
new Color(display, Integer.parseInt(s[0]), Integer.parseInt(s[1]), Integer.parseInt(s[2]));
// Creating a canvas for which the rectangle can be drawn on
Canvas canvas = new Canvas(composite, SWT.NONE);
// Maybe set the bounds of the canvas
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
e.gc.drawRectangle(1, 1, 50, 60);
e.gc.setBackground(color);
e.gc.fillRectangle(2, 2, 49, 59);
}
});
// Disposing the color after it has been used
canvas.addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
color.dispose();
}
});
// Creating a label and setting the font
Label label = new Label(composite, SWT.NULL);
Font boldFont = new Font( label.getDisplay(), new FontData( "Arial", 12, SWT.BOLD ) );
label.setFont( boldFont );
label.setText(s[3]);
composite.redraw();
composite.layout(true);
sc.setContent(composite);
}
});
}
}
I am calling add rectangle in a different class. I am fairly new at using SWT and after looking at examples and reading the docs for scrolled Composite, this is what I interpreted it as. Any help would be very appreciated.
You haven't told the ScrolledComposite how to manage the size. You must either call setSize or setMinSize. For this you probably want:
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
sc.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
I use libgdx's scene2d built-in UI library to make an UI in my game. I'm interesting how can I draw 2 images(or actors) in a table one on another? I'm looking to the similar like LayerDrawable in Android. Is there any exists stuff to make it?
There is a Stack widget in libGDX UI library for these purposes.
UPDATE: if you want to place one widget on top of another widget and these widgets have different size then you should wrap the smaller widget. Something like:
//First add actual content
stack.add(content);
//Second add wrapped overlay object
Table overlay = new Table();
overlay.add(overlayWidget).expand().fillX().bottom().left();
stack.add(overlay);
stack variable is a Stack instance
It's an actual excerpt from my project. You should tune it for your case.
You can use somethings like this :
//create stage
stage = new Stage(new StretchViewport(game.width, game.height));
//create table
Table table = new Table();
table.setSize(game.width,game.height); //fullscreen
//add Image 1
table.add(new Image(game.skin.getDrawable("image1")));
//add Image 2 (create new col)
table.add(new Image(game.skin.getDrawable("image2"))).width(xx).height(xx);
//add new row
table.row();
//add Image 3 - padding to draw over image1/2 && colspan
table.add(new Image(game.skin.getDrawable("image3"))).width(xx).height(xx).padTop(-50f).colspan(2);
//add table to stage
stage.addActor(table);
/*
* Add action
*
*/
#Override
public void render(float delta) {
...
//don't forget to draw ur stage
stage.act(delta); // or stage.act(Gdx.graphics.getDeltaTime())
stage.draw();
}
Also you can add action to stage/table or image etc ... :
stage.addAction(Actions.sequence(
Actions.fadeOut(0.0001f),
Actions.fadeIn(0.5f),
Actions.delay(0.1f),
Actions.run(new Runnable() {
#Override
public void run() {
//mmmm new screen
dispose();
game.setScreen(new BoobsScreen(game));
}
})));
Of course you can draw more than image : button, textbutton, label etc or add scrollPane for Table but before take a look at Skin on libgdx
For exemple a programmatically ninepatch textbutton :
private NinePatch processNinePatchFile(String fname) {
final Texture t = new Texture(Gdx.files.internal(fname));
final int width = t.getWidth() - 2;
final int height = t.getHeight() - 2;
return new NinePatch(new TextureRegion(t, 1, 1, width, height), 3, 3, 3, 3);
}
//create skin
skin = new Skin();
...
//create font
...
//create ninepatch button from android/assets/style/button
NinePatch ninepatch = processNinePatchFile("style/button.9.png");
skin.add("button.9", ninepatch);
//create textbuttonstyle
TextButton.TextButtonStyle textButtonStyle = new TextButton.TextButtonStyle();
textButtonStyle.font = skin.getFont("font_black_38");
textButtonStyle.fontColor = Color.DARK_GRAY;
textButtonStyle.up = skin.getDrawable("button.9");
skin.add("buttonTextStyle", textButtonStyle);
//now you can create textbutton
TextButton btn = new TextButton("Hello", game.skin.get("buttonTextStyle", TextButton.TextButtonStyle.class));
//add a clicklistener
btn.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
//mmmmmm add action for exemple
stage.addAction(Actions.sequence(Actions.fadeOut(0.5f), Actions.run(new Runnable() {
#Override
public void run() {
//dispose and load screen
dispose();
game.setScreen(new MoreBoobsScreen(game));
}
})));
}
});
table.add(btn);
To create bitmapfont take a look at Gdx freetype, it's really easy to use.
I'm attempting to create a window that is divided into three parts. A non-resizable header and footer and then a content area that expands to fill the remaining area in the window. To get started, I created the following class:
public class MyWindow extends ApplicationWindow {
Color white;
Font mainFont;
Font headerFont;
public MyWindow() {
super(null);
}
protected Control createContents(Composite parent) {
Display currentDisplay = Display.getCurrent();
white = new Color(currentDisplay, 255, 255, 255);
mainFont = new Font(currentDisplay, "Tahoma", 8, 0);
headerFont = new Font(currentDisplay, "Tahoma", 16, 0);
// Main layout Composites and overall FillLayout
Composite container = new Composite(parent, SWT.NO_RADIO_GROUP);
Composite header = new Composite(container, SWT.NO_RADIO_GROUP);
Composite mainContents = new Composite(container, SWT.NO_RADIO_GROUP);;
Composite footer = new Composite(container, SWT.NO_RADIO_GROUP);;
FillLayout containerLayout = new FillLayout(SWT.VERTICAL);
container.setLayout(containerLayout);
// Header
Label headerLabel = new Label(header, SWT.LEFT);
headerLabel.setText("Header");
headerLabel.setFont(headerFont);
// Main contents
Label contentsLabel = new Label(mainContents, SWT.CENTER);
contentsLabel.setText("Main Content Here");
contentsLabel.setFont(mainFont);
// Footer
Label footerLabel = new Label(footer, SWT.CENTER);
footerLabel.setText("Footer Here");
footerLabel.setFont(mainFont);
return container;
}
public void dispose() {
cleanUp();
}
#Override
protected void finalize() throws Throwable {
cleanUp();
super.finalize();
}
private void cleanUp() {
if (headerFont != null) {
headerFont.dispose();
}
if (mainFont != null) {
mainFont.dispose();
}
if (white != null) {
white.dispose();
}
}
}
And this results in an empty window when I run it like this:
public static void main(String[] args) {
MyWindow myWindow = new MyWindow();
myWindow.setBlockOnOpen(true);
myWindow.open();
Display.getCurrent().dispose();
}
What am I doing wrong that I don't see three labels the way I'm trying to display them? The createContents code is definitely being called, I can step through it in Eclipse in debug mode.
Apparently, I needed to set the size and location of the labels to get them to appear.
I have a composite element, that initially has a Label. Now I call dispose on the it (the label) and create another label in the same container (composite elm), but I don't see the new text. It brings me to question how do I enable redraw on the composite, so that the new label (or any other component I might create) will render in place of the old one.
Here is the code I have (separated into a unit test for redraw a composite)
private Label createLabel( Composite parent) {
Label label = new Label(parent, SWT.NONE);
label.setAlignment(SWT.CENTER);
label.setLayoutData( new GridData( SWT.CENTER, SWT.CENTER, true, true) );
return label;
}
private void changeText() {
assert testCell != null : "Please initialize test cell";
testCell.getChildren()[0].dispose();
Label l = createLabel(testCell);
l.setText("New TexT");
testCell.redraw();
}
private void draw() {
Display display = new Display();
shell = new Shell(display);
shell.setLayout(new GridLayout(2,false));
testCell = new Composite(shell,SWT.BORDER);
testCell.setLayout(new GridLayout());
Label l = createLabel(testCell);
l.setText("Old Text");
Composite btnCell = new Composite(shell,SWT.NONE);
btnCell.setLayout(new GridLayout());
Button b = new Button(btnCell, SWT.PUSH);
b.setText("Change");
b.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event e) {
changeText();
}
});
As you can see, I am calling redraw on the composite after I add a new element. Also, I have verified that after the call to dispose, testCell.getChildren().length returns 0, as expected, and when I create a new label, I get the same expression to return 1, verifying that the new element is indeed getting added to its parent composite container
Am I missing something here ?
In the changeText() function, the
testCell.redraw();
line should be replaced by
testCell.layout();
Or, if you want to resize it correctly you should use
shell.layout();.
I would say add a selectionListener on the label.
.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
//Change text by Label.setText();
}
}