TI-Nspire LUA
Grundlagen
Lua ist eine Interpretersprache welche auf der Interpreterkonsole sozusagen ins 'Nichts' geschrieben werden kann und sofort ausgeführt wird. Zum Beispiel:
print(a) -- 1
a = a + 1
print(a) -- 2
Nspire-Lua ist jedoch eventbasiert. Das heißt das Nspire-System ruft in einer Schleife und abhängig von Systemzuständen eine überschaubare Anzahl von Event-Methoden auf:
-- ...
buffer:captureDataFromKeyPad()
if buffer.charInput ~= "" then
on.charIn(buffer.charInput) -- Event-Methode für Zeicheneingabe
buffer.charInput= ""
end
if buffer.arrowKey ~= "" then
on.arrowKey(buffer.arrowKey) -- Event-Methode für Pfeiltaste
buffer.arrowKey = ""
end
----- etc ...
if platform.window.isInvalidate then
local gc = platform.gc()
gc:begin()
on.paint(gc) -- Event-Methode für Zeichenoperationen
gc:finish()
platform.window.isInvalidate = false
end
----- End of Event link
end
Der Nutzercode kann also nicht einfach ins 'Nichts' geschrieben werden, sondern nur in die vorgegebenen Event-Methoden. Natürlich kann auch außerhalb der Event-Methoden Code geschrieben werden. Dieser Muss jedoch aus den Event-Methoden heraus aufgerufen werden. Ein Beispiel:
function on.paint(gc)
gc:drawString(text,10,20) -- in Event aufgerufener Code
end
Die wichtigsten Event-Methoden wären:
- on.construction() - (einmalig) Start der Anwendung
- on.paint(gc) - Neuzeichnen des Grafikkontext gc
- on.resize(w,h) - neue Fenstergröße
- on.timer() - Durchlauf des Timers
- on.charIn(char) - Eingabe eines Zeichens über die Tastatur
- on.enterKey() / returnKey() / backspaceKey() / tabKey() / backtabKey() / deleteKey() / clearKey() / escapeKey() / arrowKey(key) - Sondertasten
- on.arrowUp() / arrowDown() / arrowLeft() / arrowRight() - Pfeiltasten
- on.mouseDown(x,y) / mouseUp(x,y) - Maustaste gedrückt / losgelassen
- on.mouseMove(x,y) - Mausbewegung
- on.getFocus() / loseFocus() - Fokus bekommen / verloren
Klassen
In Nspire Lua kann teilweise objektorientiert gearbeitet werden. Funktionen und Variablen können für eine Klasse deklariert werden, von welcher Objekte erzeugt werden können.
-- Klasse Wuerfel
Wuerfel = class() -- Klassendeklaration 'Wuerfel'
function Wuerfel:init(x,y,size) -- Konstruktor
self.x = x -- Schreiben von Klassenvariablen
self.y = y
self.size = size
end
function Wuerfel:zeichne(gc) -- beliebige Nutzermethode
gc:drawRect(self.x,self.y,self.size,self.size)
end
-- Programmcode
w1 = Wuerfel(30,30,50) -- Klasseninstanz erzeugen
function on.paint(gc)
w1:zeichne(gc) -- Methodenaufruf von w1
end
Vererbung
B = class(A) -- B erbt alles von A
function A:hello(gc)
gc:drawString("Hello",10,20)
end
function B:world(gc) -- für B wird nur die Funktion 'world(gc)' definiert
gc:drawString("World",10,40)
end
function on.paint(gc)
B:hello(gc) -- Funktion von A geerbt
B:world(gc) -- Funktionen können auch direkt von der Klasse aufgerufen werden
end
Polymorphie
Der Quelltext vom Beispiel der Vererbung wird erweitert:
gc:drawString("Holla",10,20)
end
local bi = B()
function bi:world(gc) -- Objekte können Funktionen überschreiben
gc:drawString("Welt",10,40)
end
function on.paint(gc)
bi:hello(gc) -- Holla
bi:world(gc) -- Welt
end
Methoden der Elternklasse aufrufen
B = class(A)
function A:init(x)
self.x = x
end
function B:init(x,y)
A.init(self,x) -- Konstruktor von A wird mit X aufgerufen
-- Beachte: Methodenaufruf mit Punkt anstatt Doppelpunkt
-- Funktioniert mit jeder Methode
self.y = y
end
Objektlisten
Der Quelltext baut auf das Beispiel von Klassen auf:
w2 = Wuerfel(50,40,10)
w3 = Wuerfel(80,80,80)
wuerfelListe = {w1, w2, w3} -- Liste von Würfeln
function on.paint(gc)
for _, obj in ipairs(wuerfelListe) do -- für jedes Wuerfel-Objekt in wuerfelListe...
obj:zeichne(gc)
end
-- eine Alternative
for i=1, #wuerfelListe do
wuerfelListe[i]:zeichne(gc)
end
end
Texteditor
Formeldarstellung
Durch das Umgeben der Formel mit dem Tag \0el{<formel>}
function box(expression)
return "\\0el {"..expression.."}"
end
-- Hilfsmethode zum Entfernen der Formeltags
function unbox(expression)
return (expresssion:gsub("\\0el {(.-)}","%1"))
-- der Reguläre Ausdruck gibt nur Inhalte innerhalb der geschweiften Klammern zurück
-- der gesamte Ausdruck (gsub) gibt mehrere Rückgabewerte zurück, daher
-- muss er in Klammern stehen, um nur den ersten Return-Wert von gsub auszugeben
end
Textlistener
Der Changelistener als Callback-Methode selber sollte immer eine Inline-Funktion sein, da nur innerhalb der Inline-Funktion auf den Objektkontext zugegriffen werden kann. Innerhalb der Inline-Funktion können immer noch Objektmethoden aufgerufen werden, sogar mit weiteren Parametern, was über die reine Callback-Methode nicht möglich ist.
-- e.g. for printing input on console
local box = D2Editor.newRichText()
box:setTextChangeListener( function(ed) self:objMethod(ed:getExpression(), foo) end ) --- inline function
Interaktion mit dem TI-Nspire
Informationsaustausch
var.store("varName", value)
-- Variable von TR abrufen
value = var.restore("varName")
-- Funktion in TR 'speichern'
math.evalStr("f(x):=x^2/5")
Berechnungen
math.evalStr("3/4") -- gibt 3/4 als String-Ausdruck zurück
Quellen
- Lua Scripting HQ auf compasstech.com.au
- Theorie-Tutorials auf inspired-lua.org
- Inspired-Lua-Wiki