wxJavaScript – Кросс-платформенный скриптинг десктопных приложений. Знакомство

Давно уже хотел написать по поводу wxJavaScript. По-моему сейчас как раз пришло время для этого, т.к. проект уже успел развиться до такого состояния, когда все работает более-менее стабильно.
Итак, что же это за зверь wxJavaScript? Проект начинался как обычный порт wxWidgets на JavaScript, но, со временем, “оброс” библиотеками, которых в wxWidgets отродясь не было. Это модули curl, sqlite, mysql и др. Также проект получил реинкарнацию в виде модуля к Apache, который может использоваться для создания динамических HTML-страниц. Но об этом потом. Сейчас мне бы хотелось рассказать о том, как этим всем можно пользоваться для достижения собственных корыстных целей.

wxJavaScript поставляется в виде исполняемого файла интерпретатора и дополнительных модулей в виде динамических библиотек. Перечень используемых модулей может изменяться в конфигурационном файле. Это значит, что если на вашей машине используются скрипты только для доступа к базам данных, то нет никакой необходимости подключать, например библиотеку для создания графического интерфейса. Это позволяет экономить память, используемую движком wxJavaScript.
Минимальное приложение для wxJS выглядит так:

minimal.js

print("Hello World !!!");

Запустить скрипт на выполнение можно командой

wxjs minimal.js

Теперь рассмотрим, как создать минимальное приложение с графическим интерфейсом.

minimal_gui.js

wxTheApp.onInit = init;

function init()
{
  var frame = new wxFrame(null, -1, "Minimal");
  frame.visible = true;
  wxTheApp.topWindow = frame;
  return true;
}

Для того, чтобы наше приложение запустилось, нам необходимо включить поддержку графического интерфейса в конфигурационном файле:

modules.js

...
wxjs.modules.io = new Module("../modules/wxjs_gui.dll");
wxjs.modules.io.load();
...

wxJavaScript - Минимальное приложение с графическим интерфейсом
В принципе, API очень схож с wxWidgets API для C++, но есть некоторые особенности. Например, обработчики событий от меню навешиваются к объекту меню через массив actions, а не к форме.
Давайте рассмотрим более сложный пример программы с графическим интерфейсом, использующий обработчики событий.

advanced_gui.js

// Указываем что при инициализации приложения должна 
// вызваться функция init
wxTheApp.onInit = init;

function OnFileNew()
{
  this.textCtrl.value = "";
}

function OnFileOpen()
{
  // Создаем диалог открытия файла
  var fileDialog = new wxFileDialog(this, "Open a file");
  // Устанавливаем стиль диалога
  fileDialog.style = wxFileDialog.OPEN;
  // Если диалог отработал успешно...
  if(fileDialog.showModal() == wxId.OK)
  {
    // Загружаем файл в текстовое поле
    this.textCtrl.loadFile(fileDialog.path);
  }
}

function OnFileSave()
{
  var fileDialog = new wxFileDialog(this, "Save file");
  fileDialog.style = wxFileDialog.SAVE;
  if(fileDialog.showModal() == wxId.OK)
  {
    this.textCtrl.saveFile(fileDialog.path);
  }
}

function OnFileExit()
{
  this.close();
}

function CreateMenuBar(parent)
{
  // Создаем строку меню
  var menuBar = new wxMenuBar(parent);

  // Создаем меню "Файл"	
  var fileMenu = new wxMenu;
  // Добавляем в меню элементы
  fileMenu.append(wxId.NEW, "New\tCtrl+N", "Create new file");
  fileMenu.append(wxId.OPEN, "Open\tCtrl+O", "Open existing file");
  fileMenu.appendSeparator();
  fileMenu.append(wxId.SAVE, "Save\tCtrl+S", "Save file");
  fileMenu.appendSeparator();
  fileMenu.append(wxId.EXIT, "Exit\tAlt+F4", "Exit this application");

  // Назначаем обработчики событий
  fileMenu.actions[wxId.NEW] = OnFileNew;
  fileMenu.actions[wxId.OPEN] = OnFileOpen;
  fileMenu.actions[wxId.SAVE] = OnFileSave;
  fileMenu.actions[wxId.EXIT] = OnFileExit;

  // Добавляем меню в строку меню
  menuBar.append(fileMenu, "File");
  return menuBar;
}

// Функция создания главной формы
function CreateFrame()
{
  // Создаем форму
  var frame = new wxFrame(null, -1, "Minimal");
  // Создаем строку меню с помощью функции CreateMenuBar()
  frame.menuBar = CreateMenuBar();
  // Создаем строку состояния с двумя панелями
  frame.createStatusBar(2);

  // Создаем главный сайзер
  var mainSizer = new wxBoxSizer(wxOrientation.VERTICAL);

  // Создаем текстовое поле
  var textCtrl = new wxTextCtrl(frame, wxId.HIGHEST+1, "",
    wxDefaultPosition, wxDefaultSize, wxTextCtrl.MULTILINE);

  // Добавляем текстовое поле в сайзер
  mainSizer.add(textCtrl, 1, wxStretch.EXPAND, 0);

  // Кладем сайзер на форму
  frame.sizer = mainSizer;
  // Устанавливаем значение переменной textCtrl в главной форме
  frame.textCtrl = textCtrl;

  return frame;
}

