java - JavaFX : Button never sets a graphic -
edit :
a mcve version of code has been made debug it. reproduces bug. purpose of code doing memory game. means when turn, "open" card, one. if form pair, don't turned over, stay open. otherwise, turn them on , try find pair on next turn.
simply put, bug : when opening second card of turn , both cards don't form pair, second 1 never gets opened!
hopefully, version of code find bug, me lot!
i have put code on github : https://gist.github.com/anonymous/e866671d80384ae53b53 (and find attached @ end of question)
explanation of issue
i having fun on doing little memory game in javafx , came across strange behavior card click on (represented custom class extends button class) never changes image displayed.
normally, when click on card, "opens" changing graphic displays. strange , annoying thing happens in specific case.
the behavior of card correct when "open" first card of turn of player. works when "open" second 1 , both cards pair. sadly, doesn't work in case want open second card , doesn't match pair first one.
i modified button class adding opencard()
, closecard()
methods. methods set specific graphic on button-card.
i show code hard tell might part making behavior happen. more using eclipse can't possibly figure out how debug javafx app breakpoints (i using console prints) because app crash when reach breakpoints , start crawling through lines of code.
the code
firstly, modified button class :
public class card extends button{ private string carddesign; public card(int row, int column){ this.setgraphic(new imageview("/resources/card_back.png")); this.setbackground(new background(new backgroundfill(color.slategray, new cornerradii(6), null))); } public void setopencarddesign(string design){ carddesign = design; } public void opencard(){ this.setgraphic(new imageview(carddesign)); } public void closecard(){ this.setgraphic(new imageview("/resources/card_back.png")); }
}
now controller class, event set on mouseevent
. there more code in controller (like checking if there pair), isn't issue here think problem @ line call method open card. use getsource()
method here because cards arranged in gridpane , need know 1 has been clicked on.
@override public void handle(mouseevent event) { //get card clicked on card card = (card) event.getsource(); //open card card.opencard(); //do more after this...
}
that's pretty figure out.
as stated, tried check if method opencard()
being called. comment printed in console showed up. added console printing before , after line set graphic , both showing up. can't know sure happens when app reaches setgraphic()
line nothing showing in app (the card remains closed).
any hint because sinking in madness right now. thank in advance.
the mcve version of code
the card object : card.java
package memory; import javafx.scene.control.button; import javafx.scene.layout.background; import javafx.scene.layout.backgroundfill; import javafx.scene.layout.cornerradii; import javafx.scene.paint.color; public class card extends button{ //------------------------------------------------- //store position of card private int row; private int column; //------------------------------------------------- //constructor public card(int row, int column){ //give cards specific color @ init this.setbackground(new background(new backgroundfill(color.deepskyblue, new cornerradii(6), null))); this.settext("closed"); this.row = row; this.column = column; } //------------------------------------------------- //open card public void opencard(){ system.out.println("open"); //cards red when open this.setbackground(new background(new backgroundfill(color.red, new cornerradii(6), null))); this.settext("open"); } //------------------------------------------------- //close card public void closecard(){ system.out.println("close"); //cards blue when closed this.setbackground(new background(new backgroundfill(color.deepskyblue, new cornerradii(6), null))); this.settext("closed"); } //------------------------------------------------- //getters row , column info public int getrow() { return row; } public int getcolumn() { return column; } }
the main (includes view , start point of app) : main.java
package memory; import javafx.application.application; import javafx.event.eventhandler; import javafx.geometry.insets; import javafx.geometry.pos; import javafx.scene.scene; import javafx.scene.input.mouseevent; import javafx.scene.layout.background; import javafx.scene.layout.backgroundfill; import javafx.scene.layout.borderpane; import javafx.scene.layout.cornerradii; import javafx.scene.layout.gridpane; import javafx.scene.paint.color; import javafx.stage.stage; public class main extends application { //------------------------------------------------- //the layout , cards gridpane gridcard = new gridpane(); static card [][] cardarray; //the event handler private static eventhandler<mouseevent> handler; //the array remembers pairs , reminder of last open card static int[][] indexarray; static int index; //boolean array check if card open static boolean[][] isopen; //number of pairs find static int pairs = 5; //------------------------------------------------- //cheap main public static void main(string[] args) { application.launch(args); } //------------------------------------------------- @override public void start(stage primarystage) throws exception { //init event handler handler = new controller(); //some formatting grid pane gridcard.sethgap(10); gridcard.setvgap(10); gridcard.setpadding(new insets(0, 10, 0, 10)); gridcard.setalignment(pos.center); //creating our card board, index array , bool array cardarray = new card [2][5]; indexarray = new int [2][5]; isopen = new boolean [2][5]; //adding cards our card array for(int = 0; < 2; i++){ for(int j = 0; j < 5; j++){ cardarray[i][j] = new card(i, j); //make buttons cards cardarray[i][j].setprefheight(100); cardarray[i][j].setprefwidth(70); //register event cardarray[i][j].addeventhandler(mouseevent.mouse_clicked, gamecontroller()); //add cards gridcard.add(cardarray[i][j], j, i); //set pairs (no randomness here) indexarray[i][j] = j+1; } } //print out indexes of cards system.out.println("----------------"); system.out.println("card indexes :"); (int = 0; < indexarray.length; i++) { system.out.println(); (int j = 0; j < indexarray[0].length; j++) { system.out.print(indexarray[i][j]+ " | "); } system.out.println(); } system.out.println("----------------"); //set borderpane borderpane root = new borderpane(); root.setbackground(new background(new backgroundfill(color.black, cornerradii.empty, null))); root.setcenter(gridcard); //set stage primarystage.setscene(new scene(root)); primarystage.settitle("memory test"); primarystage.show(); } //------------------------------------------------- //getter event handler public static eventhandler<mouseevent> gamecontroller() { return handler; } //------------------------------------------------- //getter, setter , "resetter" index public static void resetindex() { index = 0; } public static int getindex() { return index; } public static void setindex(int i) { index = i; } //------------------------------------------------- }
the controller : controller.java
package memory; import javafx.event.eventhandler; import javafx.scene.control.alert; import javafx.scene.control.alert.alerttype; import javafx.scene.input.mouseevent; public class controller implements eventhandler<mouseevent>{ //------------------------------------------------- @override public void handle(mouseevent event) { //get card cas clicked on card card = (card) event.getsource(); //if card open, don't if (!main.isopen[card.getrow()][card.getcolumn()]) { //open card card.opencard(); //we opened first card of turn if (main.getindex() == 0) { //set card open main.isopen[card.getrow()][card.getcolumn()] = true; //remember index main.setindex(main.indexarray[card.getrow()][card.getcolumn()]); system.out.println("index: "+main.getindex()); //we opened second card }else if (main.getindex() != 0) { //check if pair if (main.getindex() == main.indexarray[card.getrow()][card.getcolumn()]) { //decrement number of pairs main.pairs--; //open second card main.isopen[card.getrow()][card.getcolumn()] = true; //reset index main.resetindex(); }else{ //close both cards if isn't pair //wait 0.7 second let player remember cards try { thread.sleep(700); } catch (interruptedexception e) { e.printstacktrace(); } //close current card card.closecard(); system.out.println("index : " + main.indexarray[card.getrow()][card.getcolumn()]); main.isopen[card.getrow()][card.getcolumn()] = false; //close first opened card looking @ index //it closes both cards same index, doesn't matter //as pair hasn't been found anyway (int = 0; < main.indexarray.length; i++) { (int j = 0; j < main.indexarray[0].length; j++) { if (main.getindex() == main.indexarray[i][j]) { main.cardarray[i][j].closecard(); system.out.println("index: " + main.indexarray[i][j]); main.isopen[i][j] = false; } } } //reset index of last opened card main.resetindex(); } } } //check endgame if (main.pairs == 0) { //show dialog box alert incorrectpairs = new alert(alerttype.information); incorrectpairs.settitle("game over"); incorrectpairs.setheadertext("the game over"); incorrectpairs.setcontenttext("you found pairs, congrats!"); incorrectpairs.showandwait(); } } //------------------------------------------------- }
you're blocking ui thread thread.sleep(...)
. prevents pending changes being repainted, don't see first update @ all; see subsequent updates after pause complete.
the simplest way implement pause on ui thread use pausetransition
javafx animation api. basically, do
pausetransition pause = new pausetransition(duration.millis(700)); pause.setonfinished(e -> { // code execute after pause... }); pause.play();
in case, want disable user interface, user cannot click on during pause, like
pausetransition pause = new pausetransition(duration.millis(700)); pause.setonfinished(e -> { card.closecard(); // ... etc... card.getparent().setdisable(false); }); card.getparent().setdisable(true); pause.play();
Comments
Post a Comment