Blame platform-demos/ca/spinbutton.js.page

Packit 1470ea
Packit 1470ea
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:xi="http://www.w3.org/2001/XInclude" type="guide" style="task" id="spinbutton.js" xml:lang="ca">
Packit 1470ea
  <info>
Packit 1470ea
  <title type="text">SpinButton (JavaScript)</title>
Packit 1470ea
    <link type="guide" xref="beginner.js#entry"/>
Packit 1470ea
    <link type="seealso" xref="GtkApplicationWindow.js"/>
Packit 1470ea
    <link type="seealso" xref="grid.js"/>
Packit 1470ea
    <link type="seealso" xref="label.js"/>
Packit 1470ea
    <revision version="0.1" date="2012-06-24" status="draft"/>
Packit 1470ea
Packit 1470ea
    <credit type="author copyright">
Packit 1470ea
      <name>Taryn Fox</name>
Packit 1470ea
      <email its:translate="no">jewelfox@fursona.net</email>
Packit 1470ea
      <years>2012</years>
Packit 1470ea
    </credit>
Packit 1470ea
Packit 1470ea
    <desc>A number entry field that has + and - buttons</desc>
Packit 1470ea
  </info>
Packit 1470ea
Packit 1470ea
  <title>SpinButton</title>
Packit 1470ea
  <media type="image" mime="image/png" src="media/spinbuttonkittens.png"/>
Packit 1470ea
  

A SpinButton is not related to a <link xref="spinner.js">Spinner</link>. It's a text entry field which only accepts numbers, and which has plus and minus buttons to let you change the value without having to type anything in.

Packit 1470ea
  

It's best used when it's obvious that only a number can be entered into it. In this example, two SpinButtons are used for the number of kittens and number of cans of tuna to give them.

Packit 1470ea
    <links type="section"/>
Packit 1470ea
Packit 1470ea
  <section id="imports">
Packit 1470ea
    <title>Libraries to import</title>
Packit 1470ea
    
Packit 1470ea
#!/usr/bin/gjs
Packit 1470ea
Packit 1470ea
const Gio = imports.gi.Gio;
Packit 1470ea
const Gtk = imports.gi.Gtk;
Packit 1470ea
const Lang = imports.lang;
Packit 1470ea
]]>
Packit 1470ea
    

These are the libraries we need to import for this application to run. Remember that the line which tells GNOME that we're using Gjs always needs to go at the start.

Packit 1470ea
    </section>
Packit 1470ea
Packit 1470ea
  <section id="applicationwindow">
Packit 1470ea
    <title>Creating the application window</title>
Packit 1470ea
    
Packit 1470ea
const SpinButtonExample = new Lang.Class({
Packit 1470ea
    Name: 'SpinButton Example',
Packit 1470ea
Packit 1470ea
    // Create the application itself
Packit 1470ea
    _init: function() {
Packit 1470ea
        this.application = new Gtk.Application({
Packit 1470ea
            application_id: 'org.example.jsspinbutton'
Packit 1470ea
        });
Packit 1470ea
Packit 1470ea
    // Connect 'activate' and 'startup' signals to the callback functions
Packit 1470ea
    this.application.connect('activate', Lang.bind(this, this._onActivate));
Packit 1470ea
    this.application.connect('startup', Lang.bind(this, this._onStartup));
Packit 1470ea
    },
Packit 1470ea
Packit 1470ea
    // Callback function for 'activate' signal presents window when active
Packit 1470ea
    _onActivate: function() {
Packit 1470ea
        this._window.present();
Packit 1470ea
    },
Packit 1470ea
Packit 1470ea
    // Callback function for 'startup' signal builds the UI
Packit 1470ea
    _onStartup: function() {
Packit 1470ea
        this._buildUI ();
Packit 1470ea
    },
Packit 1470ea
]]>
Packit 1470ea
    

All the code for this sample goes in the SpinButtonExample class. The above code creates a <link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.Application.html">Gtk.Application</link> for our widgets and window to go in.