// Инициализация приложения
function init()
{
  // Создаем форму с помощью функции CreateFrame();
  var frame = CreateFrame();
  // Делаем форму вилимой
  frame.visible = true;
  // Делаем форму главной
  wxTheApp.topWindow = frame;
  return true;
}

wxJavaScript - Более сложный пример приложения с графическим интерфейсом
Как видно из скриншота, приложение занимает 18 МБ памяти. Минимальное приложение занимало приблизительно 12 МБ. Эти 6 мегабайт разницы “съедает” поддержка Common Dialogs при первом обращении, а именно при открытии диалога открытия файла.

Кроме всего прочего, wxJS поддерживает работу с базами данных. Ниже приведен код примера, который выполняет соединение с базой данных SQLite, при необходимости, создает таблицы в базе данных, заполняет их данными и отображает содержимое таблиц.

database.js

// Открываем базу данных
var db = new sqlite.Database(script.root + "sample.db");
// Если база была открыта успешно...
if(db.opened)
{
  print("Database opened successfully.\r\n");
  // Хитрая проверка на наличие таблиц с помощью PRAGMA
  var pragmaStmt = db.prepare("PRAGMA user_version");
  var pragma = pragmaStmt.fetchArray();
  if(pragma[0] == 0)
  {
    // Создаем таблицы в базе данных
    print("Creating tables...\r\n");
    print(db.exec("CREATE TABLE sample(id INTEGER PRIMARY KEY, somedata TEXT)"));
    print("Inserting data...\r\n");
    // Заполняем таблицы данными
    print(db.exec("INSERT INTO sample(somedata) VALUES ('test 1')")+"\r\n");
    print(db.exec("INSERT INTO sample(somedata) VALUES ('test 2')")+"\r\n");
    // Устанавливаем флаг наличия таблиц
    db.exec("PRAGMA user_version = 1");
  }
  // Получаем данные из таблицы
  print("Fetching data...\r\n");
  var stmt = db.prepare("SELECT * FROM sample");
  // если получилось вытянуть данные...
  if(stmt != null)
  {
    var row;
    // Выводим все записи в консоль
    while(row = stmt.fetchObject())
    {
      print(row.id + ": " + row.somedata + "\r\n");
    }
  }
  else
  {
   print("Unable to fetch data.\r\n");
  }
}
else
{
  print("Error opening database.");
}

Ну вот, пока на этом все. Более подробно об API wxJavaScript можно почитать на официальном сайте.

6 comments

  1. Begemot   •  

    Yet another wxPython? 🙂

    В чем глубинный смысл? какие преимущества? для чего он вообще нужен на десктопе? Тема не раскрыта:(

    Вот в вебе возможно интересно, но помнится я смотрел сайт его – и так и не увидел не одного примера использования, расстроился и ушел 🙂

  2. admin   •  

    Ммм? Ну вобще фраза “чем он лучше wxPython” из разряда “Кто сильнее, кит или слон?”. Он просто “другой”. Мне например нравится синтаксис, и кодинг на wxJS мне кажется более комфортным, но это ИМХО. А примеры использования. Ну то же самое что ты пишешь на C++, только компилить не надо. Плюс ко всему его можно использовать как скриптовый движок для своих приложений. Напишу еще об этом.
    Т.е. если например тебе надо срочно наклепать какую-то утилиту “которая что-то делает” для собственных нужд, то для этого незачем иметь на машине компилятор. Я с собой wxJS на флешке таскаю. Он без установки работает

    ЗЫ: В дистрибутиве есть гора примеров.

  3. Begemot   •  

    ты сам конкретно что-то полезное для себя уже написал на нем?
    “не машине на которой даже нет компилятора” ?:)

    тоже самое что и с++ только компилить не надо кажется мне довольно спорным преимуществом – из проекта на с++ может выйти что-то полезно + можно использовать готовые наработки, тоже в принципе и с питоном, а “утилитка которая что-то для себя делает” на джава скрипт, такой и останется, по идеи.

    Хотя может для небольших задач скриптов как раз то что надо. Но опять же новый язык учить 🙂

    А вот как скриптовый язык это может быть интересным, но это небось толстый интерпретатор?

  4. admin   •  

    Ммм? Вроде все интерпретаторы толстые, wxLua например тоже не маленький.
    А по поводу “для себя” чего нормальное делал.. Когда-то делал адресную книгу на wxJS + SQLite, даже вроде пользовался какое-то время, потом не помню куда она делась 🙂 Может исходник еще смогу найти.
    Я вроде где-то на wxForum’е видел описание какой-то неплохой фривары на wxJS, оно даже работало.

  5. Begemot   •  

    поискал на форуме, про фривары на этом скрипте не нашел.:(
    зато нашел упоминания про http://wxcode.sourceforge.net/components/wxscript/, но как-то ….

    вообщем тема скриптов не раскрыта, можно сказать не паханая целина для новых постов:)

    Кстати, по сабжу – только виндовс и убунту я так понял, мак отдыхает… еще один минус.

  6. T-Rex   •     Author

    Я думаю поддержка мака не заявлена потому что автору собирать не на чем. Я по этой же причине тоже не делаю самплов под мак, мне другой человек собирает.

    ЗЫ: Кстати под Windows 7 GUI модуль вываливается с ошибкой, по крайней мере без админской учетки.

Leave a Reply

Your email address will not be published. Required fields are marked *

Please leave these two fields as-is: