【问题标题】:Why does paint of one class does not see an array of another class?为什么一个类的油漆看不到另一个类的数组?
【发布时间】:2013-12-09 06:23:31
【问题描述】:

所以我的问题如下:我正在创建俄罗斯方块的克隆。在我的一个课程中,我有一个 Jpanel,它可以绘制所有内容并具有一个绘制方法。

public class Action extends JPanel { 
private final Color BACKGROUND_COLOR = Color.yellow; 

public Action() { 
    setBackground(BACKGROUND_COLOR); 
    setPreferredSize(new Dimension(100, 220)); 
    setVisible(true); 
    new Timer(1000, new TimerListener()).start(); 
}

@Override
protected void paintComponent(Graphics pen) { 
    super.paintComponent(pen); 
    pen.setColor(Color.gray); 
    GameMemory memory = new GameMemory(); 
    int[][] grid = memory.getGrid(); 
    for (int r = 0; r < grid.length; r++ ) 
        for (int c = 0; c < grid[c].length; c++) 
            if (grid[r][c] == 1) 
                pen.fillRect(c * 30, r * 30, 40, 40); 
} 


private class TimerListener implements ActionListener { 
    @Override
    public void actionPerformed(ActionEvent e) { 
        Action.this.repaint(); 
    } 
} 

} 

我试图让它每秒重新绘制一次。

另一个类是一个数组,它保存在内存占用的单元格中,如果它们是,则将它们标记为状态 1。

/**
This class will contain a two-dimensional array that will 
keep in itself the figures, as well as checking if the raws are 
full. 

*/

public class GameMemory { 
private final int AXIS_X = 6; //Where axis of the 
private final int AXIS_Y = 1; //figure will appear
private int curX = AXIS_X; 
private int curY = AXIS_Y; 
private final int[][] grid = new int[22][10]; 
FigureI figure = new FigureI(); 

GameMemory() {
    Timer timer = new Timer(1000, new TimerListener()); 
    timer.start(); 
}


public int[][] getGrid() { 
    return grid; 
}

private class TimerListener implements ActionListener { 
    @Override 
    public void actionPerformed(ActionEvent e) { 
        curY ++; 
        grid[curY + figure.block0[1]][curX + figure.block0[0]] = 1; 
        grid[curY + figure.block1[1]][curX + figure.block1[0]] = 1; 
        grid[curY + figure.block2[1]][curX + figure.block2[0]] = 1; 
        grid[curY + figure.block3[1]][curX + figure.block3[0]] = 1; 
        System.out.println(Arrays.deepToString(grid)); // To debug.
    } 
} 

第三个文件只包含图形坐标。

  /**
    This file contains all the figures. 
    */ 



class FigureI { 

int[] block1 = { 0, -1 }; 
int[] block0 = { 0, 0 }; 
int[] block2 = { 0, 1 }; 
int[] block3 = { 0, 2 }; 

}


    class FigureJ { 
    int[] block1 = { 1, 0 }; 
    int[] block0 = { 0, 0 }; 
    int[] block2 = { -1, 0 }; 
    int[] block3 = { -1, -1 }; 
}

class FigureL { 
    int[] block1 = { -1, 0 }; 
    int[] block0 = { 0, 0 }; 
    int[] block2 = { 1, 0 }; 
    int[] block3 = { 1, 1 }; 
}

class FigureO { 
    int[] block1 = { 1, 0 }; 
    int[] block0 = { 0, 0 }; 
    int[] block2 = { -1, 0 }; 
    int[] block3 = { -1, 1 }; 
}

class FigureS { 
    int[] block1 = { -1, 0 }; 
    int[] block0 = { 0, 0 }; 
    int[] block2 = { 0, 1 }; 
    int[] block3 = { 1, 1 }; 
}

class FigureT { 
    int[] block1 = { 1, 0 }; 
    int[] block0 = { 0, 0 }; 
    int[] block2 = { -1, 0 }; 
    int[] block3 = { 0, 1 }; 
}

class FigureZ { 
    int[] block1 = { 1, 0 }; 
    int[] block0 = { 0, 0 }; 
    int[] block2 = { -1, 1 }; 
    int[] block3 = { 0, 1 }; 
}

我有几个问题,按重要性排序:

1)如何让 Action 类的绘制识别 Game 内存类随时间的变化?

