Reorder items after mouse release - java

I am not sure what is wrong, so I will attempt to explain it, and you can test it in the following example:
The Project (3 MB): http://ryannaddy.com/downloads/dist.zip
Un-Zip and run the jar file
Open 2 image files within the application
On the right hand side is a list of all the open images, you can drag and drop the layers to eventually order z-order of the main picture.
If you drag the top layer below the bottom layer it gets moved back to the top (Should be moved below the bottom layer)
If you drag the top layer down a few pixels it will move the top layer below the bottom layer.
If you drag the bottom layer down it moves it above the top layer (Should be kept on the bottom)
In the end, I would like to drag those labels to any spot and there is where it will place the label.
Code block that gets executed after the mouse is released to organize the labels:
public void lblMouseReleased(MouseEvent evt){
if(dragging){
int componentCount = layers.getComponentCount() - 1;
LayerItem[] comps = new LayerItem[componentCount];
FocusTraversalPolicy focus = layers.getFocusTraversalPolicy();
Component comp = focus.getFirstComponent(layers);
for(int i = 0; i < componentCount; i++){
Component newComp = focus.getComponentAfter(layers, comp);
comp = newComp;
comps[i] = (LayerItem)newComp;
System.out.println(comps[i].layerID);
}
Layers.rebuild(layers, comps);
}
dragging = false;
}
Code for Layers.rebuild:
public static void rebuild(JPanel layers, Component[] list){
for(int i = 0; i < list.length; i++){
layers.remove(list[i]);
}
for(int i = 0; i < list.length; i++){
list[i].setBounds(0, i * 50 + 30, 198, 50);
layers.add(list[i]);
}
layers.revalidate();
layers.repaint();
}
This should be all the relevant code to the problem, let me know if you need more.

I got it! I it was because I wasn't getting all the items needed in the panel. The first item in my panel is a header with focus set to false, since it isn't apart of the grouping, so I was telling my code to only order items 1+ when it should have been 0+

Related

Why do I need to open all expansion panes in a list view, else they give null? - Gluon JavaFX

I don't know if this is a code issue or a bug. But this picture shows us a Glisten List View where I have included Glisten DropdownButtons inside a ExpandedPaneContainer etc.
The issue here is that I need to open the first the first expansion pane, then the second one, named Layer 2, and then the third one, named Layer 3.
I cannot directly open Layer 2 or Layer 3 at the beginning. After I have open all expanded panes and close them, then I can open them again in a random order.
Question:
Why does it behave like this? Is it a bug?
If you want to run the program, just download the code from here: https://github.com/DanielMartensson/Deeplearning2C and then create a new file inside the software, by clicking the "pen"-icon. Give it a name and then go to "Configurations -> Layer Configuration". Try to open the last expansion panel at the bottom first.
Here is the method I use when I add all these expansion panes inside a expandedPaneContainer. I know there is lot of code, but the idea is that:
Create a expansion panel
Add the expansion panel into expanded panel container
Create a collapsed panel and set its labels etc.
Set the collapsed panel to expansion panel collapsed content
Create a expanded panel and set a grid pane into it
Add a labels at column 0, row j, and drop down buttons box at column 1 and row j inside the grid pane.
Repeat the process again
private void addLayer() {
/*
* Create a expanded panels from these
*/
String[] dropDownTypes = dL4JSerializableConfiguration.getDropdownTypes();
/*
* New expansions panel and add it to the expansions panel container
*/
ExpansionPanel expansionPanel = new ExpansionPanel();
expansionPanelContainer.getItems().add(expansionPanel);
/*
* Create an collapsed panel and first set a label with the name of the layer index e.g. layer 0, layer 1 etc and the layer type
*/
CollapsedPanel collapsedPanel = new CollapsedPanel();
collapsedPanel.getTitleNodes().add(0, new Label("Layer " + expansionPanelContainer.getItems().size())); // Layer index
collapsedPanel.getTitleNodes().add(1, new Label("DenseLayer")); // Layer type
expansionPanel.setCollapsedContent(collapsedPanel); // Set collapsed panel into expansion panel
/*
* Create an expanded panel and begin to set a grid pane into it
*/
ExpandedPanel expandedPanel = new ExpandedPanel();
GridPane gridPane = new GridPane();
expandedPanel.setContent(gridPane);
expansionPanel.setExpandedContent(expandedPanel);
/*
* Add all drop downs and labels
*/
for(int j = 0; j < dropDownTypes.length; j++) {
/*
* Create the element label and set its position inside the grid
*/
Label elementLabel = new Label(dropDownTypes[j]);
gridPane.add(elementLabel, 0, j); // To the left
/*
* Create the drop down button and add the elements and set its position inside the grid
*/
DropdownButton elementDropdown = new DropdownButton();
if(dropDownTypes[j].equals(dropDownTypes[0])) { // Layer types
elementDropdown.getItems().addAll(new MenuItem("DenseLayer"), new MenuItem("LSTM"), new MenuItem("OutputLayer"));
}else if(dropDownTypes[j].equals(dropDownTypes[1])) { // Inputs
for(int i = 1; i <= 100; i++)
elementDropdown.getItems().add(new MenuItem(String.valueOf(i)));
}else if(dropDownTypes[j].equals(dropDownTypes[2])) { // Outputs
for(int i = 1; i <= 100; i++)
elementDropdown.getItems().add(new MenuItem(String.valueOf(i)));
}else if(dropDownTypes[j].equals(dropDownTypes[3])) { // Activations
for(Activation activation : Activation.values())
elementDropdown.getItems().add(new MenuItem(activation.name()));
}else if(dropDownTypes[j].equals(dropDownTypes[4])) { // Loss functions
for(LossFunctions.LossFunction lossFunction : LossFunctions.LossFunction.values())
elementDropdown.getItems().add(new MenuItem(lossFunction.name()));
}
gridPane.add(elementDropdown, 1, j); // To the middle
}
}

