JRubyでFilthyRichClients その4
色々と自分でShapeを作れれば、Grapics2Dのfillやdrawを使って、これらのShapeを描画することができる。
Filthy Rich Clientsでは、
- Area、Elipse2Dを使ったドーナツ型
- GeneratePathを使った星型
などが紹介されている。このカスタムShapeをJRubyで書いてみた。
include Java include_class %w( JFrame JComponent SwingUtilities ).map{|s| 'javax.swing.' + s} include_class %w( Color GradientPaint RadialGradientPaint RenderingHints ).map{|s| 'java.awt.' + s} include_class %w( MouseAdapter ).map{|s| 'java.awt.event.' + s} include_class %w( Area Ellipse2D Point2D GeneralPath ).map{|s| 'java.awt.geom.' + s} class Canvas < JComponent def initialize() super() addMouseListener(ClickReceiver.new) @shapes = [] @colors = [] @get_star = true end def paintComponent(g) draw_background(g) g.setRenderingHint(RenderingHints::KEY_ANTIALIASING, RenderingHints::VALUE_ANTIALIAS_ON) draw_shape(g) end def create_shape(e) inner_size = 1 + rand(25) outer_size = inner_size + 10 + rand(15) if @get_star branch_count = (rand(8) + 5).to_i @shapes << generate_star(e.getX, e.getY, inner_size, outer_size, branch_count) else @shapes << generate_donut(e.getX-outer_size/2, e.getY-outer_size/2, inner_size, outer_size) end 2.times do @colors << Color.new(rand(0xFFFFFF)) end @get_star = !@get_star repaint() end private def draw_background(g) background = GradientPaint.new(0, 0, Color::GRAY.darker(), 0, getHeight(), Color::GRAY.brighter()) g.setPaint(background) g.fillRect(0, 0, getWidth(), 4*getHeight()/5) background = GradientPaint.new(0, 4*getHeight()/5, Color::BLACK, 0, getHeight(), Color::GRAY.darker()); g.setPaint(background) g.fillRect(0, 4*getHeight()/5, getWidth(), getHeight()/5) end def draw_shape(g) @shapes.each_with_index do |shape, i| rect = shape.getBounds() center = Point2D::Float.new(rect.x + rect.width/2.0, rect.y + rect.height/2.0) radius = rect.width/2.0 dist = [0.1, 0.9].to_java(:float) colors = [@colors[i*2], @colors[i*2+1]].to_java('java.awt.Color') g.setPaint(RadialGradientPaint.new(center, radius, dist, colors)) g.fill(shape) end end def generate_donut(x, y, inner_radius, outer_radius) a1 = Area.new(Ellipse2D::Double.new(x, y, outer_radius, outer_radius)) inner_offset = (outer_radius - inner_radius)/2.0 a2 = Area.new(Ellipse2D::Double.new(x + inner_offset, y + inner_offset, inner_radius, inner_radius)) a1.subtract(a2) a1 end def generate_star(center_x, center_y, inner_radius, outer_radius, branch_count) path = GeneralPath.new path.moveTo(center_x + outer_radius, center_y) outer_angle_increment = 2.0 * Math::PI / branch_count outer_angle = 0.0 inner_angle = outer_angle_increment / 2.0 branch_count.times do x = Math.cos(outer_angle) * outer_radius + center_x y = Math.sin(outer_angle) * outer_radius + center_y path.lineTo(x, y) x = Math.cos(inner_angle) * inner_radius + center_x y = Math.sin(inner_angle) * inner_radius + center_y path.lineTo(x, y) outer_angle += outer_angle_increment inner_angle += outer_angle_increment end path.closePath() path end end class ClickReceiver < MouseAdapter def mouseClicked(e) c = e.getSource c.create_shape(e) end end SwingUtilities.invokeLater do f = JFrame.new f.add(Canvas.new) f.setSize(500, 500) f.setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE) f.setLocationRelativeTo(nil) f.setVisible(true) end