<?xml version="1.0" encoding="utf-8"?>
<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="topic" style="task" id="02_welcome_to_the_grid.js" xml:lang="sv">
  <info>
    <link type="guide" xref="beginner.js#tutorials"/>
    <link type="seealso" xref="grid.js"/>
    <link type="seealso" xref="image.js"/>
    <link type="seealso" xref="label.js"/>
    <revision version="0.1" date="2012-07-28" status="draft"/>

    <credit type="author copyright">
      <name>Taryn Fox</name>
      <email its:translate="no">jewelfox@fursona.net</email>
      <years>2012</years>
    </credit>

    <desc>Lär dig hur du placerar ut komponenter för användargränssnitt, så som bilder och etiketter.</desc>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Sebastian Rasmussen</mal:name>
      <mal:email>sebras@gmail.com</mal:email>
      <mal:years>2019</mal:years>
    </mal:credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Anders Jonsson</mal:name>
      <mal:email>anders.jonsson@norsjovallen.se</mal:email>
      <mal:years>2021</mal:years>
    </mal:credit>
  </info>

  <title>2. Välkommen till rutnätet</title>
  <synopsis>
    <p>Denna handledning kommer att visa dig hur du skapar grundläggande komponenter eller delar av ett GNOME-användargränssnitt, så som bilder (Image) och etiketter (Label). Du kommer därefter att få lära dig att arrangera dem i ett rutnät (Grid), vilket låter dig placera komponenter precis där du vill ha dem.</p>
    <note style="warning"><p>Har du redan gått genom <link xref="hellognome.js">den första handledningen i denna serie</link>? Du kommer att behöva ha gjort det innan du fortsätter.</p></note>
  </synopsis>

  <links type="section"/>

  <section id="native">
    <title>Att köra inhemskt</title>

    <p>I den senaste handledningen skapade vi vad som praktiskt taget var en GNOME-fönsterram för en webbapplikation. All GNOME-specifik kod som vi behövde lära oss kretsade kring att sätta denna WebView — komponenten som innehåller vårt program — i ett ApplicationWindow, och säga till den att visas. Programmet själv skrevs i HTML och Javascript, precis som de flesta sidor på webben.</p>
    <p>Denna gång kommer vi att enbart använda inhemska GNOME-komponenter. En komponent är en sak, så som en kryssruta eller en bild, och GNOME har en uppsjö att välja bland. Vi kallar dem ”inhemska” komponenter för att särskilja dem från saker som knappen och rubriken i webbapplikationen vi skrev. Istället för att använda webbkod kommer dessa att vara 100 procent GNOME, genom att använda GTK+.</p>
    <note style="tip"><p>GTK+ står för ”GIMP Tookit”. Det är som en verktygslåda av komponenter som du kan använda när du bygger dina program. Det skrevs från början för <link href="http://www.gimp.org/">GIMP</link>, vilket är fri programvara för att redigera bilder.</p></note>
  </section>

  <section id="setup">
    <title>Konfigurera ditt program</title>

    <p>Innan vi gräver fram några komponenter från GTK+-verktygslådan måste vi först skriva den grundläggande standardkoden som vårt program kräver.</p>
    <code mime="application/javascript">
#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;
</code>
    <p>Denna del finns alltid i början av din kod. Beroende på vad du ska göra med det kan du komma att vilja deklarera fler importer här. Det vi skriver idag är ganska grundläggande så detta är allt vi behöver; Gtk för komponenter, via det stabila API:t ”3.0”.</p>
    <p>På tal om det:</p>
    <code mime="application/javascript">
