• Stars
    star
    135
  • Rank 267,810 (Top 6 %)
  • Language
    Ruby
  • License
    MIT License
  • Created about 10 years ago
  • Updated almost 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A QML / Qt Quick bindings for Ruby

ruby-qml Gem Version

ruby-qml is a QML / Qt Quick wrapper for Ruby. It provides bindings between QML and Ruby and enables you to use Qt Quick-based GUI from Ruby.

Dependency Status Build Status Coverage Status Inline docs

What you can do with ruby-qml

  • Develop desktop GUI applications only with Ruby and QML / JavaScript
  • Easily combine codes written in C++ and Qt with your Ruby code

Gallery

Screenshot

Screenshot

Installation

Requirements

  • Ruby 2.1 or later
  • OS X or Linux
  • Qt 5.4 or later

OS X with Homebrew

To install ruby-qml on OS X with Homebrew, run the following commands:

$ brew install qt5
$ gem install qml -- --with-qmake=$(brew --prefix qt5)/bin/qmake

Both libffi and Qt5 are keg-only in Homebrew, so you must specify their paths explicitly (or force linking).

If you use official Qt installation, for example:

$ gem install qml -- --with-qmake=$HOME/Qt/5.4/clang_64/bin/qmake

The Qt installation path ($HOME/Qt/5.4/clang_64 in this example) depends on your Qt installation configuration and Qt version.

General (OSX and Linux)

$ gem install qml

Ubuntu

$ sudo apt install ruby ruby-dev build-essentials qt5-default qtdeclarative5-dev qtbase5-private-dev qml-module-qtquick2 qml-module-qtquick-controls
$ sudo gem install qml

WSL

Using Ubuntu as the linux distro, proceed as above and use either WSL2 or an XServer (e.g. vcxsrv) to show the UI on Windows.

Options

  • --with-qmake=[dir]
    • Qt qmake executable path (optional).

Use Gemfile

Add this line to your Gemfile:

gem 'qml'

And then execute:

$ bundle install

To pass build options, use bundle config. For example:

$ bundle config build.qml --with-qmake=$(brew --prefix qt5)/bin/qmake

The configuration will be saved in ~/.bundle/config.

Usage

Load QML file

The following code loads a QML file and shows an application window titled "Hello, world!".

require 'qml'

QML.run do |app|
  app.load_path Pathname(__FILE__) + '../main.qml'
end
// main.qml
import QtQuick 2.2
import QtQuick.Controls 1.1

ApplicationWindow {
    visible: true
    width: 200
    height: 100
    title: "Hello, world!"
}

Use Ruby class in QML

To make your class available to QML, include QML::Access and call register_to_qml.

By including QML::Access, you can also define properties and signals in Ruby classes like in QML.

Properties are used to bind data between QML and Ruby. Signals are used to provide the observer pattern-like notification from Ruby to QML.

Screenshot

# Ruby
class FizzBuzz
  include QML::Access
  register_to_qml under: "Example", version: "1.0"

  property(:input) { '0' }
  property(:result) { '' }
  signal :inputWasFizzBuzz, []

  on_changed :input do
    i = input.to_i
    self.result = case
    when i % 15 == 0
      inputWasFizzBuzz.emit
      "FizzBuzz"
    when i % 3 == 0
      "Fizz"
    when i % 5 == 0
      "Buzz"
    else
      i.to_s
    end
  end

  def quit
    puts "quitting..."
    QML.application.quit
  end
end
// QML - main.qml
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import Example 1.0

ApplicationWindow {
    visible: true
    width: 200
    height: 200
    title: "FizzBuzz"

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 10
        TextField {
            placeholderText: "Input"
            text: "0"
            id: textField
        }
        Text {
            id: text
            text: fizzBuzz.result
        }
        Button {
            text: 'Quit'
            onClicked: fizzBuzz.quit()
        }
        Text {
            id: lastFizzBuzz
        }
    }
    FizzBuzz {
        id: fizzBuzz
        input: textField.text
        onInputWasFizzBuzz: lastFizzBuzz.text = "Last FizzBuzz: " + textField.text
    }
}

