Nebula Grid - Select individual cells (CellSelectionEnabled) - java

I am using Eclipse.org's Nebula Grid and want to access an individual cell. Not an individual GridItem, which can be accomplished by grid.select(...) but a cell. So lets say i have a grid like this:
final Grid grid = new Grid(shell,SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
grid.setCellSelectionEnabled(true);
grid.setHeaderVisible(true);
GridColumn column = new GridColumn(grid, SWT.None);
column.setWidth(80);
GridColumn column2 = new GridColumn(grid, SWT.None);
column2.setWidth(80);
for(int i = 0; i<50; i++)
{
GridItem item = new GridItem(grid, SWT.None);
item.setText("Item" + i);
}
Like i said, grid.select selects the whole row, which is not what i want. I also tried grid.selectCell(...), but for some reason that wont work either. The coordinates used are with a high likeliness correct:
Button btn = new Button(shell, SWT.PUSH);
btn.setText("test");
btn.addSelectionListener(new SelectionAdapter(){
public void widgetSelected(SelectionEvent e){
Point pt = new Point(400,300);
grid.selectCell(pt);
}
});
Any Ideas?

For a Grid, the Point co-ordinates represent the intersecting column and the row item. i.e, x co-ordinate represents the index of the column and y co-ord is the row item index.
Button btn = new Button (shell, SWT.PUSH);
btn.setText ("test");
btn.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
// Here the x co-ordinate of the Point represents the column
// index and y co-ordinate stands for the row index.
// i.e, x = indexOf(focusColumn); and y = indexOf(focusItem);
Point focusCell = grid.getFocusCell();
grid.selectCell(focusCell);
// eg., selects the intersecting cell of the first column(index = 0)
// in the second row item(rowindex = 1).
Point pt = new Point(0, 1);
grid.selectCell(pt);
}
});

Related

JFrame not showing up after running