class WelcomeToTheGrid {
    // Skapa programmet i sig
    constructor() {
        this.application = new Gtk.Application();

        // Anslut ”activate”- och ”startup”-signaler till återanropsfunktionerna
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Återanropsfunktion för ”activate”-signal visar fönster när den aktiveras
    _onActivate() {
        this._window.present();
    }

    // Återanropsfunktion för ”startup”-signal bygger användargränssnittet
    _onStartup() {
        this._buildUI ();
    }
</code>
    <p>Detta är starten på programmet i sig, och _init-funktionen som skapar det. Det berättar för _buildUI att skapa ett ApplicationWindow, vilket vi kommer kalla för _window, och berätta för vårt fönster att presentera sig sig själv närhelst det behövs.</p>
    <p>Denna del är, återigen, ganska mycket kopiera och klistra, men du kommer alltid att vilja ge ditt program ett unikt namn.</p>

    <code mime="application/javascript">
    // Bygg programmets användargränssnitt
    _buildUI() {

        // Skapa programmets fönster
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            border_width: 10,
            title: "Välkommen till Grid"});
</code>
    <p>Avslutningsvis kommer vi att börja _buildUI-funktionen genom att skapa ett nytt ApplicationWindow. Vi anger att det följer med detta program, att det ska dyka upp mitt på skärmen och att det bör finnas åtminstone 10 bildpunkter mellan den utvändiga kanten och komponenter inuti. Vi ger det också en titel som kommer att visas i toppen av fönstret.</p>
  </section>

  <section id="toolbox">
    <title>Att gräva i GTK+-verktygslådan</title>
    <p>Vilka komponenter ska vi använda? Låt säga att vi vill skriva ett program som ser ut så här:</p>

    <media type="image" mime="image/png" src="media/02_jsgrid_01.png"/>

    <p>Vi kommer åtminstone att behöva en bild och en textetikett som följer med den. Låt oss börja med bilden:</p>
    <code mime="application/javascript">
        // Skapa en bild
        this._image = new Gtk.Image ({ file: "gnome-image.png" });
</code>

    <p>Du kan hämta bildfilen som används i detta exempel <link href="https://live.gnome.org/TarynFox?action=AttachFile&amp;do=get&amp;target=gnome-image.png">här</link>. Säkerställ att du placerar den i samma katalog som koden du skriver.</p>

    <code mime="application/javascript">
        // Skapa en etikett
        this._label = new Gtk.Label ({ label: "Välkommen även till GNOME!" });
</code>
    <p>Den koden lägger till etiketten nedanför. Du kan se hur vi skapar komponenter här; var och en är en del av Gtk och vi kan ge dem egenskaper som anpassar hur de beter sig. I detta fall sätter vi file-egenskapen för denna Image till att vara filnamnet på bilden vi önskar visa, och Labelns label-egenskap till att vara meningen vi vill ha under bilden.</p>
    <note style="tip"><p>Ja, det kan låta överflödigt att ha en Label som har en label-egenskap, men det är det inte. Andra komponenter som innehåller text har en label-egenskap, så det är <em>konsekvent</em> att Label-komponenten också har en.</p></note>
    <p>Vi kan dock inte bara lägga till dessa komponenter i vårt fönster i ordning, på samma sätt som HTML-element dyker upp i ordningen du skriver dem. Detta är för att ApplicationWindow endast kan innehålla en komponent.</p>
    <p>Hur kommer vi runt det? Genom att skapa en komponent som fungerar som en behållarkomponent, som kan innehålla mer än en komponent och organisera dem inuti. Skåda: Grid (rutnätet).</p>
    <code mime="application/javascript">
        // Skapa rutnätet
        this._grid = new Gtk.Grid ();
</code>

    <p>Vi ger det inga egenskaper än. Dessa kommer senare allt eftersom vi lär oss att använda Grids krafter. Först, låt oss koppla den Image och Label vi skapade till vår Grid.</p>
    <code mime="application/javascript">
        // Koppla bilden och etiketten till rutnätet
        this._grid.attach (this._image, 0, 0, 1, 1);
        this._grid.attach (this._label, 0, 1, 1, 1);
</code>

