wxLua is a Lua scripting language wrapper around the wxWidgets cross-platform C++ GUI library. It consists of two IDE type editors that can edit, debug, and run Lua programs (wxLua and wxLuaEdit), an executable for running standalone wxLua scripts (wxLuaFreeze), a Lua module that may be loaded using require("wx")
when using the standard Lua executable, and a library for extending C++ programs with a fast, small, fully embeddable scripting language.
Lua is a small scripting language written in ANSI C that can load and run interpreted scripts as either files or strings. The Lua language is fast, dynamic, and easy to learn. Lua contains a limited number of data types, mainly numbers, booleans, strings, functions, tables, and userdata. Perhaps the most powerful feature of the Lua language is that tables can be used as either numerically indexed arrays or associative arrays that can cross-reference any variable type to any other variable type.
wxLua adds to this small and elegant language the power of the C++ wxWidgets cross-platform GUI library. This includes the ability to create complex user interface dialogs, file and image manipulation, drawing, networking, displaying HTML, and printing to name a few. You can use as much or as little of wxWidgets as you like and C++ developers can trim down the size the bindings by turning off preprocessor directives.
Additionally, wxLua adds a library for manipulating the bits of integer numbers using a back-ported bit32
library from Lua 5.2.
wxLua website | - | http://wxlua.sourceforge.net |
wxLua Sourceforge page | - | http://sourceforge.net/projects/wxlua |
Lua website | - | http://www.lua.org |
wxWidgets website | - | http://www.wxwidgets.org |
Mailing list | - | wxlua-users@lists.sourceforge.net |
#ifdefs
for 2.6, but they are not maintained anymore since in some cases the complexity of maintaining backwards compatibility is not worth it and it is better to take advantage of the fixes and additions to newer versions of wxWidgets. With a little work you may be able to resurrect it to work with wxWidgets 2.6.wxWidgets/contrib/src/stc
. You need to have compiled this into a library if you want to compile the wxLua apps. In wxWidgets >= 2.9 the wxStyledTextCtrl is now part of the main distribution.stc, xrc, html, media, adv, net, xml, core, base, tiff, jpeg, png, zlib, regex, expat
.Lua programmers can use the binary packages of wxLua and everything that's needed is contained within it. C++ programmers or users on platforms that we don't provide binaries for will need a development library of wxWidgets; typically the source code that you have compiled on your system. More information about compiling wxLua is contained in the wxLua install.html file.
This short primer is meant to give you a good enough feeling for Lua that you should be able to understand the sample programs and begin to write your own. It assumes that you have a cursory understanding of general programming techniques. You should, in any case, read the Lua documentation at www.lua.org.
-- rest of line is commented
--[[ multiple line or inline comment ... ]]
local
in front of them, this is sometimes good practice.local
variables is limited to the current scope and its children.local
variable created with the same name as a global variable supersedes the global variable within the scope of the local variable.type(var_name)
returns the variable type as a string.
nil, boolean, number, string, table, function, userdata, thread
a = nil; local b; print(a, b, type(a), type(b))
; prints "nil nil nil nil"nil
and any variable can be reset back to nil
at any time to allow the Lua garbage collector to delete them if there are no other references to it.nil
using the or
keyword since nil
evaluates to false.
print(tonumber("a"), tonumber("a") or 1)
; prints "nil 1"true
or false
a = true; b = false; print(a, b, type(a), type(b))
; prints "true false boolean boolean"nil
works as false
, but the number 0 evaluates as true
since it has a value, i.e. not nil
, use (a ~= 0)
.a = 0; if a then print(a) end
; prints "0" since the variable "a
" evaluates to true
.a = 1; b = 3.14; print(a, b, type(a), type(b))
; prints "1 3.14 number number"n = (1E1 * 3.14 * math.sin(1) / 4)*math.pow(2.5e-1, 4)
tonumber(variable)
which returns nil
on failure.math
table.a = "hello"; b = a; b = "hi"; print(a, b, #a, type(a))
; prints "hello hi 5 string"s = "How are 'you'!"
or s = 'How\tare "You"!\n'
are both valid since either " or ' can be used to quote strings. ('\t' = tab, '\n' = line feed)s = [[How are "'you'"!]]
; double brackets can be used to create multiline strings that include new lines and whitespace...
operator
str1 = "hello"; str2 = "number"; str3 = str1.." "..str2.." "..tostring(2).."!"
("A "..2)
, but not (2.."A")
since the left hand side of the ..
operator must be a string.table.insert()
(or appended using table[#table+1] = "hello"
) and then table.concat()
called to create the single string result. The concatenation operator ..
is slower since each intermediary string has to be reallocated and hashed. The table.concat()
method only has to allocate and hash the resultant string once and its speed is quite competitive to other scripting languages.tostring(variable)
which returns nil
on failure.string
table.a = {5}; b = a; b[1] = 6; print(a, b, a[1], b[1], b[2], type(a), type(b))
tostring(t)
on the table which displays the variable type and its memory address.t = {}
creates an empty table.
t = { ["a"] = 5, "first", "second", B = 7 }; print(t.a, t["a"], t[0], t[1], t[2], t.B, t.b, t.c)
t.a = 2; t["a"] = 3; t[10] = 4
nil
.nil
, e.g. t.a = nil
#t
returns 2 since there are only two contiguous integer table indexes starting from 1 even though in this case there are actually 4 entries in the table.
t[#t+1]
will be nil
.for k, v in ipairs(t) do print(k, v) end
; Note: (k = key, v = value)
for k, v in pairs(t) do print(k, v) end
; Note: (k = key, v = value)
table.XXX, string.XXX, math.XXX, os.XXX
etc. in the Lua documentation.wx.XXX
table "namespace".The global table is called _G
and you can display it as you would any table using : - for k, v in pairs(_G) do print(k, v) end
Additional table functions are in the table
table.
function f(a, b) return a+b end; print(f, f(1,2), type(f))
f = function (a, b) return a+b end; print(f, f(1,2), type(f))
tostring(f)
on the function which displays the variable type and its memory address.Unassigned inputs are set to nil
and unassigned return values are discarded.
t = {}; t["Add"] = f; print(t.Add(1, 2), t.Add)
; prints "3 function: 01DE2AF8nil
.function table_append(t, v) t[#t+1] = v; v = 0; end; tbl = {}; item = "hello"; table_append(tbl, item); print(tbl[#tbl], item)
prints "hello hello", i.e. tbl[1] == "hello"
and the variable "item
" still equals "hello" and was not changed.
== ~= < > <= >=
(Note: not equal is ~=
)and, or, not
or
and
< > <= >= ~= ==
..
(string concatenation)+ -
* / %
not # -
(unary)^
and break do else elseif end false for function if in local nil not or repeat return then true until while
do ... end
block.function printHi() return; print("hi") end
, but you can write function printHi() do return end; print("hi") end
which can be useful for debugging functions. do
-- create a new local scope
local a = 2
end
local a, b, c = 1, 2, 3 -- can assign multiple values
a = 1; b = 2; c = 3 -- use ; for multiple lines of code on single line
a, b, c = 1, 2, 3 -- this works too
if (a == 1) and ((b <= 2) or (c ~= 3)) then
print(a+b/c)
elseif a == 2 then -- no parentheses necessary
print(a)
else
print(b)
end
table[value] = function() ... end
may be used to simulate one. case = {}
case[1] = function() print("Hello #1") end -- anonymous function
case[2] = function() print("Hello #2") end
...
if case[value] then
case[value]()
else
print("Unknown case value")
end
break
function Check5(val) -- returns nil if val ~= 5
if val == 5 then
return true
end
end
local a = 1
while a < 10 do
print(a)
if Check5(a) then break end
a = a + 1 -- no increment operator
end
local a = 0
while a < 10 do while true do
a = a + 1 -- no increment operator
if Check5 (a) then
break -- break in the inner while loop to "continue" in the outer loop
else
print(a)
end
break end -- break out of inner while loop
end
break
local a = 10
repeat
local temp = a * 2
print(temp, type(temp))
a = a - 1 -- no decrement operator
until a < 0
break
local a = "hello"
for a = 1, 10 --[[, increment]] do -- optional increment value, default increment is 1
local temp = a * 2
print(temp)
end
print(a) -- a == "hello" since loop counter variable is local to the loop
nil
, extra inputs are discarded.return
" keyword.function GetNums() return 3, 4, 5, 6 end; local _, num2 = GetNums()
select(n, ...)
function to choose return values to use.
print(select("#", GetNums()), "and", select(3, GetNums()))
; prints "4 and 5 6".select(n, ...)
returns all args after n
, but if the left hand side is a single variable the others are discarded.unpack(table, [i, [, j]])
function.
print(string.find(unpack({"Hello", "ll", 1, 1})))
; prints "3 4"function dostuff( ... ) end
local n_args = select("#", ...)
local args = { ... }
local arg3 = select(3, ...)
select()
to pick return values of a function as well. -- Print the keys in table t that have the given values.
function PrintKeys(t, values, cmp_case)
-- use nested functions for repetitive code or to simplify code
local function cmp_values(a, b)
if cmp_case then -- can use upvalue variables
return a == b
else
return string.lower(a) == string.lower(b)
end
end
local function find_key(t, val)
for k,v in pairs(t) do
if cmp_values(val, v) then return k end
end
end
for i = 1, #values do
print(find_key(t, values[i]), values[i])
end
end
data = {a1 = "a2", b1 = "b2", c1 = "c2"}
-- prints "a1 a2", "b1 b2", "nil C2"
PrintKeys(data, {"a2", "b2", "C2"}, true)
-- Varargs example demonstrating the different ways to handle them.
function Varargs(...)
local args = {...}
print(select("#", ...), #{...}, #args, args[2], unpack({...}, 2, 2))
return args, unpack(args) -- same as return ...
end
-- prints "4 4 4 20 20" and "table: 0183B820 10 30 5"
vals, val1, _, val3 = Varargs(10, 20, 30, 40)
print(vals, val1, val3, select("#", Varargs(10, 20, 30, 40)))
wxLua automatically loads a library for manipulating the bits of an integer number and puts it into the global bit32
table. This is because wxWidgets often uses enumeration flags to control the behavior of functions and for compactly storing status information. You can easily "or" bits by adding them together and this is the preferred method, for example 0x02 + 0x04 = 0x06 or bitwise 0110. If the bits you're trying to "or" are not powers of 2 (perhaps one is a bit mask) this fails, 0x01 + 0x03 = 0x04 or bitwise 0100 (oops) instead of the desired 0011.
wxLua uses a bitlib library backported from Lua 5.2 and since the code for it is very small, it's embedded into the wxLua sourcecode.
All function arguments should be integers. The number of bits available for logical operations depends on the data type used to represent Lua numbers; this is typically 8-byte IEEE floats, which give 53 bits (the size of the mantissa).
The logical operations start with "b" for "bit" to avoid clashing with reserved words; although "xor" isn't a reserved word, it is consistent.
bit32.rshift(x, disp) |
- | returns x shifted logically right disp places or left if negative |
bit32.band(...) |
- | returns the bitwise and of the input values |
bit32.bnot(x) |
- | returns the one's complement of x |
bit32.bor(...) |
- | returns the bitwise or of the input values |
bit32.btest(ยทยทยท) |
- | returns true if the and of the input values is not 0 |
bit32.bxor(...) |
- | returns the bitwise exclusive or of the input values |
bit32.extract(n, field [, width]) |
- | returns the number of bits set in n for the given 0-31 starting field to optionally field+width-1 |
bit32.replace(n, v, field [, width]) |
- | returns n with the bits in field to optionally field+width-1 replaced by the value v |
bit32.lrotate(x, disp) |
- | returns x rotated disp bits to the left |
bit32.lshift(x, disp) |
- | returns x shifted left disp places or right if negative |
bit32.rrotate(x, disp) |
- | returns x rotated disp bits to the right |
bit32.rshift(x, disp) |
- | returns x shifted right disp places or left if negative |
Programming in wxLua means that you're writing programs in the Lua language using an additional table of functions, objects, numbers, strings, and "classes" in the namespace table wx
from wxWidgets. Additional wxWidgets libraries are added as their own bindings and placed in their own "namespace" table, but for the examples below the wx
table is used.
wxLua creates five Lua tables for the binding functions and objects. These are in addition to the standard Lua tables; coroutine, debug, io, math, os, package, string, table
. Note that the wxaui
and wxstc
libraries have been separated into their own tables since they are fairly specialized libraries.
bit32 | - | A backport of the Lua 5.2 bit32 library for manipulating integer bits added to Lua 5.1. |
wxlua | - | Special functions for introspecting wxLua or |
generic functions that wxLua provides that are independent of wxWidgets. | ||
wx | - | wxWidgets functions, classes, defines, enums, strings, |
events, and objects are placed here. | ||
wxaui | - | The wxWidgets Advanced User Interface library. |
wxstc | - | The wxStyledTextCtrl wrapper around the Scintilla text editor. |
The semantics for accessing wxWidgets elements in wxLua tries to map closely to the underlying C++ notation so that the official C++ documentation may be used as a reference, http://www.wxwidgets.org/docs. The most common cases where wxLua deviates from C++ are for functions with values passed by reference that will be changed; wxLua will typically return multiple values instead. Please see the wxluaref.html document that lists all the wxWidgets objects wrapped by wxLua and take note of the functions that are marked %override since you will need to use them as described in that document. You should also look at the binding.html file, even if you do not plan to write your own bindings, to get a better understanding of the wxluaref.html file.
Strings : wxLua does not typically use the wxString class for strings, rather it uses Lua strings. This means that all wxWidgets functions that take a wxString parameter take either a wxString userdata or preferrably a Lua string (Lua variables that are of type(var) == "string"). Functions that return wxStrings convert the value into a Lua string for convenience. The conversion from the Lua ANSI C 8-bit char* string to a wxString (which may be a Unicode wchar* string) is done internally.
wxArrayString and wxSortedArrayString : Function parameters that take a "const wxArrayString& arr" or "wxArrayString arr" will accept either a wxArrayString userdata or a Lua table that has numeric indexes and string values and convert it into a wxArrayString for the function call. If the function call is "wxArrayString& arr" or "wxArrayString* arr" you must provide a wxArrayString userdata since the C++ function will most likely modify the wxArrayString that's passed to it.
wxArrayInt : Function parameters that take a "const wxArrayInt& arr" or "wxArrayInt arr" will accept either a wxArrayInt userdata or a Lua table that has numeric indexes and numeric values and convert it into a wxArrayInt for the function call. If the function call is "wxArrayInt& arr" or "wxArrayInt* arr" you must provide a wxArrayInt userdata since the C++ function will most likely modify the wxArrayInt that's passed to it.
Coroutines : wxLua works with coroutines with one important caveat.NEVER connect an event handler function callback from within a coroutine
wx
Lua tablewx.NUMBER_DEFINE
wx.wxID_ANY
wx.NUMBER_VARIABLE
wx.wxInvalidOffset
.wx.ENUM_NAME
wx.wxLEFT
wx.CLASSNAME.ENUM_NAME
wx.wxFTP.ASCII
wx.STRING_DEFINE
wx.wxIMAGE_OPTION_CUR_HOTSPOT_X
wx.STRING_VARIABLE
wx.wxEVT_XXX
wx.wxEVT_COMMAND_MENU_SELECTED
for menu item selection.Example : EVT_MENU(id, func) use window:Connect(menuId, wx.wxEVT_COMMAND_MENU_SELECTED, Lua function)
. The Lua function must have the signature of function MenuEvent(event) ... handle event ... return
where the event
variable will be the wxEvent dervied class that the wxEventType was declared in, which in this case is a wxCommandEvent.
window:Connect(wx.wxEVT_PAINT, Lua function)
. There is no Id used for this connect event function call since the paint event handler function is directly connected to the window. In the menu case, the handler is typically connected to a parent window, perhaps a wxFrame. The menu event event generated by the menu travels up the chain of window parents until a handler is found. The Id is needed to determine where the event came from.
local dc = wx.wxPaintDC(event:GetEventObject():DynamicCast("wxWindow"))
and then call dc:delete()
at the end of the function because the paint event clears the "dirty" region to repaint and if it is not cleared another paint event will be sent... and so on.wx.OBJECT_NAME
wx.wxNullImage
and functions from the wxImage class can be called as wx.wxNullImage:Ok()
which should return false.wx.POINTER_NAME
wx.wxThePenList
and functions from the wxPenList class can be made as pen = wx.wxThePenList:FindOrCreatePen(wx.wxColour(1,2,3), 1, wx.wxSOLID)
wx.FUNCTION_NAME(1, "Hello")
extern wxString wxGetUserHome(const wxString& name)"
is accessible as home_dir = wx.wxGetUserHome("john")
where wxString means to input a Lua string and a Lua string is returned.wx.CLASS_NAME
, however in order to use one you must call one of the constructors first or get the class as a return value from another function call.
pt = wx.wxPoint(1, 2); pt2 = wx.wxPoint(pt)
__call
metatable item so they can be called as a function. If you need to get the constructor function itself you can use wx.CLASS_NAME.new(...)
which is the constructor exposed as a Cfunction.__index
to call functions on the object or to get member variable values.__newindex
to set new functions or values or set member variable values.__tostring
to allow print() to show something useful
print(wx.wxPoint())
prints "userdata: 0x858df5c [wxPoint(0x84ab550, 251)]", where 0x858df5c is the Lua userdata address, 0x84ab550 is the address of the wxPoint object, and 251 is the wxLua type that wxLua uses to determine that this Lua userdata wraps a wxPoint. The wxPoint type may not always be 251 since it depends on the number and order in which the bindings were initialized, but it will be unique within a run.__gc
to tell wxLua when the userdata is no longer used so wxLua can delete the C++ object if appropriate.Declared in the bindings using the %class tag.
delete()
them when done so that your program will work equally well in MSW as it would in Linux or OSX.delete()
function on certain types of userdata when you are done.wxDC:SetPen(wx.wxPen(wx.wxColour(1,2,3), 1, wx.wxSOLID))
; notice that both a wxPen and a wxColour have been created, but there is no way for you to call delete()
on them so they will collect until Lua runs its garbage collector.collectgarbage("collect")
in Lua, but this may cause slight pauses in your program's execution.Must delete : wxDC, wxPaintDC, and ALL classed derived from wxDC.
Must delete if > 50 : wxBitmap, wxBrush, wxColour, wxCursor, wxFont, wxIcon, wxPen, wxRegion
delete()
things that aren't yours. Refer to the wxWidgets documentation about whether an object will take ownership of an object passed to it.wxlua.GetGCUserdataInfo(true)
to show what objects will be garbage collected when their reference count goes to zero and the Lua garbage collector runs.Print the output of wxlua.GetTrackedObjectInfo(true)
to get class objects that wxLua has pushed into Lua that may or may not be garbage collected.
Call the function wxlua.LuaStackDialog()
when you run your program and examine the items in the Lua LUA_REGISTRYINDEX table. Expand "wxLua objects pushed" and "wxLua gc objects to delete" tables.
size = wx.wxSize(1, 2); size:SetWidth(10); size.SetHeight(size, 11); print(size:GetWidth(), size.GetHeight(size))
where we create a wxSize, set a new width and height, and then print the numerical values.rect = wx.wxRect(wx.wxPoint(1,2), wx.wxSize(3,4)); rect:SetX(20); rect.X = 10; print(rect.X, rect.X == rect:GetX(), rect.X == rect.GetX(rect))
" should print "10, true, true".print(wx.wxFileName.GetCwd())
and print(wx.wxFileName.GetCwd)
prints that it's a function.print(wx.wxFileName:GetCwd())
and print(wx.wxFileName:GetCwd)
since there is no "self" for the ':' operator to push.f = wx.wxFileName("a"); print(f.GetCwd())
and print(f.GetCwd)
prints that it's a function.f = wx.wxFileName("a"); print(f:GetCwd())
and print(f:GetCwd)
since there is no "self" for the ':' operator to push.f = wx.wxFileName("a"); print(f.Cwd)
f = wx.wxFileName("a"); print(f.Cwd())
and print(f:Cwd)
and print(f:Cwd())
pt = wx.wxPoint(1,2); pt.x = 10; pt:SetY(11); print(pt.x, pt:GetY())
f = wx.wxFileName('dummy'); f.GetCwd() == wx.wxFileName.GetCwd()
wx.wxFTP.ASCII
This is a list of all possible operator functions:
Relational and equality operators | ||
== | op_eq() | |
!= | op_ne() | |
> | op_gt() | |
< | op_lt() | |
>= | op_ge() | |
<= | op_le() | |
Logical operators | ||
! | op_not() | |
&& | op_land() | "l" stands for logical |
|| | op_lor() | |
Bitwise operators | ||
~ | op_comp() | bitwise NOT or complement |
& | op_and() | |
| | op_or() | |
^ | op_xor() | |
<< | op_lshift() | |
>> | op_rshift() | |
Inplace bitwise assignment operators | ||
&= | op_iand() | "i" stands for inplace |
|= | op_ior() | |
^= | op_ixor() | |
>>= | op_irshift() | |
<<= | op_ilshift() | |
Arithmetic operators | ||
= | op_set() | |
+ | op_add() | |
- | op_sub() | |
* | op_mul() | |
/ | op_div() | |
% | op_mod() | |
Unary arithmetic operators | ||
- | op_neg() | negate |
Inplace arithmetic assignment operators | ||
+= | op_iadd() | |
-= | op_isub() | |
*= | op_imul() | |
/= | op_idiv() | |
%= | op_imod() | |
Increment arithmetic operators | ||
++ | op_inc() | |
-- | op_dec() | |
Other operators | ||
[] | op_index() | Array indexing |
() | op_func() | Function call |
* | op_deref() | Dereference/Indirection |
pt = wx.wxPoint(1,2); pt = pt + 1
gives an error since we're trying to use the Lua operator and even in C++ this wouldn't compile since there is no operator defined for adding a single number to a wxPoint.pt1 = wx.wxPoint(1,2); pt2 = pt1; print(pt2:GetX()); pt2:SetX(10); print(pt1:GetX(), pt1 == pt2)
the = operator works in this case because we are not copying the values of pt1, but rather the address of pt1 to pt2, meaning that pt2 is pt1 and when we set the value for pt2 we're also setting the value for pt1. We know this because the Lua == operators tells us that they have the same address and if you type print(pt1, pt2)
the result is "userdata: 0x858df5c [wxPoint(0x84ab550, 251)], userdata: 0x858df5c [wxPoint(0x84ab550, 251)]". See the wxLua userdata metatable function __tostring
above.Example : pt1 = wx.wxPoint(1,2); pt2 = wx.wxPoint(); pt2:op_set(pt1); pt1:SetX(10); print(pt2:GetX()); print(pt2:op_eq(pt1))
Creates pt1 and also creates pt2, but we don't care what value it has since we use op_set() to call the C++ =
operator to copy the values from pt1. We then change the value of pt1, test if pt2 has changed, it hasn't, and the test to see if they're still equal and as expected, they're not.
p = wx.wxPoint(1,2); p.GetX = function(self) return 10-self:_GetX() end; print(p:GetX(), p:_GetX())
; prints "9, 1".r = wx.wxRect(1,2,3,4); r.PrintXY = function(self) print(self:GetX(), self:GetY()) end; r:PrintXY()
adds the function PrintXY() to the wxRect instance r. The userdata, class instance, r is passed to the Lua function as the parameter "self" which is pushed onto the stack when the PrintXY() function is called with the ':' notation.r = wx.wxRect(1,2,3,4); function wxRect_PrintXY(r) print(r:GetX(), r:GetY()) end; wxRect_PrintXY(r)
.function wxRect_PrintXY_func(self) print(self:GetX(), self:GetY()) end; r1 = wx.wxRect(1,2,3,4); r1.PrintXY = wxRect_PrintXY_func; r1:PrintXY()
. You can see that using this idea you can write a Lua function that creates a new wxRect, sets your extra functions for it, and returns it for use.There are a number of sample programs in the wxLua/samples directory. These programs demonstrate how to write simple programs and try to show how to use some of the many classes of wxWidgets. They are a good resource to learn how to write your own more complicated programs.
We welcome any enhancements or additional samples that might be generally useful to the wxLua community. Please understand that any code you contribute has to be maintained and easily understood, so the code must be simple and clear.
If something in wxLua seems to not work as expected it is best to try to duplicate your error in the simplest possible way in one of the samples and ask on the wxlua-users@lists.sourceforge.net mailing list.
Why are the samples named sample.wx.lua? To allow them to be colorized correctly in syntax highlighting editors, yet denote to people that they are for wxLua and must be run using a wxLua executable or the wxLua module.
The examples below are for MS Windows .exe executables, but the same applies for Linux or OSX, just remove the .exe extension from the executable. See also wxLua Applications for more information about these programs. - On the command line run wxlua.exe sample.wx.lua - On the command line run wxluafreeze.exe sample.wx.lua - Open the Lua program in wxlua.exe and choose the menu item 'Run'. - Open the Lua program in wxluaedit.exe and select the menu item 'wxLua->Run' or press the toolbar 'play' button to run it. - Use wxLua as a Lua module using the function require("wx")
, run lua.exe sample.wx.lua - In order to use wxLua as a module, the Lua code must have require("wx")
to load the wxLua bindings in the beginning and wx.wxGetApp():MainLoop()
at the end to run the wxWidgets event loop. - To be sure - From the command line you can create wxFrames or wxDialogs and populate them, but nothing will happen when you call Show() on them since the wxEventLoop is not running. - For example, run this code in the Lua console: - require("wx")
- f = wx.wxFrame(wx.NULL, -1, "Title")
- f:Show()
- Note that the wxFrame is not shown or if it is you won't be able to use it... - wx.wxGetApp():MainLoop()
- The wxFrame is now shown and you can interact with it nomally, but the Lua console prompt is hung in the MainLoop() function while wxWidgets processes events. When you close the wxFrame or the last top-level window, the MainLoop() exits and control is returned to the Lua console. - You can now create new wxFrames or wxDialogs, but you always have to call wx.wxGetApp():MainLoop()
in order to use them.
- You may need to adjust the `package.cpath`{.lua} variable to have it
point to the correct location of the wx.so or wx.dll shared library
for `require("wx")`{.lua} to load.
calculator.xrc
to create its GUI.The applications that wxLua provides are in the wxLua/apps directory. These are C++ programs that are compiled against the wxWidgets library and the wxWidgets wxStyledTextCtrl library.
require("wx")
function.Utility programs for wxLua are located in the wxLua/util directory.
wxLua is broken up into "modules" that are compiled into libraries so that you can choose to link to some or all of them. The directory structure of the modules dir is such that you need only add the #include path to wxLua/modules in your compiler settings and then in the code always write #include "modulename/optionalsubname/filename.h".
The documentation for the wxLua library is in the header files and descriptions are given for each function, enum, etc. Please read through them to get a feel for what functions wxLua provides. Below is a brief synopsis of wxLua for C++ programmers.
Lua uses char strings while wxWidgets uses the wxString class which uses the wxChar data type. Depending on whether you have compiled wxWidgets in Unicode mode or not, wxChar can be either wchar or char. Therefore, wxLua uses the functions "wxString lua2wx(const char str)"* and "const wxCharBuffer wx2lua(const wxString& str)" to translate between the two. Note that wxCharBuffer can be used as a const char* string directly without any casting.
The core of wxLua is based upon a ref counted wxLuaState class derived from the wxWidget's wxObject class. The wxLuaState class contains as a member of its ref data the 'C' lua_State struct which is the heart of Lua. Since the class is ref counted, it should be passed as const wxLuaState& and can be used in much the same way as a wxBitmap, wxPen, or any of the other wxObject derived classes that make use of its ref counting mechanism. What this means for wxLua is that instead of keeping pointers to the lua_State you have instances of the wxLuaState, there is a slight overhead for this, but it is minimal. When the lua_State is closed, all the wxLuaStates sharing the ref data can check their ref data to see if the lua_State is NULL and segfaults from dangling pointers are avoided. The reason why this is a good idea is that wxWidgets has delayed wxWindow deletion and things can get out of order. Care must be taken for pushed event handlers from Lua because if the lua_State is closed, but the window hasn't been deleted just yet... It's best to have a way to check and the wxLuaState wraps this all up.
When the wxLuaState is Ok() the wxLuaState has its ref data and the lua_State is created. If it's not Ok() then most wxLuaState functions will assert in debug mode, so it's always best to compile in debug mode until you're sure things are working properly.
The wxLuaState contains all of the Lua 'C' functions, such as lua_gettop(lua_State* L), but as member functions named lua_GetTop() which use the internal lua_State and check for its validity before use. The functions are capitalized to make them easier to find in an editor. If you want the greatest performance just use wxLuaState::GetLuaState() and directly manipulate the returned pointer to the lua_State.
It is instructive to follow the creation of the wxLuaState by looking at bool wxLuaState::Create(wxEvtHandler handler, wxWindowID id) inwxLua/modules/wxlua/src/wxlstate.cpp*.
wxLua stores its bookkeeping data in the Lua's LUA_REGISTRYINDEX table that the wxLuaState creates and uses. The keys are const char* strings with its address pushed as a light userdata. Pushing the string itself requires that it be hashed and it was found to take a considerable amount of the total time of a function call. A list of all of the tables is at the top of the wxlstate.h
header file.