Erlang边读边练(1)

本文分享了使用Erlang编程语言及图形界面库gs开发IRC客户端GUI的过程,作者逐步实现了窗口创建、组件布局、文本输入与显示等功能。

我看书有个习惯,先看图和代码,然后代码中不懂的再去前后文去找说明,有人说这太浪费时间了,我觉得这样才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.

 



 

**高校专业实习管理平台设计与实现** 本设计项目旨在构建一个服务于高等院校专业实习环节的综合性管理平台。该系统采用当前主流的Web开发架构,基于Python编程语言,结合Django后端框架与Vue.js前端框架进行开发,实现了前后端逻辑的分离。数据存储层选用广泛应用的MySQL关系型数据库,确保了系统的稳定性和数据处理的效率。 平台设计了多角色协同工作的管理模型,具体包括系统管理员、院系负责人、指导教师、实习单位对接人以及参与实习的学生。各角色依据权限访问不同的功能模块,共同构成完整的实习管理流程。核心功能模块涵盖:基础信息管理(如院系、专业、人员信息)、实习过程管理(包括实习公告发布、实习内容规划、实习申请与安排)、双向反馈机制(单位评价与学生反馈)、实习支持与保障、以及贯穿始终的成绩评定与综合成绩管理。 在技术实现层面,后端服务依托Django框架的高效与安全性构建业务逻辑;前端界面则利用Vue.js的组件化特性与LayUI的样式库,致力于提供清晰、友好的用户交互体验。数据库设计充分考虑了实习管理业务的实体关系与数据一致性要求,并保留了未来功能扩展的灵活性。 整个系统遵循规范的软件开发流程,从需求分析、系统设计、编码实现到测试验证,均进行了多轮迭代与优化,力求在功能完备性、系统性能及用户使用体验方面达到较高标准。 **核心术语**:实习管理平台;Django框架;MySQL数据库;Vue.js前端;Python语言。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值