    <p>Denna kod ser oerhört komplicerad ut, men det är den inte. Detta är vad numren betyder:</p>
    <list type="numbered">
      <item><p>Det <em>första</em> numret är på vilken vänster-till-höger-position som saker ska placeras på, med början på 0. En komponent som använder 0 här, placeras längst till vänster.</p></item>
      <item><p>Det <em>andra</em> numret är på vilken topp-till-botten-position som en komponent ska placeras på, med början på 0. Labeln ska placeras under bilden, så vi anger 0 för Image och 1 för Label här.</p></item>
      <item><p>Det <em>tredje</em> och <em>fjärde</em> numret är hur många kolumner och rader en komponent ska uppta. Vi kommer att se hur dessa fungerar om en liten stund.</p></item>
    </list>

    <code mime="application/javascript">
        // Lägg till rutnätet till fönstret
        this._window.add (this._grid);

        // Visa fönstret och alla barnkomponenter
        this._window.show_all();
    }

};

// Kör programmet
let app = new WelcomeToTheGrid ();
app.application.run (ARGV);
</code>
    <p>Nu när vi skapat Grid och kopplat alla komponenter till den, så kan vi lägga till den till fönstret och be fönstret att visa sig självt, som det sista steget i _buildUI-funktionen. Som alltid avslutar vi med att skapa en ny instans av programmets klass och be den att köra.</p>
    <p>Spara ditt program som welcome_to_the_grid.js. Sedan, för att köra ditt program, öppna en terminal, gå till katalogen där ditt program finns och skriv</p>
      <screen> <output style="prompt">$ </output>gjs welcome_to_the_grid.js </screen>

    <media type="image" mime="image/png" src="media/02_jsgrid_02.png"/>

    <p>Där har vi det! Men vänta! Det ser inte helt rätt ut. Varför är Labeln upptryckt intill bilden på det där sättet? Det ser inte så fint ut och det gör det svårare att läsa. Vad kan vi göra åt detta?</p>
  </section>

  <section id="tweaking">
    <title>Att anpassa Grid</title>

    <p>En sak vi kan göra är att ge Labeln en margin_top-egenskap när vi skapar den. Detta fungerar lite grann som att sätta en marginal för ett HTML-element via inbyggda CSS-stilar.</p>
    <code mime="application/javascript">
        // Skapa en etikett
        this._label = new Gtk.Label ({
            label: "Välkommen även till GNOME!",
            margin_top: 20 });
</code>

    <p>Men om vi gör det så kommer vi så klart ifall vi ersätter Labeln med någonting annat — eller lägger in en annan komponent — även behöva upprepa margin_top för denna. Annars kommer det att sluta med att vi har någonting i stil med detta:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_03.png"/>

    <p>Vi skulle kunna ange en margin_bottom-egenskap för Imagen, men det kommer inte att fungera när Labeln är i en separat kolumn. Så hur vore det om vi provade med detta istället:</p>
    <code mime="application/javascript">
        // Skapa Grid
        this._grid = new Gtk.Grid ({
            row_spacing: 20 });
</code>

    <p>Detta kommer att göra så att det alltid finns 20 bildpunkter utrymme mellan varje horisontell rad.</p>
    <note style="tip"><p>Ja, du kan också sätta column_spacing-egenskapen på en Grid, eller margin_left- och margin_right-egenskaper på vilken komponent som helst. Prova dem om du vill!</p></note>
  </section>

  <section id="adding">
    <title>Lägga till fler komponenter</title>

    <p>Om vi skulle vilja lägga till en andra Label, hur skulle vi då göra så att det faktiskt såg ut som om den passade in? Ett sätt är att centrera Imagen i toppen så att den ligger ovanför båda förekomsterna av Label istället för bara den till vänster. Det är här dessa andra nummer i Grids attach-method kommer in:</p>
    <code mime="application/javascript">
        // Skapa en andra etikett
        this._labelTwo = new Gtk.Label ({
            label: "The cake is a pie." });

        // Koppla bilden och etiketterna till rutnätet
        this._grid.attach (this._image, 0, 0, 2, 1);
        this._grid.attach (this._label, 0, 1, 1, 1);
        this._grid.attach (this._labelTwo, 1, 1, 1, 1);
