Fare script JS in SUSE

 

Esiste un altro modo di fare script ed è con JavaScript. Vediamo come…

 

 

 

 

Volevo fare script con le QT e JavaScript. Per questo mi occorreva per prima cosa installarvi QT-Creator, il potentissimo editor della QT e Uitools, ma poi documentazione ZERO, anzi tanta “documentazione” ma totalmente inutile con esempi fini su se stessi. Vuoi fare qualcosa allora usa il Pitone (Python, ottimo linguaggio) ma questo è un modo chiuso e limitato di fare le cose.

Sono finiti i tempi del KDE3, dove tutto era ben spiegato ed era veramente libero! Quindi provo con Gnome.

Qui la musica cambia, poi si lamentano perché la gente non segue più KDE e la sua comunità diventa sempre più minima e KDE si sporca di tecnologia Gnome ogni giorno di più.  ​​​​ 

Esempi tratti da

https://gjs-tutorial.readthedocs.io/en/latest/introduction.html

Ottenibile come PDF qui:

https://readthedocs.org/projects/gjs-tutorial/downloads/pdf/latest/

 

Installazione.

Qui per fare gli script basta caricarsi dell’interprete Javascript che è GJS.

Dato che sono script direttamente eseguibili, devono essere settati come eseguibili ed essere in codifica UTF8 stile UNIX.

Vi avverto subito che dovete dichiarare le variabili con “let”.

Attenzione si usa il GTK+ 3.

Esecuzione

Ci sono due sistemi.

  • lo rendi eseguibile ​​ e poi lo esegui direttamente

chmod +x script.js

./script.js

 

  • oppure usi indirettamente l’interprete GJS

gjs simple_example.js

 

Partenza:

 

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

Gtk.init(null);

 

let win = new Gtk.Window();

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

Lo script è facilissimo, all’inizio esiste la dichiarazione dello script tipo Javascript di GJS

#!/usr/bin/gjs

 

Importiamo la sua libreria dentro una variabile (const = costante) che diventa un oggetto.

const Gtk = imports.gi.Gtk;

 

Già qui si vede che la libreria è stata fatta con molto cervello, spesso le librerie Javascript sono troppo frazionate.

partenza dello script vero è proprio

Gtk.init(null);

 

Nota: “null” è proprio per nulla.

Ma adesso vogliamo aprire una finestra (qui si chiamano Widget), quindi prendiamo la parte che la crea. Mettiamo dentro la variabile oggetto la struttura Gtk.Window() ovvero la parte di GTK che si occupa delle finestre.

let win = new Gtk.Window();

 

Nota: Qui tutte le variabili devono essere dichiarate e si usa la parola chiave “let”.

win.connect("delete-event", Gtk.main_quit);

 

Dovete sapere che ogni volta che noi creiamo un Widget, la nostra applicazione si sdoppia, quindi serve una connessione tra lo script e la finestra. Da qui win.connect, dunque nella connessione se sente un evento di cancellazione ("delete-event") deve procedere alla sua chiusura ​​ “Gtk.main_quit”.

Script

Widget

 

Connessione

 

 

 

Nota: Ogni connessione possiede un identificativo ecco come si possono avere più script in esecuzione che comandano più widget.

Quando abbiamo definito tutto allora si può veramente far partire la finestra.

win.show_all();

 

e prendiamo il controllo:

Gtk.main();

Ora puoi eseguire il programma rendendolo eseguibile ed eseguendolo direttamente.

-Gestire la finestra

Qui vediamo come posizionarla al centro dello schermo, con altezza 200px larghezza 400px, bordo 20px e il titolo del widget.

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

Gtk.init(null);

 

let win = new Gtk.Window({

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ window_position: Gtk.WindowPosition.CENTER,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ default_height: 200,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ default_width: 400,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ border_width: 20,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ title: "Widget !"}

);

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

Logicamente le possibilità sono molte di più, qui elenco quelle comuni.

-Fare un bottone

 

#!/usr/bin/gjs

 

imports.gi.versions.Gtk = '3.0';

const {GObject, Gtk} = imports.gi;

 

Gtk.init(null);

 

