- PVSM.RU - https://www.pvsm.ru -
За Lua прочно закрепилась слава полуязыка — инструмента, который при случае можно встроить, чтобы заскриптовать приложение, написанное на компилируемом языке вроде С++. Тем не менее Lua является вполне самостоятельным языком, имеющим свой интерпретатор, возможность создания модулей, большое число библиотек, и при этом данный ЯП обладает минимальным размером среди аналогов. Проще говоря у нас есть все, чтобы создавать такие же приложения как на perl, python, и вообще любом другом распространенном языке программирования.
Я могу предложить вам следующие доводы в пользу Lua:
Чтобы продемонстрировать возможности Lua, я покажу как с его использованием создать небольшую программу для построения графиков по точкам с возможностью сохранения графика в виде файла изображения.
В качестве графического тулкита будем использовать iup [1] — кроссплатформенную библиотеку, изначально созданную с расчетом использования из Lua.
В рамках идеи использования Lua как самостоятельного ЯП, была создана сборка Lua for Windows [2], которая содержит себе библиотеки, необходимые в повседневных задачах, возникающих при программировании под указанную ОС: работы с БД, GUI, парсинг XML и т.д. Пусть вас не смущает, что версия Lua в сборке 5.1, а не 5.2 — особой разницы в нашем случае между ними нет.
Скачайте и установите сборку.
Я долго думал, как же расписать процесс создания программы, не вдаваясь подробно в устройство iup. И решил коротко описать его основные принципы:
Если вы ранее писали для GUI при помощи Tk, WxWidgets или WinAPI, то все это покажется знакомым. Если нет, то программа довольно подробно покрыта комментариями.
-- подключение библиотек iup
require("iuplua" )
require("iupluacontrols")
require("iuplua_pplot")
-- библиотека для работы с Canvas, чтобы сохранять график в файл
require("cdlua")
require("iupluacd")
require("string")
-- глобальные переменные для виджетов и настроек программы
-- максимальное число графиков
plots_number = 5
-- виджеты вкладок, где будут размещаться виджеы ввода данных для каждого графика
tabs = {}
-- контейнеры для виджетов
vboxes = {}
-- чекбоксы для выбора того, какие графики строить
checkboxes = {}
-- здесь храним виджеты с текстом данных о точках
coords = {}
-- виджеты подписи для каждого графика
legends = {}
-- виджеты обозначения осей координат
global_legend = {}
-- к величайшему стыду, в Lua нет стандартной функции split
function string:split(sep)
local sep, fields = sep or ":", {}
local pattern = string.format("([^%s]+)", sep)
self:gsub(pattern, function(c) fields[#fields+1] = c end)
return fields
end
-- функция рисует на плоттере график по указаным точкам
function draw_plot(pwidget, pnum, data)
x = data[1].value:split(",")
y = data[2].value:split(",")
if checkboxes[pnum].value == "OFF" then return end
if not (#x == #y) or #x == 0 then
iup.Message("Ошибка",
"Задано неверное число точек для графика " .. pnum)
return
end
iup.PPlotBegin(pwidget, 0)
iup.PPlotAdd(pwidget, 0, 0)
for i = 1,#x do
iup.PPlotAdd(pwidget, x[i], y[i])
end
iup.PPlotEnd(pwidget)
end
-- виджет отвечающий за кнопку построения графика
plot_btn = iup.button{ title = "Построить"}
-- колбэк для кнопки "построить график"
function plot_btn:action()
-- создать виджет графопостроителя
plot = iup.pplot
{
expand="YES",
TITLE = "Simple Line",
MARGINBOTTOM="65",
MARGINLEFT="65",
AXS_XLABEL = global_legend[1].value,
AXS_YLABEL = global_legend[2].value,
LEGENDSHOW="YES",
LEGENDPOS="TOPLEFT",
size = "400x300"
}
-- этот блок для обхода бага - без него подпись к первому графику отображаться не будет
iup.PPlotBegin(plot, 0)
iup.PPlotAdd(plot,0,0)
plot.DS_LEGEND = ""
iup.PPlotEnd(plot)
-- обходим виджеты с данными
for i = 1, plots_number do
-- чтобы свеженарисованный графи отобразился с правильной подписью
print(legends[i].value)
plot.DS_LEGEND = legends[i].value
-- рисуем график
draw_plot(plot, i, coords[i])
end
-- кнопка сохранения графика в картинку на диске
save_btn = iup.button{ title = "Сохранить" }
-- теперь создаем само окно, где будет отображаться график
plot_dg = iup.dialog
{
iup.vbox -- это вертикальный сайзер, помести в него графопостроитель и кнопку
{
plot,
save_btn
},
}
-- обработчик кнопки сохранения графика
function save_btn:action()
-- создаем диалог выбора имени файла ля сохранения
-- в связи с ограничениями библиотеки сохранять можно только в EMF
fs_dlg = iup.filedlg{DIALOGTYPE = "SAVE", FILTER = "*.emf" }
iup.Popup(fs_dlg)
-- если файл выбран
if tonumber(fs_dlg.STATUS) >= 0 then
-- дописать при необходимости нужное расширение
pic = fs_dlg.value
if not (string.sub(pic, string.len(pic)-3) == ".emf") then
pic = pic .. ".emf"
end
-- создаем псевдо-холст, ассоциированный с файлом
tmp_cv = cd.CreateCanvas(cd.EMF, pic .. " 400x300")
-- выводим график на холст
iup.PPlotPaintTo(plot, tmp_cv)
-- сохраняем данные в файл
cd.KillCanvas(tmp_cv)
end
end
-- отображаем диалог с графиком
plot_dg:showxy(iup.CENTER, iup.CENTER)
-- запускаем петлю обработки событий для диалога
if (iup.MainLoopLevel()==0) then
iup.MainLoop()
end
end
-- в цикле создаем вкладки, в которых мы будем размещать виджеты
-- для сбора данных
for i=1,plots_number do
-- создание текстовых виджетов, куда будут вводиться координаты точек
coords[i] = {}
for j = 1,2 do
coords[i][j] = iup.text
{
expand="HORIZONTAL",
multiline = "YES",
VISIBLELINES = 5
}
end
-- виджет для редактирования подписи к графику
legends[i] = iup.text{ expand = "HORIZONTAL" }
-- создаем контейнер вкладки и заполняем его элементами
vboxes[i] = iup.vbox
{
iup.hbox
{
iup.label { title = "Подпись графика:" },
legends[i]
},
iup.hbox
{
iup.label
{
title="X : ",
},
coords[i][1]
},
iup.hbox
{
iup.label
{
title="Y : ",
},
coords[i][2]
};
expand="YES",
}
-- меняем заголовк вкладки
vboxes[i].tabtitle = "График " .. i
-- создаем чекбокс, который будет указывать на то, нужно ли строить
-- график по данным из указанной вкладки
checkboxes[i] = iup.toggle{ title= "График" .. i, value = "ON" }
end
-- теперь из заполненных нами контейнеров создаем вкладки
tabs = iup.tabs{unpack(vboxes)}
-- создаем текстовые виджеты для редактирования подписей осей
global_legend[1] = iup.text{}
global_legend[2] = iup.text{}
-- создаем фрейм для общих настроек графика
frame = iup.frame
{
iup.vbox
{
iup.label{
title="Использовать данные:",
expand="HORIZONTAL"
},
iup.vbox
{
unpack(checkboxes)
},
iup.label{}, -- пустую подпись можно использовать как распорку
iup.label{title = "Подписи"},
iup.hbox { iup.label{ title = "Ось X "}, global_legend[1] },
iup.hbox { iup.label{ title = "Ось Y "}, global_legend[2] },
iup.label{},
plot_btn
};
expand = "VERTICAL",
}
-- создаем главное окно программы и наносим на него настройки и табы
dg = iup.dialog
{
iup.hbox
{
frame, tabs
},
title="Строим график",
size = "HALF"
}
-- показываем главное окно и запускаем обработку событий
dg:showxy(iup.CENTER, iup.CENTER)
if (iup.MainLoopLevel()==0) then
iup.MainLoop()
end
Скрипт можно запустить при помощи команды:
lua plotter.exe
В данном случае библиотеки будут подключаться из поддиректории clibs/, которая находится в директории, куда был установлен Lua for Windows. Чтобы максимально компактно упаковать скрипт и библиотеки для переноса на другую машину, достаточно скопировать в одну папку следущие файлы(указаны с относительными путями от директории установки Lua):
lua.exe
lib/lua5.1.dll
clibs/cd.dll
clibs/cdlua51.dll
clibs/iup.dll
clibs/iup_pplot.dll
clibs/iupcd.dll
clibs/iupcontrols.dll
clibs/iupgl.dll
clibs/iuplua51.dll
clibs/iuplua_pplot51.dll
clibs/iupluacd51.dll
clibs/iupluacontrols51.dll
Не забудьте поместить в эту папку и сам скрипт с программой. Теперь вы можете перенести эту папку на другую машину и запустить вашу программы командой, указанной выше. При этом никакие другие действия по установке библиотек и рантайма не нужны.
К сожалению файлы cd.dll, cdluad51.dll и iupcd.dll в данной версии Lua for Windows могут работать некорректно, поэтому рекомендую взять их из архива по ссылке ниже.
Архив с рабочей версией тут [3], для удобства добавлена пускалка app.bat.
Скриншоты:
В результате получили, пусть и неказистую, утилиту, имеющую такой же функционал, как и если бы она была написана на «серьезном» языке программирования. При этом простую в развертывании и суммарным весом менее 2 мб. Потребление памяти — около 7 мб. Исходный код доступен для редактирования, сам Lua интерактивно понятен, что упрощает доработку подобного софта на местах.
На мой взгляд, это отличный выбор для написания учебного софта для школ и институтов, а также для внутреннего использования на предприятиях. Так как слабые машины до сих пор в изобилии присутствуют в подобных местах по всему СНГ, то использование Luа подобным образом целесообразно, особенно в свете постепнного прихода Linux на десктопы. К тому же тенденцию потери исходников самописного софта при жуткой его же забагованности можно приравнять к национальному бедствию.
Автор: PerlPower
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/freeware/13407
Ссылки в тексте:
[1] iup: http://www.tecgraf.puc-rio.br/iup/
[2] Lua for Windows: http://code.google.com/p/luaforwindows/
[3] тут: http://perlpower.16mb.com/habr/plotter.7z
Нажмите здесь для печати.