Packit 1470ea
    
Packit 1470ea
    // Build the application's UI
Packit 1470ea
    _buildUI: function() {
Packit 1470ea
Packit 1470ea
        // Create the application window
Packit 1470ea
        this._window = new Gtk.ApplicationWindow({
Packit 1470ea
            application: this.application,
Packit 1470ea
            window_position: Gtk.WindowPosition.CENTER,
Packit 1470ea
            border_width: 20,
Packit 1470ea
            title: "Kitten Feeder"});
Packit 1470ea
]]>
Packit 1470ea
    

The _buildUI function is where we put all the code to create the application's user interface. The first step is creating a new <link xref="GtkApplicationWindow.js">Gtk.ApplicationWindow</link> to put all our widgets into.

Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="spinbutton">
Packit 1470ea
    <title>Creating the SpinButtons</title>
Packit 1470ea
    
Packit 1470ea
        // Create the first spinbutton using a function
Packit 1470ea
        this._kittens = Gtk.SpinButton.new_with_range (1, 9001, 1);
Packit 1470ea
        this._kittens.connect ("value-changed", Lang.bind (this, this._newValue));
Packit 1470ea
]]>
Packit 1470ea
Packit 1470ea
    

We can use the new_with_range function to create a new SpinButton quickly. Its first parameter is the SpinButton's starting value, its second is the maximum value, and its third is how much to increment it when the plus or minus buttons are pressed.

Packit 1470ea
    

After we create the first SpinButton, we connect its value-changed signal to a function which handles what happens when the number inside either SpinButton changes.

Packit 1470ea
Packit 1470ea
    
Packit 1470ea
        // Create an adjustment to use for the second spinbutton
Packit 1470ea
        this._adjustment = new Gtk.Adjustment ({
Packit 1470ea
            value: 1,
Packit 1470ea
            lower: 0,
Packit 1470ea
            upper: 9001,
Packit 1470ea
            step_increment: 1,
Packit 1470ea
            page_increment: 10 });
Packit 1470ea
Packit 1470ea
        // Create the second spinbutton
Packit 1470ea
        this._tuna = new Gtk.SpinButton ({ adjustment: this._adjustment });
Packit 1470ea
        this._tuna.connect ("value-changed", Lang.bind (this, this._newValue));
Packit 1470ea
Packit 1470ea
        // this._tuna.set_digits (1);
Packit 1470ea
        // this._tuna.set_wrap (true);
Packit 1470ea
]]>
Packit 1470ea
Packit 1470ea
    

If you want more fine-grained control over a SpinButton, or want to create a bunch of SpinButtons which all use the same parameters, you can create an object called an <link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Adjustment.html">Adjustment</link>. Then you can use that object as a new SpinButton's adjustment property, and it sets all the values at once. Afterwards, you can change all the SpinButtons which use that adjustment by changing the Adjustment object's properties.

Packit 1470ea
    

The commented-out lines here show things you can do to customize your SpinButton. You can set the number of digits which go after the decimal point, for example, or tell it to wrap the number around if it goes past the upper or lower bounds that you set.

Packit 1470ea
    <note>

For the kitties' sake, please don't use set_digits to allow a decimal number of kittens.

</note>
Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="UI">
Packit 1470ea
    <title>Creating the rest of the UI</title>
Packit 1470ea
Packit 1470ea
    
Packit 1470ea
        // Create the text labels to go with the spinbuttons
Packit 1470ea
        this._startLabel = new Gtk.Label ({ label: "There are " });
Packit 1470ea
        this._kittenLabel = new Gtk.Label ({ label: " kitten(s), and "});
Packit 1470ea
        this._tunaLabel = new Gtk.Label ({ label: " can(s) of tuna."});
Packit 1470ea
        this.perKitten = Math.floor((this._tuna.get_value() / this._kittens.get_value()));
