MDI-sovellusten kehittäminen



Samankaltaiset tiedostot
Dokumentit, näkymät ja kehykset

Usean näkymän luominen

Luettelo-, puu-, parannetun tekstiruutu- sekä HTML-näkymän käyttö

HELIA 1 (1) Outi Virkki Käyttöliittymät ja ohjelmiston suunnittelu :04

Jypelin käyttöohjeet» Ruutukentän luominen

Kehitysympäristö LUKU. Developer Studio kehitysympäristön alkeet. Liikkuminen projektin työtilassa ja sen eri näkymissä

Hiirisanomiin vastaaminen

Tekstikontrollit LUKU. Tekstin ja sanomien esittäminen valintaikkunoissa. Tekstin muokkaaminen suorituksen aikana. Tiedon tarkistaminen syötön aikana

Harjoitustyö: virtuaalikone

Kaakkois-Suomen Ammattikorkeakoulu Oy Mikkelin Ammattikorkeakoulu Oy Kymenlaakson Ammattikorkeakoulu Oy

Visual C++ -ohjelman tekeminen ja suunnittelu

UpdateIT 2010: Editorin käyttöohje

Sovelluksen toimintojen toteuttaminen

Ohjelmoinnin perusteet Y Python

ActiveX-kontrollien käyttö

Web Services tietokantaohjelmoinnin perusteet

Sisältö. 2. Taulukot. Yleistä. Yleistä

Graafisen käyttöliittymän ohjelmointi

Siirtyminen Outlook versioon

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

KEMI-TORNIONLAAKSON KOULUTUSKUNTAYHTYMÄ LAPPIA LANGATON VIERAILIJAVERKKO 2(7) VERKKOYHTEYDEN MÄÄRITTELY WINDOWS XP:LLE (WINDOWS XP SP3)

Sisältö. 22. Taulukot. Yleistä. Yleistä

Uutiskirjesovelluksen käyttöohje

Haaga-Helia/IltaTiko ict2tcd005: Ohjelmiston suunnittelutaito 1/7 Anne Benson. Tällä opintojaksolla käytämme VS:n kolmen kokonaisuuden luomiseen:

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

OHJE EXCEL-MAKRON LUOMISEKSI JA MAKRON KÄYTÖSTÄ

EASY Tiedostopalvelin - mobiilin käyttöopas

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Väitöskirja -mallipohja

Käyttäjän käsikirja. LIB 500 ja LIB 510 v Releasettelutyökalu Yleistä. ,NNXQDMRNDLOPRLWWDDHWWlNRKGHRQSlLYLWHWWlYl

Piirtopinnalle piirtäminen

T Olio-ohjelmointi Osa 5: Periytyminen ja polymorfismi Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

Opera Hotel Edition. Arvonlisäverokantojen muutos Operaan Finland. Toukokuu 2010 MICROS-Fidelio Finland Oy, Hotel Systems HelpDesk

TIETOKONEEN ASETUKSILLA PARANNAT KÄYTETTÄVYYTTÄ

Mainosankkuri.fi-palvelun käyttöohjeita

Olio-ohjelmointi Javalla

ASENNUS- JA KÄYTTÖOHJE

Tilastokeskuksen rajapintapalveluiden käyttöönotto QGISohjelmistossa

Käyttöliittymän luominen

4. Luokan testaus ja käyttö olion kautta 4.1

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. IX Suunnittelumallit Proxy, Factory Method, Prototype ja Singleton

Gree Smart -sovelluksen (WiFi) asennus- ja käyttöohje: Hansol-sarjan ilmalämpöpumput WiFi-ominaisuuksilla

Sovellusten ohjelmointi Microsoft Foundation Classes -luokkien avulla

11. oppitunti III. Viittaukset. Osa. Mikä on viittaus?

SoleMOVE lähtevän harjoittelijan ohje

Kirkkopalvelut Office365, Opiskelijan ohje 1 / 17 IT Juha Nalli

ActiveX-kontrollien luominen

Ennen kuin aloitat lataamisen tarkista järjestelmävaatimukset:

Fonttien käyttö LUKU. Tekstin esittäminen värein ja tyylein. Fonttien käyttö sovelluksen viimeistelyyn OSA IV LUKU 17.

Ajokorttimoduuli Moduuli 2. - Laitteenkäyttö ja tiedonhallinta. Harjoitus 1

Osa. Listaus 2.1. HELLO.CPP esittelee C++ -ohjelman osat. 14: #include <iostream.h> 15: 16: int main() 17: {

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Pedacode Pikaopas. Java-kehitysympäristön pystyttäminen

WINDOWS MICROSOFT OUTLOOK 2010:N UUDET OMINAISUUDET...

Nettiposti. Nettiposti käyttöohje

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

OPTIMAverkko-oppimisalusta KÄYTTÖOPAS OPISKELIJALLE. Riitta Tammenoksa Pertti Heikkilä Versio 0.2 (luonnos)

Versio 1.1 P/N Copyright 2002, ATI Technologies Inc. Kaikki oikeudet pidätetään.

Testivetoinen ohjelmistokehitys

Transkribuksen pikaopas

Ohjelmoinnin perusteet Y Python

Written by Administrator Monday, 05 September :14 - Last Updated Thursday, 23 February :36

SSH Secure Shell & SSH File Transfer

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

TYYLIT. Word Tyylit

GPRS-lisäpalvelu INTERNET-ASETUKSET

Windows. Valmistelut. Windows

Tietokantojen ja tietuenäkymien käyttö

Listarakenne (ArrayList-luokka)

Google-dokumentit. Opetusteknologiakeskus Mediamylly

4.1 Frekvenssijakauman muodostaminen tietokoneohjelmilla

WINDOWS 10 -kurssi.

Microsoft Visual Studio 2005

Datan tallentaminen, lataaminen ja siirtäminen

Office_365_loppukäyttäjän ohje Esa Väistö

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen

14. Hyvä ohjelmointitapa 14.1

Ohjeisto Trimble Pro 6H yhdistämisestä Juno 5:een

Valintanauhan komennot Valintanauhan kussakin välilehdessä on ryhmiä ja kussakin ryhmässä on toisiinsa liittyviä komentoja.

TALLENNETAAN MUISTITIKULLE JA MUISTIKORTILLE

YH1b: Office365 II, verkko-opiskelu

Olio-ohjelmointi Syntaksikokoelma

1. HARJOITUS harjoitus3_korjaus.doc

Sähköpostitilin käyttöönotto. Versio 2.0

Jos haluat uuden Share-työkalun, valitse Pods -> Share -> Add New Share tai jos sinulla on jo auki Share-työkalu, näyttää se tältä:

Sisällys. 7. Oliot ja viitteet. Olion luominen. Olio Java-kielessä

1 (14) Ohje. Ohje. GTK-wiki. Geologian tutkimuskeskus, Verkkosivustopalvelut

Ohjeita LINDOn ja LINGOn käyttöön

Eclipse 3.2 pikku opas versio 1.0. Esittely Uuden projektin perustaminen Sovelluksen luominen Koodin siistiminen Vinkkejä

Sisällys. 18. Abstraktit tietotyypit. Johdanto. Johdanto

SISÄLLYSLUETTELO. Word Sisällysluettelo

Tapahtumapohjainen ohjelmointi. Juha Järvensivu 2007

BlueJ ohjelman pitäisi löytyä Development valikon alta mikroluokkien koneista. Muissa koneissa BlueJ voi löytyä esim. omana ikonina työpöydältä

CISS Base Excel raporttien määritys Käyttäjän käsikirja. CISS Base Käyttäjän Käsikirja Econocap Engineering Oy 1

Muuttujien määrittely

18. Abstraktit tietotyypit 18.1

Sisällys. Metodien kuormittaminen. Luokkametodit ja -attribuutit. Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2

Ohjelmoinnin perusteet Y Python

6 XML-työkalut 1. 6 XML-työkalut

13. Hyvä ohjelmointitapa (osa 1) 13.1

Transkriptio:

OSA V 491 LUKU 21 21 LUKU MDI-sovelluksen luominen Siirtyminen dokumentti, näkymä- ja kehysluokan välillä Sovelluksen kehittäminen MFC;n monidokumentti/näkymä-arkkitehtuurilla

