I have a problem with the orientation of a node (GridPane) after rotating it with setRotate() in JavaFX. When i rotate the node and put it in a cell of the GridPane, I would like the rotated node to fit inside the cell and also resize with the cell. I added some sample code to show you what I would like the result to be.
public class MonopolyApp extends Application {
#Override
public void start(Stage primaryStage) {
//Construction of the grid
GridPane square = new GridPane();
square.setGridLinesVisible(true);
final int heightPercent = 14;
final int widthPercent = 8;
RowConstraints rowsEdge = new RowConstraints();
rowsEdge.setPercentHeight(heightPercent);
RowConstraints rowsMid = new RowConstraints();
rowsMid.setPercentHeight(widthPercent);
ColumnConstraints colEdge = new ColumnConstraints();
colEdge.setPercentWidth(heightPercent);
ColumnConstraints colMid = new ColumnConstraints();
colMid.setPercentWidth(widthPercent);
square.getColumnConstraints().addAll(colEdge, colMid,
colMid, colMid, colMid, colMid, colMid, colMid, colMid, colMid, colEdge);
square.getRowConstraints().addAll(rowsEdge, rowsMid,
rowsMid,rowsMid,rowsMid,rowsMid,rowsMid,rowsMid, rowsMid,rowsMid, rowsEdge);
GridPane wrongSuare = makeMonopolySquare();
square.add(wrongSuare, 0, 4);
wrongSuare.setRotate(90);
GridPane rightSquare = makeMonopolySquare();
square.add(rightSquare, 1, 10);
Scene s = new Scene(square);
primaryStage.setHeight(500);
primaryStage.setWidth(500);
primaryStage.setScene(s);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
private GridPane makeMonopolySquare(){
GridPane monopolySquare = new GridPane();
RowConstraints top = new RowConstraints();
top.setPercentHeight(20);
RowConstraints bottom = new RowConstraints();
bottom.setPercentHeight(80);
ColumnConstraints c = new ColumnConstraints();
c.setPercentWidth(100);
monopolySquare.getRowConstraints().addAll(top,bottom);
monopolySquare.getColumnConstraints().addAll(c);
bottom.setValignment(VPos.CENTER);
monopolySquare.setGridLinesVisible(true);
Label name = new Label("name");
Pane colorPane = new Pane();
colorPane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
colorPane.setBackground(new Background( new BackgroundFill(Color.BLUE, null, null)));
GridPane.setMargin(colorPane, new Insets(1));
monopolySquare.add(colorPane,0,0);
monopolySquare.add(name, 0, 1);
return monopolySquare;
}
}
If you run the code you will see that the GridPane at the bottom of the stage perfectly fits it's cell. But the rotated GridPane does not. I will also add a picture to show you what my problem is:
Does anyone know how to solve this? I know that I could put it in a group, but the problem with putting it in a group is that the group would not resize to the cell of the GridPane.
Well, that is a tough one. No optimal solution comes to mind, but if I was in your position, I would try to stay within the confinements of the layout (not use low-level operations like rotation).
For example, build a differently layout cell for each row/column:
private static Node makeMonopolySquare( final Layout layout )
{
final GridPane monopolySquare = new GridPane();
monopolySquare.setGridLinesVisible( true );
final Label label = new Label( "name" );
final StackPane name = new StackPane( label );
final Pane colorPane = new Pane();
GridPane.setMargin( colorPane, new Insets( 1 ) );
colorPane.setMaxSize( Double.MAX_VALUE, Double.MAX_VALUE );
colorPane.setBackground( new Background( new BackgroundFill( Color.BLUE, null, null ) ) );
final RowConstraints top = new RowConstraints();
final RowConstraints bottom = new RowConstraints();
// bottom.setValignment( VPos.CENTER );
// top.setValignment( VPos.CENTER );
final ColumnConstraints c = new ColumnConstraints();
c.setPercentWidth( 100 );
final ColumnConstraints right = new ColumnConstraints();
// right.setHalignment( HPos.CENTER );
final ColumnConstraints left = new ColumnConstraints();
// left.setHalignment( HPos.CENTER );
final RowConstraints r = new RowConstraints();
r.setPercentHeight( 100 );
switch ( layout )
{
case BOTTOM:
top.setPercentHeight( 20 );
bottom.setPercentHeight( 80 );
monopolySquare.getRowConstraints().addAll( top, bottom );
monopolySquare.getColumnConstraints().addAll( c );
monopolySquare.add( colorPane, 0, 0 );
monopolySquare.add( name, 0, 1 );
break;
case LEFT:
right.setPercentWidth( 20 );
left.setPercentWidth( 80 );
monopolySquare.getColumnConstraints().addAll( left, right );
monopolySquare.getRowConstraints().addAll( r );
monopolySquare.add( name, 0, 0 );
monopolySquare.add( colorPane, 1, 0 );
break;
case RIGHT:
right.setPercentWidth( 80 );
left.setPercentWidth( 20 );
monopolySquare.getColumnConstraints().addAll( left, right );
monopolySquare.getRowConstraints().addAll( r );
monopolySquare.add( colorPane, 0, 0 );
monopolySquare.add( name, 1, 0 );
break;
case TOP:
top.setPercentHeight( 80 );
bottom.setPercentHeight( 20 );
monopolySquare.getRowConstraints().addAll( top, bottom );
monopolySquare.getColumnConstraints().addAll( c );
bottom.setValignment( VPos.CENTER );
monopolySquare.add( colorPane, 0, 1 );
monopolySquare.add( name, 0, 0 );
break;
}
This however, will not rotate the label (which, I would argue is better anyways for a digital monopoly board ;) ). As soon as you rotate the label, you get the same problem you had with the cell, only smaller.
The full code example.
Related
The code below is taken from:
How to always show vertical scroll bar in SWT table?
Table in the ScrolledComposite scrolls only by moving vertical scrollbar by Mouse or by putting Mouse directly onto vertical scrollbar and scroll the Wheel.
Could you advise, please, how to make table scrollable by Mouse Wheel by putting Mouse onto the Table?
public static void main(String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout());
final ScrolledComposite composite = new ScrolledComposite(shell, SWT.V_SCROLL);
composite.setLayout(new GridLayout());
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Table table = new Table(composite, SWT.NO_SCROLL | SWT.FULL_SELECTION);
table.setHeaderVisible(true);
composite.setContent(table);
composite.setExpandHorizontal(true);
composite.setExpandVertical(true);
composite.setAlwaysShowScrollBars(true);
composite.setMinSize(table.computeSize(SWT.DEFAULT, SWT.DEFAULT));
Button fillTable = new Button(shell, SWT.PUSH);
fillTable.setText("Fill table");
fillTable.setLayoutData(new GridData(SWT.FILL, SWT.END, true, false));
fillTable.addListener(SWT.Selection, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
if (table.getColumnCount() < 1)
{
for (int col = 0; col < 4; col++)
{
TableColumn column = new TableColumn(table, SWT.NONE);
column.setText("Column " + col);
}
}
for (int row = 0; row < 20; row++)
{
TableItem item = new TableItem(table, SWT.NONE);
for (int col = 0; col < table.getColumnCount(); col++)
{
item.setText(col, "Item " + row + " " + col);
}
}
for (int col = 0; col < table.getColumnCount(); col++)
{
table.getColumn(col).pack();
}
composite.setMinSize(table.computeSize(SWT.DEFAULT, SWT.DEFAULT));
}
});
Button clearTable = new Button(shell, SWT.PUSH);
clearTable.setText("Clear table");
clearTable.setLayoutData(new GridData(SWT.FILL, SWT.END, true, false));
clearTable.addListener(SWT.Selection, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
table.removeAll();
composite.setMinSize(table.computeSize(SWT.DEFAULT, SWT.DEFAULT));
}
});
shell.pack();
shell.setSize(400, 300);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
The table is receiving the mouse wheel events which it is ignoring because the Table control is large enough to show all the rows.
I don't see a way to just pass on the wheel events to the scrolled composite.
You could try listening to the wheel events in the table and adjusting the scrolled composite origin - something like:
table.addListener(SWT.MouseVerticalWheel, event ->
{
Point origin = scrolled.getOrigin();
origin.y -= event.count;
scrolled.setOrigin(origin);
});
The count field in the wheel event is 1/-1 depending on the scrolling direction.
I was wondering if there is a possibility to implement Sticky Headers on a GridPane in JavaFX, meaning a row of the GridPane that stays in place while you can scroll through the remaining rows of the pane.
It's possible, but you need to ensure the header nodes are the last children of the GridPane.children list. This allows you to set the translateY property of the header nodes to remain at the top of the ScrollPane wrapping the GridPane:
GridPane grid = new GridPane();
// fill grid
Color[] colors = new Color[]{Color.RED, Color.ORANGE, Color.LIGHTGREEN, Color.LIGHTBLUE};
for (int i = 1; i <= 100; i++) {
grid.add(new Rectangle(50, 50, colors[(2 * i - 2) % colors.length]), 0, i);
grid.add(new Label(Integer.toString(2 * i - 1)), 0, i);
grid.add(new Rectangle(50, 50, colors[(2 * i - 1) % colors.length]), 1, i);
grid.add(new Label(Integer.toString(2 * i)), 1, i);
}
// create & add header
Node[] headers = new Node[] {
createHeaderNode("H1"),
createHeaderNode("H2")
};
grid.addRow(0, headers);
ScrollPane scrollPane = new ScrollPane(grid);
scrollPane.setPrefHeight(400);
// keep header in position on top of the viewport
InvalidationListener headerUpdater = o -> {
final double ty = (grid.getHeight() - scrollPane.getViewportBounds().getHeight()) * scrollPane.getVvalue();
for (Node header : headers) {
header.setTranslateY(ty);
}
};
grid.heightProperty().addListener(headerUpdater);
scrollPane.viewportBoundsProperty().addListener(headerUpdater);
scrollPane.vvalueProperty().addListener(headerUpdater);
private static Label createHeaderNode(String text) {
Label label = new Label(text);
label.setMaxWidth(Double.MAX_VALUE);
label.setStyle("-fx-border-style: solid; -fx-background-color: white;");
return label;
}
I have the following problem when using any JavaFX Chart:
I dynamically add data to the chart and only the last X-Axis label shows up.
I already noticed that the chart is displayed fine when animations are disabled.
XYChart.Series<String,Double> series1= new Series<String, Double>();
series1.setName(scenario1.getName());
XYChart.Series<String,Double> series2= new Series<String, Double>();
series2.setName(scenario2.getName());
for(int period = 0; period < config1.getPeriods(); period++){
series1.getData().add(new Data<String, Double>("Period "+(period+1), rmList1.get(0).getCashflowsPerPeriod(config1)[period]));
System.out.println("Series1: "+rmList1.get(0).getCashflowsPerPeriod(config1)[period]);
}
for(int period = 0; period < config2.getPeriods(); period++){
series2.getData().add(new Data<String, Double>("Period "+(period+1), rmList2.get(0).getCashflowsPerPeriod(config2)[period]));
System.out.println("Series2: "+rmList2.get(0).getCashflowsPerPeriod(config2)[period]);
}
sacCashflows.getData().addAll(series1,series2);
Can you help me out here?
Thank you!
Disabling the animation worked for me.
sacCashflows.setAnimated(false);
I know you said in the comments that you had already tried that and it hadn't worked, but maybe for someone else having the same problem it will.
change your code like this
xAxis1.setAnimated(false);
yAxis1.setAnimated(true);
barChart.setAnimated(true);
Let's try with sample code (JavaFX-8-b40):
#Override
public void start( Stage stage )
{
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
AreaChart<String, Number> sacCashflows = new AreaChart<>( xAxis, yAxis );
Button b = new Button( "Add" );
b.setOnAction( new EventHandler<ActionEvent>()
{
#Override
public void handle( ActionEvent event )
{
XYChart.Series<String, Number> series1 = new XYChart.Series<>();
series1.setName( "series1" );
XYChart.Series<String, Number> series2 = new XYChart.Series<>();
series2.setName( "series2" );
for ( int period = 0; period < 10; period++ )
{
series1.getData().add( new XYChart.Data<>( "Period " + (period + 1), 5.0 * period ) );
}
for ( int period = 0; period < 5; period++ )
{
series2.getData().add( new XYChart.Data<>( "Period " + (period + 1), 10.0 * period ) );
}
sacCashflows.getData().addAll( series1, series2 );
}
} );
final Scene scene = new Scene( new VBox( sacCashflows, b ), 400, 300 );
stage.setScene( scene );
stage.show();
}
Here is a quick-n-dirty fix for this bug:
chartVariable.getData().add(new XYChart.Series(FXCollections.observableArrayList(new XYChart.Data("",0))));
chartVariable.getData().clear();
While initializing the chart, add fake data and then remove it. This works because the bug gets resolved after the first update/change to the chart. Setting animation to false also works, but I like the animations.
I have created a program to display red and black boxes. When I compile it there is an error saying that the variable I used to declare for my JFrame to set visible is an unreachable statement. I don't know what I am doing wrong.
import javax.swing.*;
import java.awt.*;
public class test {
public static void main(String[] args) {
JFrame theGUI = new JFrame();
theGUI.setTitle("Colour");
theGUI.setSize(300, 300);
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = theGUI.getContentPane();
pane.setLayout(new GridLayout(8, 8));
Color color1 = Color.black;
Color color2 = Color.red;
for (int i = 1; 1 <= 64; i++){
JPanel panel = new JPanel();
//Alternate colors on a row
if (i % 2 == 0)
panel.setBackground(color1);
else
panel.setBackground(color2);
pane.add(panel);
// at the end of a row start next row on the other color1
if ( i % 8 == 0){
Color temp = color1;
color1 = color2;
color2 = temp;
}
}
theGUI.setVisible(true);
}
}
I am sure you have figured it out by now. The loop condition is wrong...says 1 <= 64, should be i <= 64...
/Mattias
Can the width of the tab-header of a CTabItem be set arbitrary?
Thnx in advance!
Kind regard,
Marcus
You can try to override CTabItem, but this solution doesn't look as nice solution (nevertheless I use it):
CTabItem tabItem;
final int tabWidth = 90;
tabItem = new CTabItem( tabFolder, SWT.NONE ) {
#Override
public Rectangle getBounds( ) {
Rectangle bounds = super.getBounds();
bounds.x = 0 * tabWidth;
bounds.width = tabWidth;
return bounds;
}
};
tabItem.setText( __lang.str( this, "Tab Item I" ) );
tabItem = new CTabItem( tabFolder, SWT.NONE ) {
#Override
public Rectangle getBounds( ) {
Rectangle bounds = super.getBounds();
bounds.x = 1 * tabWidth;
bounds.width = tabWidth;
return bounds;
}
};
tabItem.setText( __lang.str( this, "Tab Item II" ) );
tabItem = new CTabItem( tabFolder, SWT.NONE ) {
#Override
public Rectangle getBounds( ) {
Rectangle bounds = super.getBounds();
bounds.x = 2 * tabWidth;
bounds.width = tabWidth;
return bounds;
}
};
tabItem.setText( __lang.str( this, "Tab Item III" ) );
No you can't do that. Not at least by any exposed API (read public methods).
A possible solution is to extend the code of CTabFolder and CTabItem.
As a workaround, you can pad the title with extra spaces
using String.format like:
cTabItem.setText(String.format("%-15s", orgTitle));
This will add extra spaces to the end of the string if its length is less than 15 characters.
Check this for more details:
https://docs.oracle.com/javase/tutorial/essential/io/formatting.html