Packit 1470ea
        this._lastLabel = new Gtk.Label ({
Packit 1470ea
            label: "That's " + this.perKitten + " can(s) of tuna per kitten." });
Packit 1470ea
]]>
Packit 1470ea
    

We create each <link xref="label.js">Label</link> individually, and then string them together along with the SpinButtons. The last label needs to show the number of cans of tuna per kitten, so it has a variable in the middle, which corresponds to an equation that uses the SpinButtons' get_value functions to find out what they're set at. JavaScript's Math function's floor method is used to round the number of cans of tuna per kitten down to the nearest whole number.

Packit 1470ea
Packit 1470ea
    
Packit 1470ea
        // Create a grid to put the spinbuttons and their labels in
Packit 1470ea
        this._spinGrid = new Gtk.Grid ({
Packit 1470ea
            halign: Gtk.Align.CENTER,
Packit 1470ea
            valign: Gtk.Align.CENTER,
Packit 1470ea
            margin_bottom: 20 });
Packit 1470ea
Packit 1470ea
        // Attach everything to the grid
Packit 1470ea
        this._spinGrid.attach (this._startLabel, 0, 0, 1, 1);
Packit 1470ea
        this._spinGrid.attach (this._kittens, 1, 0, 1, 1);
Packit 1470ea
        this._spinGrid.attach (this._kittenLabel, 2, 0, 1, 1);
Packit 1470ea
        this._spinGrid.attach (this._tuna, 3, 0, 1, 1);
Packit 1470ea
        this._spinGrid.attach (this._tunaLabel, 4, 0, 1, 1);
Packit 1470ea
Packit 1470ea
        // Create a main grid to hold it and the last label
Packit 1470ea
        this._mainGrid = new Gtk.Grid ({
Packit 1470ea
            halign: Gtk.Align.CENTER,
Packit 1470ea
            valign: Gtk.Align.CENTER });
Packit 1470ea
Packit 1470ea
        // Attach the smaller grid and the last label to the main grid
Packit 1470ea
        this._mainGrid.attach (this._spinGrid, 0, 0, 1, 1);
Packit 1470ea
        this._mainGrid.attach (this._lastLabel, 0, 1, 1, 1);
Packit 1470ea
]]>
Packit 1470ea
Packit 1470ea
    

Here we use <link xref="grid.js">Grid</link> widgets to keep everything organized. One Grid holds the labels and SpinButtons in order, while the next puts that Grid on top and the final Label on the bottom.

Packit 1470ea
    

There isn't a wrong way to organize things in Grids, so long as you like how it turns out. In this case, the top Grid has a margin on the bottom to keep it evenly spaced from the bottom Label, and the bottom Label is inside a separate Grid so it will be centered relative to the Labels and SpinButtons on the top.

Packit 1470ea
Packit 1470ea
    
Packit 1470ea
        // Add the main grid to the window
Packit 1470ea
        this._window.add (this._mainGrid);
Packit 1470ea
Packit 1470ea
        // Show the window and all child widgets
Packit 1470ea
        this._window.show_all();
Packit 1470ea
    },
Packit 1470ea
]]>
Packit 1470ea
    

Finally, we add the larger Grid to the window, then tell the window to show itself and all the widgets inside of it.

Packit 1470ea
    </section>
Packit 1470ea
Packit 1470ea
    <section id="spinbutton-handler">
Packit 1470ea
    <title>Function which handles the SpinButtons' numerical values being adjusted</title>
Packit 1470ea
Packit 1470ea
    
Packit 1470ea
    _newValue: function () {
Packit 1470ea
Packit 1470ea
        // Update the label which shows how many cans there are per kitten
Packit 1470ea
        this.perKitten = Math.floor((this._tuna.get_value() / this._kittens.get_value()))
Packit 1470ea
        this._lastLabel.set_label ("That's " + this.perKitten + " can(s) of tuna per kitten.");
Packit 1470ea
Packit 1470ea
    }
Packit 1470ea
Packit 1470ea
});
Packit 1470ea
]]>
Packit 1470ea
    

