将 Java 内部 class 翻译成 JRuby 对应物

Translating a Java internal class into a JRuby counterpart

我正在尝试将 Java class 翻译成它的 JRuby 对应部分,但我不知道如何翻译 Java 内部 class.

这个问题是众所周知的,通常来自 visibility/scope Java 和 Ruby 之间的差异。这有时可以使用 blocs 而不是 inner class.

来解决

Java 示例如下,可以在 Zetcode 网站上找到。我也在下面给出了我的 Ruby 尝试。

问题出在扩展 TimerClass 的内部 ScheduleTask class 中。而运行ning(在Java中),ScheduleTask的运行()方法允许调用其所属的Board对象的repaint()方法。这在 Java 中非常方便:在固定的时间间隔内,Board 面板会重新绘制。如何在 JRuby 中翻译这个?我只是试图从字面上翻译这个,但是 Ruby 内部 ScheduleTask 不知道重绘方法...

package com.zetcode;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.ImageIcon;
import javax.swing.JPanel;


public class Board extends JPanel  {

    private final int B_WIDTH = 350;
    private final int B_HEIGHT = 350;
    private final int INITIAL_X = -40;
    private final int INITIAL_Y = -40;    
    private final int INITIAL_DELAY = 100;
    private final int PERIOD_INTERVAL = 25;
    
    private Image star;
    private Timer timer;
    private int x, y;
    
    public Board() {
    
        
        initBoard();        
    }
    
    private void loadImage() {
        
        ImageIcon ii = new ImageIcon("star.png");
        star = ii.getImage();        
    }
    
    private void initBoard() {
        
        setBackground(Color.BLACK);
        setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
        setDoubleBuffered(true);
        
        loadImage();

        x = INITIAL_X;
        y = INITIAL_Y;
        
        timer = new Timer();
        timer.scheduleAtFixedRate(new ScheduleTask(), 
                INITIAL_DELAY, PERIOD_INTERVAL);        
    }
        

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        drawStar(g);
    }
    
    private void drawStar(Graphics g) {
        
        g.drawImage(star, x, y, this);
        Toolkit.getDefaultToolkit().sync();
    }


    private class ScheduleTask extends TimerTask {

        @Override
        public void run() {
            x += 1;
            y += 1;

            if (y > B_HEIGHT) {
                y = INITIAL_Y;
                x = INITIAL_X;
            }
            
            repaint();
        }
    }

这是 JRuby 尝试,其中 ScheduleTask class 已从 Board 中提取...

include Java

import java.awt.Color
import java.awt.Dimension
import java.awt.Graphics
import java.awt.Image
import java.awt.Toolkit
import java.util.Timer
import java.util.TimerTask
import javax.swing.ImageIcon
import javax.swing.JPanel

B_WIDTH = 650
B_HEIGHT = 450
INITIAL_X = -40
INITIAL_Y = -40    
INITIAL_DELAY = 100
PERIOD_INTERVAL = 25

class Board < JPanel

  def initialize
    super
    initBoard()        
  end
    
  def loadImage
    ii = ImageIcon.new("mario2.png")
    @star = ii.getImage()        
  end
    
  def initBoard
    setBackground(Color.new(255, 255, 255))
    setPreferredSize(Dimension.new(B_WIDTH, B_HEIGHT))
    setDoubleBuffered(true)
    loadImage()
    @x = INITIAL_X
    @y = INITIAL_Y
        
    @timer = Timer.new()
    task=ScheduleTask.new
    task.init(@x,@y)
    @timer.scheduleAtFixedRate(task, INITIAL_DELAY, PERIOD_INTERVAL)        
  end

  def paintComponent(g)
    repaint() # WAS : super.paintComponent(g)
    drawStar(g)
  end
    
  def drawStar(g)
    g.drawImage(@star, @x, @y, self)
    Toolkit.getDefaultToolkit().sync()
  end

  class ScheduleTask < TimerTask 
    def init x,y
      @x,@y=x,y
    end
    def run
      @x += 1
      @y += 1
      if (@y > B_HEIGHT) 
        @y = INITIAL_Y
        @x = INITIAL_X
       end
      repaint() # <===== ERROR in Ruby. Unknown method 
    end
  end #ScheduleTask 

 end #Board

最后是启动应用程序的方法:

require_relative 'board'

include Java

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.SwingUtilities

class UtilityTimerExample < JFrame

    def initialize
      super
      initUI();
      setVisible(true)
    end
    
    def initUI
      add(Board.new());
      setResizable(false);
      pack();
      setTitle("Star");
      setLocationRelativeTo(nil)
      setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE)
    end
end

SwingUtilities.invoke_later do
  UtilityTimerExample.new
end

你重写了 paintComponent 但永远不会调用继承的版本(它实际上完成了工作) - 这可能是一个问题......在 Ruby 版本中调用它的正确方法只是一个 super 语句(或更明确的 super(g)):

def paintComponent(g)
  super # super(g)
  drawStar(g)
end

我终于成功解决了我的问题,使用这个blog

  1. 创建一个计时器
  2. 添加方法"add_action_listener(block)"
  3. 将预期的操作传递给块