FxRuby初体验Part4
之前的:FxRuby初体验Part1,Part2,Part3。
到了PictureBook的V0.4了。这个版本算是基本的功能都做足了,包括了加上了相册选择,相册持久化等等。
#album_list_view.rb
require 'fox16'
include Fox
class AlbumListView < FXList
attr_reader :album_list
def initialize(p, opts)
super(p, :opts => opts)
end
def switcher=(sw)
@switcher = sw
end
def add_album(album)
appendItem(album.title)
AlbumView.new(@switcher, album)
end
def album_list=(albums)
@album_list = albums
@album_list.each_album do |album|
add_album(album)
end
end
end
#picture_book.rb
$KCODE = "U"
require 'fox16'
require 'yaml'
include Fox
require 'album'
require 'album_list'
require 'photo'
require 'photo_view'
require 'album_view'
require 'album_list_view'
class PictureBook < FXMainWindow
def initialize(app)
super(app, "Picture Book" , :width => 600, :height => 400)
add_menu_bar
begin
@album_list = YAML.load_file("picturebook.yml" )
rescue
@album_list = AlbumList.new
@album_list.add_album(Album.new("My Photos" ))
end
splitter = FXSplitter.new(self,
:opts => SPLITTER_HORIZONTAL|LAYOUT_FILL)
@album_list_view = AlbumListView.new(splitter, LAYOUT_FILL)
@switcher = FXSwitcher.new(splitter, :opts => LAYOUT_FILL)
@switcher.connect(SEL_UPDATE) do
@switcher.current = @album_list_view.currentItem
end
@album_list_view.switcher = @switcher
@album_list_view.album_list = @album_list
end
def create
super
show(PLACEMENT_SCREEN)
end
def add_menu_bar
# 创建一个菜单栏的实例
menu_bar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
# 创建一个菜单栏项
file_menu = FXMenuPane.new(self)
FXMenuTitle.new(menu_bar, "文件" , :popupMenu => file_menu)
# 下面是一个创建菜单栏项和所关联动作的绑定
import_cmd = FXMenuCommand.new(file_menu, "导入..." )
import_cmd.connect(SEL_COMMAND) do
dialog = FXFileDialog.new(self, "导入图片" )
dialog.selectMode = SELECTFILE_MULTIPLE
dialog.patternList = ["JPEG Images (*.jpg, *.jpeg)" ]
if dialog.execute != 0
import_photos(dialog.filenames)
end
end
new_album_command = FXMenuCommand.new(file_menu, “New Album…” )
new_album_command.connect(SEL_COMMAND) do
album_title = FXInputDialog.getString(”My Album” , self, “New Album” , “Name:” )
if album_title
album = Album.new(album_title)
@album_list.add_album(album)
@album_list_view.add_album(album)
AlbumView.new(@switcher, album)
end
end
exit_cmd = FXMenuCommand.new(file_menu, “退出” )# 一个简单的退出项
exit_cmd.connect(SEL_COMMAND) do
store_album_list
exit
end
end
def import_photos(filenames)
filenames.each do |filename|
photo = Photo.new(filename)
current_album.add_photo(photo)
current_album_view.add_photo(photo)
end
current_album_view.create
end
def current_album_view
@switcher.childAtIndex(@switcher.current)
end
def current_album
current_album_view.album
end
def store_album_list
File.open(”picturebook.yml” , “w” ) do |io|
io.write(YAML.dump(@album_list))
end
end
end
if __FILE__ == $0
FXApp.new do |app|
PictureBook.new(app)
app.create
app.run
end
end
剩下的晚上再写。。。
FxRuby初体验Part3
这个V0.3的PictureBook添加了相册视图,也就是把相片都放到其中。看看下面的代码吧,我把每次都贴上完整的代码,方便大家复制粘帖:-)
#photo.rb
class Photo
attr_reader :path
def initialize(path)
@path = path
end
end
#album.rb
class Album
attr_reader :title
def initialize(title)
@title = title
@photos = []
end
def add_photo(photo)
@photos << photo
end
def each_photo
@photos.each { |photo| yield photo }
end
end
#album_list.rb
class AlbumList
def initialize
@albums = []
end
def add_album(album)
@albums << album
end
def remove_album(album)
@albums.delete(album)
end
def each_album
@albums.each { |album| yield album }
end
end
#photo_view.rb
class PhotoView < FXImageFrame
MAX_WIDTH = 200
MAX_HEIGHT = 200
def initialize(p, photo)
super(p, nil)
load_image(photo.path)
end
def load_image(path)
File.open(path, “rb” ) do |io|
self.image = FXJPGImage.new(app, io.read)
scale_to_thumbnail
end
end
def scaled_width(width)
[width, MAX_WIDTH].min
end
def scaled_height(height)
[height, MAX_HEIGHT].min
end
def scale_to_thumbnail
aspect_ratio = image.width.to_f/image.height
if image.width > image.height
image.scale(
scaled_width(image.width),
scaled_width(image.width)/aspect_ratio,
1
)
else
image.scale(
aspect_ratio*scaled_height(image.height),
scaled_height(image.height),
1
)
end
end
end
#album_view.rb
require ‘photo_view’
class AlbumView < FXMatrix
attr_reader :album
def initialize(p, album)
super(p, :opts => LAYOUT_FILL|MATRIX_BY_COLUMNS)
@album = album
@album.each_photo { |photo| add_photo(photo) }
end
def add_photo(photo)
PhotoView.new(self, photo)
end
def layout
self.numColumns = [width/PhotoView::MAX_WIDTH, 1].max
super
end
end
#picture_book.rb
require ‘fox16′
include Fox
require ‘album’
require ‘album_view’
require ‘photo’
class PictureBook < FXMainWindow
def initialize(app)
super(app, “Picture Book” , :width => 600, :height => 400)
add_menu_bar
@album = Album.new(”My Photos” )
@album_view = AlbumView.new(self, @album)
end
def add_menu_bar
menu_bar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
file_menu = FXMenuPane.new(self)
FXMenuTitle.new(menu_bar, “File” , :popupMenu => file_menu)
import_cmd = FXMenuCommand.new(file_menu, “Import…” )
import_cmd.connect(SEL_COMMAND) do
dialog = FXFileDialog.new(self, “Import Photos” )
dialog.selectMode = SELECTFILE_MULTIPLE
dialog.patternList = ["JPEG Images (*.jpg, *.jpeg)" ]
if dialog.execute != 0
import_photos(dialog.filenames)
end
end
exit_cmd = FXMenuCommand.new(file_menu, “Exit” )
exit_cmd.connect(SEL_COMMAND) do
exit
end
end
def import_photos(filenames)
filenames.each do |filename|
photo = Photo.new(filename)
@album.add_photo(photo)
@album_view.add_photo(photo)
end
@album_view.create
end
def create
super
show(PLACEMENT_SCREEN)
end
end
if __FILE__ == $0
FXApp.new do |app|
PictureBook.new(app)
app.create
app.run
end
end
这里相对于上个版本的改动的地方有,PictureBook增加了菜单栏,增加了一个视图AlbumView,PhotoView实例的创建放在了AlbumView中,PhotoView中增加了图片的缩略图操作。
菜单栏的创建也听挺麻烦的,先创建FXMenuBar的实例,然后是创建FXMenuTitle和FXMenuPane的实例,FXMenuTitle是FXMenuBar的下级元素,就是菜单栏的每一段,FXMenuPane是FXMenuTitle的弹出菜单。然后要创建FXMenuCommand,它是FXMenuPane的下级元素,实例化后就要用connect方法给出的代码块将其绑定到一定的行为上。
File>Importd这个动作是打开一个文件对话框FXFileDialog让你选择文件,然后用filenames方法获得选择得到的文件的数组。退出的菜单项很简单,就是一个exit方法。
在PhotoView中的图片操作功能是从FXImageFrame继承得到的,这个能力和接口很像RMagic。 AlbumView 是FXMatrix的实例,FXMatrix是一种布局管理器,它以行列的方式来对组件进行布局。好像布局管理器的基类就是FXPacker ,可以通过重写它的Layout方法来改变布局流。像这里就改变了FXMatrix的行数。
接着书中作者又改了一下,因为FXMatrix不能够在图片太多的情况下全部显示,会产生因为图片过多导致产生很多行,然后让超出主窗体的图片行无法看见,所以作者又对AlbumView换了一个布局管理器。
#album_view.rb
require 'photo_view'
class AlbumView < FXScrollWindow
attr_reader :album
def initialize(p, album)
super(p, :opts => LAYOUT_FILL)
@album = album
FXMatrix.new(self, :opts => LAYOUT_FILL|MATRIX_BY_COLUMNS)
@album.each_photo { |photo| add_photo(photo) }
end
def layout
contentWindow.numColumns = [width/PhotoView::MAX_WIDTH, 1].max
super
end
def add_photo(photo)
PhotoView.new(contentWindow, photo)
end
end
FXScrollWindow是另一种布局管理器,它只是多了滚动条。其中还是包含了一个FXMatrix。
FxRuby初体验Part2
接上一篇:FxRuby初体验Part1
本书的入门例子是个相册管理的桌面应用,名曰Picture Book。这个例子书中用了5 Chapter(2-6)来讲,基本讲到了常用的Gui组件。
不废话现在来看看代码,下面是第一个版本的Picture Book App:
#photo.rb
class Photo
attr_reader :path
def initialize(path)
@path = path
end
end
#album.rb
class Album
attr_reader :title
def initialize(title)
@title = title
@photos = []
end
def add_photo(photo)
@photos << photo
end
def each_photo
@photos.each { |photo| yield photo }
end
end
#album_list.rb
class AlbumList
def initialize
@albums = []
end
def add_album(album)
@albums << album
end
def remove_album(album)
@albums.delete(album)
end
def each_album
@albums.each { |album| yield album }
end
end
#photo_view.rb
class PhotoView < FXImageFrame
def initialize(p, photo)
super(p, nil)
load_image(photo.path)
end
def load_image(path)
File.open(path, “rb” ) do |io|
self.image = FXJPGImage.new(app, io.read)
end
end
end
#picturebook.rb
require ‘fox16′
include Fox
require ‘photo’
require ‘photo_view’
class PictureBook < FXMainWindow
def initialize(app)
super(app, “Picture Book” , :width => 600, :height => 400)
photo = Photo.new(”shoe.jpg” )
photo_view = PhotoView.new(self, photo)
end
def create
super
show(PLACEMENT_SCREEN)
end
end
if __FILE__ == $0
FXApp.new do |app|
PictureBook.new(app)
app.create
app.run
end
end
这是个V0.1的版本。不过你从中看出这个应用写得很MVC。
Model部分就是Photo,Album,AlbumList三个,Controller部分(当然它还没有细化)就是PictureBook,View部分就是PhotoView。就是如此清晰的结构,我想如果是正在学着什么MFC的可怜人儿们看到了之后会把那本什么深入浅出MFC扔了吧。
对比那个HelloWorld,这堆代码除了多了几个普通的Ruby Class(扮演Model的那几个)外,就是多了一个继承自FXImageFrame的PhotoView,还有在FXMainWindow的构造方法中多了对PhotoView的实例化,实例化时将其自身挂钩到PictureBook(构造方法的第一个参数)。之后在App实例化后会实例化MainWindow,接着实例化MainWindow包含的组件,比如PhotoView这个FxImageFrame。PhotoView中对图片的包装是这样的,它先读入Photo的路径,然后用FxImage组件对图片进行包装,然后保存为自己的一个实例变量image中。
PictureBook的第一个版本就是这样。
接着下一篇讲下个版本和下下篇讲下下个版本,然后就介绍完了。
FxRuby初体验Part1
FxRuby,一个更新较为频繁的Ruby GUI 开发库。今年还出了本书,今晚刚好有空,吃了饭后,6:30开始到现在9:30,看完了它的入门例子。其实是因为今晚不用开工,而想起了一个想做很久的事情,就是开发一个编辑器,一个能够用Ruby作为配置和开发语言的编辑器,就像Emacs能用Lisp在其上开发一样,而且能支持Rails,Rspec,Rake语法和开发辅助(如MVC跳转)等等,这是个妄想:-)