</code>

    <p>Efter att vi skapat den andra Labeln, kopplar vi den till Grid till höger om den första Labeln. Kom ihåg att de första två numren räknar kolumner och rader från vänster till höger och från topp till botten, med början på 0. Som om den första Labeln är i kolumn 0 och rad 1, då kan vi placera den andra i kolumn 1 och rad 1 för att placera den till höger om den första Labeln.</p>
    <p>Notera numret 2 i attach-uttrycket för Imagen. Det är själva tricket här. Det numret är hur många kolumner Imagen sträcker sig över, eller hur? Så när vi för allting samman får vi någonting i stil med detta:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_04.png"/>

    <p>Det finns två saker som du bör notera här.</p>
    <list>
      <item><p>Att sätta Imagen till att sträcka sig över två kolumner sträcker inte bilden i sig horisontellt. Istället sträcker det den osynliga rutan som tas upp av Image-komponenten så att den fyller båda kolumnerna, sedan placeras Imagen i mitten på den rutan.</p></item>
      <item><p>Även om vi har satt Grids row_spacing- och ApplicationWindows border_width-egenskaper så har vi ännu inte satt någonting som skapar en kant mellan de två förekomsterna av Label. De var separata tidigare när Imagen bara var i en kolumn men nu när den sträcker sig över båda så ser GNOME inte en orsak till att hålla isär dem.</p></item>
    </list>

    <p>Det finns åtminstone tre sätt på vilka vi kan kommer runt det sistnämnda. Först kan vi sätta margin_left eller margin_right på endera av förekomsterna av Label:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_05.png"/>

    <p>För det andra kan vi sätta Grids column_homogeneous-egenskap till true.</p>
    <code mime="application/javascript">
        // Skapa Grid
        this._grid = new Gtk.Grid ({
            column_homogeneous: true,
            row_spacing: 20 });
</code>

    <p>Detta gör att det ser ut något i stil med det här:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_06.png"/>

    <p>Och för det tredje kan vi sätta Grids column_spacing-egenskap på samma sätt som vi satt dess row_spacing.</p>
    <code mime="application/javascript">
        // Skapa Grid
        this._grid = new Gtk.Grid ({
            column_spacing: 20,
            row_spacing: 20 });
</code>
    <p>Detta får det att se ur så här:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_07.png"/>
  </section>

  <section id="stock">
    <title>Att använda standardbilder</title>

    <p>GNOME har redan massor av standardbilder till hands, som vi kan använda om vi inte känner för att skapa egna eller om vi vill ha en universellt igenkänd ikon. Så här skapar vi en standardbild, jämfört med hur vi skapar en normal bild:</p>
    <code mime="application/javascript">
        // Skapa en bild
        this._image = new Gtk.Image ({ file: "gnome-image.png" });

        // Skapa en andra bild genom att använda en standardikon
        this._icon = new Gtk.Image ({ stock: 'gtk-about' });
</code>
    <p>Efter det kopplar vi det till Grid till vänster om vår första Label. (Vi använder inte den andra i detta exempel.)</p>
    <code mime="application/javascript">
        // Koppla bilderna och etiketten till rutnätet
        this._grid.attach (this._image, 0, 0, 2, 1);
        this._grid.attach (this._icon,  0, 1, 1, 1);
        this._grid.attach (this._label, 1, 1, 1, 1);
</code>
    <p>När vi kör det, ger detta oss:</p>
    <media type="image" mime="image/png" src="media/02_jsgrid_08.png"/>

    <p>Så ser standardikonen ”Om” ut. Du kan se en lista över alla standardobjekt från gtk-about och framåt i <link href="https://developer.gnome.org/gtk3/3.4/gtk3-Stock-Items.html#GTK-STOCK-ABOUT:CAPS">GNOME:s utvecklardokumentation</link>. Den skrevs för C-programmerare, men du måste inte känna till C för att använda den; bara titta på delen inom citationstecken, så som 'gtk-about' och kopiera den delen för att använda ikonen intill.</p>
    <note style="tip"><p>Vi placerar enkla citattecken runt 'gtk-about' här eftersom den delen aldrig kommer att behöva översättas till ett annat språk (till skillnad från textsträngar som har dubbla citattecken runt sig). Om det faktiskt <em>blev</em> översatt skulle det ha sönder ikonen eftersom dess namn fortfarande är "gtk-about" oavsett vilket språk du talar.</p></note>
  </section>


  <section id="next">
    <title>Vad är nästa steg?</title>
    <p>Innan vi går vidare till nästa handledning, låt oss prova något annat:</p>
    <code mime="application/javascript">
        // Skapa en knapp
        this._button = new Gtk.Button ({
            label: "Välkommen även till GNOME!"});

        // Koppla bilderna och knappen till rutnätet
        this._grid.attach (this._image,  0, 0, 2, 1);
        this._grid.attach (this._icon,   0, 1, 1, 1);
        this._grid.attach (this._button, 1, 1, 1, 1);
