GraphicsContext strokeLine 方法未按预期绘制到 Canvas

GraphicsContext strokeLine method does not draw onto the Canvas as expected

当我使用GraphicsContextfillRect方法时。 a 在 Canvas tilesetCanvas 上绘制了一个矩形。然后我继续使用 setStrokestrokeLine 方法,但这些方法不会像 fillRect 方法那样更新 canvas。是否有更新 Canvas 的特定方法,或者我使用的 setStrokestrokeLine 方法有误?

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 使绘图不可见。