wxLua实现的“每个字都是一朵花”小应用、双缓存动画、srLua及其他

wxLua实现的“每个字都是一朵花”小应用、双缓存动画、srLua及其他

话说,五年前的一天我曾经发博客说:我要实现个“每个字都是一朵花“的那种应用……五年过去了,终于到了我兑现诺言的时候了……

可惜,这次用的不是HTML5和JS,我已经投奔到lua这个小三门下了,所以这次用的是wxLua,也就是lua以及lua的wxWidget绑定库……心情好说不定还会实现一个wxLua版的取字模工具(注:请不要有期待)……

这个程序的代码是纯手写的,尽管后来我发现了wxFormBuilder这个神器~这东西居然能同时生成lua代码,真是大大提高了界面设计效率~可惜,我并木有使用它……

先放两个效果图:



然后我放个链接,大家先去下载下来玩吧~然后我再说说这个程序的事……

先说说这个程序的历史吧……这个程序最早的时候是我两年前的一个HelloWorld的小练手,效果图:


可以从这儿下载下来玩,它的代码是这样的:

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桌面程序……为了方便大家粘贴研讨,并且做一个备份,还是不厌其烦粘一下代码:

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的写法:

@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一起打包发过去,然后妹纸说点不开字体设置……

然后我调试了半天也没找到原因……

到最后就只能把这个程序发到博客上来了……

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值