I am working a JFrame calculator, I am not to familiar with so I was following a tutorial, and I've double checked it a couple times.
It's not working, its not throwing any errors or anything, it will compile and run. Just nothing pops up.
I am using Eclipse, and it is giving two warnings,
one about my constructor not being used in my main
that my class says this: The serializable class Gui does not declare a static final serialVersionUID field of type long.
I'm not sure why those would come up, but my code seems to be like the tutorial.
Thank you in advanced.
Ps. excuse the all commons, I just making sure I can looking back at it without having to refer back to the tutorial.
// This will make the visuals of the calc
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Gui extends JFrame implements ActionListener {
JPanel[] row = new JPanel[5];
JButton[] button = new JButton[19];
String[] buttonString = {"7", "8", "9", "+", // This is a string for the buttons that we will later apply to
"4", "5", "6", "-", // the the buttons with a loop, instead of 19 lines for each one
"1", "2", "3", "*",
".", "/", "C", "√",
"-/+", "=", "0"};
int[] dimW = {300, 45, 100, 90}; // An Array for the different widths of the display and buttons
int[] dimH = {35, 40}; // An array for the different heights of the display and buttons
Dimension displayDimension = new Dimension(dimW[0], dimH[0]); // The dims for the display using the first ints of the arrays
Dimension regularDimension = new Dimension(dimW[1], dimH[1]); // The
Dimension rColumnDimension = new Dimension(dimW[2], dimH[1]);
Dimension zeroButDimension = new Dimension(dimW[3], dimH[1]);
Boolean[] function = new Boolean[4]; // A boolean array to tell, which operator we are using
double[] temp = {0, 0}; // A temp array for the calc, might not use when using my stack calc
JTextArea display = new JTextArea(1, 20); // This is the display where the text will be displayed
Font font = new Font("Ariel", Font.BOLD, 14);
Gui() {
super("Gui");
setDesign();
setSize(380, 250); // Set the frame size
setResizable(false); // Makes so it can't be resized, can mess up layout if it true
setDefaultCloseOperation(EXIT_ON_CLOSE); // What happens when it closes
GridLayout grid = new GridLayout(5, 5); // Since we need a grid of 5 by 5 for the buttons this makes the grid
setLayout(grid);
for (int i = 0; i < 4; i++) // Sets values for the function array, might use might not with my clac
{
function[i] = false;
}
FlowLayout f1 = new FlowLayout(FlowLayout.CENTER); // This will only be use to layout row 1
FlowLayout f2 = new FlowLayout(FlowLayout.CENTER, 1, 1); // The ints are used to give a 1 pt gap vert and horiztal
for (int i = 0; i < 5; i++) // Intinalizing the Jpanel row's so we can use them
{
row[i] = new JPanel();
}
row[0].setLayout(f1); // Since we need the first row to have the special layout of f1 we just assign it
for (int i = 1; i < 5; i++) // Since we already set the first row "Row[0]" to f1, we have to start with row 2 or row[1] for i
{
row[i].setLayout(f2);
}
// After this all the rows have the correct layout, we can set up the buttons
// And set the same thing to each button with a loop
for (int i = 0; i < 19; i++) {
button[i] = new JButton(); // Creates a new button for each button in the array
button[i].setText(buttonString[1]); // Sets text on the button with the text from the list, in ButtonString
button[i].setFont(font); // Makes it nice looking with the fancy font we used in the font line
button[i].addActionListener(this); // This is what makes the button actually work
}
// Buttons done we can move to the display set up
display.setFont(font); // Set the fancy font to the display too
display.setEditable(false); // Makes it so no input from the keyboard, will have to change this on final product
display.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); // Makes it pop in right to left
// With the fonts and everything intinlized we can start to set the sizes for the compents
display.setPreferredSize(displayDimension); // Sets the size of the display
// We can use a loop for the regular buttons, i think all but zero
for (int i = 0; i < 14; i++) {
button[i].setPreferredSize(regularDimension); // Sets the size of the regular buttons
}
for (int i = 14; i < 18; i++) {
button[i].setPreferredSize(rColumnDimension); // Sets the size of the right column of buttons, the operrantors
}
button[18].setPreferredSize(zeroButDimension); // Sets the size of the zero button since its bigger
// Now that we got evrything sized up time to add everything to the panel
row[0].add(display); // Adds the display to row 1
add(row[0]); // Adds row 1 to the panel
for (int i = 0; i < 4; i++) {
row[1].add(button[i]); // all the number buttons to the row
}
row[1].add(button[14]); // adds the operator button to the row
add(row[1]); // adds the row
for (int i = 4; i < 8; i++) {
row[2].add(button[i]); // all the number buttons to the row
}
row[2].add(button[15]); // adds the operator button to the row
add(row[2]); // adds the row
for (int i = 8; i < 12; i++) {
row[3].add(button[i]); // all the number buttons to the row
}
row[3].add(button[16]); // adds the operator button to the row
add(row[3]); // adds the row
row[4].add(button[18]);
for (int i = 12; i < 14; i++) {
row[4].add(button[i]); // all the number buttons to the row
}
row[4].add(button[17]); // adds the operator button to the row
add(row[4]); // adds the row
setVisible(true); // Makes so you can see it
}
// Not sure what this is
public final void setDesign() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
}
}
// Will be use to make actionlistener work
public void actionPerformed(ActionEvent ae) {
}
public void main(String[] arguments) {
Gui c = new Gui();
}
}
You should really have this in your main method
public static void main(String[] args){
Gui c = new Gui();
c.setVisible(true);
}

JavaFX, extracting all children that are buttons from root.getChildren()