Here we update the perKitten variable based on the SpinButtons' new values, and use the set_label property to refresh what _lastLabel shows. Since both SpinButtons have their value-changed signal connected to this function, every time either of the numbers changes this function will update the Label.

Packit 1470ea
Packit 1470ea
    
Packit 1470ea
// Run the application
Packit 1470ea
let app = new SpinButtonExample ();
Packit 1470ea
app.application.run (ARGV);
Packit 1470ea
]]>
Packit 1470ea
    

Finally, we create a new instance of the finished SpinButtonExample class, and set the application running.

Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="complete">
Packit 1470ea
    <title>Complete code sample</title>
Packit 1470ea
#!/usr/bin/gjs
Packit 1470ea
Packit 1470ea
imports.gi.versions.Gtk = '3.0';
Packit 1470ea
Packit 1470ea
const Gio = imports.gi.Gio;
Packit 1470ea
const Gtk = imports.gi.Gtk;
Packit 1470ea
Packit 1470ea
class SpinButtonExample {
Packit 1470ea
Packit 1470ea
    // Create the application itself
Packit 1470ea
    constructor() {
Packit 1470ea
        this.application = new Gtk.Application({
Packit 1470ea
            application_id: 'org.example.jsspinbutton'
Packit 1470ea
        });
Packit 1470ea
Packit 1470ea
        // Connect 'activate' and 'startup' signals to the callback functions
Packit 1470ea
        this.application.connect('activate', this._onActivate.bind(this));
Packit 1470ea
        this.application.connect('startup', this._onStartup.bind(this));
Packit 1470ea
    }
Packit 1470ea
Packit 1470ea
    // Callback function for 'activate' signal presents window when active
Packit 1470ea
    _onActivate() {
Packit 1470ea
        this._window.present();
Packit 1470ea
    }
Packit 1470ea
Packit 1470ea
    // Callback function for 'startup' signal builds the UI
Packit 1470ea
    _onStartup() {
Packit 1470ea
        this._buildUI();
Packit 1470ea
    }
Packit 1470ea
Packit 1470ea
    // Build the application's UI
Packit 1470ea
    _buildUI() {
Packit 1470ea
Packit 1470ea
        // Create the application window
Packit 1470ea
        this._window = new Gtk.ApplicationWindow({
Packit 1470ea
            application: this.application,
Packit 1470ea
            window_position: Gtk.WindowPosition.CENTER,
Packit 1470ea
            border_width: 20,
Packit 1470ea
            title: "Kitten Feeder"});
Packit 1470ea
Packit 1470ea
        // Create the first spinbutton using a function
Packit 1470ea
        this._kittens = Gtk.SpinButton.new_with_range (1, 9001, 1);
Packit 1470ea
        this._kittens.connect ("value-changed", this._newValue.bind(this));
Packit 1470ea
Packit 1470ea
        // Create an adjustment to use for the second spinbutton
Packit 1470ea
        this._adjustment = new Gtk.Adjustment ({
Packit 1470ea
            value: 1,
Packit 1470ea
            lower: 0,
Packit 1470ea
            upper: 9001,
Packit 1470ea
            step_increment: 1,
Packit 1470ea
            page_increment: 10 });
Packit 1470ea
Packit 1470ea
        // Create the second spinbutton
Packit 1470ea
        this._tuna = new Gtk.SpinButton ({ adjustment: this._adjustment });
Packit 1470ea
        this._tuna.connect ("value-changed", this._newValue.bind(this));
Packit 1470ea
Packit 1470ea
        // this._tuna.set_digits (1);
Packit 1470ea
        // this._tuna.set_wrap (true);
Packit 1470ea
Packit 1470ea
        // Create the text labels to go with the spinbuttons
Packit 1470ea
        this._startLabel = new Gtk.Label ({ label: "There are " });
Packit 1470ea
        this._kittenLabel = new Gtk.Label ({ label: " kitten(s), and "});
Packit 1470ea
        this._tunaLabel = new Gtk.Label ({ label: " can(s) of tuna."});
Packit 1470ea
        this.perKitten = Math.floor((this._tuna.get_value() / this._kittens.get_value()));
Packit 1470ea
        this._lastLabel = new Gtk.Label ({
Packit 1470ea
            label: "That's " + this.perKitten + " can(s) of tuna per kitten." });
Packit 1470ea
Packit 1470ea
        // Create a grid to put the spinbuttons and their labels in
Packit 1470ea
        this._spinGrid = new Gtk.Grid ({
Packit 1470ea
            halign: Gtk.Align.CENTER,
Packit 1470ea
            valign: Gtk.Align.CENTER,
Packit 1470ea
            margin_bottom: 20 });
Packit 1470ea
Packit 1470ea
        // Attach everything to the grid
Packit 1470ea
        this._spinGrid.attach (this._startLabel, 0, 0, 1, 1);
Packit 1470ea
        this._spinGrid.attach (this._kittens, 1, 0, 1, 1);
Packit 1470ea
        this._spinGrid.attach (this._kittenLabel, 2, 0, 1, 1);
Packit 1470ea
        this._spinGrid.attach (this._tuna, 3, 0, 1, 1);
Packit 1470ea
        this._spinGrid.attach (this._tunaLabel, 4, 0, 1, 1);
Packit 1470ea
Packit 1470ea
        // Create a main grid to hold it and the last label
Packit 1470ea
        this._mainGrid = new Gtk.Grid ({
Packit 1470ea
            halign: Gtk.Align.CENTER,
Packit 1470ea
            valign: Gtk.Align.CENTER });
Packit 1470ea
Packit 1470ea
        // Attach the smaller grid and the last label to the main grid
Packit 1470ea
        this._mainGrid.attach (this._spinGrid, 0, 0, 1, 1);
Packit 1470ea
        this._mainGrid.attach (this._lastLabel, 0, 1, 1, 1);
Packit 1470ea
Packit 1470ea
        // Add the main grid to the window
Packit 1470ea
        this._window.add (this._mainGrid);
Packit 1470ea
Packit 1470ea
        // Show the window and all child widgets
Packit 1470ea
        this._window.show_all();
Packit 1470ea
    }
Packit 1470ea
Packit 1470ea
    _newValue() {
Packit 1470ea
        // Update the label which shows how many cans there are per kitten
Packit 1470ea
        this.perKitten = Math.floor((this._tuna.get_value() / this._kittens.get_value()))
Packit 1470ea
        this._lastLabel.set_label ("That's " + this.perKitten + " can(s) of tuna per kitten.");
Packit 1470ea
    }
Packit 1470ea
};
Packit 1470ea
Packit 1470ea
// Run the application
Packit 1470ea
let app = new SpinButtonExample ();
Packit 1470ea
app.application.run (ARGV);
Packit 1470ea
Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="in-depth">
Packit 1470ea
    <title>In-depth documentation</title>
Packit 1470ea
<list>
Packit 1470ea
  <item>

<link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Adjustment.html">Gtk.Adjustment</link>

</item>
Packit 1470ea
  <item>

<link href="http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.Application.html">Gtk.Application</link>

</item>
Packit 1470ea
  <item>

<link href="http://developer.gnome.org/gtk3/stable/GtkApplicationWindow.html">Gtk.ApplicationWindow</link>

</item>
Packit 1470ea
  <item>

<link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Grid.html">Gtk.Grid</link>

</item>
Packit 1470ea
  <item>

<link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.Label.html">Gtk.Label</link>

</item>
Packit 1470ea
  <item>

<link href="http://www.roojs.org/seed/gir-1.2-gtk-3.0/gjs/Gtk.SpinButton.html">Gtk.SpinButton</link>

</item>
Packit 1470ea
</list>
Packit 1470ea
  </section>
Packit 1470ea
</page>