Rainmeter之Lua详解
本帖最后由 语笑嫣然 于 2013-6-10 20:23 编辑此教程代发,作者jyf823691221
特别鸣谢@夜色之下 对教程的部分建议及补充
基础说明
你可能知道,或者不知道,这里你将要首先了解的是script是Rainmeter(下面简称RM)的一类Measure,而目前rainmeter支持的脚本只有lua,sciript类型measure的写法和其它的measure无异,本文档中将告诉你在rainmeter里面怎么使用lua,它们之间的简单交互是怎么完成的.
我们要注意的是Lua是区分大小写的.
下面是rainmeter皮肤文件中调用lua脚本的最精简写法:
Measure=Script
ScriptFile=LuaCon.lua由于script是一类Measure,那么Measure的通用设置对于script都是有效的.
上面讲的都是script在ini或者inc中的写法,而在lua文件中使用rainmeter,通常的写法是:function Initialize()
end
function Update()
end这里要说明的是,上面是rainmeter结合lua使用的,rainmeter提供的两个交互函数,在这两个函数之外你还可以在lua脚本里面建立更多其它的函数.
这个Lua只含有两个空的函数,函数名为Initialize和Update,前者是在皮肤被加载的时候运行一次,而后者是皮肤每次Update更新的时候运行.要注意的是更新和刷新是不同的,在Update这个函数里面要慎用rainmeter的刷新,也就是!refresh,因为这样往往会导致rainmeter崩溃。上面的两个函数你可以选择性的添加到你的lua脚本文件里面,你也可以不写,这也都是可以的.
函数
Lua中的自定义函数的形式为:
function 函数名 (参数1,参数2,参数3...)
函数体
end
不需要参数的将括号内留空就行了.
Lua的单行注释符号为”--“.
在Rainmeter里面调用Lua中的函数总共有两种方法:
我们先讲第一种调用方法,让RM从Measure这个Section节点中调用;
要实现这种调用,在Lua文件里面必须使用上面列出的Update函数.
第二种是使用RM还提供了另外一种调用方法(使用RM中的Bang):
!CommandMeasure "Measure" "Arguments" "(Config)"
Measure写Lua的Measure的名称,这里使用的是LuaCon.
Arguments要调用的Lua中的函数名称和参数,写法为”函数名(参数1,参数2…)”.
Config设置要调用的函数代码所在文件夹(省略的话就默认为当前编辑文件的文件夹或者说当前皮肤的配置).
官方文档中对于Lua的说明:
Lua中的公共信息:
1. 打印日志(输出信息到RM的日志里,最主要的调试手段).
写法:print(“要输出的变量的值为:”..varname)其中”..”为连接符.
2. 返回数值.
在Lua中使用”return”语句返回数值,一般写法为” return varname ”.
“ return ‘Hello’ ”返回的是一个内容为Hello的字符串;
“ return Hello ”返回的是名为Hello的变量的值,注意的是这里指的变量是在lua中定义的.
3. 返回的类型.
在Lua中,返回情况分为两种,第一种是在Update函数中进行返回,这样的返回值会直接体现在Measure的返回信息上,这个信息可以在日志窗口的皮肤选项卡下见到,它和其它的Measure使用.第二种是在自定义的函数中,自定义函数将值返回给调用函数,此时可在调用代码前加上赋值语句,例如SysInfo()函数将会返回一个值,那么在调用它的函数中可以这样写:revalue=SysInfo().
4. 注意事项.
在Lua中,函数按照代码行数从上至下一次执行,遇到return语句的时候不论返回的值是什么或者return后面有什么代码都将会直接返回,结束函数.
在lua中,使用引号括起来的都是字符,如果是数字则不需要被括起来.
局部变量以local申明,例如:local x=1 , 此变量的作用区域在包含它的块内.比如Function demo()
Local x = 1
End那么这个局部变量的作用区域就仅限于名为demo这个函数内.如果另外有一个函数Function demo2()
Print(x)
End那么调用demo2函数将返回一个nil(可以称其为空,也就是没有),因为x这个是一个局部变量它值作用在demo函数块里面,而无法在demo2函数块里面作用.
Lua的参数传递特性:
Lua可以同时返回几个值,例如:return a , b ,因此函数接收返回的值也可以是多个: i , j=fun().
Lua中操作和获取RM中信息的方式有两种.
一、 通过Meter/Measure的对象名
此方法需要预先获取Meter或Measure的对象名,在RM中,每个对象都有一个对象名,并且各不相同,因此可以在Lua中使用对象名对它们进行相应的操作.
1. 获取对象名
1) 获取Meter对象名 MyMeter=SKIN:GetMeter(‘MeterName’)
“MyMeter” lua中用于保存对象名的变量名称;
“MeterName” 指定RM中的Meter的Section节点名称;
2) 获取Measure对象名
MyMeasure = SKIN:GetMeasure('MeasureName')
“MyMeasure” 在lua中用于保存对象名的变量名称;
“MeasureName” 指定RM中Measure的Section名称;假如使用print(MyMeter)打印此变量的话,会在日志窗口显示” userdata: “外加一串很长的数字 ,这些返回的数字不是固定的,当Meter不同和每次获取时间不同时都会发生变化.
3) 获取Variables的值
此方法可以获取RM皮肤中定义的变量.MyVariable = SKIN:GetVariable('VariableName', 'n/a')
“MyVariable” 保存RM变量的值的lua变量名称;
“VariableName” 指定RM中变量名称;
“n/a” 当没有获取到时默认的值假如使用print(MyVariable)打印此变量的话,会在日志窗口显示RM中”VariableName”的值.
2. 使用对象名操作Meter/Measure.
1) 操作Meter
a. 获取Meter的Option MySolidColor = MyMeter:GetOption('SolidColor', '000000')得到皮肤文件里面对应meter的solidcolor选项的值并赋值给lua中定义的变量MySolidColor;“MySolidColor” lua中定义的保存皮肤文件meter 选项的变量名称
“MyMeter:GetOption” MyMeter是rainmeter皮肤文件里面的meter对象名称
“SolidColor” RM中Meter的Option名称;
“000000” 未获取到时默认值;b. 获取Meter的名称MyMeterName = MyMeter:GetName()
“MyMeterName” lua中保存有获取到的值的变量;
“MyMeter” MyMeter为前面获取到的对象名c. 获取Meter的坐标及大小MyX = MyMeter:GetX()
“MyX” lua中保存获取到的值的变量;
“MyMeter” MyMeter为前面获取到的对象名;
使用GetX() 获取X绝对坐标;
GetY() 获取Y绝对坐标;
GetW() 获取W值;
GetH() 获取H值;d. 设置Meter的坐标及大小MyMeter:SetX()
“MyMeter” lua中保存有获取到的值的变量
使用SetX() 设置X的值,括号中可写数字或者带值为数字的变量;
SetY() 设置Y的值,同上;
SetW() 设置W的值,同上;
SetH() 设置H的值,同上;e. 隐藏/显示Meter MyMeter:Hide()
“MyMeter” lua中保存有获取到的值的变量
使用”Hide()” 隐藏Meter;
“Show()” 显示Meter;2)操作Measure
操作Measure与Meter高度相似,只是使用的函数有所不同.GetValue() 获取Measure的值(数字);
GetStringValue() 获取Measure的值(字符);
GetOption() 获取Measure的Option,与Meter一样 (字符);
GetNumberOption() 与上面相同,只是获取的结果是数字(数字);
GetName() 获取Measure的名字(字符);
GetMinValue() 获取Measure的MinValue值;
GetMaxValue() 获取Measure的MaxValue值;
GetRelativeValue() 获取Measure的百分值(数值,从0到1);
GetValueRange() 获取Measure的值的范围(数字);
Disable() 禁用Measure;
Enable() 启用Measure;3)操作当前Lua Measure
对当前的Lua Measure进行操作的时候,可以不用获取Measure的对象名,直接使用”SELF”(大小写敏感),使用方面和其他的Measure一样.
上面对于Meter/Measure的操作分为两种:一种获取信息型的,一种是设置型的.其中获取信息型的函数均有返回值,在函数前面需要使用赋值语句来得到获取值,而设置型的没有.
这些函数对于大小写都是敏感的,因此编写的过程中需要多加注意.
另外上面这些函数只能修改少数信息,更加多的自定义需要使用第二种控制方法.
二、 通过Lua中的Bang语句
在Lua中也可以使用类似于RM中的Bang对Measure以及Meter等进行操作,并且这些Bang语句的适用性更加强,几乎能实现RM中的大多数功能,且语句写法也高度类似.
Lua中Bang有两种写法:
1. 将整条语句作为单一字符来写SKIN:Bang('!SetOption "MyMeter" "Text" "Hello, world!"')括号中的单引号间的语句是我们自己修改的,写法都与RM中没什么区别,只是注意一点,此语句中有双引号括起来的是字符,当需要将lua的变量的值写入时,直接写变量名,也可以将两个字符进行拼接,拼接使用”..”符号,例如:”Hello “..”World !”就等同于”Hello World !”,还可以将字符串和lua变量的值连接到一起,例如:”Hello “..World,后面的World没有被引号括起来,因此是lua变量.
单个语句包含多个Bang可以这样写SKIN:Bang('[!UpdateMeter "MyMeter"][!Redraw]')2. 每个Bang参数都作为一个单独的参数写SKIN:Bang('!SetOption', 'MyMeter', 'Text', 'Hello, world!')这种写法我认为更加便于理解字符和变量的表示方法的不同.
三 、其他的操作
1. 转换文件路径(从相对路径到绝对路径)
函数接受文件名(可带有路径),返回文件的绝对路径MyPath = SKIN:MakePathAbsolute('MyImage.png')2. 使用RM中的变量替换字符并返回 MyString = SKIN:ReplaceVariables('The value of MyVariable is #MyVariable#.')在上面的语句中,Lua会从RM中查找名为MyVariables的变量并取得它的值,然后将#MyVariable#替换,与引号间的其他东西组合,再将组合好的信息赋值给MyString.在这个语句中#MyVariable#表示RM中的变量,并且Section Variables(节点变量)也是允许使用的,若在RM中没有找到这个变量,那么将使用”nil”进行替换,”nil”也就是空.
3. 计算MyNumber = SKIN:ParseFormula('2+2')假如括号中引号包围的是一个可计算的计算式,那么将会把计算的结果返回给MyNumber.
在RM中能使用的Lua自带函数功能
Lua函数查询文件下载 pdf文件,全英文
Lua官网函数查询 网站,全英文
也可以搜索Lua + 函数类型进行搜索,常用的函数类型有: table , string , math , OS , io 等,不过目前RM不支持Lua的Debug , External libraries(外部库) , Require , Dofile .尽管这些很重要的东西不支持,但是我们还可以使用lua为RM编写更加强劲的皮肤.
下面是常用的lua函数: stvar=tostring(var) 此函数将括号内的var转换成字符串,并赋值给stvar;
numvar=tonumber(var) 此函数将括号内的var转换成数字,并赋值给numvar;
print(var) 打印括号内的变量的值,最常用的调试手段,assert目测不支持;
typ=type(x) 返回x的类型给typ;
select(i,a,b,c…) 返回第i个以后的量,从a开始,a为第一个,此函数常为多返回值;
unpack(t) 参数t必须为table,函数会将t内全部元素分开返回,此时为多返回值;
next(t,inx) 如果inx是nil的话,返回t的第一个元素的序号和值,而当inx是序号的时候返回下一个元素的序号和值;
ipairs(t) 以数字序号的方式对t进行迭代(遍历),并返回序号和值;
pairs(t) 与上一个近似,只不过并不以一定的顺序遍历;
以上两个函数单独使用并不多见,更多的是与for循环配合使用,后面会讲到.
table.insert(t,v) 在表t的序号为i的位置插入变量v的值,若i省略则默认为末尾;
table.remove(t[,i]) 删除表t中序号为i的位置的值,i省略则是末尾的值,并且返回那个值;
table.maxn(t) 返回t中序号最大的位置的值,如果表为空则返回0;
table.sort(t[,cf]) 对表内元素进行排列,排列方式可定义cf函数进行设置,默认从小到大,此函数在某些情况下很好用,cf函数具体写法可百度得到;
table.concat(t[,s[,i[,j]]]) 返回表t中序号从i到j的元素,并且以变量s分隔开,在i和j省略的时候默认返回全部值;
math.abs(x) 返回x的绝对值;
math.mod(x,y) 此函数已经被弃用,新函数为math.fmod(x,f)
math.modf(x) 分别返回x的整数部分和小数部分;
math.fmod(x,y) 求模
math.floor(x) 向下取整;
math.ceil 向上取整;
math.max(x,y,z…) 返回一系列参数中最大的那个;
math.min(x,y,z…) 返回一系列参数中最小的那个;头部为math的函数还有很多,它们都属于math函数,更多的信息可以百度或者去前面给的Lua官网的介绍中查看.string.len(s) 返回字符串s长度;
string.sub(s,i[,j]) 返回字符串s从第i到第j个字符;注意:lua中的序号都是从1开始的.
更多的string库函数请查看官方文档或者百度.
下面讲讲io库的函数,io库的函数是用来读写本地文件的,io库分为简单和完整两个,我一般使用完整的.file=io.open(fn[,m]) 打开名为fn的文件,其中fn包含路径和拓展名,m为打开模式,可以使用的值为:”r”=只读模式,”w”=只写模式,”a”=添加模式,还有其他的模式,不过基本上是用的是这几种,更过请查看前面给出的资料,此函数如果成功打开一个文件会返回一个文件的对象,这里我们使用了file变量接收了这个对象,如果打开失败,那么将会返回nil;
file:close() 使用保存有对象的变量file关闭文件;
file:read(fm) 读取文件内容,fm为读取模式,可用的值为:”*n”=读取一个数值,”*a”=读取全部内容,文件末尾返回空(””),”*l”=读取一行,在文件末尾的时候返回nil;
另外完整的io模式可以使用迭代器遍历整个文件,更多情况可在百度中获取;
OS库中用的多点的也就是os.execute(),此函数用法与命令行类似,另外os库中的函数还能获取系统时间,详细情况百度去吧.
Lua中的流程控制函数等资料均可在网上找到详细的教程,这里就不一一赘述了.
楼下继续
本帖最后由 语笑嫣然 于 2013-6-10 19:16 编辑
下面附上FunDock和jyf823691221课程表的Lua代码作为示例:
FunDock:
--下面的表用于保存各个白色图标的Alpha值hit={icon1t=0,icon2t=0,icon3t=0,icon4t=0,icon5t=0,icon6t=0,icon7t=0,icon8t=0,icon9t=0}--下面的函数在加载皮肤的时候运行,初始化一些值function Initialize( ... )
x=0
on=0
showalpha=255
iconon=nil
y=0
draw='no'
speed=SELF:GetOption('drawspeed')
end--下面的函数在皮肤每次刷新的时候运行,根据一些全局变量对meter做相应的修改function Update( ... )--鼠标在某红色图标上时,开始渐变显示白色图标 if showalpha < 255 and iconon~= nil and draw=='ok' then
SKIN:Bang('!SetOption',iconon,'ImageAlpha',showalpha)
hit=showalpha
showalpha=showalpha+17
end
if (-17-y)==-353 then
draw='ok'
else if (-17-y)~=-353 then
draw='no'
end
end--检查鼠标未在上面的图标的白色的alpha值,发现则渐变隐藏之 for icon,alpha in pairs(hit) do
if icon~=iconon and alpha > 0 then
hit=hit-17
SKIN:Bang('!SetOption',icon,'ImageAlpha',hit)
end
end
--从SysInfo改变的on值获取鼠标状态,在皮肤上的时候渐变显示meter-->dock if x <= 180 and on==1 then
dx=x*math.pi/180
y=DrawFunc(dx)
x=x+speed*3
return(-17-y)
else if x > 180 and on==1 then
return -353
end
end--从SysInfo改变的on值获取鼠标状态,在离开皮肤的时候渐变隐藏meter-->dockif x > 0 and on == 0 then
dx=x*math.pi/180
y=DrawFunc(dx)
x=x-speed*3
return(-17-y)
else if on==0 and x<=0 then
return -17
end
end
end--获取鼠标与皮肤的交互状态function SysInfo(st)
if st=='OVER' then
on=1
else if st=='LEAVE' then
on=0
end
end
end--获取鼠标与图标的交互状态并设置鼠标激活的图标function Icon(sc,st)
if st=='ON' then
showalpha=0
iconon=sc
else if st=='LV' then
iconon=nil
end
end
end--dock的动画曲线函数function DrawFunc(dx)
local tmp=168*(1-math.cos(dx))
return tmp
end
课程表:MonthDay={31,28,31,30,31,30,31,31,30,31,30,31}--皮肤加载时候执行,获取句柄以及一些变量值function Initialize()
FilePath=SKIN:GetVariable('FilePath')
hYEAR=SKIN:GetMeasure('mYear')
hMONTH=SKIN:GetMeasure('mMonth')
hDAY=SKIN:GetMeasure('mDay')
hWEEKNAME=SKIN:GetMeasure('mweekname')
end--每次Update时执行function Update()
end--读取课程表,并将获取的值写入tablefunction Read()
local Meter={}
local day=hWEEKNAME:GetStringValue()
local week=Calc()
local w1={}
local w2={}
local file=io.open(FilePath,"r")
if file==nil then
NoFile()
else
for i=1,linenum(),1 do
local txt=file:read()
_,_,c,d=string.find(txt,"W%[(%d+)%-(%d+)%]")
_,_,e=string.find(txt,"D%[(%w-)%]")
if week >= tonumber(c) and week <= tonumber(d) and day==e then
_,_,y=string.find(txt,"S%[(%d+%-%d+)%]")
_,_,v=string.find(txt,"C%[(.-)%]")
_,_,g=string.find(txt,"R%[(.-)%]")
--print(WeekDay.." "..y.." 节 "..g..v)
table.insert(w1,(string.len(g)*10+32))
table.insert(w2,(string.len(v)*10.5+10))
table.insert(Meter,{Section=y,Room=g,Class=v})
end
end
file:close()
if (#Meter)~=0 then
table.sort(w1,FindMax)
table.sort(w2,FindMax)
table.sort(Meter,SortRuler)
Show(Meter,w1,w2)
else
NoClass()
end
end
end--计算开学周数function Calc()
local sdy=tonumber(SKIN:GetVariable('SDY'))
local sdm=tonumber(SKIN:GetVariable('SDM'))
local sdd=tonumber(SKIN:GetVariable('SDD'))
local days=0
if sdy==hYEAR:GetValue() then
days=Days(hYEAR:GetValue(),hMONTH:GetValue(),hDAY:GetValue())-Days(sdy,sdm,sdd)
else if sdy<hYEAR:GetValue() then
days=Days(hYEAR:GetValue(),hMONTH:GetValue(),hDAY:GetValue())+365+YearType(sdy)
end
end
return(math.floor((days+1) / 7) + 1)
end--计算平年闰年function YearType(Year)
if ( Year % 100 == 0 and Year % 400 == 0 ) or ( Year % 100 ~= 0 and Year % 4 == 0)then
return 1
else
return 0
end
end--获取课程表行数function linenum()
local i=0
local tfile=io.open(FilePath,"r")
for l in tfile:lines() do
i=i+1
end
tfile:close()
return i
end--计算元旦至给定日期的天数function Days(y,m,d)
local days=0
if m>1 then
for i=1,m-1,1 do
days=days+MonthDay<i>
</i>end
days=days+d
else if m==1 then
days=d
end
end
if m>2 then
days=days+YearType(y)
end
return days
end--函数结束
--排列table中的课程节次顺序function SortRuler(a,b)
if a.Section<b.Section then
return a.Section < b.Section
end
end--函数结束
--从大到小排列table中的值的顺序function FindMax(a,b)
if a>b then
return a>b
end
end--函数结束
--输出信息到RM中的Meter,修改Meter的属性function Show(tClass,wide1,wide2)
SKIN:Bang('!HideMeterGroup','c')
for i=1,#(tClass) do
SKIN:Bang('!SetOption',"bg"..i.."_2",'W',wide1)
SKIN:Bang('!SetOption',"bg"..i.."_3",'W',wide2)
SKIN:Bang('!SetOption',i.."_1",'Text',tClass.Section)
SKIN:Bang('!SetOption',i.."_2",'Text',tClass.Room)
SKIN:Bang('!SetOption',i.."_3",'Text',tClass.Class)
SKIN:Bang('!ShowMeterGroup',"c"..i)
end
end--函数结束
--没找到课程表文件输出信息function NoFile()
SKIN:Bang('!HideMeterGroup','c')
SKIN:Bang('!SetOption',"bg1_2",'W',string.len("File!")*10+20)
SKIN:Bang('!SetOption',"bg1_3",'W',string.len("Sorry")*10.5+10)
SKIN:Bang('!SetOption',"1_1",'Text',"No")
SKIN:Bang('!SetOption',"1_2",'Text',"File!")
SKIN:Bang('!SetOption',"1_3",'Text',"Sorry")
SKIN:Bang('!ShowMeterGroup',"c1")
end--函数结束
--当天输出无课信息function NoClass()
SKIN:Bang('!HideMeterGroup','c')
SKIN:Bang('!SetOption',"bg1_2",'W',string.len("Day")*10+20)
SKIN:Bang('!SetOption',"bg1_3",'W',string.len("No Classes")*10.5+10)
SKIN:Bang('!SetOption',"1_1",'Text',"To")
SKIN:Bang('!SetOption',"1_2",'Text',"Day")
SKIN:Bang('!SetOption',"1_3",'Text',"No Classes")
SKIN:Bang('!ShowMeterGroup',"c1")
end--函数结束
最后附上doc文件,方便有兴趣的朋友查看
也可加入核心群:238427914(此群仅作技术探讨,其余一律踢出。基础代码求助请加会员群)
{:10_452:}虽然不懂,但是觉得好泥嗨 前段时间想自己学习一下,搞得懵懵懂懂的,高一伤不起呀- - 语笑嫣然 发表于 2013-6-10 18:53
下面附上FunDock和jyf823691221课程表的Lua代码作为示例:
FunDock:
{:10_468:} 不得不说的是。。
卤煮很流逼
弱弱问。。是男是女。能否勾搭一个。 这东西貌似不是我们小白学习的{:10_421:} 支持一下。楼主辛苦了 我就是在这个帖子了看到群号的!{:10_452:} webqq 发表于 2013-6-15 17:19
不得不说的是。。
卤煮很流逼
弱弱问。。是男是女。能否勾搭一个。
代花花回复你,做版主就勾搭,主动勾搭,各种勾搭
然后你就不会想勾搭了