GraphicsContext strokeLine 方法未按预期绘制到 Canvas
GraphicsContext strokeLine method does not draw onto the Canvas as expected
当我使用GraphicsContext
的fillRect
方法时。 a 在 Canvas tilesetCanvas
上绘制了一个矩形。然后我继续使用 setStroke
和 strokeLine
方法,但这些方法不会像 fillRect
方法那样更新 canvas。是否有更新 Canvas 的特定方法,或者我使用的 setStroke
和 strokeLine
方法有误?
public class RedHacker extends Application {
// The four colors used for the tileset palette
final Color WHITE = new Color(1,1,1,0);
final Color LIGHTPURPLE = new Color(0.66,0,0.66,0);
final Color DARKPURPLE = new Color(0.33,0,0.33,0);
final Color BLACK = new Color(0,0,0,0);
private int[] redData;
private int[] tilesetHeaderAddresses;
private TilesetHeader[] tilesetHeaders;
private int[] mapHeaderPointers;
private int[] mapHeaderBanks;
private int[] mapHeaderAddresses;
private MapHeader[] mapHeaders;
public static void main(String[] args) {
launch(args);
}
@Override
/* Description:
* Sets up and starts the GUI.
*
* Parameters:
* hackingStage: The Stage for this GUI
*/
public void start(Stage hackingStage) {
initStage(hackingStage);
hackingStage.show();
}
/* Description:
* Sets up the Stage with its various children
*
* Parameters:
* hackingStage: The Stage for this GUI
*/
private void initStage(Stage hackingStage) {
// Root node for this GUI
// TODO Set alignments and margins for children
BorderPane hackingRoot = new BorderPane();
// Scene for this GUI
Scene hackingScene = new Scene(hackingRoot);
hackingStage.initStyle(StageStyle.DECORATED);
hackingStage.setMaximized(true);
hackingStage.setScene(hackingScene);
hackingStage.setTitle("Pokemon Red Hacker :)");
initBorderPane(hackingStage, hackingRoot);
}
/* Description:
* Sets up the children in the BorderPane
*
* Parameters:
* hackingStage: The stage for this GUI
* hackingRoot: The root pane for this GUI
*/
private void initBorderPane(Stage hackingStage, BorderPane hackingRoot) {
// Typical MenuBar
MenuBar hackingMB = new MenuBar();
// Shows File on the MenuBar
Menu fileMenu = new Menu("File");
// MenuItem for opening a file
MenuItem openMI = new MenuItem("Open");
// TabPane for different editors
TabPane hackingTP = new TabPane();
// Tab for the tileset editor
Tab tilesetTab = new Tab("Tilesets");
// Canvas for the tileset editor
Canvas tilesetCanvas = new Canvas(90, 90);
// GraphicsContext for drawing on the canvas
GraphicsContext gc = tilesetCanvas.getGraphicsContext2D();;
hackingMB.getMenus().add(fileMenu);
fileMenu.getItems().add(openMI);
openMI.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent e) {
openMIEvent(hackingStage, gc);
}
});
hackingRoot.setTop(hackingMB);
hackingTP.setSide(Side.LEFT);
hackingTP.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
tilesetTab.setClosable(false);
tilesetTab.setContent(tilesetCanvas);
hackingTP.getTabs().add(tilesetTab);
hackingRoot.setCenter(hackingTP);
gc.setFill(Color.BLUE);
gc.fillRect(10,10,80,80);
}
/* Description:
* Opens a FileChooser when the File MenuItem is triggered
*
* Parameters:
* hackingStage: The stage for this GUI
*/
private void openMIEvent(Stage hackingStage, GraphicsContext gc) {
// Typical FileChooser for opening a .gb file
FileChooser fc = new FileChooser();
fc.setSelectedExtensionFilter(new ExtensionFilter("GameBoy File", ".gb"));
fc.setTitle("Open GameBoy File:");
File sf = fc.showOpenDialog(hackingStage);
if(sf != null){
try{
parseFile(sf, gc);
}catch (IOException e) {
System.out.println("Error opening file");
}
}
}
private void parseFile(File sf, GraphicsContext gc) throws IOException {
FileInputStream in = null;
int i = 0;
int size;
redData = new int[(Math.toIntExact(sf.length()))];
size = redData.length;
try{
in = new FileInputStream(sf);
while(i < size){
redData[i] = in.read();
i++;
}
} finally{
if(in != null){
in.close();
}
}
getTilesetHeaderAddresses();
generateTilesetHeaders();
drawTileset(1, gc);
getMapHeaderPointers();
getMapHeaderBanks();
getMapHeaderAddresses();
generateMapHeaders();
System.out.println(":)");
}
private void getTilesetHeaderAddresses() {
int i = 0;
tilesetHeaderAddresses = new int[23];
while(i < 23){
tilesetHeaderAddresses[i] = (51134 + (i * 12));
i++;
}
}
private void generateTilesetHeaders() {
int i = 0;
tilesetHeaders = new TilesetHeader[23];
while(i < 23){
tilesetHeaders[i] = new TilesetHeader(redData, tilesetHeaderAddresses[i]);
i++;
}
}
private void drawTileset(int tilesetIndex, GraphicsContext gc) {
int i = 0;
while(i < 95){
if(i < 10){
drawTile(tilesetIndex, i*8, 0, gc);
} else if(i < 20){
drawTile(tilesetIndex, (i-10)*8, 8, gc);
} else if(i < 30){
drawTile(tilesetIndex, (i-20)*8, 16, gc);
} else if(i < 40){
drawTile(tilesetIndex, (i-30)*8, 24, gc);
} else if(i < 50){
drawTile(tilesetIndex, (i-40)*8, 32, gc);
} else if(i < 60){
drawTile(tilesetIndex, (i-50)*8, 40, gc);
} else if(i < 70){
drawTile(tilesetIndex, (i-60)*8, 48, gc);
} else if(i < 80){
drawTile(tilesetIndex, (i-70)*8, 56, gc);
} else if(i < 90){
drawTile(tilesetIndex, (i-80)*8, 64, gc);
} else{
drawTile(tilesetIndex, (i-90)*8, 72, gc);
}
i++;
}
}
private void drawTile(int tilesetIndex,int xStart, int yStart, GraphicsContext gc) {
boolean bitTwoIsOne;
boolean bitOneIsOne;
int tileByte1;
int tileByte2;
int i = 0;
int y = yStart;
int j;
int x;
PixelWriter pw;
int temp1;
int temp2;
int address;
try{
temp1 = xStart/8;
} catch(Exception e){
temp1 = 0;
}
try{
temp2 = 10*(yStart/8);
} catch(Exception e){
temp2 = 0;
}
address = temp1+temp2;
tileByte1 = redData[(tilesetHeaders[tilesetIndex].getTilesAddress())+address];
tileByte2 = redData[(tilesetHeaders[tilesetIndex].getTilesAddress())+1+address];
while(i < 8){
j = 7;
x = 0;
while(j > -1){
bitTwoIsOne = false;
bitOneIsOne = false;
if(((tileByte2 & (1 << (j))) >> (j)) == 1){
bitTwoIsOne = true;
}
if(((tileByte1 & (1 << (j))) >> (j)) == 1){
bitOneIsOne = true;
}
if(bitTwoIsOne && bitOneIsOne){
gc.setStroke(BLACK);
gc.strokeLine(x, y, x+1, y+1);
}else if(bitTwoIsOne){
gc.setStroke(DARKPURPLE);
gc.strokeLine(x, y, x+1, y+1);
}else if(bitOneIsOne){
gc.setStroke(LIGHTPURPLE);
gc.strokeLine(x, y, x+1, y+1);
}else{
gc.setStroke(WHITE);
gc.strokeLine(x, y, x+1, y+1);
}
j--;
x++;
}
y++;
i++;
}
}
private void getMapHeaderPointers() {
int i = 0;
mapHeaderPointers = new int[248];
while(i < 248){
short test1 = (short) (redData[(2*i)+431] << 8);
short test2 = (short) (redData[(2*i)+430] & 0xFF);
mapHeaderPointers[i] = (short) ((test1) | (test2));
i++;
}
}
private void getMapHeaderBanks() {
int i = 0;
mapHeaderBanks = new int[248];
while(i < 248){
mapHeaderBanks[i] = redData[49725+i];
i++;
}
}
private void getMapHeaderAddresses() {
int i = 0;
mapHeaderAddresses = new int[248];
while(i < 248){
mapHeaderAddresses[i] = (mapHeaderBanks[i]*0x4000) + (mapHeaderPointers[i]%0x4000);
i++;
}
}
private void generateMapHeaders() {
int i = 0;
mapHeaders = new MapHeader[248];
while((i < 248)){
if((i != 11) & (i != 105) & (i != 106) & (i != 107) & (i != 109) & (i != 110) & (i != 111) & (i != 112) & (i != 114) & (i != 115) & (i != 116) & (i != 117) & (i != 204) & (i != 205) & (i != 206) & (i != 231) & (i != 237) & (i != 238) & (i != 241) & (i != 242) & (i != 243) & (i != 244)){
mapHeaders[i] = new MapHeader(redData, mapHeaderAddresses[i], mapHeaderBanks);
}
i++;
}
}
}
特别是使用颜色:
final Color WHITE = new Color(1,1,1,0);
final Color LIGHTPURPLE = new Color(0.66,0,0.66,0);
final Color DARKPURPLE = new Color(0.33,0,0.33,0);
final Color BLACK = new Color(0,0,0,0);
使用方法:
gc.setStroke(BLACK);
gc.strokeLine(x, y, x+1, y+1);
不要在 Canvas 上画画。
我不得不将颜色的不透明度更改为大于 0 的值。Canvas 正在绘制,但不透明度为 0 使绘图不可见。
当我使用GraphicsContext
的fillRect
方法时。 a 在 Canvas tilesetCanvas
上绘制了一个矩形。然后我继续使用 setStroke
和 strokeLine
方法,但这些方法不会像 fillRect
方法那样更新 canvas。是否有更新 Canvas 的特定方法,或者我使用的 setStroke
和 strokeLine
方法有误?
public class RedHacker extends Application {
// The four colors used for the tileset palette
final Color WHITE = new Color(1,1,1,0);
final Color LIGHTPURPLE = new Color(0.66,0,0.66,0);
final Color DARKPURPLE = new Color(0.33,0,0.33,0);
final Color BLACK = new Color(0,0,0,0);
private int[] redData;
private int[] tilesetHeaderAddresses;
private TilesetHeader[] tilesetHeaders;
private int[] mapHeaderPointers;
private int[] mapHeaderBanks;
private int[] mapHeaderAddresses;
private MapHeader[] mapHeaders;
public static void main(String[] args) {
launch(args);
}
@Override
/* Description:
* Sets up and starts the GUI.
*
* Parameters:
* hackingStage: The Stage for this GUI
*/
public void start(Stage hackingStage) {
initStage(hackingStage);
hackingStage.show();
}
/* Description:
* Sets up the Stage with its various children
*
* Parameters:
* hackingStage: The Stage for this GUI
*/
private void initStage(Stage hackingStage) {
// Root node for this GUI
// TODO Set alignments and margins for children
BorderPane hackingRoot = new BorderPane();
// Scene for this GUI
Scene hackingScene = new Scene(hackingRoot);
hackingStage.initStyle(StageStyle.DECORATED);
hackingStage.setMaximized(true);
hackingStage.setScene(hackingScene);
hackingStage.setTitle("Pokemon Red Hacker :)");
initBorderPane(hackingStage, hackingRoot);
}
/* Description:
* Sets up the children in the BorderPane
*
* Parameters:
* hackingStage: The stage for this GUI
* hackingRoot: The root pane for this GUI
*/
private void initBorderPane(Stage hackingStage, BorderPane hackingRoot) {
// Typical MenuBar
MenuBar hackingMB = new MenuBar();
// Shows File on the MenuBar
Menu fileMenu = new Menu("File");
// MenuItem for opening a file
MenuItem openMI = new MenuItem("Open");
// TabPane for different editors
TabPane hackingTP = new TabPane();
// Tab for the tileset editor
Tab tilesetTab = new Tab("Tilesets");
// Canvas for the tileset editor
Canvas tilesetCanvas = new Canvas(90, 90);
// GraphicsContext for drawing on the canvas
GraphicsContext gc = tilesetCanvas.getGraphicsContext2D();;
hackingMB.getMenus().add(fileMenu);
fileMenu.getItems().add(openMI);
openMI.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent e) {
openMIEvent(hackingStage, gc);
}
});
hackingRoot.setTop(hackingMB);
hackingTP.setSide(Side.LEFT);
hackingTP.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
tilesetTab.setClosable(false);
tilesetTab.setContent(tilesetCanvas);
hackingTP.getTabs().add(tilesetTab);
hackingRoot.setCenter(hackingTP);
gc.setFill(Color.BLUE);
gc.fillRect(10,10,80,80);
}
/* Description:
* Opens a FileChooser when the File MenuItem is triggered
*
* Parameters:
* hackingStage: The stage for this GUI
*/
private void openMIEvent(Stage hackingStage, GraphicsContext gc) {
// Typical FileChooser for opening a .gb file
FileChooser fc = new FileChooser();
fc.setSelectedExtensionFilter(new ExtensionFilter("GameBoy File", ".gb"));
fc.setTitle("Open GameBoy File:");
File sf = fc.showOpenDialog(hackingStage);
if(sf != null){
try{
parseFile(sf, gc);
}catch (IOException e) {
System.out.println("Error opening file");
}
}
}
private void parseFile(File sf, GraphicsContext gc) throws IOException {
FileInputStream in = null;
int i = 0;
int size;
redData = new int[(Math.toIntExact(sf.length()))];
size = redData.length;
try{
in = new FileInputStream(sf);
while(i < size){
redData[i] = in.read();
i++;
}
} finally{
if(in != null){
in.close();
}
}
getTilesetHeaderAddresses();
generateTilesetHeaders();
drawTileset(1, gc);
getMapHeaderPointers();
getMapHeaderBanks();
getMapHeaderAddresses();
generateMapHeaders();
System.out.println(":)");
}
private void getTilesetHeaderAddresses() {
int i = 0;
tilesetHeaderAddresses = new int[23];
while(i < 23){
tilesetHeaderAddresses[i] = (51134 + (i * 12));
i++;
}
}
private void generateTilesetHeaders() {
int i = 0;
tilesetHeaders = new TilesetHeader[23];
while(i < 23){
tilesetHeaders[i] = new TilesetHeader(redData, tilesetHeaderAddresses[i]);
i++;
}
}
private void drawTileset(int tilesetIndex, GraphicsContext gc) {
int i = 0;
while(i < 95){
if(i < 10){
drawTile(tilesetIndex, i*8, 0, gc);
} else if(i < 20){
drawTile(tilesetIndex, (i-10)*8, 8, gc);
} else if(i < 30){
drawTile(tilesetIndex, (i-20)*8, 16, gc);
} else if(i < 40){
drawTile(tilesetIndex, (i-30)*8, 24, gc);
} else if(i < 50){
drawTile(tilesetIndex, (i-40)*8, 32, gc);
} else if(i < 60){
drawTile(tilesetIndex, (i-50)*8, 40, gc);
} else if(i < 70){
drawTile(tilesetIndex, (i-60)*8, 48, gc);
} else if(i < 80){
drawTile(tilesetIndex, (i-70)*8, 56, gc);
} else if(i < 90){
drawTile(tilesetIndex, (i-80)*8, 64, gc);
} else{
drawTile(tilesetIndex, (i-90)*8, 72, gc);
}
i++;
}
}
private void drawTile(int tilesetIndex,int xStart, int yStart, GraphicsContext gc) {
boolean bitTwoIsOne;
boolean bitOneIsOne;
int tileByte1;
int tileByte2;
int i = 0;
int y = yStart;
int j;
int x;
PixelWriter pw;
int temp1;
int temp2;
int address;
try{
temp1 = xStart/8;
} catch(Exception e){
temp1 = 0;
}
try{
temp2 = 10*(yStart/8);
} catch(Exception e){
temp2 = 0;
}
address = temp1+temp2;
tileByte1 = redData[(tilesetHeaders[tilesetIndex].getTilesAddress())+address];
tileByte2 = redData[(tilesetHeaders[tilesetIndex].getTilesAddress())+1+address];
while(i < 8){
j = 7;
x = 0;
while(j > -1){
bitTwoIsOne = false;
bitOneIsOne = false;
if(((tileByte2 & (1 << (j))) >> (j)) == 1){
bitTwoIsOne = true;
}
if(((tileByte1 & (1 << (j))) >> (j)) == 1){
bitOneIsOne = true;
}
if(bitTwoIsOne && bitOneIsOne){
gc.setStroke(BLACK);
gc.strokeLine(x, y, x+1, y+1);
}else if(bitTwoIsOne){
gc.setStroke(DARKPURPLE);
gc.strokeLine(x, y, x+1, y+1);
}else if(bitOneIsOne){
gc.setStroke(LIGHTPURPLE);
gc.strokeLine(x, y, x+1, y+1);
}else{
gc.setStroke(WHITE);
gc.strokeLine(x, y, x+1, y+1);
}
j--;
x++;
}
y++;
i++;
}
}
private void getMapHeaderPointers() {
int i = 0;
mapHeaderPointers = new int[248];
while(i < 248){
short test1 = (short) (redData[(2*i)+431] << 8);
short test2 = (short) (redData[(2*i)+430] & 0xFF);
mapHeaderPointers[i] = (short) ((test1) | (test2));
i++;
}
}
private void getMapHeaderBanks() {
int i = 0;
mapHeaderBanks = new int[248];
while(i < 248){
mapHeaderBanks[i] = redData[49725+i];
i++;
}
}
private void getMapHeaderAddresses() {
int i = 0;
mapHeaderAddresses = new int[248];
while(i < 248){
mapHeaderAddresses[i] = (mapHeaderBanks[i]*0x4000) + (mapHeaderPointers[i]%0x4000);
i++;
}
}
private void generateMapHeaders() {
int i = 0;
mapHeaders = new MapHeader[248];
while((i < 248)){
if((i != 11) & (i != 105) & (i != 106) & (i != 107) & (i != 109) & (i != 110) & (i != 111) & (i != 112) & (i != 114) & (i != 115) & (i != 116) & (i != 117) & (i != 204) & (i != 205) & (i != 206) & (i != 231) & (i != 237) & (i != 238) & (i != 241) & (i != 242) & (i != 243) & (i != 244)){
mapHeaders[i] = new MapHeader(redData, mapHeaderAddresses[i], mapHeaderBanks);
}
i++;
}
}
}
特别是使用颜色:
final Color WHITE = new Color(1,1,1,0);
final Color LIGHTPURPLE = new Color(0.66,0,0.66,0);
final Color DARKPURPLE = new Color(0.33,0,0.33,0);
final Color BLACK = new Color(0,0,0,0);
使用方法:
gc.setStroke(BLACK);
gc.strokeLine(x, y, x+1, y+1);
不要在 Canvas 上画画。
我不得不将颜色的不透明度更改为大于 0 的值。Canvas 正在绘制,但不透明度为 0 使绘图不可见。