#wxLua实现的“每个字都是一朵花”小应用、双缓存动画、srLua及其他 话说,五年前的一天我曾经[发博客说](../js_based_html5_canvas_font_extraction_tool/detail.html "js基于html5中canvas的字模提取工具"):我要实现个“每个字都是一朵花”的那种应用……五年过去了,终于到了我兑现诺言的时候了…… 可惜,这次用的不是`HTML5`和`JS`,我已经投奔到`Lua`这个小三门下了,所以这次用的是`wxLua`,也就是`Lua`以及`Lua`的`wxWidget`绑定库……心情好说不定还会实现一个`wxLua`版的取字模工具(_注:请不要有期待_)…… 这个程序的代码是纯手写的,尽管后来我发现了`wxFormBuilder`这个神器~这东西居然能同时生成`Lua`代码,真是大大提高了界面设计效率~可惜,我并木有使用它…… 先放两个效果图: ![每个字都是一朵花效果图](EveryWordIsFlowerDemo.png "每个字都是一朵花效果图") ![每个字都是一幅画效果图](EveryWordIsPictureDemo.png "每个字都是一幅画效果图") 然后我[放个链接](http://pan.baidu.com/s/1dFOIFAx "放个链接"),大家先去下载下来玩吧~然后我再说说这个程序的事…… 先说说这个程序的历史吧……这个程序最早的时候是我两年前的一个`HelloWorld`的小练手,效果图: ![Hello wxLua效果图](HellWxLuaDemo.png "Hello wxLua效果图") 可以[从这儿下载下来玩](http://pan.baidu.com/s/1hsv6sKG "从这儿下载下来玩"),它的代码是这样的: ```Lua require("wx") frame = nil panel = nil gstimer = nil cx=25 cy=25 sx=10 sy=10 function OnPaint(event) local dc = wx.wxBufferedPaintDC(panel) --local dc = wx.wxPaintDC(panel) dc:SetPen(wx.wxTRANSPARENT_PEN) dc:SetBrush(wx.wxWHITE_BRUSH) --dc:Clear() local w, h = panel:GetClientSizeWH() dc:DrawRectangle(0, 0, w,h); dc:SetBrush(wx.wxRED_BRUSH) dc:DrawCircle(cx,cy,5) local str="Hello World!" local tw,th=dc:GetTextExtent(str) dc:DrawText(str, math.max(0,(w-tw)/2),math.max(0,(h-th)/2)); dc:delete() end function TimerTick(event) if not panel then return nil end local w, h = panel:GetClientSizeWH() if not w or not h then return nil end if cx > w-sx then sx=-10 end if cx < sx then sx=10 end if cy > h-sy then sy=-10 end if cy < sy then sy=10 end cx=cx+sx cy=cy+sy panel:Refresh(false) end function main() frame = wx.wxFrame( wx.NULL, wx.wxID_ANY, "你好~", wx.wxDefaultPosition, wx.wxSize(331, 331), wx.wxDEFAULT_FRAME_STYLE + wx.wxFULL_REPAINT_ON_RESIZE) panel = wx.wxPanel(frame, wx.wxID_ANY) panel:Connect(wx.wxEVT_PAINT, OnPaint) local fileMenu = wx.wxMenu() fileMenu:Append(wx.wxID_EXIT, "退出(&X)", "退出程序!") local helpMenu = wx.wxMenu() helpMenu:Append(wx.wxID_ABOUT, "关于(&A)", "关于程序的一些说明……") local menuBar = wx.wxMenuBar() menuBar:Append(fileMenu, "游戏(&F)") menuBar:Append(helpMenu, "帮助(&H)") frame:SetMenuBar(menuBar) frame:CreateStatusBar(1) frame:SetStatusText("欢迎来到这儿!") frame:Connect(wx.wxID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED,function(event) frame:Close(true) end ) frame:Connect(wx.wxEVT_CLOSE_WINDOW,function(event) gstimer:Stop() frame:Destroy() end) frame:Connect(wx.wxID_ABOUT, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) wx.wxMessageBox('作者:花楹/仙儿(yimengqiannian)\n邮箱:huaying1988@gmail.com\n版本号:0.0.0\n版权:木有~\n对!就是闲的没事写着玩的!\n', "关于应用", wx.wxOK + wx.wxICON_INFORMATION, frame) end ) --frame:Connect(wx.wxEVT_ERASE_BACKGROUND,function(event) end) frame:SetBackgroundStyle(wx.wxBG_STYLE_CUSTOM) frame:Show(true) gstimer = wx.wxTimer(frame) frame:Connect(wx.wxEVT_TIMER, TimerTick) end main() gstimer:Start(10) wx.wxGetApp():MainLoop() ``` 大家可不要小瞧这段代码,虽然只有一百来行,由于我当时对`Lua`以及`wxLua`的了解及其有限(_其实现在也是_),它花费了我一下午的时间去调试,同时,还包括其他的时间去整改……最后虽然各种全局变量之类的很难看,但是当时可能是尝试做过模块化尝试的…… 程序中涉及一个跳动的小球,这个小球动画也是花费了不少时间,幸好`wxWidget`提供比较好的双缓存支持,也就是`wxBufferedPaintDC`,它隐藏了很多实现细节,感觉还是挺爽的……具体的调用方式见代码…… 之后这个`HelloWorld`代码一直沉寂……直到最近,我又开始重操旧业,搞`Lua`……然后看到了五年前许下的要实现“每个字都是一朵花”,想想,写个小东西用来哄妹纸也不错呢~ 于是便有了上面那个小应用……可惜,妹纸的电脑就是跳不出设置字体的对话框来……有相同现象的网友能帮忙研究研究这是怎么回事么? 这个小应用能说的不多,其实逻辑复杂性比`Hello World`还要简单,因为没有`Timer`,没有双缓存动画……应用了一些公用的`Dialog`……很中规中矩,很板正的一个小`Windows`桌面程序……为了方便大家粘贴研讨,并且做一个备份,还是不厌其烦粘一下代码: ```Lua require("wx") function main() local generateID= (function(beginID) local count = beginID; return function() count = count + 1; return count; end end)(wx.wxID_HIGHEST); local ID_SET_FONT = generateID(); local ID_SET_FTCOLOR = generateID(); local ID_SET_BGCOLOR = generateID(); local ID_SET_TEXT = generateID(); local ID_SET_ANGEL = generateID(); local ID_SET_RATIO = generateID(); local frame = wx.wxFrame( wx.NULL, wx.wxID_ANY, "每个字都是一朵花~", wx.wxDefaultPosition, wx.wxSize(250, 350), wx.wxDEFAULT_FRAME_STYLE + wx.wxFULL_REPAINT_ON_RESIZE); frame:Centre(); frame:SetIcon(wx.wxIcon("icon/favicon.ico",wx.wxBITMAP_TYPE_ICO)); local ftColor = wx.wxColourData(); ftColor:SetChooseFull(true); ftColor:SetColour(wx.wxColour(213,31,201)); local fontData = wx.wxFontData(); --fontData:SetColour(ftColor:GetColour()); --fontData:SetInitialFont(wx.wxNORMAL_FONT); --local font = wx.wxFont(wx.wxNORMAL_FONT); local font = wx.wxTheFontList:FindOrCreateFont(12, wx.wxFONTFAMILY_DEFAULT, wx.wxNORMAL, wx.wxNORMAL, false, "幼圆"); font:SetPointSize(42); fontData:SetInitialFont(font); fontData:SetChosenFont(font); local bgColor = wx.wxColourData(); bgColor:SetChooseFull(true); bgColor:SetColour(wx.wxColour(198,255,140)); local text = "苏"; local angel = 10; local ratio = 1.2; local panel = wx.wxPanel(frame, wx.wxID_ANY); panel:SetBackgroundColour(bgColor:GetColour()); panel:Connect(wx.wxEVT_PAINT, function (event) local dc = wx.wxPaintDC(panel) dc:SetFont(fontData:GetChosenFont()) dc:SetTextForeground(ftColor:GetColour()) dc:Clear() local w, h = panel:GetClientSizeWH() local tw,th=dc:GetTextExtent(text) dc:DrawText(text, math.max(0,(w-tw)/2),0); local t = 0; local r = 0; for t = 0,360,360/(angel) do r = math.pi * t / 180; dc:DrawRotatedText(text, w/2-th*ratio*math.sin(r), th/2+h/2-th*ratio*math.cos(r), t); end dc:delete() end) local fileMenu = wx.wxMenu() fileMenu:Append(ID_SET_FONT, "字体(&F)", "设置字体") fileMenu:Append(ID_SET_FTCOLOR, "颜色(&C)", "设置字的颜色") fileMenu:Append(ID_SET_BGCOLOR, "背景(&B)", "设置背景") fileMenu:Append(ID_SET_TEXT, "文字(&W)", "设置文字") fileMenu:Append(ID_SET_ANGEL, "字数(&G)", "设置一圈要显示多少字") fileMenu:Append(ID_SET_RATIO, "半径(&D)", "设置字圈的半径系数") local helpMenu = wx.wxMenu() helpMenu:Append(wx.wxID_ABOUT, "关于(&A)", "关于\"每个字都是一朵花\"的一些说明……") helpMenu:Append(wx.wxID_EXIT, "退出(&X)", "退出本应用") local menuBar = wx.wxMenuBar() menuBar:Append(fileMenu, "设置(&F)") menuBar:Append(helpMenu, "帮助(&H)") frame:SetMenuBar(menuBar) frame:CreateStatusBar(1) panel:Connect( wx.wxEVT_SET_FOCUS, function(event) frame:SetStatusText("欢迎来到\"每个字都是一朵花\"!"); event:Skip(); end ) local toolBar = frame:CreateToolBar(wx.wxTB_HORIZONTAL, wx.wxID_ANY); toolBar:AddTool(ID_SET_FONT, "字体", wx.wxBitmap( "icon/font.png", wx.wxBITMAP_TYPE_PNG ), wx.wxNullBitmap, wx.wxITEM_NORMAL, "字体", "设置字体") ; toolBar:AddTool(ID_SET_FTCOLOR, "颜色", wx.wxBitmap( "icon/color.png", wx.wxBITMAP_TYPE_PNG ), wx.wxNullBitmap, wx.wxITEM_NORMAL, "颜色", "设置文字颜色") ; toolBar:AddTool(ID_SET_BGCOLOR, "背景", wx.wxBitmap( "icon/bgcolor.png", wx.wxBITMAP_TYPE_PNG ), wx.wxNullBitmap, wx.wxITEM_NORMAL, "背景", "设置背景颜色") ; toolBar:AddTool(ID_SET_TEXT, "文本", wx.wxBitmap( "icon/text.png", wx.wxBITMAP_TYPE_PNG ), wx.wxNullBitmap, wx.wxITEM_NORMAL, "文本", "设置要显示的文本") ; toolBar:AddTool(ID_SET_ANGEL, "字数", wx.wxBitmap( "icon/wnum.png", wx.wxBITMAP_TYPE_PNG ), wx.wxNullBitmap, wx.wxITEM_NORMAL, "字数", "设置一圈要显示几个字") ; toolBar:AddTool(ID_SET_RATIO, "半径", wx.wxBitmap( "icon/ratio.png", wx.wxBITMAP_TYPE_PNG ), wx.wxNullBitmap, wx.wxITEM_NORMAL, "距离", "设置字圈的半径系数") ; toolBar:AddSeparator(); toolBar:AddTool(wx.wxID_ABOUT, "关于", wx.wxBitmap( "icon/about.png", wx.wxBITMAP_TYPE_PNG ), wx.wxNullBitmap, wx.wxITEM_NORMAL, "关于", "关于该程序") ; toolBar:AddTool(wx.wxID_EXIT, "退出", wx.wxBitmap( "icon/close.png", wx.wxBITMAP_TYPE_PNG ), wx.wxNullBitmap, wx.wxITEM_NORMAL, "退出", "退出该程序") ; toolBar:Realize(); local setFont = function(event) local dlg = wx.wxFontDialog(frame, fontData); if dlg:ShowModal() == wx.wxID_OK then fontData = dlg:GetFontData(); --ftColor:SetColour(fontData:GetColour()); panel:Refresh(false); end --event:Skip(); end local setBgColor = function(event) local dlg = wx.wxColourDialog(frame,bgColor); if dlg:ShowModal() == wx.wxID_OK then bgColor = dlg:GetColourData(); panel:SetBackgroundColour(bgColor:GetColour()); panel:Refresh(); end --event:Skip(); end local setFtColor = function(event) local dlg = wx.wxColourDialog(frame,ftColor); if dlg:ShowModal() == wx.wxID_OK then ftColor = dlg:GetColourData(); --fontData:SetColour(ftColor:GetColour()); panel:Refresh(); end --event:Skip(); end local setText = function(event) local dlg = wx.wxTextEntryDialog(frame, "请在底部输入框内输入您要展示的字", "请输入要显示的字", text, wx.wxOK + wx.wxCANCEL); if dlg:ShowModal() == wx.wxID_OK then text = dlg:GetValue(); panel:Refresh(); end --event:Skip(); end local showAbout = function (event) wx.wxMessageBox('作者:花楹/仙儿(yimengqiannian)\n邮箱:jingchangjiang1988@163.com\n版本号:0.0.0\n版权:木有~\n对!就是闲的没事写着玩的!\n', "关于应用", wx.wxOK + wx.wxICON_INFORMATION, frame); --event:Skip(); end local doExit = function(event) frame:Close(true); --event:Skip(); end local doDestroy = function(event) frame:Destroy(); --event:Skip(); end local setAngel = function(event) local dlg = wx.wxTextEntryDialog(frame, "请在底部输入框内输入您要展示字旋转的间隔角度", "请输入间隔角度", tostring(angel), wx.wxOK + wx.wxCANCEL); local num = nil; repeat if dlg:ShowModal() == wx.wxID_OK then num = tonumber(dlg:GetValue()); else num = angel; end if num == nil then wx.wxMessageBox('请输入一个正确的数字', "参数错误", wx.wxOK + wx.wxICON_EXCLAMATION, frame); elseif num <= 0 or num > 360 then num = nil; wx.wxMessageBox('角度要在0~360之间', "参数错误", wx.wxOK + wx.wxICON_EXCLAMATION, frame); end until num ~= nil if angel ~= num then angel = num; panel:Refresh(); end --event:Skip(); end local setRatio = function(event) local dlg = wx.wxTextEntryDialog(frame, "请在底部输入框内输入您要展示字的距离系数", "请输入距离系数", tostring(ratio), wx.wxOK + wx.wxCANCEL); local num = nil; repeat if dlg:ShowModal() == wx.wxID_OK then num = tonumber(dlg:GetValue()); else num = ratio; end if num == nil then wx.wxMessageBox('请输入一个正确的数字', "参数错误", wx.wxOK + wx.wxICON_EXCLAMATION, frame); elseif num < 0 or num > 10 then num = nil; wx.wxMessageBox('系数要在0~10之间', "参数错误", wx.wxOK + wx.wxICON_EXCLAMATION, frame); end until num ~= nil if ratio ~= num then ratio = num; panel:Refresh(); end --event:Skip(); end frame:Connect(ID_SET_FONT, wx.wxEVT_COMMAND_MENU_SELECTED,setFont); frame:Connect(ID_SET_BGCOLOR, wx.wxEVT_COMMAND_MENU_SELECTED,setBgColor); frame:Connect(ID_SET_FTCOLOR, wx.wxEVT_COMMAND_MENU_SELECTED,setFtColor); frame:Connect(ID_SET_TEXT, wx.wxEVT_COMMAND_MENU_SELECTED,setText); frame:Connect(ID_SET_ANGEL, wx.wxEVT_COMMAND_MENU_SELECTED,setAngel); frame:Connect(ID_SET_RATIO, wx.wxEVT_COMMAND_MENU_SELECTED,setRatio); frame:Connect(wx.wxID_ABOUT, wx.wxEVT_COMMAND_MENU_SELECTED,showAbout); frame:Connect(wx.wxID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED,doExit); frame:SetBackgroundStyle(wx.wxBG_STYLE_CUSTOM) frame:Show(true) wx.wxGetApp():MainLoop(); return 0; end return main() ``` 好了,既然说明了目的是哄妹纸,当然要做得高大上一点,怎么也得有菜单、状态栏、工具栏吧……尤其是工具栏,一排小图标多给力…… 于是,我就从各种乱七八糟的应用里面扣了几个图标放进去了……扣得不好有毛边,风格也不一致,那也没办法,谁叫我美工技能树没点亮,哄妹纸的时候就蹩脚了…… 然后就是,不能让妹纸来运行`Lua`命令来执行程序吧……也不能让妹纸安装`wxLua`库吧…… 所以,我希望尽可能的把需要的`dll库`打包起来,发给妹纸,妹纸只需要解压缩,然后双击`exe`就行了…… 然后就轮到lua脚本绑定利器`srlua`出场了……我下载了这个项目的源码,导入`code::blocks`,然后重新编译了一下…… 为何要如此麻烦呢?因为……我要给妹纸看一个漂漂的图标啊……图标太丑了,妹纸都不愿意去点,然后不就没后话了…… 因为只有`wsrlua`项目有图标,所以只需要重新编译一下`wsrlua`就行…… 把项目中的`icon1.ico`换成自己想要的图标,或者修改`wsrlua.rc`中这一行中的`icon1.ico`,换成你想要的`ico文件`: ``` ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON1 ICON DISCARDABLE "icon1.ico" ``` 然后重新编译就可以了…… 其实还有一串描述也可以改……比如说`wsrlua.rc`中的这一段: ``` BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "2c0a04b0" BEGIN VALUE "Comments", "\0" VALUE "CompanyName", "Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br> \0" VALUE "FileDescription", "wsrlua\0" VALUE "FileVersion", "1, 5, 1, 0\0" VALUE "InternalName", "wsrlua\0" VALUE "LegalCopyright", "This code is hereby placed in the public domain. \0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "wsrlua.exe\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "Lua interpreter for self-running programs \0" VALUE "ProductVersion", "1, 5, 1, 0\0" VALUE "SpecialBuild", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x2c0a, 1200 END END ``` 这一段涉及编译出来的文件描述,修改成妹纸喜欢的话语说不定效果拔群,然而更多时候妹纸不会注意这些东西…… 大家最好用`rc编辑器`去改,改个图标没啥问题,改的多了,就不好维护一致性了…… 编译完之后,将写完的脚本用`glue`绑定一下,大家可以参考`src`中的`bind.bat`的写法: ```Shell @echo off title 绑定lua脚本到exe color 1D echo 正在绑定drawText脚本到exe glue.exe wsrlua.exe drawText.lua drawText.exe move drawText.exe ../每个字都是一幅画.exe echo 正在绑定drawText脚本到exe glue.exe wsrlua.exe drawTextCircle.lua drawTextCircle.exe move drawTextCircle.exe ../每个字都是一朵花.exe echo 执行完成 pause ``` 找个好基友帮忙在他的机器上测一下缺哪些`dll`,就打包进哪些`dll`,然后打包发给妹纸就可以了…… 然后妹纸说……缺`libgcc_s_dw2-1.dll`……然后我感觉我大意了,好基友的机器大约也是有`gcc`之类的库的吧…… 我又把`libgcc_s_dw2-1.dll`一起打包发过去,然后妹纸说点不开字体设置…… 然后我调试了半天也没找到原因…… 到最后就只能把这个程序发到博客上来了……


花楹2017-7-16 17:40:19 说:
这么好看的名字,不用浪费啦~\(≧▽≦)/~啦啦啦
羽夏2017-7-16 17:18:23 说:
随便用人家的名字,申请使用权了吗~
发表评论

必填,公开,这样称呼起来方便~

必填,不会被公开,不必担心~

http://

非必填,公开,目的是方便增进友好访问~

必填,请输入下方图片中的字母或数字,以证明你是人类

看不清楚
必填,最好不要超过500个字符
     ↑返回顶端↑