Render multiple heights in an isometric tile based map

Good evening everyone.
I've been messing a bit with isometric tile worlds and I have a few doubts about rendering the elements on it.
When I build a single height map I render it first and then add the diferent elements on top, and the displacement of the last seem right.
public void render(Graphics2D g2d) {
for(int i = 0; i < tileGrid.length; i++) {
Point isop = NeoMath.getInstance().cartToIso(i % yAmmount, i / yAmmount, GlobalDataStorage.tileWidth, GlobalDataStorage.tileHeight);
TileManager.getInstance().getTileByID(tileGrid[i]).render(g2d, isop.x, isop.y);
}
for(Entity entity : entityList) {
entity.render(g2d);
}
}
(The position of the entity is calculated inside it's update).
With this I have no problems as everything is rendered on the same height, the problem comes when I try to add other floors to it.
Let's say that I want it to have three heights. I have a list of list of tiles instead of the single array, and render every element on them:
public void render(Graphics2D g2d) {
int flag = 0;
for(int i = 0; i < tileGrid.size(); i++) {
Point isop = NeoMath.getInstance().cartToIso(i % yAmmount, i / yAmmount, GlobalDataStorage.tileWidth, GlobalDataStorage.tileHeight);
for(int k = 0; k < tileGrid.get(i).size(); k++) {
TileManager.getInstance().getTileByID(tileGrid.get(i).get(k)).render(g2d, isop.x, isop.y - (GlobalDataStorage.tileZ * k));
}
while(flag < currentList.size() &&
currentList.get(flag).getPosition().equals(new Point(i % yAmmount, i /
yAmmount))) {
currentList.get(flag).render(g2d);
flag++;
}
}
}
Where the currentList is the list of entities.
With this I have the problem that, when the entities move to a new position, they get overlaped by the tiles, as these are rendered after the entity, and the position of the entity does not change until it reached the destiny. I could change the position to the new one before rendering, but that implies that in the other axis the previous tile get rendered after the entity, making it disapear for a second due to the overlap.
This also mess when I try to draw selection rectangle as it get stuck behind the tiles being rendered. I don't want them to overlap the whole map so can't draw them after all the rendering has been done either.
Does someone know of another approach that I can try out?
Thank you beforehand.
Draw your entire floor layer in a first pass. Then in the second pass draw all walls and objects and moving entities.
I could change the position to the new one before rendering,
David Brevik, programmer on Diablo, mentions using this option in his GDC talk Diablo: A Classic Games Postmortem. It was his first "What Went Wrong" example!
Reference: https://www.youtube.com/watch?v=VscdPA6sUkc&t=20m17s
Turns out this is a classic hurdle in isometric games.

Why does a JButton under a JPanel still react?

I looked around for my problem, and i couldn't find an answer, so here I go:
I have a JLayeredPane, and in there there are 2 JPanels.
The deepest one ( furthest down ) has JButtons on there.
The second one ( The one on top ) has a partially transparent background color ( although i don't think this should influence it ).
Now when I hover over my JButtons ( which are behind the other JPanel ), they still fire events to the MouseListener I added to them. I don't know why...
Why is this the case? What can I do to make it stop?
Here I add both the panels to the layered pane, and this refers to my class which extends a JFrame.
JLayeredPane layer = this.getLayeredPane();
layer.removeAll();
this.gamePanel = new GamePanel(game);
this.ghostPanel = new GhostPanel();
this.ghostPanel.setOpaque(true);
this.ghostPanel.setVisible(true);
layer.add(this.gamePanel, new Integer(0));
layer.add(this.ghostPanel, new Integer(1));
Here I have some buttons ( with an absolute layout ) added to the lowest panel
this.setLayout(null);
for (int j = 0; j < 5; j++) {
for (int i = 0; i < 5 + j; i++) {
this.add(this.buttons[i][j]);
}
}
for (int j = 1; j < 5; j++) {
for (int i = j; i < 9; i++) {
this.add(this.buttons[i][4 + j]);
}
}
Here this refers to the most bottom JPanel
The purpose of this is a game called gipf, and the layout I went with is absolute because it was very hard to align everything in a hexagonal shape.
Now when I hover over my JButtons ( which are behind the other JPanel ), they still fire events to the MouseListener I added to them
When an event is generated in needs to be passed to a component, so Swing searches from the bottom of the parent/child hierarchy to the top until it finds a component that wants to handle the event.
What can I do to make it stop?
Add a MouseMotionListener to the top panel to intercept events like mouseEntered/mouseExited. This way you will still be able to handle button clicks in the other panel.

Gridbag layout or Grid layout?

I am a little new to swing. In order to learn to use the API correctly, I am designing the following project:
The project is a solving block puzzle solver sliding block puzzle similar to the rush-hour puzzles common in toy stores - https://en.wikipedia.org/wiki/Rush_Hour_(board_game) except there is no escape for a special car.
By dragging the blocks from an off board area to the board, the user specifies the starting configuration of the puzzle. The user, in the same way, specifies an ending goal configuration which dictates where some (or all) of the blocks the user specified initially must be at the end of the puzzle - the ending configuration can be specified using only SOME of the blocks, making multiple legal ending configurations.
The algorithm for solving the puzzle is already complete - I just need to design the interface and I am getting stuck. For designing the tray, I used a grid layout. Since blocks need to be entered at certain positions, I need to be able to place blocks in specific cells in the grid and move them around.
A 'block' object has four attributes - its height, width, its top row, and its left most column (ie - each block is addressed by its top left corner).
I used the suggestion here ( https://stackoverflow.com/questions/2510159/can-i-add-a-component-to-a-specific-grid-cell-when-a-gridlayout-is-used ) for the grid layout.
Right now I have only programmed to the point where java reads the puzzle from a .txt file and is supposed to display it on the screen ( I have not designed any user interactablity yet ).
First, here is the code I have written so far.
public class SolverPuzzleGUI extends JFrame {
//Specs from the puzzle.
Board initBoard;
ArrayList<Block> goalBlocks;
LinkedList<Move> moveList;
JLayeredPane layeredpane;
JPanel Board;
Dimension boardsize = new Dimension(400, 500);
JPanel[][] panelHolder = new JPanel[5][4];
public SolverPuzzleGUI(Board startBoard, ArrayList<Block> startGoalBlocks,
LinkedList<Move> startMoveList) {
this.initBoard = startBoard;
this.goalBlocks = startGoalBlocks;
this.moveList = startMoveList;
} // end constructor.
//gives the actual simulation
public void runSimulation() {
// Initalizing the main window.
setSize(500, 600);
setName("Solution");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setMinimumSize(getMinimumSize());
//Using layered pane
layeredpane = new JLayeredPane();
add(layeredpane);
layeredpane.setPreferredSize(boardsize);
layeredpane.setBackground(Color.YELLOW);
layeredpane.setVisible(true);
// adding the game tray
Board = new JPanel();
layeredpane.add(Board, JLayeredPane.DEFAULT_LAYER);
Board.setLayout(new GridLayout(5, 4));
// centering the game tray.
Board.setPreferredSize(boardsize);
Board.setMinimumSize(boardsize);
Board.setMaximumSize(boardsize);
Box box = new Box(BoxLayout.Y_AXIS);
box.add(Box.createVerticalGlue());
box.add(Board);
box.add(Box.createVerticalGlue());
add(box);
//Adding placeholders to the board for creating blocks
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 4; j++) {
panelHolder[i][j] = new JPanel();
panelHolder[i][j].setBackground(Color.DARK_GRAY);
Board.add(panelHolder[i][j]);
layeredpane.setLayer(panelHolder[i][j], JLayeredPane.DEFAULT_LAYER);
panelHolder[i][j].setVisible(false);
} // end 'j' for
} // end 'i' for
ArrayList<Block> initBlocks = initBoard.getBlocks();
//int count = 0; //DEBUG
for (Block block : initBlocks) {
this.drawBlock(block);
//count++;
//if(count > 4) { break; }
} // end 'for'
Board.setBackground(Color.DARK_GRAY);
Board.setVisible(true);
setVisible(true);
} // end 'run'
private void drawBlock(Block block) {
Dimension blockSize = new Dimension(block.getWidth()*100, block.getHeight()*100);
System.out.println(blockSize.width);
System.out.println(blockSize.height);
JPanel screenBlock = new JPanel();
screenBlock.setPreferredSize(blockSize);
screenBlock.setMinimumSize(blockSize);
screenBlock.setMaximumSize(blockSize);
screenBlock.setSize(blockSize);
screenBlock.setBackground(Color.BLUE);
screenBlock.setBorder(BorderFactory.createLineBorder(Color.BLACK));
layeredpane.setLayer(screenBlock, JLayeredPane.MODAL_LAYER);
int leftRow = block.getRow();
int leftCol = block.getColumn();
panelHolder[leftRow][leftCol].setSize(blockSize);
panelHolder[leftRow][leftCol].setVisible(true);
panelHolder[leftRow][leftCol].add(screenBlock);
layeredpane.setLayer(panelHolder[leftRow][leftCol], JLayeredPane.MODAL_LAYER);
screenBlock.setVisible(true);
}// end 'drawBlock'
public static void main(String[] args) {
String file = "C:\\Users\\Tim\\Desktop\\init.from.handout.txt";
String goal = "C:\\Users\\Tim\\Desktop\\goal.2.from.handout.txt";
/*
A SolverPuzzle object is the object which actually solves the algorithm -
when the class is constructed, it takes the file path of the inital
configuration as an input, as well as the file path of the goal
configuration. It has the following fields:
A 'board' object which specifies the inital configuration of the board.
It contains an ArrayList of Block objects(Remember block objects store
the height and width of the block, as well as the address of the
top left corner of block) which specify the starting
blocks, an ArrayList of EmptySpace objects which specify the empty
spaces on the board, an ArrayList of Move objects, which contain
the legal moves of the configuration, and the height and width of
the tray (in this application, the tray will always be 5 x 4).
An ArrayList of Block objects which specify the ending configuration.
A LinkedList of Move objects which specify the shortest possible
list of Moves which brings the configuration to a position which
satisfies the goal position. A Move object has three fields -
The block object being moved, and the row and column of the
top left corner of the block in the new position.
*/
SolverPuzzle test;
try { test = new SolverPuzzle(file, goal); }
catch (IOException ex) {
System.out.println("IOException");
return;
}
Board testBoard = test.getStartBoard();
ArrayList<Block> testGoalBlocks = test.getGoalBlocks();
LinkedList<Move> testMoveSolution = test.getMoveList();
// testing the gui
SolverPuzzleGUI testGUI = new SolverPuzzleGUI(testBoard, testGoalBlocks,
testMoveSolution);
testGUI.runSimulation();
}
} // end class 'SolverPuzzleGUI'
Here's the current output vs desired output.
http://imgur.com/a/ykXXP
So specifically, I have two questions:
1 - Why is the image only showing the top left corners of the blocks instead of the whole block?
2 - Is it better to continue using the GridLayout or switch to GridBagLayout?
Thanks
GridBagLayout would definitely be suitable for want you want to do. For example, you can expand components to envelop more than one column or row - just like what you want to do. Check out the java tutorials for how to use them.
A key point to remember when using GridBagLayoutis that you need to reset the Constraints after each component, assuming that they're unique to that particular component.
Also - I can't discern what you mean by only showing the top-left - it looks likes its showing the whole thing to me...

Creating a GUI with for loop using Java Swing

I have a GUI, from this GUI I choose an input file with the dimensions of a Booking system(new GUI) If the plane has 100 seats the GUI will be for example 10x10, if the plane has 200 seats it will be 10x20, all the seats are going to be buttons, and should store passenger information on them if they are booked.Also a booked seat shall not be booked again.
The question is the dimensions of the GUI will change according to the seat numbers and orientation, which means in one version there can be lots of buttons on another less, also more seats means the GUI will be longer or wider maybe 10 cm x 10 cm or 10 cm x 20 cm, or 15 cm x 25 cm...
I am thinking to do this with a for loop but I dont want to put buttons out of the GUI.I dont know how can I add a button next to the other button arbitrarily. I always used Eclipse Window Builder for building GUIs but I guess I need to write this one on my own... can someone help me?Some hints?Thanks for your time!
Try something like this:
// The size of the window.
Rectangle bounds = this.getBounds();
// How many rows of buttons.
int numOfRows = 100;
// How many buttons per row.
int numOfColumns = 50;
int buttonWidth = bounds.width / numOfRows;
int buttonHeight = bounds.height / numOfColumns;
int x = 0;
int y = 0;
for(int i = 0; i < numOfColumns; i++){
for(int j = 0; j < numOfRows; j++){
// Make a button
button.setBounds(x, y, buttonWidth, buttonHeight);
y += buttonHeight;
}
x += buttonWidth;
}
This will make all the buttons fit inside of your window.
Here's a link on rectangles, they come in pretty handy when doing things like this.
http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fswt%2Fgraphics%2FRectangle.html
Also, you can still use windowbuilder, infact I recommend you do. It really helps you to visualize the dimensions you want. AND you can also create stuff (buttons, lists, dropdowns... etc) manually with code and, assuming you put the variables where WindowBuilder would, it will still display them in the 'design' tab.
Hope this helps!
EDIT: I was kinda vague on how to make buttons using a loop
To make buttons with a loop you will need a buffer (to store a temporary button long enough to add to a list) and... a list :D.
This is how it should look:
Outside loop:
// The list to store your buttons in.
ArrayList<Button> buttons = new ArrayList<Button>();
// The empty button to use as a buffer.
Button button;
Inside loop (where the '//Make a button' comment is):
button = new Button(this, SWT.NONE);
buttons.add(button);
Now you have a list of all the buttons, and can easily access them and make changes such as change the buttons text like so;
buttons.get(indexOfButton).setText("SomeText");
EDIT:
Seeing as you're new to swt (and I couldn't get awt/JFrame to work) here's the full code.
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class ButtonTest extends Shell {
/**
* Launch the application.
* #param args
*/
// Code starts here in main.
public static void main(String args[]) {
try {
Display display = Display.getDefault();
// Creates a window (shell) called "shell"
ButtonTest shell = new ButtonTest(display);
// These two lines start the shell.
shell.open();
shell.layout();
// Now we can start adding stuff to our shell.
// The size of the window.
Rectangle bounds = shell.getBounds();
// How many rows of buttons.
int numOfRows = 5;
// How many buttons per row.
int numOfColumns = 3;
int buttonWidth = bounds.width / numOfRows;
int buttonHeight = bounds.height / numOfColumns;
Button button;
int x = 0;
int y = 0;
for(int i = 0; i < numOfColumns; i++){
for(int j = 0; j < numOfRows; j++){
button = new Button(shell, SWT.NONE);
button.setBounds(x, y, buttonWidth, buttonHeight);
x += buttonWidth;
}
x = 0;
y += buttonHeight;
}
// This loop keeps the shell from killing itself the moment it's opened
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Create the shell.
* #param display
*/
public ButtonTest(Display display) {
super(display, SWT.SHELL_TRIM);
createContents();
}
/**
* Create contents of the shell.
*/
protected void createContents() {
setText("SWT Application");
setSize(800, 800);
}
#Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
Also, I made a little typo in my nested loop (and forgot to reset the x value to 0 after each row). It's fixed in this edit.
Also you will need to import swt for this to work.
Go here: http://www.eclipse.org/swt/ and download the latest version for your operating system, then go in eclipse, right click your project > Build Path > configure Build Path > Libraries tab > Add external JAR's > find the swt file you downloaded and click.
Sorry for such a long answer, hope it helps :D
Start with a GridLayout. Each time you need to change the seat layout, reapply the GridLayout.
Ie, if you need 100 seats, use something like, new GridLayout(20, 10)...
Personally, I'd use a GridBagLayout, but it might be to complex for the task at hand
Its a little more difficult to add/rmove new content. I would, personally, rebuild the UI and reapply the model to it.
As for the size, you may not have much control over it, as it will appear differently on different screens. Instead, you should provide means by which you can prevent the UI from over sizing the screen.
This is achievable by placing the seating pane within a JScrollPane. This will allow the seating pane to expand and shrink in size without it potentially over sizing on the screen
Take a look at
Creating a UI with Swing
Using Layout Managers
A Visual Guide to Layout Managers

Categories