const MyWindow = GObject.registerClass(class MyWindow extends Gtk.Window {

 ​​ ​​ ​​​​ _init() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ super._init({ title: "Hello World" });

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.button = new Gtk.Button({ label: "Click here" });

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.button.connect("clicked", MyWindow.onButtonClicked);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(this.button);

 ​​ ​​ ​​​​ }

 

 ​​ ​​ ​​​​ static onButtonClicked() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ print("Hello World");

 ​​ ​​ ​​​​ }

});

 

let win = new MyWindow();

win.connect("delete-event", () => Gtk.main_quit());

win.show_all();

Gtk.main();

 

 

Qui chiediamo di più e quindi vediamo di importare giusto.

​​ imports.gi.versions.Gtk = '3.0';

const {GObject, Gtk} = imports.gi;

 

Scegliamo solo le GTK 3.0 e gestiamo ben due oggetti: ​​ GObject, Gtk.

const MyWindow = GObject.registerClass(class MyWindow extends Gtk.Window {

 ​​ ​​ ​​​​ _init() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ super._init({ title: "Hello World" });

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.button = new Gtk.Button({ label: "Click here" });

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.button.connect("clicked", MyWindow.onButtonClicked);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(this.button);

 ​​ ​​ ​​​​ }

(......)

}

 

Qui la cosa si fa complessa, nella nostra variabile oggetto creiamo una classe (grazie ad Gobject di prima) partendo da Gtk.Window di prima. Qui ci mettiamo il titolo (3 riga), un bottone (4 riga) che se premuto (5 riga) eseguirà ​​ MyWindow.onButtonClicked. Infine nella 5 riga addizioniamo questo bottone alla finestra.

Ma dove finisce questo ​​ MyWindow.onButtonClicked?

Qui

 ​​ ​​ ​​ ​​​​ static onButtonClicked() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ print("Hello World");

 ​​ ​​ ​​​​ }

 

Ok, adesso facciamo le solite operazioni finali:

let win = new MyWindow();

win.connect("delete-event", () => Gtk.main_quit());

win.show_all();

Gtk.main();

 

Nota: La grandezza della finestra si dimensiona con la grandezza della scritta sul bottone.

-Il BOX

 

Se fate diverse prove di scrittura sul Widget (nell’esempio aggiungere un altro bottone) noterete che diventa tutto pasticciato, questo perché serve un contenitore o più contenitori all’interno del Widget per organizzare il tutto.

Uno dei contenitori interni si chiama BOX. Questo separa orizzontalmente un Widget.

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

const Lang = imports.lang;

 

Gtk.init(null);

 

const MyWindow = new Lang.Class({

 ​​ ​​ ​​​​ Name: 'MyWindow',

 ​​ ​​ ​​​​ Extends: Gtk.Window,

 

 ​​ ​​ ​​​​ _init: function() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent({title:"Hello World"});

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.box = new Gtk.Box({spacing: 6});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(this.box);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.button1 = new Gtk.Button({label: "Hello"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.button1.connect("clicked", this.onButton1Clicked);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.box.pack_start(this.button1, true, true, 0);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.button2 = new Gtk.Button({label: "Goodbye"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.button2.connect("clicked", this.onButton2Clicked);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.box.pack_start(this.button2, true, true, 0);

 ​​ ​​ ​​​​ },

 

 ​​ ​​ ​​​​ onButton1Clicked: function(widget) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ print("Hello");

 ​​ ​​ ​​​​ },

 

 ​​ ​​ ​​​​ onButton2Clicked: function(widget) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ print("Goodbye");

 ​​ ​​ ​​​​ }

});

 

let win = new MyWindow();

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

Come vedete prima si crea la finestra principale

​​ this.parent({title:"Hello World"});

ma poi si mette un box all’interno

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.box = new Gtk.Box({spacing: 6});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(this.box);

Notate che bisogna dagli una grandezza che in questo caso corrisponde sui 6 spazi.

Il bottone poi si mette dentro al BOX.

this.box.pack_start(this.button1, true, true, 0);

 

Questo consente nell’esempio di mettere due bottoni in modo ordinato.

Logico che quando il bottone viene premuto:

​​ this.button1.connect("clicked", this.onButton1Clicked);

 

si esegua la sua funzione dedicata

 ​​ ​​ ​​​​ onButton1Clicked: function(widget) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ print("Hello");

 ​​ ​​ ​​​​ },

 

