语笑嫣然 发表于 2013-6-10 18:52:37

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 18:53:14

本帖最后由 语笑嫣然 于 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(此群仅作技术探讨,其余一律踢出。基础代码求助请加会员群)





1235678 发表于 2013-6-10 19:08:01

{:10_452:}虽然不懂,但是觉得好泥嗨

Soliv_ctx 发表于 2013-6-10 19:28:56

前段时间想自己学习一下,搞得懵懵懂懂的,高一伤不起呀- -

zzz_zq 发表于 2013-6-12 19:40:49

语笑嫣然 发表于 2013-6-10 18:53
下面附上FunDock和jyf823691221课程表的Lua代码作为示例:

FunDock:


{:10_468:}

webqq 发表于 2013-6-15 17:19:26

不得不说的是。。
卤煮很流逼
弱弱问。。是男是女。能否勾搭一个。

shen493098817 发表于 2013-6-18 02:06:31

这东西貌似不是我们小白学习的{:10_421:}

s314500 发表于 2013-6-29 12:11:02

支持一下。楼主辛苦了

呆毛骑士_ 发表于 2013-7-14 19:01:05

我就是在这个帖子了看到群号的!{:10_452:}

呆毛骑士_ 发表于 2013-7-14 19:03:28

webqq 发表于 2013-6-15 17:19
不得不说的是。。
卤煮很流逼
弱弱问。。是男是女。能否勾搭一个。

代花花回复你,做版主就勾搭,主动勾搭,各种勾搭
然后你就不会想勾搭了
页: [1] 2 3
查看完整版本: Rainmeter之Lua详解