You can omit arguments of register_to_qml if they are obvious:

module Example
  VERSION = '1.0.0'

  class FizzBuzz
    include QML::Access
    register_to_qml

    ...
  end
end

Pass data to QML ListModels

To bind list data between QML ListView and Ruby, you can use ListModels.

  • QML::ListModel - the base class for ruby-qml list models.

  • QML::ArrayModel - provides a simple list model implementation using Array.

  • QML::QueryModel - for databases (like ActiveRecord, Sequel or something)

This example uses ArrayModel to provide list data for a QML ListView. When the content of the ArrayModel is changed, the list view is also automatically updated.

Examples

# Ruby
class TodoController
  include QML::Access
  register_to_qml under: "Example", version: "1.0"

  property(:model) { QML::ArrayModel.new(:title, :description, :due_date) }

  def add(title, description, due_date)
    # Items of list models must be "Hash-like" (have #[] method to get columns)
    item = {
      title: title,
      description: description,
      due_date: due_date
    }
    model << item
  end
end
// QML
ListView {
    model: todo.model
    delegate: Text {
        text: "Title: " + title + ",  Description: " + description + ", Due date: " + due_date
    }
}
TodoController {
  id: todo
}

Combile asynchronous operations

In QML, all UI-related operations are done synchronously in the event loop. To set result of asynchronous operations to the UI, use QML.next_tick.

Examples

# Ruby
class HeavyTaskController
  include QML::Access
  register_to_qml under: "Example", version: "1.0"

  property(:result) { '' }

  def set_result(result)
    self.result = result
  end

  def start_heavy_task
    Thread.new do
      QML.next_tick do
        set_result do_heavy_task()
      end
    end
  end
end
// QML
Text {
  text: controller.result
}
Button {
  text: "Start!!"
  onClicked: controller.start_heavy_task()
}
HeavyTaskController {
  id: controller
}

Value conversions between Ruby and QML JavaScript

Ruby to QML

Ruby QML/JavaScript
nil null
true/false boolean
Numeric number
String/Symbol string
Array Array
Hash plain Object
Proc Function
Time Date
QML::Access Object(QObject derived)
QML::ListModel Object(QAbstractListModel)

You can customize this by implementing #to_qml method.

QML to Ruby

QML/JavaScript Ruby
null/undefined nil
boolean true/false
number Float
string String
Array QML::JSArray
Function QML::JSFunction
Object QML::JSObject
Object wrapping QML::Access QML::JSWrapper

You can convert Objects further through QML::JSObject methods.

QML::JSObject usage

QML::JSObject is the wrapper class for JavaScript objects.

obj = QML.engine.evaluate <<-JS
  ({
    value: 1,
    add: function(d) {
      this.value += d;
    }
  })
JS

# Getter
obj.value #=> 1

# Setter
obj.value = 2
obj.vaue #=> 2

# Call method if the property is a function
obj.add(10)
obj.value #=> 11

# Subscription
obj[:value] #=> 11
obj[:add] #=> #<QML::JSFunction:...>

Load and use Qt C++ plugins

PluginLoader loads Qt C++ plugins. It enables you to use your Qt C++ codes from Ruby easily.

// C++ - plugin example
class MyPlugin : public QObject
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.myplugin.MyPlugin")
signals:
    void added(int value);

public slots:
    int add(int x, int y) {
        int result = x + y;
        emit added(result);
        return result;
    }
};
# Ruby

# The instance will be a `QML::JSObject` which represents the plugin Qt object
plugin = QML::PluginLoader.new(directory, "myplugin").instance

# Connect to signal (see http://doc.qt.io/qt-5/qtqml-syntax-signals.html#connecting-signals-to-methods-and-signals)
plugin[:added].connect do |value|
  puts "added value: #{value}"
