我看书有个习惯,先看图和代码,然后代码中不懂的再去前后文去找说明,有人说这太浪费时间了,我觉得这样才0距离接触代码。Armstrong的代码看得我十分的不爽,可是,学erlang就是像受戒律一样,忍啊忍,悟啊悟,之后,如修炼得道般豁然开朗。
ok,废话少说,读programming erlang 读到 IRC Lite的时候发现在自己面前横着一道槛了。io_widget是什么?lib_chan是什么?mm是什么?太多东西复杂东西了呢。我下载来老头子的源代码,编译运行一下,看了下前面的说明,知道人与这个IRCLite交互的界面大概是什么样子的了,模仿着老头的代码边读练习写IRC Lite,看下我们的需求列表(我喜欢做一点事然后喘口气,把事情分成一小段一小段来做,完成一个小段,奖励下自己,比如喝口茶,需求列表也是我的备忘录,指导我下一步该做什么,它是不断变化,动态增长的一张表):
%%在io_widget应该封装好gs,所以应该这么写,
start(Pid)->
io_widget_init().
io_widget_init()->
GS = gs:start(),
Size = [{width,500,{height,200}],
Win = gs:window(Gs,
[{map,true},
{configure,true},
{title,"chat windows"}|Size]),
State=nil,
loop(Win,state).
loop(Win,State)->
receive
after 5000->
true
end.
编译运行一下
恩不错,顺心的开始是成功的一半。
再来看下我们的需求列表:
io_widget_init()->
GS = gs:start(),
Size = [{width,500,{height,200}],
Win = gs:window(Gs,
[{map,true},
{configure,true},
{title,"chat windows"}|Size]),
gs:config(IdOrName, Option).
%%Frame options:%%{packer_x,PackList}
where PackList
is list() of PackOption
, and%%{packer_y,PackList}
where PackList
is list() of PackOption
.
%%PackOption
is:%%{stretch, Weight}
where Weight
is integer() > 0, or%%{stretch, Weight, MinPixelSize, or}
%%{stretch, Weight, MinPixelSize, MaxPixelSize}, or
%%{fixed, PixelSize}
gs:frame(packer,Win,[{packer_x,[{stretch,1,500}]},
{packer_y,[{stretch,10,120,100},
{stretch,1,15,15}]}]),
%%这里我有个不明白的地方, {packer_y,[{stretch,10,120,100},为什么MinPixerlSize会比
%%MaxPixerlSize难道它们会自动交换?
%%gs:create(Obttype, Parent).
%%gs:create(Objtype, Parent, Options).
%%gs:create(Objtype, Parent, Option).
%%gs:create(Objtype, Name, Parent, Options).
%%gs:create(Objtype, Name, Parent, Option).
gs:create(editor,editor,packer,
[{pack_x,1},{pack_y,1},{vscroll,right}]),
gs:create(entry ,entry ,packer,
[{pack_x,1},{pack_y,2},{keypress,true}]),
gs:config(packer,Size),
State=nil,
loop(Win,state).
io_widget_init()->
GS = gs:start(),
Size = [{width,500,{height,200}],
Win = gs:window(Gs,
[{map,true},
{configure,true},
{title,"chat windows"}|Size]),
gs:frame(packer,Win,[{packer_x,[{stretch,1,500}]},
State=nil,
loop(Win,state).
ps:这里所有红色边框是因为截屏软件引起的,不要误解~:)
loop(Win,State)->
receive
{gs,_,destroy,_,_}->
io:format("Destroyed ~n ",[]),
exit(windowDestroyed)
end.
%%当这个循环接收到来自gs的窗口关闭信息的时候,作出退出整个应用的系统的反应。这里发出一个windowDestroy
%%的消亡信号,所以与这个loop进程相联系的进程都会收到这个信号。我们当前代码中与这个loop进程相关联的进程是
%%我们shell的进程。
widget(Gs)->
%%这里省略一段代码...
%%原先的gs:config(entry,{insert,{0,Prompt}}).删掉改成如下,算是DRY吧-_-!!!
reset_prompt(Prompt),
loop(Win,State,Prompt).
loop(Win,State,Prompt)->
receive
{gs,entry,keypress,_,['Return'|_]}->
Text = gs:read(entry,text),
Parse_Text = parse(Text),
io:format("Read:~p ~n",[Parse_Text]),
gs:config(entry,{delete,{0,last}}),
reset_prompt(Prompt),
loop(Win,State,Prompt);
{gs,_,destroy,_,_}->
io:format("Destroyed ~n ",[]),
exit(windowDestroyed)
end.
reset_prompt(Prompt)->
gs:config(entry,{insert,{0,Prompt}}).
parse([$>|T])->T;
parse([_|T])->parse(T);
parse([])->exit("no >").
loop(Win,State,Prompt)->
receive
{gs,entry,keypress,_,['Return'|_]}->
Text = gs:read(entry,text),
Parse_Text = parse(Text),
gs:config(editor,{insert,{'end',Parse_Text++"\n"}}),
%%这里我本想把最后收到信息放在最上面一行的,因为editor的默认vscrollpos一直定位在0的,把
%%最后收到的信息放在最后一行不能进行自动的滚动,想要查看还得使用滚动条,麻烦!
%%尝试过gs:config(editor,{insert,{'0',Parse_Text++"\n"}}),
%%gs:config(editor,{insert,{0,Parse_Text++"\n"}}),
%%gs:config(editor,{insert,{'begin',Parse_Text++"\n"}}),
%%都出错,gs的api上面也没写着!这里知道的朋友请告之下!
scroll_to_show_last_line(),
gs:config(entry,{delete,{0,last}}),
reset_prompt(Prompt),
loop(Win,State,Prompt);
{gs,_,destroy,_,_}->
io:format("Destroyed ~n ",[]),
exit(windowDestroyed)
end.
scroll_to_show_last_line()->
Size = gs:read(editor,size),
Height = gs:read(editor,height),
CharHeight = gs:read(editor,char_height),
TopRow = Size - Height/CharHeight,
if
TopRow >0 -> gs:config(editor,{vscrollpos,TopRow});
true -> gs:config(editor,{vscrollpos,0})
end.