-Il Grid

Un altro dei contenitori interni si chiama GRID. Questo separa sia verticalmente che orizzontalmente un Widget. Qui ovviamente la cosa si complica… quindi non metto la chiamata alle funzione se premuto un tasto, tanto l’avete già capita.

Nota: Questo è quello più usato per fare le GUI. ​​ 

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

const Lang = imports.lang;

 

Gtk.init(null);

 

const GridWindow = Lang.Class({

 ​​ ​​ ​​​​ Name: 'GridWindow',

 ​​ ​​ ​​​​ Extends: Gtk.Window,

 

 ​​ ​​ ​​​​ _init: function() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent({title: "Grid Example"});

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let grid = new Gtk.Grid();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(grid);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let button1 = new Gtk.Button({label: "Button 1"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let button2 = new Gtk.Button({label: "Button 2"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let button3 = new Gtk.Button({label: "Button 3"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let button4 = new Gtk.Button({label: "Button 4"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let button5 = new Gtk.Button({label: "Button 5"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let button6 = new Gtk.Button({label: "Button 6"});

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ grid.add(button1);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ grid.attach(button2, 1, 0, 2, 1);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ grid.attach_next_to(button3, button1, Gtk.PositionType.BOTTOM, 1, 2);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ grid.attach_next_to(button4, button3, Gtk.PositionType.RIGHT, 2, 1);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ grid.attach(button5, 1, 2, 1, 1);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ grid.attach_next_to(button6, button5, Gtk.PositionType.RIGHT, 1, 1);

 ​​ ​​ ​​​​ }

});

 

let win = new GridWindow();

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

Prima definiamo la variabile del bottone (con “let” si definiscono le variabili)

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let button1 = new Gtk.Button({label: "Button 1"});

 

Poi questa dobbiamo posizionarla nella “grid”:

 ​​ ​​​​ grid.add(button1);

(.....)

grid.attach_next_to(button3, button1, Gtk.PositionType.BOTTOM, 1, 2);

 

“attach” attacca mentre “attach_next_to” attacca dopo un precedente posizionamento.

Nell’esempio button1 si prende il primo spazio disponibile, poi il suo posizionamento serve per button3.

​​ Gtk.PositionType.BOTTOM dice che “PositionType” è il tipo di posizionamento ed in questo caso “BOTTOM” è sotto.

Nota: BOTTOM=sotto , UP=sopra, ​​ RIGHT=destra, LEFT=sinistra.

Poi esiste il posizionamento nella grid tipo scacchiera: Nell’esempio orizzontalmente prende una zona (1) ​​ ma verticalmente prende 2 zone.

 ​​​​ grid.attach_next_to(button3, button1, Gtk.PositionType.BOTTOM, 1, 2);

 

button1

button2

button2

button3

button4

button4

button3

button5

button6

 

Notare le posizioni del codice:

grid.add(button1);

 ​​​​ grid.attach(button2, 1, 0, 2, 1);

 ​​​​ grid.attach_next_to(button3, button1, Gtk.PositionType.BOTTOM, 1, 2);

 ​​​​ grid.attach_next_to(button4, button3, Gtk.PositionType.RIGHT, 2, 1);

 ​​​​ grid.attach(button5, 1, 2, 1, 1);

 ​​​​ grid.attach_next_to(button6, button5, Gtk.PositionType.RIGHT, 1, 1);

 

-ListBox

Un altro dei contenitori interni si chiama ListBox. Questo separa una lista per la scelta della voce, vediamo come

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

const Lang = imports.lang;

 

Gtk.init(null);

 

const ListBoxRowWithData = Lang.Class({

 ​​ ​​ ​​​​ Name: "ListBoxRowWithData",

 ​​ ​​ ​​​​ Extends: Gtk.ListBoxRow,

 

 ​​ ​​ ​​​​ _init: function(data) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.data = data;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(new Gtk.Label({label: data}));

 ​​ ​​ ​​​​ }

});

 

const ListBoxWindow = Lang.Class({

 ​​ ​​ ​​​​ Name: "ListBoxWindow",

 ​​ ​​ ​​​​ Extends: Gtk.Window,

 

 ​​ ​​ ​​​​ _init: function() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent({title: "ListBox Demo"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.border_width = 10;

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let box_outer = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL, spacing: 6});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(box_outer);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let listbox = new Gtk.ListBox();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox.selection_mode = Gtk.SelectionMode.NONE;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ box_outer.pack_start(listbox, true, true, 0);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let row = new Gtk.ListBoxRow();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let hbox = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, spacing: 50});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ row.add(hbox);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let vbox = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox.pack_start(vbox, true, true, 0);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox.add(row);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let listbox2 = new Gtk.ListBox();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let items = "This is a sorted ListBox Fail".split(' ');

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ items.forEach(

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ item => listbox2.add(new ListBoxRowWithData(item))

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ );

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let sortFunc = function(row1, row2, data, notifyDestroy) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ return row1.data.toLowerCase() > row2.data.toLowerCase();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ };

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let filterFunc = function(row, data, notifyDestroy) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ return (row.data != 'Fail');

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ };

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.set_sort_func(sortFunc, null, false);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.set_filter_func(filterFunc, null, false);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.connect("row-activated", (widget, row) => print(row.data));

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ box_outer.pack_start(listbox2, true, true, 0);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.show_all();

 ​​ ​​ ​​​​ }

});

 

let win = new ListBoxWindow();

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

Chiamiamolo ​​ "ListBox Demo" e gli diamo un bordo da 10px

 

this.parent({title: "ListBox Demo"});

 ​​ ​​​​ this.border_width = 10;

​​ 

 

Gli diamo l’orientamento (verticale) con spazio da 6px

 ​​ ​​​​ let box_outer = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL, spacing: 6});

 

lo riempiamo (vedremo dopo il trucchetto per prendere dei dati, comunque punta su ListBoxRowWithData):

 

items.forEach(

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ item => listbox2.add(new ListBoxRowWithData(item))

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ );

 

Funzione: Ordiniamolo :

 

 ​​​​ let sortFunc = function(row1, row2, data, notifyDestroy) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ return row1.data.toLowerCase() > row2.data.toLowerCase();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ };

 

