Olen pitkään kummastellut näitä puhtaasti olio-ohjelmointi kieliä, aiemmin C#, nyt Java. Kaikki koostuu olioista, olio siellä ja olio täällä. Osaan kyllä niitä käyttää, mutta en ymmärrä tätä, kun ohjelma itsessään on olio, eikä sisällä mitään päälooppia.
Esimerkiksi tämä väsäämäni koodi, joka piirtää pyörivän kuution, noh, minusta siellä ei ole mitään looppia, mutta silti se jää päälle eikä vain vilahda. Missä oikein luen syötteet, muutan koordinaatteja jne. Olen ihan pihalla. :(
import javax.media.j3d.*; import javax.vecmath.*; import java.applet.*; import java.awt.*; import com.sun.j3d.utils.applet.*; import com.sun.j3d.utils.geometry.*; import com.sun.j3d.utils.universe.*; public class T3tris { public static void main(String[] args) { // Luodaan ikkuna, ja määritetään sen ominaisuudet GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); Frame frame = new Frame("T3tris", config); frame.setSize(800, 600); frame.setLayout(new BorderLayout()); Canvas3D canvas = new Canvas3D(config); frame.add("Center", canvas); // Luodaan universumi SimpleUniverse universe = new SimpleUniverse(canvas); universe.getViewingPlatform().setNominalViewingTransform(); // Luodaan 3D-data (BranchGroup) BranchGroup cube = createCube(); cube.compile(); universe.addBranchGraph(cube); frame.show(); } private static BranchGroup createCube() { BranchGroup branch = new BranchGroup(); // Transform TransformGroup transform = new TransformGroup(); transform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); branch.addChild(transform); // Muoto ColorCube demo = new ColorCube(0.4); transform.addChild(demo); // Animaatio Alpha spinAlpha = new Alpha(-1, 4000); RotationInterpolator spinner = new RotationInterpolator(spinAlpha, transform); spinner.setSchedulingBounds(new BoundingSphere(new Point3d(), 1000.0)); transform.addChild(spinner); return branch; } }
Myös olio-ohjelmoinnissa jossain pitää olla (pää)silmukka. Mitähän komento "frame.show()" tekee? Silmukka on kenties piilotettu sen sisään. Vaikka ohjelmassa olisi miten olioita ja muita kummallisuuksia, niin kyllä sen suoritus etenee aina jollain tietyllä rivillä. Noista valmiista järjestelmistä on kyllä vaikea sanoa niihin perehtymättä, miten mikäkin asia pitäisi toteuttaa.
Frame-olio ilmeisesti luo säikeen, jossa looppi on.
edit.
Mitä taas syötteen lukuun tulee, niin sinun täytyy antaa ikkunallesi tapahtumankäsittelijä-olio, jonka metodeja ikkunan looppi kutsuu aina, kun näppäintä painetaan tai jotain vastaavaa tapahtuu.
Framen näyttäminen käynnistää ainakin tapahtumankäsittelijäsäikeen, joka käsittelee ikkunoihin (kaikkiin, jos luot useita ikkunoita) tulevat tapahtumat (napin painallukset yms.) ja niiden piirtämisen päivittämisen. En ole tehnyt Java3D:llä mitään suurenpaa, mutta on mahdollista, että myös sillä on oma sisäinen silmukkansa, joka piirtää kaikki 3D-objektit ruudulle ja askeltaa animaatiota edelliseen piirtoon kuluneen ajan verran. Tuossa createCube:ssa kuutiolle luodaan toi spinner olio, joka pyörittää tuota kuutiota tietyssä ajassa tietyn verran tietyn verran.
Graafisen käyttöliittymän, eli GUI:n koodaamisessa on itse kukin pihalla aluksi. Siihen liittyy monta vaikeaa asiaa, joista kuitenkin suurin osa voidaan tehdä etukäteen ja antaa ohjelmoijan käyttöön kirjastorutiineiden ja -olioiden kautta.
ALoitan antamalla hieman pseudokoodia. Oletetaan, että yleisellä tasolla frame-olion sisäinen pääluuppi olisi tällainen:
// toiminto on jotain, mitä käyttäjä aiheuttaa, esim. hiiren siirto tai kliksu toista kunnes frame suljetaan muuttuja toiminto <- odota seuraavaa toimintoa muuttuja tapahtuma <- määritä toiminnosta tapahtuma toteuta tapahtuma
Miten seuraavan toiminnon odottamien pitäisi toteuttaa? Saattaisi olla huono idea kirjoittaa vain silmukka, kuten tässä:
funktio odota-toimintoa silmukka muuttuja toiminto <- lue toimintojonosta seuraava toiminto jos toiminto == tyhjä palaa silmukan alkuun muutoin palauta toiminto
Tämä suorittaisi koko ajan koodia ja veisi prosessoriaikaa. Lisäksi suurin osa ajasta kuluisi odotteluun, koska tietokone toimii mikrosekuntien aikaskaalassa ja ihmiskäyttäjä ei. En minä ainakaan kovin nopeasti osaa kliksutella hiirelläni niitä namiskoja. Enkä edes halua kirjoittaa siitä, miten se hiirtä käsittelevä koodi tunnistaisi ne toiminnot ja pukkaisi ne jonoon.
Mitä haluaisimme olisi se, että lukiessa seuraava toimintoa ohjelman suoritus katkeaisi, kunnes toiminto on saatavilla ja jatkuisi sitten. Juuri tällaisia asioita varten on olemassa rinnakkaisrutiineja (niitä on esim. Luassa) tai säikeitä (niitä on lähes jokaisessa kielessä, ainakin kirjastoissa).
Esimerkiksi webbiselaimen käyttöliittymä voi olla levossa ja odottaa seuraavaa komentoa, sillä välin kun toinen säie hakee netistä pyydettyä sivua ja renderöi sitä luettavaksi.
Tärkeä idea tässä on, että ohjelman suoritus voi luopua koneen (prosessorin) hallinnasta. Sitä voisi vaikka ajatella uneen menona. Nukun siihen asti kunnes minua taas tarvitaan. Vaikka tämä idea on hyvin yksinkertainen, se on hyvin vaikea toteuttaa oikein useimmilla kielillä, jos itse täytyy. Yleensä itse ei täydy.
Tavallista tekstipohjaista perusohjelmaa (ehkä jotain graafistakin) kirjoittaessa olemme tottuneet, että asiat voi tehdä yksi kerrallaan. Ensin käyttäjältä kysytään tietoa, sitten sen pohjalta lasketaan tuloksia ja ne näytetään. Ohjelma jatkuu seuraavaan vaiheeseen, jos käyttäjä ei sitä erikseen kysyttäessä anna lopetuskomentoa. Komentoja yleensäkin voi antaa vain, kun ohjelma niitä erikseen kysyy.
Ohjelmoijina me annamme käskyt, ja työtahdin määrää ohjelma.
GUI-ohjelmassa työtahdin määrää käyttäjä. Hän päättää, milloinka hän haluaa tuloksia näkyviin. Ohjelman hän voi sulkea siitä ruksista milloinka haluaa.
Homma kääntyy siis ympäri. Niin kauan kuin tätä käännöstä ei sisäistä, on todella pihalla GUI-ohjelmien teossa.
Mutta ei asia ole kohtuuttoman vaikeaa. Frame-olio tai vastaava tekee ne hankalat asiat tapahtumien odottelun ym. kanssa. Ohjelmoijan tehtäväksi jää määrittää järkevät reaktiot annettuihin toimintoihin, jotta ohjelma toimii oikein. Sekin vaatii työtä, mutta hyvä kirjasto antaa siihen hyvät työkalut ja hyvä suunnittelu auttaa. Hyväksi suunnittelijaksi oppii tekemällä huolellisesti suunnitelmia ja toteuttamalla niitä.
Ehkä se auttaa ajattelemaan asiaa oikein, että näkee ohjelmansa tietävän, mitä sen tulee tehdä, kun sitä käsketään. Kun toiminto on annettu, se toteutetaan parhaan mukaan ja sitten annetaan taas kontrolli muualle. Toimintoa ei tarvitse itse odotella ja hakea mistään, vaan se annetaan systeemistä käsin.
Ohjelmointiaan voi siis yhä ajatella käskyjen antamisena koneelle, mutta nyt ehtona on ensin se, että käyttäjä antaa sen ensimmäisen käskyn, jonka mukaan lisäkäskyt määräytyvät. Niin se on itse asiassa tavallisessakin ohjelmassa. Sitä pitää erikseen käskeä (suorittaa tai ajaa), että se alkaa tehdä jotain. GUI-ohjelmassa on vain tavallista enemmän mahdollisuuksia antaa käskyjä. Se on siis enemmän vuorovaikutteinen kuin yksinkertainen perusohjelma, jos vielä hienostellaan termeillä.
Filosofinen turinatuokio on nyt ohi. Takaisin koodaamaan siitä :-)
Koopekka: kiitoksia kattavasta selostuksesta. Tuo avasi jo jonkin verran tätä uutta ja ihmeellistä maailmaa, ja lisää sain selville lukemalla kaiken maailman materiaalia netistä. Monimutkainen on homman nimi, mutta kyllä se tästä, hitaasti mutta varmasti. Sellaista kuitenkin mietin, että mikä hyöty tässä vaikeasti lähestyttävässä toteutuksessa on? Samat asiat hoituisivat esim. C++:lla, mutta vähän selkeämmin.
Aihe on jo aika vanha, joten et voi enää vastata siihen.