http://pragprog.com/titles/fxruby/fxruby
先来看看它的HelloWorld的代码:
require 'fox16'
include Fox
class HelloWindow < FXMainWindow
def initialize(app)
super(app, "Hello, World!" , :width => 200, :height => 100)
end
def create
super
show(PLACEMENT_SCREEN)
end
end
if __FILE__ == $0
FXApp.new do |app|
HelloWindow.new(app)
app.create
app.run
end
end
HW没什么太多好讲的,有些东西要提一提就Ok了。GUI应用,肯定有个明显的入口点,就是FxApp的实例,因为是Desktop app,所以一般都有个主窗体,在FxRuby中是FXMainWindow的实例。FxRuby中,App实例创建之后还要调用create和run两个方法,主窗体的构造函数要做的事情是设置好主窗体的属性,App的create方法会调用会调用每个下级控件的create方法,在create中要加入的就是显示的方式(好像窗体才需要)等等。从上面的HW就可以看到这些。
FxRuby官方手册中还有另一个复杂一点点的HelloWorld。
入门例子是个相册管理的桌面应用,名曰Picture Book。这个例子书中用了5 Chapter(2-6)来讲,基本讲到了常用的Gui组件。
好像太长了,拆开放到另一个日志上吧。
参考Link:
FxRuby官站:http://www.fxruby.org/
FxRuby的Rdoc:http://www.fxruby.org/doc/api/
FxRuby在线手册:http://www.fxruby.org/doc/book.html