492 Kehittyneet dokumentti/näkymä-tekniikat Useat tämän päivän suosituimmista ja käytetyimmistä ohjelmistosovelluksista perustuvat dokumentti/näkymä-arkkitehtuuriin tai sen muunnelmaan. Tämä arkkitehtuuri erottaa sovelluksen tiedonhallintakoodin selvästi käyttöliittymäosan koodista. Sovelluksen tiedot hallitaan dokumentissa ja käyttöliittymää hallitaan näkymässä (view). Dokumentti on usein tekemisissä tiedoston kanssa. MFC-kirjaston sovellusrunko tarjoaa kaksi eri tyyppistä dokumentti/ näkymä-sovellusta: SDI (single document interface, yksidokumenttiliittymä) ja MDI (multiple document interface, monidokumenttiliittymä). SDI-sovelluksia on jo käsitelty luvussa 12. Dokumentti/näkymäsovelluksen perusarkkitehtuuri on pääosin sama SDI- ja MDIsovelluksissa. Ellei dokumentti/näkymä-käsite ole sinulle vielä tuttu, lue tämän luvun ohessa myös lukua 12. SDI:n ja MDI:n vertaamiseksi olemme käyttäneet samoja esimerkkejä tässä luvussa ja aiemmissa SDIluvuissa. SDI- ja MDI-sovellusten perusero selviää jo nimestä. SDI-sovelluksessa avoinna voi olla kerrallaan vain yksi dokumentti, MDI-sovelluksessa monta ja kullakin on vielä oma käyttöliittymä näkymäikkunassa. KATSO MYÖS Lisätietoja SDI-sovelluksista luvusta 12. MDI-sovelluksen luominen On kiistelty siitä, pitäisikö sovellukset tehdä SDI- vai MDI-tyyppisiksi. Toisten mielestä kaikkien sovellusten tulisi toimia hyvin dokumenttikeskeiseksi ja käyttää näin ainoastaan SDI-liittymää. Kuitenkin monet käyttäjät haluavat suorituskykyisiä ohjelmia. MDI-sovellukset MS Wordin ja Excelin tavoin käyvät kuitenkin hyvin kaupaksi. Tietyntyyppisissä ohjelmistopaketeissa useiden eri dokumenttien (tai tiedostojen) käsittely yhdellä sovelluksella saattaa kuitenkin olla käyttäjälle helpompaa kuin eri ohjelman käyttäminen kullekin dokumentille. MDI-sovelluksen luominen käy helposti AppWizardin asetuksia valitsemalla. Muista kuitenkin, että projektin luomisen jälkeen SDI-sovelluksen muuttaminen MDI-sovellukseksi tai päinvastoin on hankalaa. Riippuen siitä, kuinka pitkälle sovelluksen kehittämisessä on päästy, saattaa olla jopa helpompaa aloittaa sovelluksen tekeminen alusta pitäen. Ennen aloittamista kannattaa siis harkita hyvin, kumpi käyttöliittymätyyppi sopii paremmin

OSA V LUKU 21 493 omaan sovellukseesi. Tässä kappaleessa teet MDI-sovelluksen, jonka avulla luotuihin luokkiin sekä dokumentti/näkymä-arkkitehtuurin toimintaan tullaan tutustumaan. Luo siis uusi projekti nimeltään MDICoin seuraavasti. MDI-sovelluksen luominen AppWizardilla 1. Valitse File-valikosta New ja New Projects ikkunasta Projectsvälilehdeltä MFC AppWizard (exe). 2. Anna projektille nimi (tässä MDICoin) ja napauta OK. 3. Valitse MFC AppWizardin Step 1 ikkunassa Multiple Documents valintapainike ja varmista, että Document/View Architecture Support? asetus on valittu (kuva 21.1). Napauta Next. KUVA 21.1 AppWizardin Step 1 ikkuna. 4. Valitse Step 2 ikkunassa None-valintapainike. Tässä ikkunassa voisit valita sovellukselle tietokantatukea, jota tässä esimerkissä ei tarvita. Napauta Next. 5. Valitse Step 3 ikkunassa None-valintapainike ja valitse ActiveX Controls. Tämän ikkunan muut valinnat koskevat OLEautomaatio -ominaisuuksia, joita tässä esimerkissä ei tarvita. Napauta Next. 6. Rastita Step 4 ikkunassa seuraavat valinnat: Docking Toolbar, Initial Status Bar, Printing and Print Preview ja 3D Controls. Valitse työkalurivin tyyli Normal-valintapainikkeella (oikeat asetukset on esitetty kuvassa 21.2). Napauta Next.

494 Kehittyneet dokumentti/näkymä-tekniikat KUVA 21.2 AppWizardin Step 4 ikkuna. 7. Valitse Step 5 ikkunassa projektin tyyliksi MFC Standard, lähdekoodin kommentointi Yes-valinnalla ja MFC-kirjaston käyttötavaksi As a Shared DLL. Napauta Next. 8. Napauta Step 6 vaiheessa Finish. Saat esiin kuvan 21.3 mukaisen New Project Information ikkunan. Ikkunassa näet tarpeellisia tietoja luotavista luokista ja lähdekooditiedostojen nimistä. Näet myös projektiin tehtävät lisäominaisuudet. Napauta OK ja uusi projekti luodaan ja avataan Developer Studiossa. KUVA 21.3 New Project Information ikkuna. Tulet kehittämään sovelluksen, joka esittää kolikkopinoa. Valikon komennoilla pinosta voidaan poistaa tai siihen voidaan lisätä kolikoita. Sovelluksen tietoina toimii kolikoiden lukumäärä, joka sijaitsee

dokumenttiluokassa ja jota luetaan näkymäluokasta pinon esittämiseksi. Tämä MDICoin-esimerkki perustuu luvun 12 SDICoin-esimerkkiin ja koodikin on varsin samanlaista. MDICoin-esimerkissä voidaan kuitenkin pitää avoinna useita dokumentti/näkymä-ikkunoita samanaikaisesti. Esimerkkiä parannellaan vielä uudella dokumenttiluokalla, joka esittää seteleitä kolikoiden sijaan. SDI-sovelluksessa käytettiin yhtä CDocumentkantaluokasta johdettua luokkaa, mutta MDI-sovelluksessa CDocumentluokasta johdettuja luokkia voi olla tarpeellinen määrä. OSA V LUKU 21 495 Kuhunkin dokumenttiluokkaan liitetään näkymäluokka. Näkymäluokka voi olla useiden dokumenttiluokkien käytössä tai se voi olla ainoastaan yhden dokumenttiluokan käytössä. Näkymän kantaluokka valitaan AppWizardin Step 6 ikkunassa: vaihtoehdot ovat CView, CScrollView, CListView, CTreeView, CEditView, CRichEditView, CFormView, CRecordView ja CHtmlView. MDICoin-esimerkissä käytetään kantaluokkaa CView. KATSO MYÖS Yleiskatsaus MFC:n näkymäluokista taulukossa 12.1. Lisätietoja CListView-luokasta luvusta 19. Lisätietoja CTreeView-luokasta luvusta 19. Lisätietoja CRichEditView-luokasta luvusta 19. Lisätietoja CHTMLView-luokasta luvusta 19. Lisätietoja CScrollView-luokasta luvusta 18. Lisätietoja CFormView- ja CRecordView-luokista luvusta 24. Lisätietoja dokumentti/näkymä-arkkitehtuurin tiedostonkäsittelystä luvusta 23. Lisätietoja tietokantatuen lisäämisestä sovellukseen luvusta 24. Lisätietoja OLE-automaatiosta luvusta 25. Dokumentit kapseloivat sovelluksen tiedot Dokumenttiluokka on johdettu CDocument-kantaluokasta ja sen jäsenmuuttujissa on sovelluksen data. CDocumentista johdettu oma luokka tarjoaa palvelut tuon datan käsittelemiseksi. Esimerkiksi Serialize()-funktiota käytetään datan lukemiseen ja kirjoittamiseen levylle. MDI-sovelluksen luokat Monidokumenttisovelluksen luokkarakenne ClassView-ikkunassa näyttää miltei identtiseltä SDI-sovelluksen luokkarakenteen kanssa. Ainoa näkyvä ero on uuden CChildFrame-luokan lisäys. Pinnan alla on kuitenkin useita selkeitä eroavaisuuksia. AppWizardin tekemien luokkien periytyminen on esitetty kuvassa 21.4. SDI- ja MDI-sovellusten perusrakenne on varsin samanlainen. CWinApp-luokasta johdettu CMDICoinApp-luokka huolehtii sovelluksen alustamisesta. Kantaluokka CWinApphuolehtii dokumentin, näkymän ja kehyksen liittämisestä toisiinsa. Se myös saa sanomat Windowsilta ja

