Here is my the TableCell made by my CellFactory:
#Override
protected void updateItem(Void value, boolean empty) {
if (empty) {
setBackground(Background.EMPTY);
} else {
Fish fish = getTableRow().getItem();
if (fish == null) {
setBackground(Background.EMPTY);
} else {
setStyle("-fx-background-color: " + Utils.colorToString(fish.getColor()));
}
}
}
It works ok, but when I delete an item from the Table's items, it looks like this:
How can I stop those colors from appearing at the bottom? I have spent at least 10 hours looking for a solution..
You're using two different mechanisms to set the background: either setting a background directly with setBackground(...), or setting the style.
If the style is set on a cell, and then the cell becomes empty, the style is not removed, so a background color remains.
Stick to either one or the other:
#Override
protected void updateItem(Void value, boolean empty) {
if (empty) {
setStyle("");
} else {
Fish fish = getTableRow().getItem();
if (fish == null) {
setStyle("");
} else {
setStyle("-fx-background-color: " + Utils.colorToString(fish.getColor()));
}
}
}
or
#Override
protected void updateItem(Void value, boolean empty) {
if (empty) {
setBackground(Background.EMPTY);
} else {
Fish fish = getTableRow().getItem();
if (fish == null) {
setBackground(Background.EMPTY);
} else {
setBackground(new Background(new BackgroundFill(fish.getColor(), CornerRadii.EMPTY, Insets.EMPTY)));
}
}
}
I'm making a simple procedural generated dungeon where your character spawns in a room with randomly opened or closed doors in random direction. This is already complete.
When the character leaves the room it will generate new random numbers for a new room. Storing the numbers of the old room and to generate a room with those numbers if the character travels backwards. This part isn't finished, but would be easy to do, but I don't want to do that yet, because it will cause the problem below.
How could I create something that could store that no matter where the player travels and know when to use the variables? How could I automatically create variables like that?
Current Code:
public class Executable extends JFrame implements KeyListener {
Container contentPane=this.getContentPane();
Graphics bufferGraphics;
int xAxis; //Universal Variables:
int yAxis;
int characterX=463;
int characterY=486;
int oldCharacterX=463;
int oldCharacterY=486;
Image characterNorth = CustomImages.createImageIcon("Images/characterNorth.jpg").getImage();
Image characterEast = CustomImages.createImageIcon("Images/characterEast.jpg").getImage();
Image characterSouth = CustomImages.createImageIcon("Images/characterSouth.jpg").getImage();
Image characterWest = CustomImages.createImageIcon("Images/characterWest.jpg").getImage();
Image brickWall = CustomImages.createImageIcon("Images/brickWall.jpg").getImage();
Image brickFloor = CustomImages.createImageIcon("Images/brickFloor.jpg").getImage();
Image character=characterNorth;
boolean pressed=false;
static boolean northDoor;
static boolean eastDoor;
static boolean southDoor;
static boolean westDoor;
static boolean Randomizer=true;
static int north;
static int east;
static int south;
static int west;
static Random r=new Random();
boolean doorOpen=false;
public static void main(String[] args) { //Main
north=r.nextInt(3)+1;
east=r.nextInt(3)+1;
south=r.nextInt(3)+1;
west=r.nextInt(3)+1;
if(north==1) {
northDoor=true;
}else {
northDoor=false;
}
if(east==1) {
eastDoor=true;
}else {
eastDoor=false;
}
if(south==1) {
southDoor=true;
}else {
southDoor=false;
}
if(west==1) {
westDoor=true;
}else {
westDoor=false;
}
Executable e=new Executable();
}
public Executable() { //Canvas
this.setBounds(0, 0, 1680, 1050);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addKeyListener(this);
setFocusable(true);
requestFocusInWindow();
}
public void paint(Graphics g) { //Paint
for(xAxis=58;xAxis<=858;xAxis=xAxis+50) {
for(yAxis=81;yAxis<=881;yAxis=yAxis+50) {
g.drawImage(brickFloor,xAxis,yAxis,null);
}
yAxis=31;
}
for(xAxis=8;xAxis<958;xAxis=xAxis+50) {
g.drawImage(brickWall,xAxis,yAxis,null);
}
yAxis=931;
for(xAxis=8;xAxis<=908;xAxis=xAxis+50) {
g.drawImage(brickWall,xAxis,yAxis,null);
}
xAxis=8;
for(yAxis=81;yAxis<=881;yAxis=yAxis+50) {
g.drawImage(brickWall,xAxis,yAxis,null);
}
xAxis=908;
for(yAxis=81;yAxis<=881;yAxis=yAxis+50) {
g.drawImage(brickWall,xAxis,yAxis,null);
}
while(!doorOpen) {
if(northDoor==false && eastDoor==false && southDoor==false && westDoor==false) {
north=r.nextInt(3)+1;
east=r.nextInt(3)+1;
south=r.nextInt(3)+1;
west=r.nextInt(3)+1;
if(north==1) {
northDoor=true;
}else {
northDoor=false;
}
if(east==1) {
eastDoor=true;
}else {
eastDoor=false;
}
if(south==1) {
southDoor=true;
}else {
southDoor=false;
}
if(west==1) {
westDoor=true;
}else {
westDoor=false;
}
}else {
doorOpen=true;
}
}
if(northDoor) {
g.drawImage(brickFloor,458,31,null);
}
if(eastDoor) {
g.drawImage(brickFloor,908,481,null);
}
if(southDoor) {
g.drawImage(brickFloor,458,931,null);
}
if(westDoor) {
g.drawImage(brickFloor,8,481,null);
}
g.drawImage(character,characterX,characterY,null);
}
#Override
public void keyPressed(KeyEvent arg0) { //Character rotation and movement.
if(pressed==false) {
pressed=true;
if(arg0.getKeyCode() == KeyEvent.VK_W){
if(character==characterNorth) {
if(characterY>86 && characterX>13 && characterX<913) {
characterY=characterY-50;
}else if(northDoor && characterX==463) {
oldCharacterY=characterY;
characterY=characterY-50;
}
}else {
character=characterNorth;
}
}
if(arg0.getKeyCode() == KeyEvent.VK_A){
if(character==characterWest && characterY>36 && characterY<926) {
if(characterX>63) { //and y is greater than and less than
oldCharacterX=characterX;
characterX=characterX-50;
}else if(westDoor && characterY==486) {
oldCharacterX=characterX;
characterX=characterX-50;
}
}else {
character=characterWest;
}
}
if(arg0.getKeyCode() == KeyEvent.VK_S){
if(character==characterSouth) {
if(characterY<871 && characterX>13 && characterX<913) {
oldCharacterY=characterY;
characterY=characterY+50;
}else if(southDoor && characterX==463) {
oldCharacterY=characterY;
characterY=characterY+50;
}
}else {
character=characterSouth;
}
}
if(arg0.getKeyCode() == KeyEvent.VK_D){
if(character==characterEast && characterY>36 && characterY<926) {
if(characterX<848) { //and y is greater than and less than
oldCharacterX=characterX;
characterX=characterX+50;
}else if(eastDoor && characterY==486) {
oldCharacterX=characterX;
characterX=characterX+50;
}
}else {
character=characterEast;
}
}
repaint(oldCharacterX,oldCharacterY,40,40);
repaint(characterX,characterY,40,40);
}
}
#Override
public void keyReleased(KeyEvent arg0) { //Prevents keys from being held down.
if(arg0.getKeyCode() == KeyEvent.VK_W){
pressed=false;
}
if(arg0.getKeyCode() == KeyEvent.VK_A){
pressed=false;
}
if(arg0.getKeyCode() == KeyEvent.VK_S){
pressed=false;
}
if(arg0.getKeyCode() == KeyEvent.VK_D){
pressed=false;
}
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
Hopefully this will help a bit. I would suggest you have a game state, this handles drawing, moving, key events like your current Executable class.
Basic overview of what is below. The GameState has a reference to a currentRoomState this is what you should deem the character is in. Upon moving to a door, you will need to check for this, the call to currentRoomState.MoveToNextRoom() with the appropreate parameters.
This will trigger the current room state to generate a new room, set the reference to the new room to be tied to the correct door, place the character at the correct door in the new room, tie a refernce to the old room in the new room and set the current room to the new room.
When you move to a door that has a previous room tied to it, the variables will have been persisted.
Best of luck
-Chris
eg:
class GameState{
RoomState startingRoomState = new RoomState();
RoomState currentRoomState = startingRoomState;
public void move(int x, int y)
{
currentRoomState.iCharacterPosX += x;
currentRoomState.iCharacterPosY += y;
// Check if need to move to a new room (eg move north)
currentRoomState = currentRoomState.MoveToNextRoom(true, false, false, false);
}
public void draw()
{
//Based on the character pos and draw variables in currentRoomState
}
}
And then you have a room state, which describes a room
class RoomState{
//Where the doors are
boolean northDoor = false;
boolean eastDoor = false;
boolean southDoor = false;
boolean westDoor = false;
// Reference to the room adjacent rooms
RoomState rs_NorthDoor = null;
RoomState rs_EastDoor = null;
RoomState rs_SouthDoor = null;
RoomState rs_WestDoor = null;
int iCharacterPosX = 0;
int iCharacterPosY = 0;
// Initial
RoomState(){
northDoor = true; eastDoor = true; southDoor = true; westDoor = true;
}
RoomState(RoomState prevState, boolean north, boolean east, boolean south, boolean west){
// Randomise door states
// Put character in the position he should be
iCharacterPosX = 0;//right most x Coord - oldX
iCharacterPosX = 0;//bottom most y Coord - oldy
if(north)
{
rs_NorthDoor = prevState;
} //elseif other doors
}
public RoomState MoveToNextRoom(boolean north, boolean east, boolean south, boolean west){
if(north){
if(rs_NorthDoor == null)
{
rs_NorthDoor = new RoomState(this, north, east, south, west);
}
return rs_NorthDoor;
} //else if the others
return null;
}
}
If you are looking to store the random number associated with each room and then traverse backward, in order, through the random numbers, a stack is the data structure you are looking for. To gain a conceptual understanding of a stack, see Stack (abstract data type). In short, a stack is like a pile of papers, where the last item placed at the top of the pile is the first element removed from the pile when traversing through the papers, termed Last-in-First-out (LIFO) ordering.
In Java, a Deque (double-ended queue, pronounced "deck") can be used as a stack. To put an element on the top of the stack, you use the push method and remove an element from the top of the stack, you use the pop method (note that pop both obtains the value at the top of the stack and removes it from the stack). For example:
Deque<Integer> stack = new ArrayDeque<>();
stack.push(10);
stack.push(20);
System.out.println(stack.pop());
stack.push(30);
System.out.println(stack.pop());
System.out.println(stack.pop());
This code will produce the following output:
20
30
10
To encapsulate this functionality, you can create a new class called RoomTracker (or something similarly named to denote the action of tracking the previous rooms) and implement it as follows:
public class RoomTracker {
private final Deque<Integer> rooms = new ArrayDeque<>();
public void addRoomNumber(Integer roomNumber) {
rooms.push(roomNumber);
}
public Integer getPreviousRoomNumber() {
return rooms.pop();
}
}
In a similar fashion as before, you can use this code as follows:
RoomTracker tracker = new RoomTracker();
tracker.addRoomNumber(10);
tracker.addRoomNumber(20);
System.out.println(tracker.getPreviousRoomNumber());
tracker.addRoomNumber(30);
System.out.println(tracker.getPreviousRoomNumber());
System.out.println(tracker.getPreviousRoomNumber());
This will produce the following output:
20
30
10
If you need to track the direction in which you entered the room (so that you find if a player is going to a previous room), you can create a class called Room and store the randomly generated number and the direction in which the player entered:
public enum Direction {
TOP, RIGHT, BOTTOM, LEFT;
}
public class Room {
private final int number;
private final Direction enteredFrom;
public Room(int number, Direction enteredFrom) {
this.number = number;
this.enteredFrom = enteredFrom;
}
public int getNumber() {
return number;
}
public Direction getEnteredFrom() {
return enteredFrom;
}
}
You can then redefine RoomTracker in terms of Room:
public class RoomTracker {
private final Deque<Room> rooms = new ArrayDeque<>();
public void addRoom(Room room) {
rooms.push(room);
}
public Room getPreviousRoom() {
return rooms.pop();
}
}
You can then push Room objects onto the stack as the player travels from one room to the next. For example:
RoomTracker tracker = new RoomTracker();
tracker.push(new Room(10, Direction.LEFT); // Travel right into room 10
tracker.push(new Room(20, Direction.TOP); // Travel down into room 20
I've got Path element, which is manually drawn and saved as a Node. I cannot figure how to get center coordinates for this entire node, so if relocate my Path using relocate() method and later decide to put it back where it was, it does not return to it's initial position. I have tried using getLayoutX() and getLayoutY() methods, but it moves my node further up from original position.
Code i use for relocate
class PathEventHandler implements EventHandler<MouseEvent>{
//element number in paths
public int n;
public PathEventHandler(int n){
this.n=n;
}
#Override
public void handle(MouseEvent me) {
if (me.getEventType() == MouseEvent.MOUSE_ENTERED) {
paths.get(n).setEffect(new DropShadow(20, Color.BLACK));
}
if (me.getEventType() == MouseEvent.MOUSE_EXITED) {
paths.get(n).setEffect(null);
}
if (i == 2) {
if (me.getEventType() == MouseEvent.MOUSE_DRAGGED) {
listX.add(paths.get(n).getLayoutX());
listY.add(paths.get(n).getLayoutY());
paths.get(n).relocate(me.getSceneX(), me.getSceneY());
cachePath.add(paths.get(n));
cacheType.add("Relocate");
}
if (me.getEventType() == MouseEvent.MOUSE_CLICKED) {
if (me.getButton() == MouseButton.SECONDARY) {
root.getChildren().remove(paths.get(n));
cachePath.add(paths.get(n));
cacheType.add("Remove");
}
}
}
}
}
Based on your previous question, and what you've barely described in this one, I've tried to figure out what you are trying to accomplish.
Maybe it's far from there, but this short but functional code should be enough for you to understand how to deal with path creation (as for the first question) and path movement (for the actual question), all within the same mouse listener.
private Path path;
private double x1, y1;
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
root.addEventHandler(MouseEvent.ANY, e -> {
if(e.getTarget() instanceof Path){
// Select existing path
Path path1 = (Path)e.getTarget();
if (e.getEventType() == MouseEvent.MOUSE_ENTERED_TARGET) {
path1.setEffect(new DropShadow(20, Color.BLACK));
} else if (e.getEventType() == MouseEvent.MOUSE_EXITED_TARGET) {
path1.setEffect(null);
} else if (e.getEventType() == MouseEvent.MOUSE_PRESSED) {
x1=e.getX();
y1=e.getY();
} else if (e.getEventType() == MouseEvent.MOUSE_DRAGGED) {
// traslate path
path1.setTranslateX(e.getX()-x1+path1.getTranslateX());
path1.setTranslateY(e.getY()-y1+path1.getTranslateY());
x1=e.getX();
y1=e.getY();
} else if (e.getButton()==MouseButton.SECONDARY) {
// right-click over the path to move it to its original position
path1.setTranslateX(0);
path1.setTranslateY(0);
}
} else {
// Generate new path
if (e.getEventType() == MouseEvent.MOUSE_PRESSED) {
path = new Path();
path.setStroke(Color.BLACK);
path.setStrokeWidth(10);
path.getElements().add(new MoveTo(e.getX(), e.getY()));
root.getChildren().add(path);
} else if (e.getEventType() == MouseEvent.MOUSE_DRAGGED ||
e.getEventType() == MouseEvent.MOUSE_RELEASED) {
path.getElements().add(new LineTo(e.getX(), e.getY()));
}
}
});
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
This is the method im trying to invoke.
public void update(int status) {
if (status == 1)
{
setBorder(new LineBorder(Color.YELLOW, BORDERSIZE+1));
}
else if (status == 2)
{
setBorder(new LineBorder(Color.CYAN, BORDERSIZE+1));
}
else if (status == 3)
{
setBorder(new LineBorder(Color.BLACK, BORDERSIZE));
}
revalidate();
}
This is the code trying to use it.
private void handleMouseClick(int x, int y, int button) {
try {
// This is called by the board squares when they are clicked
// Handle the logic of updates to the client/game here
if(button == 1){
if(x != -1 && y != -1){
update(1);
x = -1;
y = -1;
updateGrids();
}
else{
update(3);
}
}
else if(button == 3){
}
}
catch (IOException ex) {
System.err.println(ex);
}
The update method is inside a class called GridLayout, I've tried to just simply use GridLayout.update(aninteger); but it didn't work for me.
You need an instance of GridLayout object in order to call the update function.
Withouth knowning how GridLayout is related to your existing code I cannot advice further. However if GridLayout is a temporary object you could try:
GridLayout worker = new GridLayout(... whatever ...);
worker.update(aninteger);
Otherwise, you might need to get it from the framework involved, or something along these lines:
this.getGridLayout().update(aninteger);
I have made a custom BasicScrollBarUI.
I have replaced the incrButton / decrButton by JLabels.
Therefore i had to override the InstallListeners(), to add the Listener to the incr/decrLabel instead of the JButtons.
//TODO
protected void installListeners() {
trackListener = createTrackListener();
buttonListenerCustom = createArrowButtonListenerCustom();
modelListener = createModelListener();
propertyChangeListener = createPropertyChangeListener();
scrollbar.addMouseListener(trackListener);
scrollbar.addMouseMotionListener(trackListener);
scrollbar.getModel().addChangeListener(modelListener);
scrollbar.addPropertyChangeListener(propertyChangeListener);
// scrollbar.addFocusListener(getHandler());
if (incrLabel != null) {
incrLabel.addMouseListener(buttonListenerCustom);
System.out.println("OK gemacht");
}
if (decrLabel != null) {
decrLabel.addMouseListener(buttonListenerCustom);
}
scrollListener = createScrollListener();
scrollTimer = new Timer(scrollSpeedThrottle, scrollListener);
scrollTimer.setInitialDelay(300); // default InitialDelay?
}
Therefore i had to override the ArrowButtonListener, to react on the Labels.
protected class ArrowButtonListenerCustom extends MouseAdapter {
boolean handledEvent;
public void mousePressed(MouseEvent e) {
if (!scrollbar.isEnabled()) {
return;
}
// not an unmodified left mouse button
// if(e.getModifiers() != InputEvent.BUTTON1_MASK) {return; }
if (!SwingUtilities.isLeftMouseButton(e)) {
return;
}
int direction;
if (e.getSource() == incrLabel) {
direction = 1;
incrLabel.setIcon(new ImageIcon(increaseButtonPressedImage));
} else {
direction = -1;
decrLabel.setIcon(new ImageIcon(decreaseButtonPressedImage));
}
scrollByUnit(direction);
scrollTimer.stop();
scrollListener.setDirection(direction);
scrollListener.setScrollByBlock(false);
scrollTimer.start();
handledEvent = true;
if (!scrollbar.hasFocus() && scrollbar.isRequestFocusEnabled()) {
scrollbar.requestFocus();
}
}
public void mouseReleased(MouseEvent e) {
scrollTimer.stop();
handledEvent = false;
scrollbar.setValueIsAdjusting(false);
incrLabel.setIcon(new ImageIcon(increaseButtonImage));
decrLabel.setIcon(new ImageIcon(decreaseButtonImage));
}
}
Of course createArrowButtonListenerCustom() returns a new instance of ArrowButtonListenerCustom.
Now my Problem:
When I click on the incr/decrLabel, the List scrolls correctly, but the thumb of the ScrollBar doesn't move (or better: the Thumb isn't repainted. If I move the Mouse over the thumb, it gets repainted on the right place). I have the same problem, when I scroll with the MouseWheel.
I don't understand, why this doesn't work.
Thanks for your help!