Funzione: Evitiamo qualche buco:

 ​​ ​​ ​​​​ 

 ​​​​ let filterFunc = function(row, data, notifyDestroy) {

 ​​ ​​ ​​ ​​​​  return (row.data != 'Fail');

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ };

 

Chiamiamo le funzioni prima e poi ci colleghiamo (“connect”) e scriviamo (“print”) il tutto nel widget

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.set_sort_func(sortFunc, null, false);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.set_filter_func(filterFunc, null, false);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.connect("row-activated", (widget, row) => print(row.data));

 

Start e visualizziamo

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ box_outer.pack_start(listbox2, true, true, 0);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.show_all();

 

Abbiamo ottenuto una lista cliccabile, volendo ogni punto può richiamare un’azione.

+++---

Vogliamo fare di più???

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

const Lang = imports.lang;

 

Gtk.init(null);

 

const ListBoxRowWithData = Lang.Class({

 ​​ ​​ ​​​​ Name: "ListBoxRowWithData",

 ​​ ​​ ​​​​ Extends: Gtk.ListBoxRow,

 

 ​​ ​​ ​​​​ _init: function(data) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.data = data;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(new Gtk.Label({label: data}));

 ​​ ​​ ​​​​ }

});

 

const ListBoxWindow = Lang.Class({

 ​​ ​​ ​​​​ Name: "ListBoxWindow",

 ​​ ​​ ​​​​ Extends: Gtk.Window,

 

 ​​ ​​ ​​​​ _init: function() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent({title: "ListBox Demo"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.border_width = 10;

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let box_outer = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL, spacing: 6});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(box_outer);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let listbox = new Gtk.ListBox();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox.selection_mode = Gtk.SelectionMode.NONE;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ box_outer.pack_start(listbox, true, true, 0);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let row = new Gtk.ListBoxRow();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let hbox = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, spacing: 50});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ row.add(hbox);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let vbox = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox.pack_start(vbox, true, true, 0);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let label1 = new Gtk.Label({label: "Automatic Date & Time", xalign: 0});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let label2 = new Gtk.Label({label: "Requires internet access", xalign: 0});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ vbox.pack_start(label1, true, true, 0);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ vbox.pack_start(label2, true, true, 0);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let swtch = new Gtk.Switch();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ swtch.valign = Gtk.Align.CENTER;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox.pack_start(swtch, false, true, 0);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox.add(row);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ row = new Gtk.ListBoxRow();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, spacing: 50});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ row.add(hbox);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let label = new Gtk.Label({label: "Enable Automatic Update", xalign: 0});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let check = new Gtk.CheckButton();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox.pack_start(label, true, true, 0);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox.pack_start(check, false, true, 0);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox.add(row);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ row = new Gtk.ListBoxRow();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, spacing: 50});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ row.add(hbox);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ label = new Gtk.Label({label: "Date Format", xalign: 0});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let combo = new Gtk.ComboBoxText();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ combo.insert(0, "0", "24-hour");

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ combo.insert(1, "1", "AM/PM");

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox.pack_start(label, true, true, 0);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ hbox.pack_start(combo, false, true, 0);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox.add(row);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let listbox2 = new Gtk.ListBox();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let items = "This is a sorted ListBox Fail".split(' ');

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ items.forEach(

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ item => listbox2.add(new ListBoxRowWithData(item))

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ );

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let sortFunc = function(row1, row2, data, notifyDestroy) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ return row1.data.toLowerCase() > row2.data.toLowerCase();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ };

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let filterFunc = function(row, data, notifyDestroy) {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ return (row.data != 'Fail');

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ };

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.set_sort_func(sortFunc, null, false);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.set_filter_func(filterFunc, null, false);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.connect("row-activated", (widget, row) => print(row.data));

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ box_outer.pack_start(listbox2, true, true, 0);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ listbox2.show_all();

 ​​ ​​ ​​​​ }

});

 

