Erlang边读边练(1)

我看书有个习惯,先看图和代码,然后代码中不懂的再去前后文去找说明,有人说这太浪费时间了,我觉得这样才0距离接触代码。Armstrong的代码看得我十分的不爽,可是,学erlang就是像受戒律一样,忍啊忍,悟啊悟,之后,如修炼得道般豁然开朗。

ok,废话少说,读programming erlang 读到 IRC Lite的时候发现在自己面前横着一道槛了。io_widget是什么?lib_chan是什么?mm是什么?太多东西复杂东西了呢。我下载来老头子的源代码,编译运行一下,看了下前面的说明,知道人与这个IRCLite交互的界面大概是什么样子的了,模仿着老头的代码边读练习写IRC Lite,看下我们的需求列表(我喜欢做一点事然后喘口气,把事情分成一小段一小段来做,完成一个小段,奖励下自己,比如喝口茶,需求列表也是我的备忘录,指导我下一步该做什么,它是不断变化,动态增长的一张表):

 

  • 一个500×200的窗口
  • 在这个窗口里面放入一个frame的布局2行1列,上面的作为历史记录显示框,下面的输入框
  • 历史记录框是一个editor
  • 输入框是一个entry
  • 输入框有一个提示符

 

%%在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.

 

编译运行一下


恩不错,顺心的开始是成功的一半。

 

再来看下我们的需求列表:

 

  • 在这个窗口里面放入一个frame的布局2行1列,上面的作为历史记录显示框,下面的输入框
  • 历史记录框是一个editor
  • 输入框是一个entry
  • 输入框有一个提示符

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}]},

                       {packer_y,[{stretch,10,120,100},
                   {stretch,1,15,15}]}]),
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),
Prompt = ">",
gs:config(entry,{insert,{0,Prompt}}),

State=nil,

loop(Win,state).

 



 

ps:这里所有红色边框是因为截屏软件引起的,不要误解~:)

 

 

  • 能用标题右边的红叉来关闭整个应用。
  • 能接受从entry输入的文字信息。
  • 把entry输入的文字信息显示在editor上面。
  • 把entry输入在editor上显示的提示符去掉。

loop(Win,State)->

receive

{gs,_,destroy,_,_}->

io:format("Destroyed ~n ",[]),

exit(windowDestroyed)

end.

%%当这个循环接收到来自gs的窗口关闭信息的时候,作出退出整个应用的系统的反应。这里发出一个windowDestroy

%%的消亡信号,所以与这个loop进程相联系的进程都会收到这个信号。我们当前代码中与这个loop进程相关联的进程是

%%我们shell的进程。



 

 

 

  • 能接受从entry输入的文字信息(在entry中输入文字,当按下enter键就接收一次entry中的数据)。
  • 把entry输入的文字信息显示在editor上面。
  • 把entry输入在editor上显示的提示符去掉。
  • reset下entry
loop(Win,State)->
receive
{gs,entry,keypress,_,['Return'|_]}->
Text = gs:read(entry,text),
io:format("Read:~p ~n",[Text]),
loop(Win,State);
{gs,_,destroy,_,_}->
io:format("Destroyed ~n ",[]),
exit(windowDestroyed)
end.



 
 
  • 把entry输入的文字信息显示在editor上面。
  • 把entry输入在editor上显示的提示符去掉。
  • reset下entry

 

 

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 >").


  •  把entry输入的文字信息显示在editor上面。
  • 当editor中文字信息满掉的时候,能向下滚动。

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.

 



 

你可能感兴趣的:(windows,erlang)