</code>

    <p>Det är helt rätt, vi gjorde om Labeln till en Button bara genom att ändras dess namn! Om du kör programmet och klickar på den så kommer du dock att upptäcka att den inte gör något. Hur får vi vår Button att göra något? Det kommer vi att upptäcka i <link xref="03_getting_the_signal.js">nästa handledning</link>.</p>
    <p>Om du vill, spendera lite tid på att experimentera med Grid, Label och Image, inklusive standardbilder.</p>
    <note style="tip"><p>Ett trick du kan använda för att åstadkomma mer komplexa layouter är att nästla flera Grid inuti varandra. Detta låter dig gruppera relaterade komponenter och enkelt omarrangera dem. Titta på kodexemplet <link xref="radiobutton.js">RadioButton</link> om du vill se hur detta görs.</p></note>
  </section>

  <section id="complete">
    <title>Fullständigt kodexempel</title>
<code mime="application/javascript" style="numbered">#!/usr/bin/gjs

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

class WelcomeToTheGrid {

    // Skapa programmet i sig
    constructor() {
        this.application = new Gtk.Application();

    // Anslut ”activate”- och ”startup”-signaler till återanropsfunktionerna
    this.application.connect('activate', this._onActivate.bind(this));
    this.application.connect('startup', this._onStartup.bind(this));
    }

    // Återanropsfunktion för ”activate”-signal visar fönster när den aktiveras
    _onActivate() {
        this._window.present();
    }

    // Återanropsfunktion för ”startup”-signal bygger användargränssnittet
    _onStartup() {
        this._buildUI ();
    }

    // Bygg programmets användargränssnitt
    _buildUI() {

        // Skapa programmets fönster
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            border_width: 10,
            title: "Välkommen till Grid"});

        // Skapa Grid
        this._grid = new Gtk.Grid ({
            // column_homogeneous: true,
            // column_spacing: 20,
            row_spacing: 20 });

        // Skapa en bild
        this._image = new Gtk.Image ({ file: "gnome-image.png" });

        // Skapa en andra bild med hjälp av en standardikon
        this._icon = new Gtk.Image ({ stock: 'gtk-about' });

        // Skapa en etikett
        this._label = new Gtk.Label ({
            label: "Välkommen även till GNOME!",
            /* margin_top: 20 */ });

        /* Skapa en andra etikett
        this._labelTwo = new Gtk.Label ({
            label: "The cake is a pie." }); */

        /* Skapa en knapp
        this._button = new Gtk.Button ({
            label: "Välkommen även till GNOME!"}); */

        // Anslut bilderna och knappen till rutnätet
        this._grid.attach (this._image,  0, 0, 2, 1);
        this._grid.attach (this._icon,   0, 1, 1, 1);
        this._grid.attach (this._label,  1, 1, 1, 1);

        // this._grid.attach (this._label, 0, 1, 1, 1);
        // this._grid.attach (this._labelTwo, 1, 1, 1, 1);

        // this._grid.attach (this._button, 1, 1, 1, 1);

        // Lägg till rutnätet till fönstret
        this._window.add (this._grid);

        // Visa fönstret och alla barnkomponenter
        this._window.show_all();
    }

};

// Kör programmet
let app = new WelcomeToTheGrid ();
app.application.run (ARGV);
</code>
  </section>

</page>