end

plugin.add(1, 2) #=> 3

Use with EventMachine

You can use EventMachine with ruby-qml. It is more powerful than the default ruby-qml event loop.

Instead of using QML.run, start an EventMachine event loop by EM.run and process QML events periodically by QML::Application#process_events.

require 'qml'
require 'eventmachine'

EM.run do
  QML.init
  EM.add_periodic_timer(0.01) { QML.application.process_events }
  QML.application.load_path(Pathname.pwd + 'main.qml')
end

You can also use em-synchrony to write callback-free asynchronous operation for ruby-qml.

require 'qml'
require 'eventmachine'
require 'em-synchrony'
require 'em-http-request'

class Controller
  include QML::Access
  property(:result) { '' }

  def get
    EM.synchrony do
      content = EM::Synchrony.sync EM::HttpRequest.new('http://www.example.com/').get
      self.result = content.response
    end
  end

  def quit
    EM.stop
  end

  register_to_qml under: 'Example', version: '0.1'
end

EM.run do
  QML.init
  EM.add_periodic_timer(0.01) { QML.application.process_events }
  QML.application.load_path(Pathname.pwd + 'main.qml')
end

Contributing

Init submodules

$ git submodule init
$ git submodule update

Install dependencies

$ bundle install

Build native extension

Before running ruby-qml in development, the native extension of ruby-qml needs to have been built. To build it, run the following commands:

$ cd ext/qml
$ bundle exec ruby extconf.rb --with-qmake=/path/to/qmake
$ make -j4

Run tests

Tests for ruby-qml is written in RSpec. To run tests, do:

$ bundle exec rspec

Run examples

$ bundle exec ruby examples/fizzbuzz/fizzbuzz.rb