I just start my journey with JavaFX and I'll try to make a simple calc.
I have that code to make all my buttons:
Button one = new Button("1");
Button two = new Button("2");
Button three = new Button("3");
Button four = new Button("4");
Button five = new Button("5");
Button six = new Button("6");
Button seven = new Button("7");
Button eight = new Button("8");
Button nine = new Button("9");
Button zero = new Button("0");
Button dot = new Button(".");
Button pow = new Button("^2");
TextField equation = new TextField();
Button equal = new Button("=");
Button multiple = new Button("*");
Button divide = new Button("/");
Button takefrom = new Button("-");
Button add = new Button("+");
In the start method ill add them all to the boxes and then to the root. My main class implements EvendHandler. Now i want apply .onAction(this), to each button.
There is a way to extract only buttons from root node?
I tried getChildren() and then for each but I can't get it to work.
Is there a good habit to make a arraylist for my buttons only and then make a loop that can do it?
Or there is another way?
All code can be found at:
http://pastebin.com/RBzbn8bT
You can use an instanceof test for this, or (with a bit of trickery) do a lookup. But neither of these are particularly nice solutions: a more elegant solution is just to define one or more methods for creating the buttons, and put all the code you need for each button there. That way you can easily define a different handler for each button.
This basic idea is something like:
public class Calculator extends Application {
private GridPane root ;
#Override
public void start(Stage primaryStage) {
root = new GridPane()
// zero button:
root.add(1, 4, createNumericalButton(0));
// buttons for 1-9:
for (int i = 1 ; i <= 9 ; i++) {
Button button = createNumericalButton(i);
int row = 2 - (i-1)/3 ; // {7,8,9} -> 0; {4,5,6} -> 1; {1,2,3}->2
int col = (i-1) % 3 ;
root.add(col, row, button);
}
// other layout...
}
private Button createNumericalButton(final int n) {
Button button = new Button(Integer.toString(n));
button.setMinSize(32, 32);
button.setOnAction(event -> {
// replace with real handler...
System.out.println("Pressed "+n);
}
return button ;
}
}
You can similarly define a createOperationButton(...) method for creating the buttons for +, -, *, and / etc. If you want to get a bit more sophisticated, that method could take a DoubleBinaryOperator as a parameter, for specifying the behavior of each button. So you'd end up doing something like:
root.add(4, 3, createOperationButton("+", (x, y) -> x + y));
root.add(4, 2, createOperationButton("-", (x, y) -> x - y));
root.add(4, 1, createOperationButton("*", (x, y) -> x * y));
root.add(4, 0, createOperationButton("/", (x, y) -> x / y));
In order to extract only buttons, you can use the instanceof keyword.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html
In your case, you could iterate through all the children of your root and check if they belong to the Button class.
For example:
for(int i=0; i<root.getChildren().size(); i++)
if(root.getChildren().get(i) instanceof Button) {
your code here
}

Blank fields in Libgdx's table

I have another problem with tables in Libgdx. I want to create a game board using it and give to user a possibility to add / remove elements from that board ( table ). So first of all I would like to know how to initialize that table so that it already has fields but invisible fields ( so that it's possible to get position of that field and put there new element ). So those are my 2 first questions :
How to create those invisible fields ( all fields have fixed static size ) ?
How to get position and change element ( actor ) in that field?
Hope someone can help me.
You can create those by adding a cell to a table and set the size of the cell.
You can then add a invisible button to that cell and if the button is clicked you can remove it and add a new element.
Here some example code:
// uiskin from libgdx tests
skin = new Skin(Gdx.files.internal("uiskin.json"));
table = new Table();
// invisible button style
final ButtonStyle bStyle = new ButtonStyle();
int colNum = 10, rowNum = 10;
for (int row = 0; row < rowNum; row++)
{
for (int col = 0; col < colNum; col++)
{
final Button l = new Button(bStyle);
l.addListener(new ClickListener()
{
#Override
public void clicked(InputEvent event, float x, float y)
{
Cell<Button> cell = table.getCell(l);
cell.clearActor();
cell.setActor(new Label("test", skin));
}
});
table.add(l).size(100, 100);
}
table.row();
}
stage = new Stage();
table.setFillParent(true);
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
The skin files can be downloaded here: https://github.com/libgdx/libgdx/tree/master/tests/gdx-tests-android/assets/data
You need the uiskin.json, uiskin.atlas and uiskin.png file.

How would I add an action listener to buttons on a loop?

I want it so every time a button is pressed in my 4x4 grid, that it increments moves by 1 . This is creating a 4x4 layout of buttons. Each time any of those buttons are pressed, I want moves to increment. Basically I'm creating the memory game, where you flip cards over to match each other. I just have to keep count of the total amount of moves a player does to solve the puzzle.
private int moves = 0;
private GridPane makeGridPane(){
ConcentrationModel c = new ConcentrationModel();
GridPane grid = new GridPane();
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth( 50 );
grid.getColumnConstraints().addAll(col1, col1, col1, col1);
RowConstraints row1 = new RowConstraints();
row1.setPercentHeight( 50 );
grid.getRowConstraints().addAll(row1, row1, row1, row1);
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
ImageView image = new ImageView(c.getCards().get(0).getImage());
image.setFitWidth(WIDTH/4);
image.setFitHeight(HEIGHT/4);
btn.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btn.setGraphic(image);
grid.add(btn, col, row);
}
}
return grid;
}
You can create a single event handler and reuse it for all the buttons. Since you probably want the buttons to do other things too, I would recommend adding this as an event handler, instead of using the convenience method setOnAction(...):
EventHandler<ActionEvent> incrementMovesHandler = e -> moves++ ;
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
btn.addEventHandler(ActionEvent.ACTION, incrementMovesHandler);
// ...
}
}
This is actually pretty simple. All you have to do is add this bit of code just before your grid.add(...):
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
moves++;
}
});
Or, equivalently, the Java 8 version:
btn.setOnAction((ActionEvent e) -> {moves++;});
(I can't currently test this, but it should work. If not, lemme know and I'll try to fix it.)
If you're concerned about memory, Christian points out below that this creates a new instance of EventHandler for every button. While this may not be too terrible, it's probably a bad habit to get into. The best way to handle (no pun intended) this is by making an object before your for loop:
EventHandler<ActionEvent> eh = new EventHandler<>() {
#Override public void handle(ActionEvent event) {
moves++;
}
};
Then, for each of your buttons, instead of the top-most code, you'd simply write:
btn.setOnAction(eh);
That way, a single EventHandler is being created and used to handle all the events. You'll want to use this one if you need to create more than just a few buttons, both because it's faster (doesn't need to allocate memory for each object) and more memory-efficient (...it, uh, doesn't need to allocate the memory for each object). In this case, I think it's pretty trivial, but it's good to know nonetheless.
You need to implement the ActionListener interface in your class.
Then in the actionPerformed function, just increment the moves variable.
You just have to call btn.addActionListener(this); for each of the button that
you created.
public class Sample extends JFrame implements ActionListener {
public Sample ()
{
}
private GridPane makeGridPane()
{
ConcentrationModel c = new ConcentrationModel();
GridPane grid = new GridPane();
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth( 50 );
grid.getColumnConstraints().addAll(col1, col1, col1, col1);
RowConstraints row1 = new RowConstraints();
row1.setPercentHeight( 50 );
grid.getRowConstraints().addAll(row1, row1, row1, row1);
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
ImageView image = new ImageView(c.getCards().get(0).getImage());
image.setFitWidth(WIDTH/4);
image.setFitHeight(HEIGHT/4);
btn.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btn.setGraphic(image);
btn.addActionListener(this);
grid.add(btn, col, row);
}
}
return grid;
}
public void actionPerformed(ActionEvent e)
{
moves++;
}
}