496 Kehittyneet dokumentti/näkymä-tekniikat KUVA 21.4 MDI-sovelluksen luokkahierarkia. Aktiivinen näkymä ja dokumentti Näkymäikkunasta tulee aktiivinen käyttäjän aloittaessa sen käytön. Aina aktiivisen näkymän vaihtuessa kutsutaan OnActivate()-funktiota. Ensiksi kutsutaan sen ikkunan OnActivete()-funktiota, joka oli aktiivinen ja sen jälkeen aktivoituvan ikkunan funktiota. Syöteparametri kertoo, mikä ikkunan uusi tila on. Parametrin arvot voivat olla WA_INACTIVE, WA_ACTIVE tai WA_CLICKACTIVE. Aktiiviseen näkymään liitettyä dokumenttia kutsutaan aktiiviseksi dokumentiksi. välittää ne edelleen oikealle kohdeikkunalle. CDocument-luokasta johdettu CMDICoinDoc-luokka säilöö dokumentin tiedot ja vastaa tietojen serialisoinnista (peräkkäistallennuksesta) pysyvään tallennusvälineeseen ja sieltä takaisin, esimerkiksi levytiedostoon. Yhden dokumenttiolion SDI-sovelluksista poiketen MDI-sovelluksessa voi olla käytössä useita yhtäaikaisia dokumenttiolioita. Kuki dokumenttiolio vastaa yhdessä tiedostossa ylläpidettävistä tiedoista. Dokumenttiolion luominen luo aina myös uuden näkymäikkunan, liittää näkymän dokumenttiin ja luo näkymää varten vielä uuden kehysikkunankin. Koska dokumenttiolioita voi olla useita, MDI-sovellusrunko käyttää termiä aktiivinen dokumentti viittaamaan siihen, jonka jonkun näkymän kanssa käyttäjä juuri toimii. Luokka CMDICoinView vastaa dokumentin tietojen näyttämisestä jossain muodossa näyttäjälle. MDICoin-esimerkissä näkymä piirtää kolikkopinon. Kukin näkymistä voi toimia käyttöliittymänä ainoastaan

yhteen dokumenttiolioon, mutta yhdellä dokumentilla voi kyllä olla useita näkymäolioita. Näkymäluokka saa tarvitsemansa tiedot dokumenttiluokan julkisten saantifunktioiden avulla. CMainFrame-luokka antaa sovellukselle käyttöön ikkunan. Kehysikkunoiden toteutus poikkeaa SDI- ja MDI-sovelluksissa selvästi toisistaan. MDI-sovellukset johtavat CMainFrame-luokan CMDIFrameWndluokasta, jolloin itse sovellukselle luodaan yksi kehysikkuna (pääikkuna) ja kullekin näkymälle omansa. Työkalurivit ja tilarivi ovat pääkehysikkunassa ja se huolehtii myös ikkunoiden hallinnasta. Esimerkiksi CFrameWnd::RecalcLayout-funktio huolehtii ikkunan koosta ja työkalurivin ja tilarivin oikeasta paikasta. Kukin näkymäikkuna on omassa kehysikkunassaan tämä saadaan CChildFrame-luokan ominaisuutena. Kuvasta 21.4 näkyy, että CChildFrameon johdettu CMDIChildWnd-luokasta. MDI-arkkitehtuurin lisäominaisuuksien vuoksi tämä luokka hyödyntää suoraan Windowsin järjestelmäikkunaa MDIClient. Kun MDI-kehysikkuna on luotu, luodaan MDIClient ikkuna sen lapsiikkunaksi, joten MDI-lapsi-ikkunat ovat MDIClientin lapsia eli pääkehysikkunan lapsenlapsia. OSA V LUKU 21 497 KATSO MYÖS Lisätietoja SDI- ja MDI-luokkien eroista luvusta 12. MDI-sovelluksen näkyvät osat Luvussa 12 kerrottiin, että AppWizard tekee myös SDI-sovelluksen tarvitsemat resurssit, kuten valikon ja työkalurivin ja näille annetaan sama ID-tunnus, IDR_MAINFRAME. MDI-sovelluksessa projektiin tehdään nuo resurssit ja vielä muutama ylimääräinenkin. Lisäresursseja tarvitaan, koska MDI-sovellukset voivat käsitellä useantyyppisiä dokumentteja ja SDIsovelluksilla on pakko olla dokumenttiolio, mutta MDI:llä ei. Kuvassa 21.5 on esitetty MDICoin-esimerkin resurssit.

498 Kehittyneet dokumentti/näkymä-tekniikat KUVA 21.5 MDI-sovelluksen resurssit. Dokumenttikohtaiset valikot MDI-sovelluksen käsittelemillä erityyppisillä dokumenteilla on omat IDR_-valikkoresurssinsa, jotka näytetään automaattisesti dokumenttiolion aktivoituessa. On mahdollista, ettei MDIohjelmassa ole aktiivista dokumenttia, jolloin näytetään IDR_MAINFRAMEvalikkoresurssi. IDR_MAINFRAME-resurssin lisäksi AppWizard on tehnyt dokumenttityyppikohtaisen kuvakkeen, valikon ja merkkijonotaulukon ja antanut näille kaikille ID-tunnukseksi IDR_MDICOITYPE. Voit siten muokata näitä resursseja dokumentin tyypin mukaisesti. Dokumentin kuvake IDR_MDICOITYPE esitetään valikon vasemmalla puolen, kun näkymäikkuna on suurennettu ja muutoin näkymäikkunan otsikkopalkissa. Dokumenttityyppiin liitetty valikkoresurssi aktivoituu automaattisesti dokumenttia aktivoitaessa. Ellei aktiivista dokumenttia ole (mikä on MDI-sovelluksissa aivan hyväksyttävää), aktivoidaan IDR_MAINFRAMEvalikko. Kuvassa 21.5 näet eron pääikkunan File-valikon ja dokumentin File-valikon välillä: MDI lisää myös Window-valikon, jonka Tile- (vierekkäin) ja Cascade-komennoilla (limittäin) käyttäjä voi järjestää ikkunoita. Tässä valikossa on myös New Window komento, jonka avulla käyttäjä saa helposti esiin useita näkymiä, kunkin omaan MDI-kehysikkunaansa.

Projektissa on myös IDR_MDICOITYPE-merkkijonotaulukkoresurssi, josta sovellusrunko saa automaattisesti tietoa dokumentista; se myös liittyy ikkunoiden otsikon automaattiseen näyttämiseen. MDI-sovelluksen näkyvien osien yhteenveto on esitetty kuvassa 21.6. Osat ovat seuraavat: CMainFrame johdetaan CMDIFrameWnd-luokasta tämä on sovelluksen pääikkuna. CToolbar toteuttaa pääkehysikkunaan kiinnitetyn työkalurivin. CChildFrame on johdettu CMDIChildWnd-luokasta ja se toteuttaa kunkin näkymän oman kehysikkunan. CMDICoinView toteuttaa näkymän MDI-kehysikkunan lapsena. CStatusBar toteuttaa pääkehysikkunaan kiinnitetyn tilarivin. MDI-näkymäikkunat korvaavat pääkehysikkunan työalueen. OSA V LUKU 21 499 1 2 KUVA 21.6 MDI-sovelluksen näkyvät osat. 1 CMainFrame 2 CToolBar 3 CChildFrame 4 CMDICoinView 5 CStatusBar 6 MDI-näkymäikkunat 6 5 4 3

500 Kehittyneet dokumentti/näkymä-tekniikat KATSO MYÖS Lisätietoja valikoista luvusta 13. Lisätietoja työkaluriveistä luvusta 14. MDI-dokumenttimallit Dokumentti/näkymä-arkkitehtuurin ytimessä ovat dokumenttimallit (document template). Vaikka näitä käytetään myös SDI-sovelluksissa, ne ovat MDI-sovelluksia kehitettäessä selvästi tärkeämmässä osassa. Dokumenttimalli liittää yhteen dokumentin, näkymän ja tietyn dokumenttityypin kehykset. SDI-projektissa ei tavallisesti tarvitse käsitellä AppWizardin tekemää dokumenttimallikoodia. MDIprojekteissa saatat joskus haluta luoda uusia dokumenttityyppejä ja liittää niihin eri kehys- ja näkymäluokkia, jolloin joudut itse koodaamaan dokumenttimallikoodin. Onneksi uusien dokumenttimallien koodaaminen ei ole erityisen hankalaa, etenkin kun löydät AppWizardin tekemän mallikoodin ensimmäiselle dokumentille, näkymälle ja kehykselle. Löydät kuvasta 21.4 MDI-sovelluksen luokkahierarkiasta CMultiDocTemplateluokan, joka on MDI-sovellusten käyttämä dokumenttimalli. CMDICoinApp::InitInstance-funktiosta (jota MFC-sovellusrunko kutsuu sovelluksen alustamiseksi) löytyy puolivälin jälkeen seuraava koodi: 1 Luodaan uusi monidokumenttimalliolio syöttäen luontifunktiolle resurssitunnuksen sekä dokumentin, näkymän ja kehyksen ajonaikaiset luokat. 2 Rekisteröi luodun dokumenttimallin sovellusluokkaan. 3 Luo sovelluksen kehysikkunan. 4 Ilmoittaa pääkehysikkunalle, mitkä resurssit ladataan (esimerkiksi valikko ja työkalurivi). 1 // Register the application's document templates. Document templates 2 // serve as the connection between documents, frame windows and views. 3 CMultiDocTemplate* pdoctemplate; 4 pdoctemplate = new CMultiDocTemplate( 5 IDR_MDICOITYPE, 6 RUNTIME_CLASS(CMDICoinDoc), 7 RUNTIME_CLASS(CChildFrame), 8 RUNTIME_CLASS(CMDICoinView)); 1 9 AddDocTemplate(pDocTemplate); 2 10 11 // create main MDI Frame window 12 CMainFrame* pmainframe = new CMainFrame; 3 13 if (!pmainframe->loadframe(idr_mainframe)) 4 14 return FALSE; 15 m_pmainwnd = pmainframe;

