標籤:ruby mac os x tktcl
我記得在老早在OS X10.8下使用ruby1.9.x的時候只要到下載安裝ActiveTcl8.5,沒怎麼配置就運行tk好好的。但是近日想重新執行下tk代碼,發現在require ‘tk‘的時候就報錯鳥!現在用的是ruby2.1.3版本。上網搜了一下,1.9.x之後的版本預設不再將tcl/tk支援編譯到ruby裡面,so如果你想用則必須重新編譯ruby!我勒個去!就不能做成個gem嗎?但在多種外圍嘗試無果的的情況下只有一條路,就是重新編譯ruby了...
到ruby官網下載最新的ruby2.1.5的原始碼15MB左右,解壓後257MB,console進入解壓目錄,輸入:
./configure -prefix=/Users/apple/src/ruby_src/ruby2.1.5_installed --with-arch=x86_64,i386 --enable-pthread --enable-shared --with-tk --with-tcl
注意-prefix必須要絕對路徑,否則不讓過;這是你要最後安裝ruby2.1.5的路徑,一旦固定下來,就不可以再動了。因為我後來用rvm也安裝了ruby2.1.5版,所以這裡換了個臨時位置,只是測試用的。接著可以輸入make命令編譯ruby,大概要等一會,最後執行make install就將ruby2.1.5安裝到了我前面設定的位置上。下面測試一下對tk的支援如何:
[email protected]: bin$ls
erb gem irb rake rdoc ri ruby testrb
[email protected]: bin$./ruby -e "require ‘tk‘"
可以看到是ok的,然後運行一下我的tk.rb看一下效果(代碼節選):
require 'dbm'#require 'tempfile'#require 'zip/zip'#require 'win32api'#PATH = '/Users/apple/src/c_src/ruby-1.9.3-p362/ext/tk/lib/'require 'tk'#require PATH+'tk'require 'tkextlib/tkimg/bmp'require 'tkextlib/tkimg/jpeg'require 'tkextlib/tkimg/png'require 'tkextlib/iwidgets'require 'tkextlib/bwidget'SM_CXSCREEN = 0SM_CYSCREEN = 1def get_screen_size#get_screen_size_nv = Win32API.new('user32','GetSystemMetrics',['L'],'L')#x = get_screen_size_nv.Call(SM_CXSCREEN)#y = get_screen_size_nv.Call(SM_CYSCREEN)`./s`.split.map {|x| x.to_i}#[x,y]enddef zip(path)zip_path = path + '.zip'File.delete(zip_path) if File.exist? zip_path Zip::ZipFile.open(zip_path,Zip::ZipFile::CREATE) {|f| f.add(File.split(path)[1],path)}enddef unzip(path)unzip_path = path[0..-5]Zip::ZipFile.open(path) {|f| f.extract(f.entries[0],unzip_path) {true}}endDB_PATH = File.expand_path(".") + '/movies.dbm'#zip(DB_PATH + '.dir')#zip(DB_PATH + '.pag')#unzip(DB_PATH + '.dir.zip')#unzip(DB_PATH + '.pag.zip')db = DBM.new(DB_PATH)#db.clearat_exit {db.close#壓縮資料庫#zip(DB_PATH + '.dir')#zip(DB_PATH + '.pag')#File.delete(DB_PATH + '.dir');File.delete(DB_PATH + '.pag')}ROOT_W = 1000ROOT_H = 610x,y = get_screen_size#計算螢幕置中顯示時需要移動到的座標mov_x = (x - ROOT_W)/2mov_y = (y - ROOT_H)/2root = TkRoot.new(:title=>"movie query v1.2")Tk::Wm.geometry(root,"+#{mov_x}+#{mov_y}")#Tk::Wm.attributes(root,:toolwindow=>true)Tk::Wm.geometry(root,"#{ROOT_W}x#{ROOT_H}")Tk::Wm.minsize(root,ROOT_W,ROOT_H)Tk::Wm.maxsize(root,ROOT_W,ROOT_H)img_love = TkPhotoImage.new(:file=>File.expand_path(".") + '/logo.gif')Tk::Wm.iconphoto(root,img_love)def dlgbox_input_name(in_name)#puts Tk::Wm.state dlg#Tk::Wm.deiconify dlgdlg = Tk::Toplevel.new(:title=>"輸入演員名")#Tk::Wm.attributes(dlg,:toolwindow=>true)Tk::Wm.attributes(dlg,:notify=>true)#隱藏視窗#Tk::Wm.withdraw dlgout_name = niltxt_input_name = Tk::Tile::Entry.new(dlg,:width=>40) dogrid :row=>0,:column=>0endtxt_input_name.value = in_namebtn_add_name = Tk::Tile::Button.new(dlg) dotext "添 加"command doout_name = txt_input_name.valuedlg.destroyendgrid :row=>1,:column=>0endtxt_input_name.bind("Return") dobtn_add_name.invokeendtxt_input_name.focus#將toplevel視窗(對話方塊視窗)設為主視窗的"瞬時視窗"Tk::Wm.transient dlg#強制回應對話方塊Tk::BWidget.grab :set,dlg#暫時掛起主視窗線程#TkTimer.new.tkwait dlgdlg.wait_windowout_nameend#(r0,c0)lab_app = Tk::Tile::Label.new dotext "大熊貓最愛電影查詢工具"font "新宋體 14 bold"foreground "blue"grid :row=>0,:column=>0,:columnspan=>8,:padx=>10,:pady=>10end#(r1,c0)lab_names = Tk::Tile::Label.new dotext "電影名稱"font "新宋體 12 bold"grid :row=>1,:column=>0,:padx=>10,:pady=>10end#(r1,c1)txt_names = TkText.new(:width=>35,:height=>2) dofont "新宋體 12 bold"grid :row=>1,:column=>1end#(r2,c0)lab_stars = Tk::Tile::Label.new dotext "熊貓星級"font "新宋體 12 bold"grid :row=>2,:column=>0,:padx=>10,:pady=>40,:sticky=>:nendimg_file = File.open(File.expand_path(".") + '/star.jpg','r+b')img_data = img_file.read#img_star = TkPhotoImage.new(:data=>img_data,:gamma=>0.01)img_star = TkPhotoImage.new(:data=>img_data,:palette=>10)img_star_chk = TkPhotoImage.new(:data=>img_data)img_file.closestar = 0btn_stars = []btn_chks = [false,false,false,false,false]clr_all_chk = proc dobtn_chks = [false]*5btn_stars.each do |btn|btn.configure(:image=>img_star)endend#(r2,c1)frm_stars = TkFrame.new dogrid :row=>2,:column=>1,:padx=>10,:pady=>10,:sticky=>:n5.times do |i|btn_stars << TkButton.new(self,:width=>45,:height=>50) dotext i.to_simage img_starrelief :flatgrid :row=>0,:column=>i+1command doidx = self.cget(:text).to_iunless btn_chks[idx]btn_chks[0..idx] = [true]*(idx+1)elseif btn_chks[idx+1]btn_chks[(idx+1)..-1] = [false]*(5-idx-1)elsebtn_chks[0..idx] = [false]*(idx+1)endend5.times do |j|img = if btn_chks[j];img_star_chk else img_star endbtn_stars[j].configure(:image=>img)endstar = btn_chks.count(true)endendendend#(r3,c0)lab_direct = Tk::Tile::Label.new dotext "導 演"font "新宋體 12 bold"grid :row=>3,:column=>0end#(r3,c1)txt_direct = Tk::Tile::Entry.new(:width=>35) dofont "新宋體 12 bold"grid :row=>3,:column=>1end#(r4,c0)lab_nil = Tk::Tile::Label.new dogrid :row=>4,:column=>0end#(r5,c0)lab_artist = Tk::Tile::Label.new dotext "演 員"font "新宋體 12 bold"grid :row=>5,:column=>0,:padx=>10,:pady=>10,:sticky=>:nendlst_artist = lst_xroll = lst_yroll = nil#(r5,c2)lst_yroll = Tk::Tile::Scrollbar.new docommand proc{|*idx|lst_artist.yview *idx}grid(:row=>5,:column=>2,:sticky=>:ns)end#(r11,c4)btn_del = Tk::Tile::Button.new(frm_btns) dotext "刪 除command doif db.each_key.select {|k|a = k.split(" ")[0].force_encoding("gbk");b = txt_names.value.split(" ")[0]a =~ /#{b}/}.count == 0Tk.messageBox(:icon=>:error,:type=>:ok,:title=>"error",:message=>"該主電影名不在資料庫中!");breakenddb.delete(txt_names.value)txt_names.value = ""endgrid :row=>11,:column=>4,:padx=>10,:sticky=>:nendbtn_exit = Tk::Tile::Button.new(frm_btns) dotext "退 出"command doexitendgrid :row=>11,:column=>5,:padx=>10,:sticky=>:nend#TkGrid.grid(btn_add,"-","x",btn_del,:sticky=>:nsew)#(r0,c5)cvs_line = TkCanvas.new(:width=>"0.1c") docreate :line,"0.1c","1c","0.1c","30c",:dash=>"10",:width=>4,:fill=>"blue"grid :row=>0,:column=>5,:rowspan=>12,:sticky=>:wnsendyrl_lst_find = nil#(r1,c6)lst_find = TkListbox.new(:width=>20,:height=>20) dofont "新宋體 12 bold"yscrollcommand proc {|*idx|yrl_lst_find.set *idx}grid :row=>1,:column=>6,:rowspan=>13,:sticky=>:wnend#(r1,c7)yrl_lst_find = Tk::Tile::Scrollbar.new docommand proc{|*idx|lst_find.yview *idx}grid(:row=>1,:column=>7,:rowspan=>5,:sticky=>:wns)endflash_movie_info = proc do |name|vals = eval(db[name].force_encoding("gbk"))#先按一下btn[0],以防上一個star>0#btn_stars[0].invokeidx = vals[:star].to_i#idx -= 1 if idx > 0clr_all_chk[]btn_stars[idx-1].invoke if idx > 0txt_names.value = nametxt_direct.value = vals[:direct]list.value = vals[:artist]scl_clarity.value = vals[:scl].to_itxt_size.value = vals[:size]txt_len.value = vals[:len]txt_locate.value = vals[:locate]txt_mark.value = vals[:mark]txt_note.value = vals[:note]pic = TkPhotoImage.new(:data=>vals[:pic].force_encoding("ASCII-8BIT")) if vals[:pic]lab_pic.configure(:image=>pic)endflash_vals = proc do |vals|idx = vals[:star].to_iclr_all_chk[]btn_stars[idx-1].invoke if idx > 0txt_names.value = vals[:name]txt_direct.value = vals[:direct]list.value = vals[:artist]scl_clarity.value = vals[:scl].to_itxt_size.value = vals[:size]txt_len.value = vals[:len]txt_locate.value = vals[:locate]txt_mark.value = vals[:mark]txt_note.value = vals[:note]pic = TkPhotoImage.new(:data=>vals[:pic].force_encoding("ASCII-8BIT")) if vals[:pic]lab_pic.configure(:image=>pic)endlst_find.bind("<ListboxSelect>") doi = lst_find.curselection[0]if i.to_s != ""name = lst_find.get(i)flash_movie_info[name]endendlst_find.bind("ButtonRelease-1") doi = lst_find.curselection[0]if i.to_s != ""name = lst_find.get(i)flash_movie_info[name]endend#(r10,c6)txt_find = Tk::Tile::Entry.new(:width=>20) dofont "新宋體 12 bold"grid :row=>10,:column=>6endbtn_find = niltxt_find.bind("Return") dobtn_find.invokeend#(r11,c6)btn_find = Tk::Tile::Button.new dotext "查 找"command doname_to_find = txt_find.valuenext if name_to_find == ""lst_find.clearif name_to_find == "*"db.each_key.select do |k|lst_find.insert(:end,k.force_encoding("gbk"))endnextenddb.each_key.select do |k|names = k.force_encoding("gbk").split(" ")for n in names(lst_find.insert(:end,k.force_encoding("gbk"));break) if n =~ /#{name_to_find}/endendendgrid :row=>11,:column=>6endmenu = TkMenu.new(:parent=>root,:tearoff=>0)root.configure(:menu=>menu)menu_file = TkMenu.new(:parent=>root,:tearoff=>0)cmd_import = proc doimp_path = Tk.getOpenFilenext if imp_path == ""data = nilFile.open(imp_path,"r+") do |f|data = f.readendvals = eval(data.force_encoding("gbk"))flash_vals[vals]endmenu_file_import = menu_file.add_command(:label=>"Import movie",:underline=>1,:command=>cmd_import)cmd_export = proc dounless chk_vals[]Tk.messageBox(:icon=>:error,:type=>:ok,:title=>"error",:message=>"請選擇一部電影!");nextendexp_path = Tk.getSaveFilenext if exp_path == ""m = get_vals[]m[:name] = txt_names.valueFile.open(exp_path,"w+") do |f|f.write m.to_sendendmenu_file_export = menu_file.add_command(:label=>"Export movie",:underline=>1,:command=>cmd_export)menu_file.add_separatorcmd_exit = proc doexitendmenu_file_exit = menu_file.add_command(:label=>"Exit",:underline=>2,:command=>cmd_exit)menu.add_cascade(:menu=>menu_file,:label=>"File",:underline=>1)#menu_file = menu.add(:cascade,:label=>"File",:underline=>0)Tk.mainloop
介面醜是醜了點,不過後期可以再調整哦,關鍵是這段代碼windows,linux,OS X下跑都沒問題啊,輕鬆跨平台鳥:
還有一種辦法是用rvm重新安裝支援tcl/tk的版本:
rvm reinstall 2.1.5 --enable-shared --enable-pthread --with-tk --with-tcl
不過我試了一下,在brew update無限卡住了,所以才有了開篇的那一坨文章...
最後本貓覺得這樣用不太爽,尤其是自己編譯的irb用不了,因為其還是調用了rvm的路徑。要替換也很容易,做軟串連吧:
[email protected]: rubies$ls -lh
total 16
lrwxr-xr-x 1 apple staff 35B 12 10 13:03 default -> /Users/apple/.rvm/rubies/ruby-2.1.5
drwxr-xr-x 8 apple staff 272B 7 27 19:47 ruby-2.1.2
lrwxr-xr-x 1 apple staff 45B 12 10 16:08 ruby-2.1.5 -> /Users/apple/src/ruby_Src/ruby2.1.5_installed
drwxr-xr-x 8 apple staff 272B 12 10 13:02 tmp_ruby-2.1.5
先把原來的ruby目錄改名,然後將編譯的路徑加入即可,可以看到其版本號碼顯示略有不同:
[email protected]: rubies$ruby -v
ruby 2.1.5p273 (2014-11-13 revision 48405) [universal.x86_64-darwin14.0]
[email protected]: rubies$./tmp_ruby-2.1.5/bin/ruby -v
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]
Mac OS X下讓ruby支援tcl/tk