Equal width of the first column between multiple composites

So the case is that I have a SWT composite A which aggregates composite B and C.
The content of B and C consists of multiple rows that consists of Label and Text.
Within composite B or C rows are aligned properly ( you can draw a straight vertical line in the place where label border ends and text starts). But if you compare B and C then C content looks like it is indented against B.
For example:
Does anyone have an idea how to achieve it ?
The only way I can think of to align the first column of each Composite is to set the GridData#widthHint to the same value. This value would have to be the maximal width of any of the elements in the first column.
I gave it a try and came up with this solution (it's not optimized and consequently might not be the most efficient way to do it):
private static Random random = new Random(System.currentTimeMillis());
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(1, false));
Composite first = createComposite(shell);
Composite second = createComposite(shell);
synchronizeFirstColumn(2, first, second);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
private static Composite createComposite(Shell shell)
{
Composite comp = new Composite(shell, SWT.BORDER);
comp.setLayout(new GridLayout(2, false));
comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
for (int i = 0; i < 3; i++)
{
String content = UUID.randomUUID().toString();
content = content.substring(0, Math.round(random.nextFloat() * content.length()));
Label label = new Label(comp, SWT.RIGHT);
label.setText(content);
label.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
Text text = new Text(comp, SWT.BORDER);
text.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
}
return comp;
}
private static void synchronizeFirstColumn(int nrOfColumns, Composite... comps)
{
if (comps == null || comps.length == 0)
return;
int maxWidth = 0;
for (Composite comp : comps)
{
Control[] controls = comp.getChildren();
for (int i = 0; i < controls.length; i += nrOfColumns)
{
int width = controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
if (width > maxWidth)
maxWidth = width;
}
}
for (Composite comp : comps)
{
Control[] controls = comp.getChildren();
for (int i = 0; i < controls.length; i += nrOfColumns)
{
Object data = controls[i].getLayoutData();
if(data instanceof GridData)
{
GridData grid = (GridData) data;
grid.widthHint = maxWidth;
}
}
}
}
Looks like this:

Categories