OSA V LUKU 21 501 Tässä luodaan CMultiDocTemplate-olio, jolle annetaan neljä parametriä (rivi 4). Ensimmäinen näistä on resurssin ID-tunnus IDR_MDICOITYPE (rivi 5). Tällä tunnistetaan kolme CMDICoinDoc-dokumenttiin liitettyä resurssia: kuvake, valikko ja merkkijonotaulukko. Seuraavat kolme parametriä viittaavat dokumentti-, kehys- ja näkymäluokkien ajonaikaisiin tietoihin (rivit 6,7 ja 8). Nämä osoitteet tehdään RUNTIME_CLASSmakrolla. Tämä onnistuu, koska AppWizard tukee näiden luokkien dynaamista luomista käyttämillään DECLARE_DYNCREATE ja IMPLEMENT_DYNCREATE-makroilla. SDI- ja MDI-dokumenttimallien välillä on erojakin. Luokat CSingleDocTemplate ja CMultiDocTemplate johdetaan samasta kantaluokasta CDocTemplate. Näistä CSingleDocTemplate hallitsee yhtä dokumenttioliota, mutta CMultiDocTemplateluetteloa osoittimista dokumentteihin (eli siis CMDICoinDoc-olioihin). Itse dokumentti-, näkymä- ja kehysolioita ei luoda vielä tässä vaiheessa. Koodi alustaa CMultiDocTemplate-olion tarpeellisilla tiedoilla resurssien lataamista ja dokumenttien, näkymien ja kehyksien tarvittaessa varaamista varten. Sovellusluokka (application) pitää yllä luetteloa dokumenttimalleista. Rivillä 9 kutsuttu AddDocTemplate -funktio lisää dokumenttimalliolion tähän luetteloon. Halutessasi rekisteröidä lisää dokumenttimalleja, voit tehdä sen tällä funktiolla. Näin yksi sovellus voi käsitellä erilaisia liityntöjä dokumenttien, näkymien ja kehyksien välillä. CWinApp-luokka pitää CMultiDocTemplate-olion tuhoamiseensa, eli sovelluksen lopettamiseen asti. Tuhoamisensa aikana CWinApp-luokka vapauttaa AddDocTemplate -funktiolla lisätyille dokumenttimalleille varatun muistitilan. Dokumenttimallit eivät vie edes paljon muistia, joten ne voivat aivan hyvin elää koko sovelluksen ajan. Pääkehysikkuna luodaan rivillä 12 CMainFrame-luokan muodostimessa. Rivin 13 LoadFrame-funktiolle syötetään ladattavien ja kehysikkunaan liitettävien resurssien ID-tunnus IDR_MAINFRAME. Voit käyttää LoadFramella myös toista valinnaista parametriä, jolla määrätään ikkunatyylejä. Oletuksena käytetään tyylilippuja WS_OVERLAPPEDWINDOW ja FWS_ADDTOTITLE. WS_OVERLAPPEDWINDOWtyyli yhdistää taulukossa 21.1 esitetyt tyyliliput. FWS_ADDTOTITLE kuuluu MFC:n lippuihin se saa aikaan aktiivisen dokumentin nimen kirjoittamisen otsikkopalkkiin. Tavallisesti otsikkopalkissa esitetään ensin sovelluksen nimi ja tämän jälkeen aktiivisen dokumentin nimi. Uusi dokumenttivalintaikkuna Jos sovellusluokkaan on rekisteröity usean tyyppisiä dokumentteja, File-valikon Newkomennolla saadaan esiin ikkuna, jossa kysytään, millaisen dokumentin käyttäjä halulaa luoda. Valintaikkunassa esitettävä kuvaus saadaan merkkijonotaulukon dokumenttiin liittyvästä IDR_- alkiosta.

502 Kehittyneet dokumentti/näkymä-tekniikat Voit vaihtaa järjestystä halutessasi FWS_PREFIXTITLE-lipulla. TAULUKKO 21.1 WS_OVERLAPPEDWINDOW-lippuun yhdistetyt pääkehysikkunan tyylit Tyyli WS_OVERLAPPED WS_CAPTION Kuvaus Luo tavallisen, peittävän ikkunan Lisää ikkunaan otsikkopalkin WS_SYSMENU L isää otsikkopalkkiin perusjärjestelmävalikon WS_MINIMIZEBOX WS_MAXIMIZEBOX WS_THICKFRAME Lisää otsikkopalkkiin pienennyspainikkeen Lisää otsikkopalkkiin suurennuspainikkeen Sallii ikkunan koon muuttamisen KATSO MYÖS Lisätietoja ajonaikaisista luokkatiedoista luvusta 23. Dokumentin, näkymän ja MDI-kehyksen luomisen vaiheet Kuten aiemmin mainittiin, dokumenttimalliolion muodostaminen ei välttämättä luo yhtään dokumenttia, näkymää tai MDI-lapsi-ikkunaoliota. Dokumenttimalli yksinkertaisesti pitää tallessa kunkin dokumentti/näkymä/kehysjoukon ajonaikaisia luokkatietoja. Näiden tietojen avulla luodaan oliot ja talletetaan osoittimet niihin sovellusolioon ( App) ainoastaan, kun käyttäjä päättää luoda uuden dokumentin tai avata olemassa olevan. CMultiDocTemplate-olion onnistuneen luomisen ja alustamisen ja kehysikkunan luomisen jälkeen CWinApp::InitInstance-funktiossa on seuraava koodi: 1 // Parse command line for standard shell commands, DDE, file open 2 CCommandLineInfo cmdinfo; 3 ParseCommandLine(cmdInfo); 4 // Dispatch commands specified on the command line 5 if (!ProcessShellCommand(cmdInfo)) 6 return FALSE; 7 // The one and only window has been initialized, so show and update it. 8 pmainframe->showwindow(m_ncmdshow);