let win = new ListBoxWindow();

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

 

In questo caso introduciamo altri elementi e come vedete sono ordinati in verticale.

 

-Stack

 

Questo richiama dei “figli” ovvero dei widget collegati.

Un Gtk.Stack è un contenitore che mostra solo uno dei suoi figli alla volta. A differenza di Gtk.Notebook, Gtk.Stack non fornisce agli utenti un mezzo per modificare il figlio visibile. Invece, il widget Gtk.StackSwitcher può essere utilizzato con Gtk.Stack per fornire questa funzionalità.

Le transizioni tra le pagine possono essere animate come diapositive o dissolvenze. Questo può essere controllato con Gtk.Stack.set_transition_type . Queste animazioni rispettano l'impostazione "gtk-enable-animations". Insomma avrete gli effetti speciali.

 

Nota: La velocità di transizione può essere regolata con Gtk.Stack.set_transition_duration (). È possibile associare più widget Gtk.StackSwitcher allo stesso widget Gtk.Stack.

Il widget Gtk.StackSwitcher funge da controller per Gtk.Stack; mostra una fila di pulsanti per passare tra le varie pagine del widget dello stack associato.

 

Tutto il contenuto dei pulsanti proviene (deve) dalle proprietà figlio di Gtk.Stack.

Qui vedremo un effetto speciale di sparizione di una scritta (anche cliccabile).

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

const Lang = imports.lang;

 

Gtk.init(null);

 