2) 当我将网格和图形变量放入 Action 类中,并将 TimeListener 从 GameMemory 替换为 Action 时,图形确实会移动。如果我从另一个班级这样做有什么问题呢? 我试图将记忆与绘画分开,因为这对我来说似乎是合乎逻辑的。可能吗?

3) 我有一个包含一大堆包含相对图形坐标的包私有类的文件。一开始我试图让它成为一个包含私有内部类的公共类,但是我遇到了实例化内部私有类的问题,所以我正在考虑如何为我的带有数字的文件进行更好的设计。

我是一个完整的 Java 菜鸟,所以任何建议都将不胜感激。

【问题讨论】:

  • 代码太多了。你能限制你的代码吗,这样可以让读者的生活更轻松。
  • 好吧,我想你可以忽略带有数字的代码和第三个问题。有两个第一个 sn-ps 它不应该太多......

标签: java swing oop


【解决方案1】:

不要在paintComponent() 方法中调用GameMemory memory = new GameMemory()。单独定义模型并重用它。您的渲染器使用模型并仅在 paintComponent() 方法中反映模型状态。

在您的 TimerListener 中,只需更新模型(移动图形、清除行等)并调用视图的 repaint() 以反映模型变化。

【讨论】:

  • 嗨!感谢您及时的回复。但我不知道模型是什么。 oracle.com/technetwork/java/architecture-142923.html 看的链接对吗?您能否建议任何可以以紧凑的方式向我解释这个概念的好的链接?在我的特殊情况下,我将如何分离模型?如果我将 new GameMemory() 放在构造函数中,它会给我一个找不到符号错误...我仍然很困惑。
  • 在您的情况下,模型是 GameMemory。实际上,您应该有一个存储游戏数据的类(带有单元格值的网格、数字等)。想象并创建一些数据结构类,其中包含单元格列表(或数组)、带有位置的图形、速度、分数等。模型可以由某个视图表示,可以存储和加载回,可以重置以恢复初始值。
  • 谢谢!这很有帮助,尽管术语让我感到困惑。
【解决方案2】:

好的,所以使用我非常有限的脑容量,我能够理解 StanislavL 在说什么,所以我假设他所说的“模型”一词是指程序中发生的所有逻辑。

因此,如果我将模型的定义放入 paintComponent 方法中,在我的情况下,每次计时器到时都会创建一个实例。这是不必要的。取而代之的是,实例化一个模型一次,并在每个计时器启动时对其进行更新。我想我也应该只留下一个 TimerTask(GameMemory 中的那个),因为 super.paintComponent(pen) 会自动为我重新绘制 JPanel。

总的来说,这是我想出的代码并且有效(仍然需要删除计时器):

public class Action extends JPanel { 
    private final Color BACKGROUND_COLOR = Color.yellow; 
    private GameMemory memory;
    private int[][] grid;

    public Action() { 
        memory = new GameMemory();
        grid = memory.getGrid();
        setBackground(BACKGROUND_COLOR); 
        setPreferredSize(new Dimension(100, 220)); 
        setVisible(true); 
        new Timer(1000, new TimerListener()).start(); 
    }

    @Override
    protected void paintComponent(Graphics pen) { 
        super.paintComponent(pen); 
        pen.setColor(Color.gray); 
        for (int r = 0; r < grid.length; r++ ) 
            for (int c = 0; c < grid[c].length; c++) 
                if (grid[r][c] == 1) 
                    pen.fillRect(c * 30, r * 30, 40, 40); 
    } 


    private class TimerListener implements ActionListener { 
        @Override
        public void actionPerformed(ActionEvent e) { 
            Action.this.repaint(); 
        } 
    } 

} 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-09
    • 1970-01-01
    • 1970-01-01
    • 2012-05-01
    • 2011-03-21
    • 1970-01-01
    相关资源
    最近更新 更多