Send pull requests

  1. Fork it ( http://github.com/seanchas116/ruby-qml/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Write some tests
  5. Push to the branch (git push origin my-new-feature)
  6. Create new Pull Request

More Repositories

1

qtimgui

Qt (QOpenGLWidget / QOpenGLWindow) backend for ImGui
C++
358
star
2

SimpleDALPlugin

Simple CoreMediaIO DAL virtual camera plugin example written in Swift
Swift
145
star
3

PaintField

A simple cross-platform digital painting tool
C++
42
star
4

electron-pdfjs

Electron + PDF.js viewer example
JavaScript
32
star
5

react-draggable-tree

Unstyled draggable tree view for React
TypeScript
32
star
6

libqmlbind

A C library for creating QML bindings for other languages easily through exporting objects to QML
C++
31
star
7

electron-safe-ipc

Safe communication between main process and renderer processes in Electron
JavaScript
26
star
8

uimix

A WYSIWYG React component builder ๐Ÿšง Very work-in-progress
TypeScript
20
star
9

wasm-face-detection

Face Detection using dlib/OpenCV in WebAssembly
C++
19
star
10

sketch-glass

Simple & fast realtime online whiteboard powered by WebGL and Google Drive
TypeScript
18
star
11

paintvec

JavaScript 2D vector math library
TypeScript
17
star
12

paintkit

[WIP] UI components and utilities for graphics editors or similar apps
TypeScript
17
star
13

transparent-titlebar

Transparent title bar with native title label in Electron for Mac
Objective-C++
15
star
14

glob-loader

webpack loader to load files at once with glob
JavaScript
15
star
15

wasm-text-rendering

Get glyph data and render text to a canvas using Rust wasm
Rust
15
star
16

amulet

C++ library for container manipulation and monads
C++
14
star
17

node-tflite

TensorFlow Lite bindings for Node.js
C
14
star
18

figma-to-tailwind

Figma plugin to convert layers to Tailwind HTML/JSX (utilizing JIT and custom configs)
TypeScript
12
star
19

electron-md-editor

Markdown editor example using Electron
JavaScript
11
star
20

tparse

A Parser Combinator for JavaScript/TypeScript
TypeScript
8
star
21

frame

[WIP] Minimum viable digital design app
TypeScript
8
star
22

Garnet

mruby bindings for Qt (QObject & QML)
C++
8
star
23

macaron-app

Open design platform
TypeScript
7
star
24

draggabletab

a draggable tab widget implementation in Qt
C++
7
star
25

swift-qt-experiment

Experimenting Swift + Qt bindings
Swift
7
star
26

StarCat

Browse GitHub repos in iOS
Swift
6
star
27

simple-drawing-tool

Simple collaborative drawing tool example
TypeScript
5
star
28

qmlrequire

`require` node modules from QML (work in progress)
C++
5
star
29

bezier-subdivide

Bezier curve subdivision in JavaScript
JavaScript
5
star
30

design-icons

Icon set for design tools
TypeScript
4
star
31

meta_meta_object

A QMetaObject Dynamic Construction Library
C++
4
star
32

macaron

[WIP] A JavaScript alternative with static typing
TypeScript
4
star
33

tensorflow-lite-cpp-builds

[WIP] TensorFlow Lite C++ builds for several platforms
C++
3
star
34

vcam-socket-client

Send frame data to virtual camera via socket (macOS)
C++
3
star
35

qt-opencascade-experiment

Qt + Open CASCADE experiment
C++
3
star
36

TFLiteSegmentationQt

Run TensorFlow Lite image segmentation in Qt desktop app
C++
3
star
37

yjs-realtime-database

Firebase Realtime Database + Y.js
TypeScript
3
star
38

wgpu-shape-rendering

Experimenting vector graphics rendering on wgpu (wasm)
Rust
2
star
39

bundlelibs

A tool for bundling .dylib libs into Mac apps easily
Ruby
2
star
40

meshlib

3D mesh manipulating library in C++
C++
2
star
41

learn-typescript

TypeScript
2
star
42

CraftKit

Building blocks for Qt-based editor applications
2
star
43

Malachite

2D Graphics Engine Based on Qt
C++
2
star
44

decompose

A simple component system built on top of virtual-dom
CoffeeScript
2
star
45

simple-lang

A very simple programming language written in Ruby
Ruby
2
star
46

SwiftQML

Swift bindings for QML
Swift
2
star
47

slide-learn-typescript

TypeScript้€Ÿ็ฟ’ไผš@Wantedly ็™บ่กจ่ณ‡ๆ–™
HTML
2
star
48

shapecraft

[WIP] 3D drawing tool
C++
2
star
49

webgl-painting

Painting tool test in WebGL
CoffeeScript
2
star
50

vtree-kup

CoffeeKup-like DSL for building virtual-dom tree
CoffeeScript
2
star
51

Wirework

Simple reactive programming & data binding utility for Swift
Swift
1
star
52

typedoc-theme-clean

A super minimalistic theme for typedoc
HTML
1
star
53

inline-import

Inline (function-like) ES6 `import` like good old CommonJS `require`
JavaScript
1
star
54

Lattice

[WIP] 3D modeling tool
C++
1
star
55

super-iterable

JavaScript / TypeScript library providing ES6 Iterable utilities
JavaScript
1
star
56

randomicon

simple icon generator with seeded random
JavaScript
1
star
57

CQMLBind

libqmlbind wrapper for Swift
C
1
star
58

Ropework

Minimalistic reactive programming in Swift
Swift
1
star
59

figma-plugins

[WIP] Experimental Figma plugin for code import/export
TypeScript
1
star
60

try-cloud-run

JavaScript
1
star
61

JSIL-helloworld

JSIL Hello World Example
HTML
1
star
62

konomi

Declarative object tree construction system for JavaScript, mainly for UI programming
JavaScript
1
star
63

tensorflow-lite-build-actions

[WIP] Build TensorFlow Lite in GitHub Actions
1
star