OSA V LUKU 21 503 9 pmainframe->updatewindow(); CCommandLineInfo-luokka käsittelee sovellukselle komentorivillä syötetyt argumentit. Oletuksena komentoriviparametrit on alustettu luomaan uusi dokumentti sovellusta käynnistettäessä. Dokumentin, näkymän ja MDI-kehysikkunoiden varsinainen muodostaminen tapahtuu pinnan alla CWinApp::ProcessShellCommand-funktiossa (rivi 5). Listauksessa 21.1 esitetään yleiskatsaus luomisen vaiheista. Huomaa, että listauksen 21.1 koodi esitetään selkeyden vuoksi karsittuna. LISTAUS 21.1 LST21_1.CPP Dokumentin, näkymän ja MDI-kehysikkunan luomisen vaiheet 1 BOOL CWinApp::ProcessShellCommands(CCommandLineInfo& rcmdinfo) 1 2 { 3 if(fcmdinfo.newfile) 4 { 5 OnFileNew(); 6 } 7 if(fcmdinfo.openfile) 8 { 9 OpenDocumentFile(rCmdInfo.strFileName); 10 } 11 12 } 13 void CWinApp::OnFileNew() 2 14 { 15 m_pdocmanager->onfilenew(); 16 } 17 void CDocManager::OnFileNew() 18 { 19 ptemplate = m_templatelist.gethead(); 3 20 if(m_templatelist.getcount() > 1) 21 { 22 // more than one document Template 23 // bring up dialog prompting user 24 ptemplate = dlg.m_pselectedtemplate; 4 25 } 26 ptemplate->opendocumentfile(null); 27 } 28 CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszpathname) 29 { 30 pdocument = CreatenewDocument(); 31 pframe = CreateNewFrame(pDocument); 5 32 33 if(lpszpathname == NULL) 34 { 35 SetDefaultTitle(pDocument); 36 pdocument->onnewdocument(); 6 37 } 38 else 39 pdocument->onopendocument(); 40 InitialUpdateFrame(pFrame, pdocument); 7 1 InitInstance-funktio kutsuu tätä. 2 Sanomankäsittelijä Filevalikon New-komennolle. 3 ptemplate on osoitin CMultiDoctemplate-olioon. 4 Jos useampi kuin yksi dokumenttityyppi on rekisteröity, käyttäjää pyydetään valitsemaan tyyppi. 5 Dokumentti- ja kehysoliot muodostetaan mallissa ajonaikaisia luokkatietoja käyttäen. CreateNewFrame muodostaa myös näkymän. 6 OnNewDocument ja OnOpenDocument ovat virtuaalifunktioita, jotka tulee korvata dokumentin alustamiseksi. 7 Näkymä aktivoidaan ja lähetetään WM_INITIALUPDATEsanoma, joka saa aikaan OnInitialUpdate-käsittelijän kutsumisen.

504 Kehittyneet dokumentti/näkymä-tekniikat 41 } SDI- ja MDI-rakenteen luomisen ero on se, että MDI-malli luo uuden dokumenttiolion aina OpenDocumentFile-funktiota kutsuttaessa (rivi 26), kun taas SDI luo yhden dokumenttiolion ja käyttää sitä tarvittaessa uudelleen. Rivillä 30 kutsuttu CreateNewDocument-funktio käyttää mallin ajonaikaisia luokkatietoja sovelluskohtaisen dokumenttiolion muodostamiseen. Funktio myös lisää dokumentin sovelluksen dokumenttiluetteloon. Dokumentin luomisen jälkeen luodaan myös kehys ja näkymä toisella mallin funktiolla CreateNewFrame. Rivillä 31 kutsuttu CreateNewFramemuodostaa mallin ajonaikaisten luokkatietojen mukaan sekä kehysikkuna- että näkymäoliot. Kun kehys on luotu, kutsutaan CFrameWnd::LoadFrame-funktiota mallin muodostimessa annetulla resurssin ID-tunnuksella. MDI-sovelluksessa tämä resurssin ID-tunnus on dokumenttikohtainen. MDICoinesimerkissä tunnuksena syötetään IDR_MDICOITYPE. LoadFramefunktio lataa resurssit (valikon, työkalurivin, kuvakkeen, pikavalinnat ja merkkijonot) ja liittää ne kehysikkunaan. Huomaa, että mikäli jonkin resurssin lataaminen ei onnistu, LoadFrame-funktio ei onnistu ja se tulostaa tällöin virhesanoman: Warning: CDocTemplate couldn t create a frame. Luomisen lopuksi kutsutaan dokumenttimallin funktiota InitialUpdateFrame (rivillä 40). Tämä asettaa juuri luodun näkymän aktiiviseksi ja lähettää kehysikkunan lapsille WM_INITIALUPDATE-sanoman siis myös näkymälle. Tämän viestin vastaanottaminen saa aikaan CView::OnInitialUpdate-virtuaalifunktion kutsumisen. On varsin tavallista korvata tämä funktio sovelluskohtaisella näkymän alustamisella. Huomaa myös, että tavallisesti tässä funktiossa on myös huolehdittava kantaluokan OnInitialUpdate-funktion kutsumisesta. KATSO MYÖS Tietoja komentorivin parametreistä luvusta 12. Siirtyminen dokumentti/näkymä-olioiden välillä Dokumentti/näkymä-ajattelulla kehitetyistä olioista joudutaan usein viittaamaan toisten luokkien olioihin. Tavallisimmin viitataan dokumentista siihen liitettyyn näkymään ja päinvastoin, mutta viittauksia myös muihin sovelluksen luokkiin tarvitaan toisinaan. Sovellusluokassa

( App) saattaa esimerkiksi olla muuttujia, joita tarvitaan näkymäluokasta. Taulukossa 21.2 on esitetty MFC:n tarjoamat funktiot MDI-sovelluksen eri luokkien välillä viittaamista varten. TAULUKKO 21.2 MDI:n luokanhakufunktiot Luokka Funktio Palauttaa Yleinen AfxGetApp Osoittimen CWinApp-olioon Yleinen AfxGetMainWnd Osoittimen pääkehysikkunaan (CWnd-luokan olioon) CMDIFrameWnd MDIGetActive Osoittimen aktiiviseen MDI-lapsiikkunaan (CMDIChildWnd) CWnd GetParentFrame Osoittimen isäkehysikkunaolioon (CFrameWnd) CFrameWnd GetActiveView Osoittimen aktiiviseen näkymään (CView) CFrameWnd GetActiveDocument Osoittimen aktiiviseen kumenttiin (CDocument) CView GetDocument Osoittimen näkymään liitettyyn dokumenttiin (CDocument) CDocument GetFirstViewPosition Dokumenttiin liitettyjen näkymien luettelosta ensimmäisen näkymän paikka. Aloittaa dokumentin näkymien läpikäymisen. CDocument GetNextView Osoitin dokumenttiin liitettyjen näkymien (CView) luettelosta seuraavaan. OSA V LUKU 21 505 AfxGetAppja AfxGetMainWndovat globaaleja funktioita, joita voidaan kutsua mistä tahansa. Näiden funktioiden palauttamat osoittimet voidaan huoletta muuttaa oman sovellusluokkasi tyylisiksi seuraavan esimerkin tavoin: CMDICoinApp* papp = (CMDICoinApp*) AfxGetApp(); CMainFrame* pframe = (CMainFrame*) AfxGetMainWnd(); Näkymä on aina liitetty ainoastaan yhteen dokumenttiin, joten

506 Kehittyneet dokumentti/näkymä-tekniikat näkymäluokalle riittää yksinkertaisesti yksi GetDocument-funktio. Tämän funktion palauttama osoitin muutetaan automaattisesti sovelluskohtaisen dokumenttiluokkasi tyyppiseksi AppWizardin tekemässä koodissa. Dokumenttiin puolestaan voi liittyä yksi tai useampi näkymä, ja lisäksi dokumenttiolioita saattaa olla useita. Aktiivisen dokumentin tai näkymän löytämiseksi tulee ensin löytää aktiivinen MDI-lapsi-ikkuna ja sen jälkeen voidaan kutsua joko GetActiveDocument- tai GetActiveView-funktiota, kuten seuraavassa esimerkissä on esitetty: // Etsi aktiivinen MDI-lapsi-ikkuna CMDIChildWnd* pchild = ((CMDIChildWnd*) AfxGetMainWnd())- >MDIGetActive(); // Hae aktiivinen dokumentti CMDICoinDoc* pdoc = (CMDICoinDoc*) pchild- >GetActiveDocument(); Näkymä tuntee ainoastaan yhden dokumentin Dokumenttioliolla voi olla useita näkymiä, mutta näkymä voidaan liittää ainoastaa yhteen dokumenttiin. // Hae aktiinen näkymä CMDICoinview* pview = (CMDICoinview*) pchild- >GetActiveView(); Jos haluat suorittaa tehtävän joissain tai kaikissa dokumenttiin liittyvissä näkymissä, käy dokumentin kaikki näkymät läpi dokumentin funktioilla GetFirstViewPosition ja GetNextView seuraavan esimerkin tavoin: void MyDoc::DoTaskForAllViews() { POSITION pos = GetFirstViewPosition(); while (pos!= NULL) { CMyView* pmyview = GetNextView(pos); PMyView->DoTask(); // tee jotain, esimerkiksi omalla DoTask-funktiolla } MDI-esimerkkisovelluksen kehittäminen Tämän luvun alussa teit MDICoin-esimerkkiprojektin. Tähän asti se on toiminut esimerkkikoodina selittämään MDI-sovellusrungon toimintaa. Tässä kappaleessa kehität esimerkkiä, aluksi esittämään kuvan

kolikkopinosta sekä lisäämään ja poistamaan kolikoista valikon komennoilla. Sen jälkeen luot toisen dokumenttityypin esittämään seteleitä. Tämä toinen dokumenttityyppi vaatii oman dokumenttiluokkansa, omat näkymänsä sekä resurssit. Tälle tyypille tulee myös luoda, alustaa ja rekisteröidä sovellukseen dokumenttimalliolio. OSA V LUKU 21 507 Jäsenmuuttujien lisääminen dokumenttiin Esimerkin dokumenttiluokka CMDICoin tarvitsee ainoastaan yhden jäsenmuuttujan eli kolikoiden lukumäärän pinossa. Jotta näkymäluokka voisi käsitellä tätä tietoa, dokumenttiluokkaan joudutaan lisäämään funktio, jolla tieto saadaan. Lisää tämä koodi seuraavien ohjeiden mukaan. Dokumentin tietojen varastoinnin ja saantimetodin toteutus 1. Valitse ClassView-ruudussa CMDICoinDoc-luokka ja sen pikavalikosta Add Member Variable komento. 2. Valitse Member Variables välilehti. Anna muuttuja tyypiksi Variable Type ruutuun int ja nimeksi Variable Name ruutuun m_ncoins. Valitse vielä Protected Access - valintapainike. Napauta OK. 3. Kun CMDICoinDoc-luokka on vielä valittuna, valitse sen pikavalikosta Add Member Function komento. 4. Syötä funktion tyypiksi Function Type ruutuun int ja määrittelyksi Function Declaration ruutuun GetCoinCount. Valitse vielä Public Access valintapainike. 5. Kirjoita seuraava koodi GetCoinCount-funktion sisään: return m_ncoins; 6. Kaksoisnapauta ClassView-ruudussa muodostinfunktiota CMDICoinDoc. 7. Lisää seuraava koodirivi muodostinfunktioon TODO-kommenttien jälkeen: m_ncoins = 1; Nyt CMDICoinDoc-luokassa on suojattu (protected) jäsenmuuttuja m_ncoins, joka alustetaan muodostinfunktiossa. Huomaa, että muuttujien alustaminen dokumentin muodostimessa on turvallista MDI-sovelluksissa muttei välttämättä SDI-sovelluksissa. MDI-

508 Kehittyneet dokumentti/näkymä-tekniikat sovelluksissa uusi dokumenttiolio varataan aina uutta dokumenttia avattaessa ja tuhotaan sitä suljettaessa. SDI-sovelluksissa dokumenttiolio varataan vain kerran ja sitä käytetään uudelleen seuraavissa dokumenteissa; olio tuhotaan vasta sovellusta suljettaessa. Olet lisännyt myös saantifunktion GetCoinCount, jolla näkymä saa luettua m_ncoins-muuttujan arvon. Dokumentin muuttujien suojaaminen Dokumenttiluokassa tulee käyttää suojattuja (protected) jäsenmuuttujia, joita käsitellään julkisilla (public) saantifunktioilla. KATSO MYÖS Lisätietoja alustuksista SDI-sovelluksissa luvusta 12. Dokumentin tietojen hakeminen näkymästä Jotta näkymä saisi tietoja dokumentista, sen tulee ensiksi päästä käsiksi dokumenttiolioon. MFC-sovellusrungossa tämä onnistuu automaattisesti sovelluksen näkymäluokkaan lisätyn GetDocument-funktion avulla. Tämä funktio palauttaa osoittimen dokumenttimallissa näkymään liitettyyn dokumenttiin. CMDICoinView-luokka näyttää kolikkopinon OnDraw-funktiolla. MFCsovellusrunko kutsuu OnDraw-funktiota aina, kun näkymä tulee piirtää näytölle. Muokkaa siis CMDICoinView::OnDraw-funktiosi listauksen 21.2 mukaiseksi. LISTAUS 21.2 LST21_2.CPP Näkymän piirtäminen dokumentista luetun tiedon perusteella 1 void CMDICoinView::OnDraw(CDC* pdc) 2 { 3 CMDICoinDoc* pdoc = GetDocument(); 4 ASSERT_VALID(pDoc); 5 6 // TODO: add draw code for native data here 7 // ** Save the current brush 8 CBrush* poldbrush = pdc->getcurrentbrush(); 9 10 // ** Create a solid yellow brush 11 CBrush br; 12 br.createsolidbrush(rgb(255,255,0)); 13 14 // ** Select the yellow brush in to the device context 15 pdc->selectobject(&br); 16 17 // ** Retrieve the number of coins from the document 18 // ** and draw two ellipses to represent each coin 19 for(int ncount = 0; ncount < pdoc->getcoincount();ncount++) 20 { 21 int y = 100-10 * ncount;

OSA V LUKU 21 509 22 pdc->ellipse(40, y, 100, y-30); 23 pdc->ellipse(40, y-10, 100, y-35); 24 } 25 26 // ** Restore the current brush 27 pdc->selectobject(poldbrush); 28 } AppWizard on tehnyt valmiiksi funktion kaksi ensimmäistä riviä (3 ja 4). GetDocument-funktio palauttaa osoittimen tähän näkymään liitettyyn dokumenttiolioon. Dokumenttiosoitinta käytetään riviltä 19 alkavassa forsilmukassa kolikoiden lukumäärän selvittämiseen GetCoinCountfunktiolla. KATSO MYÖS Lisätietoja piirtopinnasta luvusta 15. Lisätietoja grafiikan piirtämisestä luvusta 16. Dokumentin tietojen muuttaminen ja näkymän päivittäminen Kolikoiden lukumäärän muuttamiseksi joudut lisäämän MDICoinesimerkkiin kaksi valikon komentoa toisen lisäämään ja toisen poistamaan kolikon. Nämä komennot kutsuvat ne valittaessa dokumenttiluokan funktiota, joka joko kasvattaa tai vähentää pinossa olevien kolikoiden lukumäärää ja joka varmistaa, että tuohon dokumenttiin liittyvät näkymät päivitetään. Lisää valinnat IDR_MDICOITYPE-valikkoresurssiin, koska komennot ovat dokumenttityyppikohtaisia. Lisäämisohjeet on esitetty seuraavaksi. Valikon komentojen lisääminen 1. Avaa ResourceView-sivulla Menu-kansio ja kaksoisnapauta IDR_MDICOITYPE-alkiota. Saat valikkoresurssin esiin editoriin. 2. Napauta resurssieditorissa Edit-valikon otsikkoa ja saat esiin alasvetovalikon. 3. Kaksoisnapauta alasvetovalikon viimeistä tyhjää alkiota. Menu Item Properties ikkuna tulee esiin (kuva 21.7). 4. Syötä valikon ID-tunnus, joka tässä esimerkissä on ID_EDIT_ADD_COIN.

510 Kehittyneet dokumentti/näkymä-tekniikat 5. Syötä valikon komennon nimi Caption-ruutuun, tässä Add a Coin. 6. Syötä komennon tilarivin ohjeteksti Prompt-ruutuun, tässä Increase the number of coins. 7. Kaksoisnapauta alasvetovalikon tyhjää alkiota. 8. Syötä valikon ID-tunnus, joka tässä esimerkissä on ID_EDIT_REMOVE_COIN. 9. Syötä valikon komennon nimi Caption-ruutuun, tässä Remove a Coin. 10. Syötä komennon tilarivin ohjeteksti Prompt-ruutuun, tässä Decrease the number of coins. 11. Käynnistä ClassWizard näppäilemällä Ctrl+W tai valitsemalla View-valikosta ClassWizard. 12. Valitse Message Maps välilehti. 13. Valitse Class Name yhdistelmäruudussa CMDICoinDoc. 14. Valitse Object IDs -luetteloruudusta ID_EDIT_ADD_COIN. 15. Valitse Messages-luettelosta COMMAND ja napauta sitten Add Function painiketta. Napauta Add Member Function ikkunassa OK. 16. Valitse Object IDs-luetteloruudusta ID_EDIT_REMOVE_COIN. 17. Valitse Messages-luettelosta COMMAND ja napauta sitten Add Function painiketta. Napauta Add Member Function ikkunassa OK. 18. Napauta Edit Code painiketta. 19. Dokumentin tietojen muuttamisen pitäisi näkyä kaikissa siihen liitetyissä näkymissä. Tämä saadaan aikaan kutsumalla näkymän uudelleenpiirtofunktiota. Muokkaa uusia komennonkäsittelijöitä OnEditAddCoin ja OnEditRemoveCoin listauksen 21.3 mukaisesti.

OSA V LUKU 21 511 KUVA 21.7 Menu Item Properties ikkuna. LISTAUS 21.3 LST21_3.CPP Dokumenttiin liitettyjen näkymien päivittäminen 1 void CMDICoinDoc::OnEditAddCoin() 2 { 3 // TODO: Add your command handler code here 4 5 // ** Increment the number of coins 6 m_ncoins++; 7 8 // ** Update view to redraw coin stack 9 UpdateAllViews(NULL); 10 } 11 12 void CMDICoinDoc::OnEditRemoveCoin() 13 { 14 // TODO: Add your command handler code here 15 16 // ** Decrement the number of coins 17 if(m_ncoins > 0) 18 m_ncoins--; 19 20 // ** Update view to redraw coin stack 21 UpdateAllViews(NULL); 22 }

512 Suorituskyvyn parantaminen näkymiä päivitettäessä Voit syöttää sovelluskohtaista vinkkitietoa UpdateAllViews()- funktiolle. Vinkki välitetään edelleen OnUpdate()-funktiolle ja se voidaan edelleen tulkita päivityskohteista päätettäessä. Kehittyneet dokumentti/näkymä-tekniikat Kuten huomaat, koodin funktio joko kasvattaa tai pienentää m_ncoinsmuuttujaa (rivit 6 ja 18). Tämän jälkeen kutsutaan UpdateAllViewsfunktiota NULL-parametrillä (rivit 9 ja 21). NULL-arvo parametrissä tarkoittaa, että kaikki dokumenttiin liitetyt näkymät tulee päivittää. Kukin näkymä päivitetään kutsumalla sen OnUpdate-funktiota. Tämä merkitsee ikkunan työalueen vanhentuneeksi (invalidate), mikä saa aikaan OnDrawfunktion kutsumisen. Käännä ja aja nyt MDICoin-projektisi. Kokeile uuden dokumentti-ikkunan luomista valitsemalla File-valikosta New ja valitse sitten Add a Coin tai Remove a Coin komento valikosta. Ohjelman tulisi näyttää tällöin kuvan 21.8 mukaiselta. Myös toisen näkymän luomisen samaan dokumenttiin pitäisi onnistua Window-valikon New Window komennolla. KUVA 21.8 MDICoin-sovellus. Uusien dokumenttimallien lisääminen MDI-sovellusten etu SDI-sovelluksiin nähden ei ole pelkästään mahdollisuus työstää useampia avoimia dokumentteja, vaan myös mahdollisuus käsitellä eri tyyppisiä dokumentteja samassa sovelluksessa. Tämän onnistumiseksi joudut luomaan omat dokumentti- ja näkymäluokkasi, lisäämään resurssit sekä koodin luomaan ja alustamaan CMultiDocTemplate-olion. Tässä kappaleessa tulet lisäämään MDICoin-sovellukseen uuden dokumenttiluokan, joka näyttää kolikoiden sijaan seteleitä. Tee aluksi uusi dokumentti- ja näkymäluokka seuraavien ohjeiden mukaan. Uuden dokumentti- ja näkymäluokan luominen

1. Käynnistä ClassWizard näppäilemällä Ctrl+W tai valitsemalla Viewvalikosta ClassWizard. 2. Napauta Add Class painiketta ja valitse esitetystä luettelosta New. Saat esiin New Class ikkunan. 3. Anna uudelle luokalle nimeksi Name-ruutuun (tässä sovelluksessa) CMDIBillDoc. 4. Valitse kantaluokaksi Base Class yhdistelmäruudusta CDocument. Lisää luokka painamalla OK. 5. Napauta Add Class painiketta ja valitse esitetystä luettelosta New. Saat esiin New Class ikkunan. 6. Anna uudelle luokalle nimeksi Name-ruutuun (tässä sovelluksessa) CMDIBillView. 7. Valitse kantaluokaksi Base Class yhdistelmäruudusta CView. Lisää luokka painamalla OK. 8. Sulje ClassWizard OK-painikkeella. 9. Valitse ClassView-sivulla CMDIBillDoc-luokka ja sen pikavalikosta Add Member Variable. 10. Valitse Member Variables välilehti. Syötä muuttujan tyypiksi Variable Type ruutuun int ja nimeksi Variable Name ruutuun m_nbills. Valitse lisäksi Protected valintapainike ja napauta OK. 11. Kun CMDIBillDoc-luokka on vielä valittuna, valitse sen pikavalikosta Add Member Function komento. 12. Syötä funktion tyypiksi Function Type ruutuun int ja määrittelyksi Function Declaration ruutuun GetBillCount. Valitse vielä Public Access valintapainike. 13. Kirjoita seuraava koodi GetBillCount-funktion sisään: return m_nbills; 14. Kaksoisnapauta ClassView-sivulla muodostinfunktiota CMDIBillDoc. 15. Lisää seuraava koodirivi muodostinfunktioon TODO-kommenttien jälkeen: m_nbills = 1; 16. Valitse ClassView-sivulla CMDIBillView-luokka ja sen pikavalikosta Add Member Function. 17. Syötä funktion tyypiksi Function Type ruutuun CMDIBillDoc* OSA V LUKU 21 513

514 Kehittyneet dokumentti/näkymä-tekniikat ja määrittelyksi Function Declaration ruutuun GetDocument. Valitse vielä Public Access valintapainike. 18. Lisää seuraava koodirivi muodostinfunktioon TODO-kommenttien jälkeen: return (CMDIBillDoc*)m_pDocument; Nyt olet tehnyt uuden dokumentti- ja näkymäluokan. Dokumentilla on jäsenmuuttuja tiedon tallentamiseen ja sille saantifunktio. Näkymäluokalla on metodi, jolla se saa selville siihen liitetyn dokumentin. Huomaa, että joudut lisäämään seuraavan #include-lauseen MDIBillView.cpp tiedoston alkuun ennen #include MDIBillView.h lausetta: #include MDIBillDoc.h Seuraava vaihe on valikkoresurssin lisääminen. Saat tehtyä uuden valikkoresurssin olemassa olevasta kopioimalla seuraavin ohjein. Dokumenttivalikon luominen 1. Laajenna ResourceView-sivulla Menu-kansio ja valitse siitä IDR_MDICOITYPE-alkio. Näppäile Ctrl+C ja sen jälkeen Ctrl+V, jolloin kopioitu valikko saa ID-tunnuksen IDR_MDICOITYPE1. 2. Valitse ResourceView-sivulla IDR_MDICOITYPE1 ja sen pikavalikosta Properties. Saat esiin Menu Properties asetusikkunan. 3. Syötä valikon ID-tunnukseksi (tässä esimerkissä) IDR_MDIBILTYPE. Sulje Menu Properties ikkuna. 4. Kaksoisnapauta ResourceView-sivulla IDR_MDIBILTYPE-alkiota ja saat valikon esiin resurssieditoriin. 5. Napauta editorin ikkunassa Edit-valikkoa. Saat esiin valikon komennot. 6. Kaksoisnapauta Add a Coin komentoa. Saat esiin Menu Properties asetusikkunan. 7. Syötä valikon alkion ID-tunnukseksi (tässä esimerkissä) ID_EDIT_ADD_BILL. 8. Syötä valikon komennon nimi Caption-ruutuun, tässä Add a Bill. 9. Syötä komennon tilarivin ohjeteksti Prompt-ruutuun, tässä Increase the number of bills ja kaksoisnapauta Remove a Coin - alkiota.

10. Syötä valikon ID-tunnus, joka tässä esimerkissä on ID_EDIT_REMOVE_BILL. 11. Syötä valikon komennon nimi Caption-ruutuun, tässä Remove a Bill. 12. Syötä komennon tilarivin ohjeteksti Prompt-ruutuun, tässä Decrease the number of bills. 13. Valitse File-valikosta Save ja sitten samasta valikosta Close. 14. Käynnistä ClassWizard näppäilemällä Ctrl+W tai valitsemalla View-valikosta ClassWizard ja valitse Message Maps välilehti. 15. Valitse Class Name yhdistelmäruudussa CMDIBillDoc. 16. Valitse Object IDs-luetteloruudusta ID_EDIT_ADD_BILL. 17. Valitse Messages-luettelosta COMMAND ja napauta sitten Add Function painiketta. Napauta Add Member Function ikkunassa OK. 18. Valitse Object IDs-luetteloruudusta ID_REMOVE_ADD_BILL. 19. Valitse Messages-luettelosta COMMAND ja napauta sitten Add Function painiketta. Napauta Add Member Function ikkunassa OK. 20. Sulje ClassWizard napauttamalla OK. Nyt CMDIBillDoc-luokassasi on kaksi uutta komennonkäsittelijäfunktiota: OnEditAddBill ja OnEditRemoveBill. Näiden funktioiden tulee kasvattaa ja vähentää m_nbills-muuttujan arvoa. Muokkaa nämä kaksi uutta funktiota listauksen 21.3 pohjalta käyttämään m_ncoins-muuttujan sijaan m_nbills-jäsenmuuttujaa. Funktioiden koodaamisen jälkeen pääset luomaan dokumentille resurssitekstin. OSA V LUKU 21 515 Dokumenttimerkkijonon luominen 1. Avaa ResourceView-sivulla String Table kansio ja kaksoisnapauta siitä String Table alkiota. Merkkijonotaulukko (string table) avautuu resurssieditoriin. 2. Pääset lisäämään uuden merkkijonon IDR_MDICOITYPE-tekstin alle valitsemalla ensin merkkijonotaulukosta IDR_MDICOITYPEalkion ja sen pikavalikosta New String. Saat tällöin esiin String Properties ikkunan. 3. Anna merkkijonolle ID-tunnukseksi (tässä esimerkissä)

516 Kehittyneet dokumentti/näkymä-tekniikat IDR_MDIBILTYPE. 4. Syötä varsinainen teksti Caption-ruutuun. Tässä esimerkissä tuo teksti on: \nmdibil\nbills\n\n\nmdibill.document\nmdibil Document 5. Muokkaa IDR_MAINFRAME-merkkijonoksi MDICoins&Bills. 6. Muokkaa IDR_MDICOITYPE-merkkijonoksi: \nmdicoi\ncoins\n\n\nmdicoi.document\nmdicoi Document 7. Sulje String Properties ikkuna. Dokumentin teksti on annettava määrätyssä muodossa tämä on sama SDI- ja MDI-sovelluksissa. Teksti on jaettu seitsemäksi rivinvaihdoilla (\n) erotetuksi kentäksi. Näiden kenttien merkitys on esitetty taulukossa 21.3. TAULUKKO 21.3 Dokumenttimerkkijonoresurssi Kenttä Esimerkki Kuvaus 1 MDI-sovelluksessa tyhjä. SDI-sovelluksessa tämä on sovelluksen nimi. MDI-sovelluksissa nimi on erikseen IDR_MAINFRAME:ssa. 2 MDICoi Dokumentin oletusnimi. Kuhunkin uuteen dokumenttiin lisätään automaattisesti tunnusnumero. Esimerkiksi MS Word ohjelmassa merkkijono on Document (Asiakirja), jolloin ensimmäisestä uudesta dokumentista tulee Document1, toisesta Document2 jne. 3 Coins Dokumentin otsikko. Tätä käytetään esitettäessä dokumenttiluettelo käyttäjälle. Jos haluat piilottaa dokumentin käyttäjältä, jätä tämä kenttä tyhjäksi. 4 Coin Viewer (*.coi) Dokumentin tyyppi ja tiedostotyyppi suodattimen kuvaus. Tätä käytetään Avaa tiedosto valintaikkunan Tiedostotyypityhdistelmäruudussa. 5.coi Dokumenttiin liitetty tiedostotarkenne. Asteriskia (*) ei tarvita tässä kentässä.

Kenttä Esimerkki Kuvaus 6 MDICoi.Document Rekisteröintinimi Resurssienhallinnalle. Tällä dokumentin tyyppi liitetään Resurssien hallintaan, jotta dokumenttitiedostoa avattaessa käynnistettäisiin siihen liitetty sovellus. 7 MDICoi Document Rekisterin ja OLE:n tunnistenimi. Tämä merkkijono tallennetaan rekisteriin OLEtoimintojen käyttämiseksi. Käyttäjät näkevät tämän nimen valitessaan OLE-komennon Insert Object (Lisää Objekti). OSA V LUKU 21 517 Kaikki on nyt valmista uusien MDICoin-esimerkin dokumentti- ja näkymäluokkien käyttöä varten. Voit antaa MFC-sovellusrungon huolehtia olioiden alustamisesta ja näkymä- ja kehysikkunoiden hallinnasta.. Tätä varten joudut ainoastaan rekisteröimään sovellukseesi dokumentti/näkymä/kehysjoukon luomalla toisen dokumenttimallin. Dokumenttimallit rekisteröidään sovelluksen korvatussa CWinApp::InitInstance-funktiossa. Saat luotua dokumenttimallin lisäämällä rivien 16 25 koodin listauksesta 21.4. Huomaa, että tarvitset vielä seuraavat #include-lauseet MDICoinApp.Cpp-tiedoston alkuun: #include MDIBillDoc.h #include MDIBillView.h LISTAUS 21.4 LST21_4.CPP Dokumenttimallin luominen ja alustaminen 1 BOOL CMDICoinApp::InitInstance() 2 { 3 // ** Alusta on poistettu selkeyden vuoksi rivejä 4 5 // Register the application's document templates.document templates 6 // serve as the connection between documents,frame windows and views. 7 8 CMultiDocTemplate* pdoctemplate; 9 pdoctemplate = new CMultiDocTemplate( 10 IDR_MDICOITYPE, 11 RUNTIME_CLASS(CMDICoinDoc), 12 RUNTIME_CLASS(CChildFrame), // custom MDI child frame 13 RUNTIME_CLASS(CMDICoinView)); 1 14 AddDocTemplate(pDocTemplate); 15 1 Alkuperäinen AppWizardin lisäämä dokumenttimalliolio.

518 Kehittyneet dokumentti/näkymä-tekniikat 2 Lisää sovellukseen toinen dokumenttimalliolio. 16 // Luodaan ja alustetaan toinen dokumenttimalli 17 // syöttäen parametreinä dokumentin resurssitunnus 18 // sekä dokumentti-, kehys- ja näkymäluokkien 19 // ajonaikaiset luokkatiedot. Sen jälkeen sovellus rekisteröidään AddDocTemplate-funktiolla 20 pdoctemplate = new CMultiDocTemplate( 21 IDR_MDIBILTYPE, 22 RUNTIME_CLASS(CMDIBillDoc), 23 RUNTIME_CLASS(CChildFrame), // custom MDI child frame 24 RUNTIME_CLASS(CMDIBillView)); 2 25 AddDocTemplate(pDocTemplate); 26 27 // create main MDI Frame window 28 CMainFrame* pmainframe = new CMainFrame; 29 if (!pmainframe->loadframe(idr_mainframe)) 30 return FALSE; 31 m_pmainwnd = pmainframe; 32 33 // ** Lopusta on poistettu rivejä selkeyden vuoksi 34 } Lopuksi tarvitset vielä näkymäluokkaan setelit näyttävän koodin dokumentissa olevan lukumäärän mukaan. Muokkaa siis CMDIBillView::OnDraw-funktio listauksen 21.5 mukaiseksi. LISTAUS 21.5 LST21_5.CPP Näkymän piirtokoodin toteutus 1 Hakee osoittimen dokumenttiolioon. 2 Kutsuu dokumentin saantifunktiota, joka palauttaa seteleiden lukumäärän. 1 void CMDIBillView::OnDraw(CDC* pdc) 2 { 3 // ** Retrieve a pointer to the document 4 CMDIBillDoc* pdoc = GetDocument(); 1 5 ASSERT_VALID(pDoc); 6 7 // ** Save the current brush 8 CBrush* poldbrush = pdc->getcurrentbrush(); 9 10 // ** Create a solid yellow brush 11 CBrush br; 12 br.createsolidbrush(rgb(0,128,32)); 13 14 // ** Select the yellow brush in to the device context 15 pdc->selectobject(&br); 16 17 // ** Retrieve the number of coins from the document 18 // ** and draw two ellipses to represent each coin 19 for(int ncount = 0; ncount < pdoc->getbillcount();ncount++)2 20 { 21 int x = 40 + 20 * ncount; 22 pdc->rectangle(x, 40, x+100, 90); 23 pdc->textout(x + 5, 45, "$"); 24 }

25 26 // ** Restore the current brush 27 pdc->selectobject(poldbrush); 28 } OSA V LUKU 21 519 GetDocument-funktio palauttaa osoittimen dokumenttiolioon ja osoitin talletetaan pdoc-muuttujaan. Osoittimen avulla haetaan riviltä 19 alkavassa for-silmukassa seteleiden lukumäärä kutsumalla saantifunktiota GetBillCount. Varsinainen piirtokoodi esittää ainoastaan halvan väärennöksen dollarin setelistä käyttämällä vihreää sivellintä suorakulmion täyttämiseen ja tekstiä $. Käännä ja suorita sovelluksesi. Kun valitset File-valikosta New tulisi New ikkunan tulla esiin. Kokeile molempien dokumenttityyppien avaamista ja vaihtamista toiseen; huomaa tällöin Edit-valikon vaihtuminen aktiivisen dokumentin mukaan. Huomaa myös, että dokumentin ja sovelluksen otsikkopalkin teksti muodostetaan dokumenttityyppiin liittyvän merkkijonoresurssin mukaan. Esimerkki MDICoinsovelluksesta on kuvassa 21.9. KUVA 21.9 MDICoin-sovellus. KATSO MYÖS Lisätietoja valikoista luvusta 13. Lisätietoja piirtopinnoista luvusta 15. Lisätietoja grafiikan piirtämisestä luvusta 16.

520 Kehittyneet dokumentti/näkymä-tekniikat