const StackWindow = Lang.Class({

 ​​ ​​ ​​​​ Name: "StackWindow",

 ​​ ​​ ​​​​ Extends: Gtk.Window,

 

 ​​ ​​ ​​​​ _init: function() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent({title: "Stack Demo"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.border_width = 10;

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let vbox = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL, spacing: 6});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(vbox);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let stack = new Gtk.Stack();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ stack.transition_duration = 1000;

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let checkbutton = new Gtk.CheckButton({label: "Click Me"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ stack.add_titled(checkbutton, "check", "Check Button");

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let label = new Gtk.Label();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ label.markup = "<big>A fancy label</big>";

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ stack.add_titled(label, "label", "A label");

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ let stackSwitcher = new Gtk.StackSwitcher();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ stackSwitcher.stack = stack;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ vbox.pack_start(stackSwitcher, true, true, 0);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ vbox.pack_start(stack, true, true, 0);

 ​​ ​​ ​​​​ }

});

 

let win = new StackWindow();

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

Come potete vedere potete fare diversi effetti molto carini, tenete conto di usare la semantica XUL (esempio <big>) se volete usare il makup e non quello di HTML (esempio <b>).

 

-Avere i Tab

 

Per dividere un widget in vari tab si usa Notebook:

​​ 

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

const Lang = imports.lang;

 

Gtk.init(null);

 

const MyWindow = Lang.Class({

 ​​ ​​ ​​​​ Name: "MyWindow",

 ​​ ​​ ​​​​ Extends: Gtk.Window,

 

 ​​ ​​ ​​​​ _init: function() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent({title: "Simple Notebook Example"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.border_width = 3;

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.notebook = new Gtk.Notebook();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(this.notebook);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page1 = new Gtk.Box();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page1.border_width = 10;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page1.add(new Gtk.Label({label: "Default Page!"}));

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.notebook.append_page(this.page1, new Gtk.Label({label: "Plain Title"}));

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page2 = new Gtk.Box();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page2.border_width = 10;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page2.add(new Gtk.Label({label: "A page with an image for a title."}));

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.notebook.append_page(

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page2,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ Gtk.Image.new_from_icon_name("help-about", Gtk.IconSize.MENU)

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ );

 ​​ ​​ ​​​​ }

});

 

let win = new MyWindow();

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

La cosa è talmente semplice che non perdo nemmeno tempo nel spiegare.

Anzi vi mostro un esempio più complesso che spiega meglio:

#!/usr/bin/gjs

 

const Gtk = imports.gi.Gtk;

const Lang = imports.lang;

 

Gtk.init(null);

 

const MyWindow = Lang.Class({

 ​​ ​​ ​​​​ Name: "MyWindow",

 ​​ ​​ ​​​​ Extends: Gtk.Window,

 

 ​​ ​​ ​​​​ _init: function() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.parent({title: "Simple Notebook Example"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.border_width = 3;

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.notebook = new Gtk.Notebook();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.add(this.notebook);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page1 = new Gtk.Box();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page1.border_width = 10;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page1.add(new Gtk.Label({label: "Default Page!"}));

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.notebook.append_page(this.page1, new Gtk.Label({label: "Plain Title"}));

//

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page3 = new Gtk.Box();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page3.border_width = 10;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page3.add(new Gtk.Label({label: "My Page!!!"}));

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.notebook.append_page(this.page3, new Gtk.Label({label: "My Title"}));

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page4 = new Gtk.Box();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page4.border_width = 15;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page4.add(new Gtk.Label({label: "Figo Page!!!"}));

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.notebook.append_page(this.page4, new Gtk.Label({label: "Figo Title"}));

//

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page2 = new Gtk.Box();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page2.border_width = 10;

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page2.add(new Gtk.Label({label: "A page with an image for a title."}));

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.notebook.append_page(

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.page2,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ Gtk.Image.new_from_icon_name("help-about", Gtk.IconSize.MENU)

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ );

 ​​ ​​ ​​​​ }

});

 

let win = new MyWindow();

win.connect("delete-event", Gtk.main_quit);

win.show_all();

Gtk.main();

 

Che emette questo :

​​ 

-Glade

Potete farvi le strutture usando il programma Glade (serve per fare le GUI in GTK3) e poi importarlo nello script:

builder = Gtk.Builder()

builder.add_from_file("file.glade")

Oppure solo una parte (nell’esempio button1 e button2):

builder.add_objects_from_file("file.glade", ("button1", "button2"))

Solo rispettate la struttura quando richiamate il tutto

Esempio di file XML di Glade (per convenzione usa l’estensione del file “.glade”)

<?xml version="1.0" encoding="UTF-8"?>

<interface>

 ​​​​ <!-- interface-requires gtk+ 3.0 -->

 ​​​​ <object class="GtkWindow" id="window1">

 ​​ ​​ ​​​​ <property name="can_focus">False</property>

 ​​ ​​ ​​​​ <signal name="destroy" handler="onDestroy" swapped="no"/>

 ​​ ​​ ​​​​ <child>

 ​​ ​​ ​​ ​​ ​​​​ <object class="GtkButton" id="button1">

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ <property name="label" translatable="yes">button</property>

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ <property name="use_action_appearance">False</property>

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ <property name="visible">True</property>

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ <property name="can_focus">True</property>

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ <property name="receives_default">True</property>

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ <property name="use_action_appearance">False</property>

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ <signal name="pressed" handler="onButtonPressed" swapped="no"/>

 ​​ ​​ ​​ ​​ ​​​​ </object>

 ​​ ​​ ​​​​ </child>

 ​​​​ </object>

</interface>

 

Conclusioni

 

Esistono parecchie altre, per tutti i gusti, qui avrei elencato quelle più usate. Su

https://gjs-tutorial.readthedocs.io/en/latest/introduction.html

Infatti troverete anche altri esempi.

Man mano che la librerie GTK3 si evolve nascono non solo nuovi ma anche quelli vecchi si potenziano. Qui tutta la struttura:

https://developer.gnome.org/gtk3/stable/

Inoltre qui è affrontato il lato di costruire tramite comandi JS mentre esiste anche quella di sfruttare strutture XML molto simili allo XUL, sempre per costruire i widget, brevemente ripreso nel paragrafo Glade.

Il bello è che pur cambiando linguaggio la struttura rimane identica (logicamente rispettando la sintassi del linguaggio) quindi non bisogna re-imparare ad usarle.

Esempio vale questo tutorial su Python

https://python-gtk-3-tutorial.readthedocs.io/en/latest/

Ogniuno può usare il suo stile, esempio con struttura ad Oggetti:

#!/usr/bin/gjs

 

imports.gi.versions.Gtk = '3.0';

const Gtk = imports.gi.Gtk;

 

class WelcomeToTheGrid {

 ​​ ​​ ​​​​ // Create the application itself

 ​​ ​​ ​​​​ constructor() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.application = new Gtk.Application();

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ // Connect 'activate' and 'startup' signals to the callback functions

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.application.connect('activate', this._onActivate.bind(this));

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this.application.connect('startup', this._onStartup.bind(this));

 ​​ ​​ ​​​​ }

 

 ​​ ​​ ​​​​ // Callback function for 'activate' signal presents windows when active

 ​​ ​​ ​​​​ _onActivate() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._window.present();

 ​​ ​​ ​​​​ }

 

 ​​ ​​ ​​​​ // Callback function for 'startup' signal builds the UI

 ​​ ​​ ​​​​ _onStartup() {

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._buildUI ();

 ​​ ​​ ​​​​ }

 

 ​​ ​​ ​​​​ // Build the application's UI

 ​​ ​​ ​​​​ _buildUI() {

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ // Create the application window

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._window = new Gtk.ApplicationWindow({

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ application: this.application,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ window_position: Gtk.WindowPosition.CENTER,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ border_width: 10,

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ title: "Welcome to the Grid"});

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ // Create an image

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._image = new Gtk.Image ({ file: "02_jsgrid_02.png" });

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ // Create a label

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._label = new Gtk.Label ({ label: "Welcome to GNOME, too!" });

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ // Create the Grid

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._grid = new Gtk.Grid ();

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ // Attach the image and label to the grid

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._grid.attach (this._image, 0, 0, 1, 1);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._grid.attach (this._label, 0, 1, 1, 1);

 ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ // Add the grid to the window

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._window.add (this._grid);

 

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ // Show the window and all child widgets

 ​​ ​​ ​​ ​​ ​​ ​​ ​​​​ this._window.show_all();

 ​​ ​​ ​​​​ }

 

};

 

// Run the application

let app = new WelcomeToTheGrid ();

app.application.run (ARGV);

https://developer.gnome.org/gnome-devel-demos/stable/02_welcome_to_the_grid.js.html.en

 

Ciaooooooooooooooooooooooooooooooooo

 

 

 

Precedente Fare script in SUSE Successivo Installare OpenSuse 15-1 e poi?