Development/Tutorials/Qt4 Ruby Tutorial/Chapter 08/fi: Difference between revisions

From KDE TechBase
(Created page with "Tiedostot:")
(Updating to match new version of source page)
 
(46 intermediate revisions by one other user not shown)
Line 1: Line 1:
<languages />
<languages />


{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 08}}


{{TutorialBrowser|
{{TutorialBrowser|
Line 17: Line 16:
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t8/cannon.rb cannon.rb]
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t8/cannon.rb cannon.rb]


=== Overview ===
=== Yleistä ===


In this example, we introduce the first custom widget that can paint itself. We also add a useful keyboard interface (with two lines of code).  
Tässä esimerkissä esittelemme ensimmäisen räätälöidyn käyttöliittymäkomponentin, joka voi piirtää itsensä. Lisäämme myös hyödyllisen näppäimistörajapinnan (kahdella koodirivillä).  


=== Line by Line Walkthrough ===
=== Läpikäynti rivi riviltä ===
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t8/lcdrange.rb lcdrange.rb]'''
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t8/lcdrange.rb lcdrange.rb]'''


This file is very similar to the lcdrange.rb in [[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_07|Chapter 7]]. We have added one slot: '''<tt>setRange()</tt>'''.
Tämä tiedosto on hyvin samanlainen kuin lcdrange.rb [[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_07|Kappaleessa 7]]. Olemme lisänneet yhden välin: '''<tt>setRange()</tt>'''.


We now add the possibility of setting the range of the '''<tt>LCDRange</tt>'''. Until now, it has been fixed at 0 to 99.
Lisäämme nyt mahdollisuuden asettaa '''<tt>LCDRange</tt>'''-lukualueen. Tähän asti se on ollut kiinteä välillä 0 ... 99.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 41: Line 40:
</syntaxhighlight>
</syntaxhighlight>


The '''<tt>setRange()</tt>''' slot sets the range of the slider in the '''<tt>LCDRange</tt>'''. Because we have set up the [http://doc.qt.nokia.com/latest/qlcdnumber.html QLCDNumber] to always display two digits, we want to limit the possible range of '''<tt>minVal</tt>''' and '''<tt>maxVal</tt>''' to avoid overflow of the [http://doc.qt.nokia.com/latest/qlcdnumber.html QLCDNumber]. (We could have allowed values down to -9 but chose not to.) If the arguments are illegal, we use Qt's [http://doc.qt.nokia.com/latest/qtglobal.html#qWarning QtGlobal::qWarning()] function to issue a warning to the user and return immediately. [http://doc.qt.nokia.com/latest/qtglobal.html#qWarning QtGlobal::qWarning()] is a '''<tt>printf</tt>'''-like function that by default sends its output to '''<tt>$stderr</tt>'''. If you want, you can install your own handler function using [http://doc.qt.nokia.com/latest/qtglobal.html#qInstallMsgHandler QtGlobal::qInstallMsgHandler()].
'''<tt>setRange()</tt>'''-väli asettaa liukukytkimen lukualueen '''<tt>LCDRange</tt>'''. Koska olemme asettaneet [http://doc.qt.nokia.com/latest/qlcdnumber.html QLCDNumber] näyttämään aina kaksi numeroa, haluamme rajoittaa mahdollisen lukualueen '''<tt>minVal</tt>''' ja '''<tt>maxVal</tt>''' ylivuoden välttämiseksi käyttöliittymäkomponentissa [http://doc.qt.nokia.com/latest/qlcdnumber.html QLCDNumber]. (Meillä olisi lupa laskea arvot aina arvoon -9, mutta valitsemme olemaan tekemättä sitä.) Jos argumentit ovat virheellisiä, käytämme Qt:n [http://doc.qt.nokia.com/latest/qtglobal.html#qWarning QtGlobal::qWarning()]-funktiota julkaisemaan varoituksen käytäjälle ja palaamme välittömästi. [http://doc.qt.nokia.com/latest/qtglobal.html#qWarning QtGlobal::qWarning()] on '''<tt>printf</tt>'''-tyyppinen funktio, joka oletuksena lähettää tulosteensa kohteeseen '''<tt>$stderr</tt>'''. Jos haluat, voit asentaa oman käsittelijäfunktion käyttäen [http://doc.qt.nokia.com/latest/qtglobal.html#qInstallMsgHandler QtGlobal::qInstallMsgHandler()]-objektia.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 47: Line 46:
</syntaxhighlight>
</syntaxhighlight>


This makes our lcd numbers look way better. I'm not certain, but I believe what makes it possible to do this is setting a palette (see next section). What I do know is that this line has no effect when I tried it in previous chapters, but works here.
Tämä saa nestekidenumeromme näyttämään paremmilta. En ole varma, mutta uskon, että mikä tekee sen mahdolliseksi on paletin asettaminen (katso seuraava lohko). Tiedän nyt, on että tällä rivillä ei ollut vaikutusta kun sitä yritettiin edellisessä kappaleessa, mutta se toimii tässä.


'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t8/cannon.rb cannon.rb]'''
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t8/cannon.rb cannon.rb]'''
Line 57: Line 56:
</syntaxhighlight>
</syntaxhighlight>


The constructor initializes the angle value to 45 degrees and sets a custom palette for this widget.
Konstruktori alustaa kulma-arvon 45 asteeseen ja asettaa räätälöidyn paletin tälle käyttöliittymäkomponentille.


This palette uses the indicated color as background and picks other colors suitably. (For this widget only the background and text colors will actually be used.) We then call setAutoFillBackground(true) to tell Qt fill the background automatically.
Tämä paletti käyttää indikoitua väriä taustana ja poimii muita värejä siihen sopivasti. (Tälle käyttöliittymäkomponentille käytetään todellisuudessa vain tausta- ja tekstivärit). Kutsumme sitten setAutoFillBackground(true) kertomaan Qt:lle, että taustan voi täyttää automaattisesti.


The [http://doc.qt.nokia.com/latest/qcolor.html Qt::Color] is specified as a RGB (red-green-blue) triplet, where each value is between 0 (dark) and 255 (bright). We could also have used a predefined color such as [http://doc.qt.nokia.com/latest/qt.html#GlobalColor-enum Qt::yellow] instead of specifying an RGB value.
[http://doc.qt.nokia.com/latest/qcolor.html Qt::Color] määriteltiin RGB (punainen-vihreä-sininen) -triplettinä, missä jokainen arvo on välillä 0 (tumma) ja 255 (kirkas). Voisimme myös käyttää ennakolta määriteltyjä värejä kuten [http://doc.qt.nokia.com/latest/qt.html#GlobalColor-enum Qt::yellow] eikä RGB-arvojen määrittelyjä.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 81: Line 80:
</syntaxhighlight>
</syntaxhighlight>


This function sets the angle value. We have chosen a legal range of 5 to 70 and adjust the given number of degrees accordingly. We have chosen not to issue a warning if the new angle is out of range.
Tämä funktio asettaa kulma-arvon. Olemme valinneet lailliseksi arvoalueeksi 5 ... 70 ja säätäneet annetun asetenumeron sen mukaan. Olemme valinneet, että emme julkaise varoitusta, jos uusi kulma on lukualueen ulkopuolella.


If the new angle equals the old one, we return immediately. It is important to only emit the '''<tt>angleChanged()</tt>''' signal when the angle really has changed.
Jos uusi kulma on sama kuin vanha, palaamme välittömästi. On tärkeää lähettää vain '''<tt>angleChanged()</tt>'''-signaali kun kulma on todella muuttunut.


Then we set the new angle value and repaint our widget. The [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] function clears the widget (usually filling it with its background color) and sends a paint event to the widget. This results in a call to the paint event function of the widget.
Sitten asetamme uuden kulman ja piirrämme käyttöliittymäkomponenttimme. [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()]-funktio tyhjentää käyttöliittymäkomponentin (tavallisesti täyttämällä sen taustavärin) ja asettaa piirtämistapahtuman käyttöliittymäkomponentille. Tästä seuraa kutsu käyttöliittymäkomponentin piirtämistapahtumafunktiolle.


Finally, we emit the '''<tt>angleChanged()</tt>''' signal to tell the outside world that the angle has changed. The '''<tt>emit</tt>''' keyword is unique to Qt and not regular Ruby syntax.
Lopuksi lähetämme '''<tt>angleChanged()</tt>'''-signaalin kertomaan ulkopuoliselle maailmalle, että kulma on muuttunut. Avainsana '''<tt>emit</tt>''' on ainutlaatuinen Qt:lle ja ei ole säännöllistä Ruby-syntaksia.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 97: Line 96:
</syntaxhighlight>
</syntaxhighlight>


This is our first attempt to write a paint event handler. The event argument contains a description of the paint event. [http://doc.qt.nokia.com/latest/qpaintevent.html Qt::PaintEvent] contains the region in the widget that must be updated. For the time being, we will be lazy and just paint everything.
Tämä oli ensimmäinen yrityksemme kirjoittaa piirtämistapahtumakäsittelijä. Tapahtuma.argumentti sisältää piirtämistapahtuman kuvauksen. [http://doc.qt.nokia.com/latest/qpaintevent.html Qt::PaintEvent] sisältää käyttöliittymäkomponentin alueen, joka on päivitettävä. Toistaiseksi olemma laiskoja ja piirrämme kaikki.


Our code displays the angle value in the widget at a fixed position. We create a [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter] operating on this widget and use it to paint a string. We'll come back to [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter] later; it can do a great many things.
Koodimme näyttää kulma-arvon käyttöliittymäkomponentissa kiinteässä paikassa. Luomme [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter]-toiminnon tälle käyttöliittymäkomponentille ja käytämme sitä merkkijonon piirtämiseen. Palaamme [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter]-toimintoon myöhemmin; se voi tehdä todella monia asioita.


'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t8/t8.rb t8.rb]'''
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t8/t8.rb t8.rb]'''
Line 108: Line 107:
</syntaxhighlight>
</syntaxhighlight>


In the constructor, we create and set up the LCDRange widget. We set the LCDRange to accept angles from 5 to 70 degrees.
Konstruktorissa luomme ja asetamme LCDRange-käyttöliittymäkomponentin. Asetamme LCDRange-komponentin hyväksymään kulmat välillä 5 ... 70 astetta.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 114: Line 113:
</syntaxhighlight>
</syntaxhighlight>


We create our CannonField widget.
Luomme CannonField-käyttöliittymäkomponentin.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 123: Line 122:
</syntaxhighlight>
</syntaxhighlight>


Here we connect the '''<tt>valueChanged()</tt>''' signal of the '''<tt>LCDRange</tt>''' to the '''<tt>setValue()</tt>''' slot of the '''<tt>CannonField</tt>'''. This will update '''<tt>CannonField</tt>''''s angle value whenever the user operates the '''<tt>LCDRange</tt>'''. We also make the reverse connection so that changing the angle in the '''<tt>CannonField</tt>''' will update the '''<tt>LCDRange</tt>''' value. In our example we never change the angle of the '''<tt>CannonField</tt>''' directly; but by doing the last connect() we ensure that no future changes will disrupt the synchronization between those two values.
Tässä yhdistämme '''<tt>LCDRange</tt>'''-komponentin '''<tt>valueChanged()</tt>'''-signaalin '''<tt>CannonField</tt>'''-kentän '''<tt>setValue()</tt>'''-väliin . Tämä päivittää '''<tt>CannonField</tt>'''-kentän kulma-arvon joka kerran, kun käyttäjä käyttää '''<tt>LCDRange</tt>'''-komponenttia. Teemme myös päinvastaisen yhteyden niin että kulman muuttuminen '''<tt>CannonField</tt>'''-kentässä päivittää '''<tt>LCDRange</tt>'''-arvon. Esimerkissämme emme koskaan muuta '''<tt>CannonField</tt>'''-kulmaa suoraan; mutta tekemällä viimeisen connect() varmistamme, että mikään tulevaisuuden muutos ei häiritse noiden kahden arvon välistä synkronointia.


This illustrates the power of component programming and proper encapsulation.
Tämä kuvaa komponenttiohjelmoinnin voimaa ja oikeaa kapselointia.


Notice how important it is to emit the '''<tt>angleChanged()</tt>''' signal only when the angle actually changes. If both the '''<tt>LCDRange</tt>''' and the '''<tt>CannonField</tt>''' had omitted this check, the program would have entered an infinite loop upon the first change of one of the values.
Huomaa kuinka on tärkeää lähettää '''<tt>angleChanged()</tt>'''-signaali vain silloin kun kulma todella muuttuu. Jos sekä '''<tt>LCDRange</tt>''' että '''<tt>CannonField</tt>''' ohittivat tämän tarkistuksen, ohjelma siirtyisi päättymättömään silmukkaan toisen arvon ensimmäisellä muutoksella.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 133: Line 132:
</syntaxhighlight>
</syntaxhighlight>


So far, we have used [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::VBoxLayout] for geometry management. Now, however, we want to have a little more control over the layout, and we switch to the more powerful [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] class. [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] isn't a widget; it is a different class that can manage the children of any widget.
Toistaiseksi olemme käyttäneet [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::VBoxLayout]-luokkaa ulkoasuhallintaan. Nyt haluamme kuintenkin hallita ulkoasua paremmin, ja vaihdamme tehokkaampaan [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout]-luokkaan. [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] ei ole käyttöliittymäkomponenttit; se on erilainen luokka, joka hallitsee minkä tahansa käyttöliittymäkomponentin lapsia.


We don't need to specify any dimensions to the [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::GridLayout] constructor. The [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] will determine the number of rows and columns based on the grid cells we populate.
Meidän ei tarvitse määritellä mitään mittoja [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::GridLayout]-konstruktorille. Luokka [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] määrittelee rivien ja sarakkeiden lukumäärän niiden rasterisolujen perusteella, jotka otamme käyttöön.


[[Image:Qt4_Ruby_Tutorial_Screenshot_8-layout.png]][[Image:Qt4_Ruby_Tutorial_Screenshot_8-reallayout.png]]
[[Image:Qt4_Ruby_Tutorial_Screenshot_8-layout.png]][[Image:Qt4_Ruby_Tutorial_Screenshot_8-reallayout.png]]


The diagram above shows the layout we're trying to achieve. The left side shows a schematic view of the layout; the right side is an actual screenshot of the program. ''(These two images are copyrighted/owned by Nokia.)''
Yllä oleva kuva näyttää asettelun, jonka yritämme saavuttaa. Vasen puoli näyttää asettelun kytkentäkaaviopuolen; oikea puoli on ohjelman todellinen näytönkaappaus. ''(Nokia omistaa näiden kahden kuvan copyright-oikeudet.)''


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 145: Line 144:
</syntaxhighlight>
</syntaxhighlight>


We add the <strong>Quit</strong> button in the top-left cell of the grid, i.e., the cell with coordinates (0, 0).
Lisäämme <strong>Quit</strong>-painikkeen rasterin vasempaan yläkulmaan, ts. solun koordinaatit ovat (0, 0).


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 151: Line 150:
</syntaxhighlight>
</syntaxhighlight>


We put the angle '''<tt>LCDRange</tt>''' cell (1, 0).
Laitamme kulman '''<tt>LCDRange</tt>''' soluun (1, 0).


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 157: Line 156:
</syntaxhighlight>
</syntaxhighlight>


We let the '''<tt>CannonField</tt>''' object occupy cells (1, 1) and (2, 1).
Annamme ''<tt>CannonField</tt>'''-objektin varata solut (1, 1) ja (2, 1).


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 163: Line 162:
</syntaxhighlight>
</syntaxhighlight>


We tell [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] that the right column (column 1) is stretchable, with a stretch factor of 10. Because the left column isn't (its stretch factor is 0, the default value), [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] will try to let the left-hand widgets' sizes be unchanged and will resize just the '''<tt>CannonField</tt>''' when the '''<tt>MyWidget</tt>''' is resized.
Kerromme [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout]-luokalle, että oikea sarake (sarake 1) on venytettävä, venytyskertoimella 10. Koska vasen sarake ei ole venytettävä (sen venytyskerroin on 0, oletusarvo), [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout]-luokka yrittää pitää vasemmanpuoleisen käyttöliittymäkomponentin koon muuttumattomana ja muuttaa vain '''<tt>CannonField</tt>'''-kenttää kun '''<tt>MyWidget</tt>'''-käyttöliittymäkomponentin koko muuttuu.


In this particular example, any stretch factor greater than 0 for column 1 would have the same effect. In more complex layouts, you can use the stretch factors to tell that a particular column or row should stretch twice as fast as another by assigning appropriate stretch factors.
Tässä erityisessä esimerkissä mikä tahansa venytyskerroin, joka on suurempi kuin 0 sarakkeessa 1 aiheuttaisi saman vaikutuksen. Mutkikkaammissa asetteluissa voimme käyttää venytyskerrointa kertomaan, että tietty sarake tai rivi pitäisi venyttää kaksi kertaan niin nopeasti kuin joku toinen asettamalla sopivat venytyskertoimet.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 171: Line 170:
</syntaxhighlight>
</syntaxhighlight>


We set an initial angle value. Note that this will trigger the connection from '''<tt>LCDRange</tt>''' to '''<tt>CannonField</tt>'''.
Asetamme alustuskulma-arvon. Huomaa, että tämä liipaisee yhteyden '''<tt>LCDRange</tt>'''-komponentista '''<tt>CannonField</tt>'''-kenttään.


<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
Line 177: Line 176:
</syntaxhighlight>
</syntaxhighlight>


Our last action is to set '''<tt>angle</tt>''' to have keyboard focus so that keyboard input will go to the '''<tt>LCDRange</tt>''' widget by default.
Viimeinen toimemme on asettaa '''<tt>angle</tt>'''-näppäimistökohdistus niin että näppäimistösyöttö menee oletuksena '''<tt>LCDRange</tt>'''-käyttöliittymäkomponentille.


=== Running the Application ===
=== Sovelluksen suorittaminen ===


When the slider is operated, the '''<tt>CannonField</tt>''' displays the new angle value. Upon resizing, '''<tt>CannonField</tt>''' is given as much space as possible.
Kun liukukytkintä käytetään '''<tt>CannonField</tt>''' näyttää uuden kulma-arvon. Kokoa muutettaessa '''<tt>CannonField</tt>'''-kentälle annetaan tilaa niin paljon kuin on mahdollista.


=== Exercises ===
=== Harjoitukset ===


Try to resize the window. What happens if you make it really narrow or really squat?
Yritä muuttaa ikkuna kokoa. Mitä tapahtuu, jos yrität tehdä siitä todella kapean tai matalan?


If you give the left-hand column a non-zero stretch factor, what happens when you resize the window?
Mitä tapahtuu ikkunan kokoa muutettaessa, jos annat vasemmanpuoleiselle sarakkeelle venytyskertoimen nollasta poikkeavan arvon?


Try to change "Quit" to "&Quit". How does the button's look change? ( Whether it does change or not depends on the platform.) What happens if you press <strong>Alt+Q</strong> while the program is running?
Yritä muuttaa tekstiä "Quit" tekstiksi "&Quit". Kuinka painikkeen ulkoasu muuttuu? (Ulkoasun mahdollinen muuttuminen riippuu käyttöjärjestelmäalustasta.) Mitä tapahtuu, jos painat näppäimiä <strong>Alt+Q</strong> ohjelman suorituksen aikana?


Center the text in the '''<tt>CannonField</tt>'''.
Keskitä teksti '''<tt>CannonField</tt>'''-kentässä.


[[Category:Ruby]]
[[Category:Ruby]]

Latest revision as of 14:20, 18 July 2012

Other languages:


Valmistaudutaan taisteluun
Tutorial Series   Qt4 Ruby -oppikurssi
Previous   Oppikurssi 7 - Yksi asia johtaa toiseen
What's Next   Oppikurssi 9 - Kanuunalla kykenet
Further Reading   n/a

Valmistaudutaan taisteluun

Tiedostot:

Yleistä

Tässä esimerkissä esittelemme ensimmäisen räätälöidyn käyttöliittymäkomponentin, joka voi piirtää itsensä. Lisäämme myös hyödyllisen näppäimistörajapinnan (kahdella koodirivillä).

Läpikäynti rivi riviltä

lcdrange.rb

Tämä tiedosto on hyvin samanlainen kuin lcdrange.rb Kappaleessa 7. Olemme lisänneet yhden välin: setRange().

Lisäämme nyt mahdollisuuden asettaa LCDRange-lukualueen. Tähän asti se on ollut kiinteä välillä 0 ... 99.

def setRange(minVal, maxVal)
  if minVal < 0 || maxVal > 99 || minVal > maxVal
    qWarning("LCDRange::setRange(#{minVal}, #{maxVal})\n" +
               "\tRange must be 0..99\n" +
               "\tand minVal must not be greater than maxVal")
    return
  end

  @slider.setRange(minVal, maxVal)
end

setRange()-väli asettaa liukukytkimen lukualueen LCDRange. Koska olemme asettaneet QLCDNumber näyttämään aina kaksi numeroa, haluamme rajoittaa mahdollisen lukualueen minVal ja maxVal ylivuoden välttämiseksi käyttöliittymäkomponentissa QLCDNumber. (Meillä olisi lupa laskea arvot aina arvoon -9, mutta valitsemme olemaan tekemättä sitä.) Jos argumentit ovat virheellisiä, käytämme Qt:n QtGlobal::qWarning()-funktiota julkaisemaan varoituksen käytäjälle ja palaamme välittömästi. QtGlobal::qWarning() on printf-tyyppinen funktio, joka oletuksena lähettää tulosteensa kohteeseen $stderr. Jos haluat, voit asentaa oman käsittelijäfunktion käyttäen QtGlobal::qInstallMsgHandler()-objektia.

lcd.setSegmentStyle(Qt::LCDNumber::Filled)

Tämä saa nestekidenumeromme näyttämään paremmilta. En ole varma, mutta uskon, että mikä tekee sen mahdolliseksi on paletin asettaminen (katso seuraava lohko). Tiedän nyt, on että tällä rivillä ei ollut vaikutusta kun sitä yritettiin edellisessä kappaleessa, mutta se toimii tässä.

cannon.rb

@currentAngle = 45
setPalette(Qt::Palette.new(Qt::Color.new(250, 250, 200)))
setAutoFillBackground(true)

Konstruktori alustaa kulma-arvon 45 asteeseen ja asettaa räätälöidyn paletin tälle käyttöliittymäkomponentille.

Tämä paletti käyttää indikoitua väriä taustana ja poimii muita värejä siihen sopivasti. (Tälle käyttöliittymäkomponentille käytetään todellisuudessa vain tausta- ja tekstivärit). Kutsumme sitten setAutoFillBackground(true) kertomaan Qt:lle, että taustan voi täyttää automaattisesti.

Qt::Color määriteltiin RGB (punainen-vihreä-sininen) -triplettinä, missä jokainen arvo on välillä 0 (tumma) ja 255 (kirkas). Voisimme myös käyttää ennakolta määriteltyjä värejä kuten Qt::yellow eikä RGB-arvojen määrittelyjä.

def setAngle(angle)
  if angle < 5
    angle = 5
  elsif angle > 70
    angle = 70
  end

  if @currentAngle == angle
    return
  end

  @currentAngle = angle
  update()
  emit angleChanged(@currentAngle)
end  def setAngle(degrees)

Tämä funktio asettaa kulma-arvon. Olemme valinneet lailliseksi arvoalueeksi 5 ... 70 ja säätäneet annetun asetenumeron sen mukaan. Olemme valinneet, että emme julkaise varoitusta, jos uusi kulma on lukualueen ulkopuolella.

Jos uusi kulma on sama kuin vanha, palaamme välittömästi. On tärkeää lähettää vain angleChanged()-signaali kun kulma on todella muuttunut.

Sitten asetamme uuden kulman ja piirrämme käyttöliittymäkomponenttimme. Qt::Widget::update()-funktio tyhjentää käyttöliittymäkomponentin (tavallisesti täyttämällä sen taustavärin) ja asettaa piirtämistapahtuman käyttöliittymäkomponentille. Tästä seuraa kutsu käyttöliittymäkomponentin piirtämistapahtumafunktiolle.

Lopuksi lähetämme angleChanged()-signaalin kertomaan ulkopuoliselle maailmalle, että kulma on muuttunut. Avainsana emit on ainutlaatuinen Qt:lle ja ei ole säännöllistä Ruby-syntaksia.

def paintEvent(event)
  painter = Qt::Painter.new(self)
  painter.drawText(200, 200, tr("Angle = #{@currentAngle}"))
  painter.end()
end

Tämä oli ensimmäinen yrityksemme kirjoittaa piirtämistapahtumakäsittelijä. Tapahtuma.argumentti sisältää piirtämistapahtuman kuvauksen. Qt::PaintEvent sisältää käyttöliittymäkomponentin alueen, joka on päivitettävä. Toistaiseksi olemma laiskoja ja piirrämme kaikki.

Koodimme näyttää kulma-arvon käyttöliittymäkomponentissa kiinteässä paikassa. Luomme Qt::Painter-toiminnon tälle käyttöliittymäkomponentille ja käytämme sitä merkkijonon piirtämiseen. Palaamme Qt::Painter-toimintoon myöhemmin; se voi tehdä todella monia asioita.

t8.rb

angle = LCDRange.new()
angle.setRange(5, 70)

Konstruktorissa luomme ja asetamme LCDRange-käyttöliittymäkomponentin. Asetamme LCDRange-komponentin hyväksymään kulmat välillä 5 ... 70 astetta.

 cannonField = CannonField.new()

Luomme CannonField-käyttöliittymäkomponentin.

connect(angle, SIGNAL('valueChanged(int)'),
        cannonField, SLOT('setAngle(int)'))
connect(cannonField, SIGNAL('angleChanged(int)'),
        angle, SLOT('setValue(int)'))

Tässä yhdistämme LCDRange-komponentin valueChanged()-signaalin CannonField-kentän setValue()-väliin . Tämä päivittää CannonField-kentän kulma-arvon joka kerran, kun käyttäjä käyttää LCDRange-komponenttia. Teemme myös päinvastaisen yhteyden niin että kulman muuttuminen CannonField-kentässä päivittää LCDRange-arvon. Esimerkissämme emme koskaan muuta CannonField-kulmaa suoraan; mutta tekemällä viimeisen connect() varmistamme, että mikään tulevaisuuden muutos ei häiritse noiden kahden arvon välistä synkronointia.

Tämä kuvaa komponenttiohjelmoinnin voimaa ja oikeaa kapselointia.

Huomaa kuinka on tärkeää lähettää angleChanged()-signaali vain silloin kun kulma todella muuttuu. Jos sekä LCDRange että CannonField ohittivat tämän tarkistuksen, ohjelma siirtyisi päättymättömään silmukkaan toisen arvon ensimmäisellä muutoksella.

gridLayout = Qt::GridLayout.new()

Toistaiseksi olemme käyttäneet Qt::VBoxLayout-luokkaa ulkoasuhallintaan. Nyt haluamme kuintenkin hallita ulkoasua paremmin, ja vaihdamme tehokkaampaan Qt::GridLayout-luokkaan. Qt::GridLayout ei ole käyttöliittymäkomponenttit; se on erilainen luokka, joka hallitsee minkä tahansa käyttöliittymäkomponentin lapsia.

Meidän ei tarvitse määritellä mitään mittoja Qt::GridLayout-konstruktorille. Luokka Qt::GridLayout määrittelee rivien ja sarakkeiden lukumäärän niiden rasterisolujen perusteella, jotka otamme käyttöön.

Yllä oleva kuva näyttää asettelun, jonka yritämme saavuttaa. Vasen puoli näyttää asettelun kytkentäkaaviopuolen; oikea puoli on ohjelman todellinen näytönkaappaus. (Nokia omistaa näiden kahden kuvan copyright-oikeudet.)

    gridLayout.addWidget(quit, 0, 0)

Lisäämme Quit-painikkeen rasterin vasempaan yläkulmaan, ts. solun koordinaatit ovat (0, 0).

    gridLayout.addWidget(angle, 1, 0)

Laitamme kulman LCDRange soluun (1, 0).

gridLayout.addWidget(cannonField, 1, 1, 2, 1)

Annamme CannonField'-objektin varata solut (1, 1) ja (2, 1).

    gridLayout.setColumnStretch(1, 10)

Kerromme Qt::GridLayout-luokalle, että oikea sarake (sarake 1) on venytettävä, venytyskertoimella 10. Koska vasen sarake ei ole venytettävä (sen venytyskerroin on 0, oletusarvo), Qt::GridLayout-luokka yrittää pitää vasemmanpuoleisen käyttöliittymäkomponentin koon muuttumattomana ja muuttaa vain CannonField-kenttää kun MyWidget-käyttöliittymäkomponentin koko muuttuu.

Tässä erityisessä esimerkissä mikä tahansa venytyskerroin, joka on suurempi kuin 0 sarakkeessa 1 aiheuttaisi saman vaikutuksen. Mutkikkaammissa asetteluissa voimme käyttää venytyskerrointa kertomaan, että tietty sarake tai rivi pitäisi venyttää kaksi kertaan niin nopeasti kuin joku toinen asettamalla sopivat venytyskertoimet.

    angle.setValue(60)

Asetamme alustuskulma-arvon. Huomaa, että tämä liipaisee yhteyden LCDRange-komponentista CannonField-kenttään.

    angle.setFocus()

Viimeinen toimemme on asettaa angle-näppäimistökohdistus niin että näppäimistösyöttö menee oletuksena LCDRange-käyttöliittymäkomponentille.

Sovelluksen suorittaminen

Kun liukukytkintä käytetään CannonField näyttää uuden kulma-arvon. Kokoa muutettaessa CannonField-kentälle annetaan tilaa niin paljon kuin on mahdollista.

Harjoitukset

Yritä muuttaa ikkuna kokoa. Mitä tapahtuu, jos yrität tehdä siitä todella kapean tai matalan?

Mitä tapahtuu ikkunan kokoa muutettaessa, jos annat vasemmanpuoleiselle sarakkeelle venytyskertoimen nollasta poikkeavan arvon?

Yritä muuttaa tekstiä "Quit" tekstiksi "&Quit". Kuinka painikkeen ulkoasu muuttuu? (Ulkoasun mahdollinen muuttuminen riippuu käyttöjärjestelmäalustasta.) Mitä tapahtuu, jos painat näppäimiä Alt+Q ohjelman suorituksen aikana?

Keskitä teksti CannonField-kentässä.