3. Dialogruta

 

 

·     Ny resurs.

 

·     CDialog.

 

·     UpdateData().

 

·     DoModal().

 

·     Globalt objekt.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Ny resurs.                 

                       [Insert  - Resource...] Ctrl + R

 

Man kan skapa en ny resurs, i detta fall en dialogruta, med hjälp av menykommando, snabbtangent eller verktygsknapp enligt ovan. Om man väljer menykommando eller snabbtangent öppnas vissa valmöjligheter via dialogrutan ‘Insert Resource’:

 

 

Som synes finns ett antal standarddialoger att välja bland, samt möjlighet att importera och kundanpassa dialogrutor.

 

Om vi dubbelklickar på ‘Dialog’, eller om vi från början använde verktygsknap­pen, startas dialogredigeraren:

 

               

 

Liksom vi fann färdiga menyval i menyn vi redigerade i första och andra kapitlet, finner vi här två färdiga knappar: OK och Cancel. Samma sak gäller för dem som för menyvalen. De är redan kopplade till vissa funktioner, och vi tar bara bort dem om vi är säkra på att vi inte kommer att använda dem. Annars blir vi tvungna att ‘koppla rätt’ när vi senare lägger till dem igen. Vi ska behålla dem i vårt exempel.

 

Här finns också ett verktygsfält med diverse kontroller. En gul informationsruta visas om man håller muspekaren över en verktygsknapp, samtidigt som en något fylligare information syns i statusraden. Vi ska just nu intressera oss för två sorters kontroller: ‘Edit Box’ och ‘Button’.

 

Man kan lägga till en kontroll på flera olika sätt. Man kan kopiera en befintlig kontroll och göra lämpliga ändringar i kopian, man kan trycka in en knapp och sedan ‘dra ut’ kontrollens form i dialogrutan och därigenom ge den vissa dimen­sioner. Man kan även trycka ned en verktygsknapp och dra den till den position där man vill ha den, så skapas kontrollen med fördefinierade dimensioner.

 

I nederkanten har vi fått ett annat verktygsfält som hör till dialogeditorn:

 

 

 

 

 

 

 

 

 

 

Längst till vänster är en testknapp som gör att man kan testa hur dialogrutan kommer att se ut när man använder den. Man lämnar sedan testläget med hjälp av Esc. Längst till höger finns en knapp som visar/gömmer linjalerna, och bredvid den en knapp som aktiverar/stänger av rutnätet. Alla knappar däremellan är till för att justera markerade kontroller på olika sätt. Vi har dessutom fått en extra meny som har motsvarande funktioner.

 

Man kan markera kontroller genom att klicka på dem, eller genom att dra ut en ram runt dem. Vill man markera flera kontroller kan man låta ramen innefatta de kontroller man vill ha markerade, eller klicka på kontrollerna en i taget med Ctrl-tangenten nedtryckt.


Dubbelkickar man på en kontroll, eller trycker på ‘Enter’ när den är markerad, öppnas egenskapsrutan för kontrollen. Så här ser det ut om man öppnar egenskaperna för ‘OK’-knappen:

 

 

Här finns en knapp i vänstra övre hörnet med en anslagstavlenål. Om man trycker in den kommer egenskapsrutan att vara öppen hela tiden. När man sedan klickar på olika objekt byter egenskapsrutan utseende allteftersom den visar de olika objektens egenskaper. När man lämnar egenskapsrutan med ‘Enter’, eller klickar utanför rutan, uppdateras kontrollen enligt de ändringar man gjort.

 

Knappen bredvid leder till ett hjälpavsnitt som i korthet beskriver de egenskaper man kan ställa in. Egenskapsrutan har tre flikar, men för vårt exempel behöver vi bara använda den första.

 

Övningsuppgift:

·      Skapa en tryckknapp med texten ‘Skriv’ och id = IDC_SKRIV.

·      Skapa en tryckknapp med texten ‘Sudda’ och id = IDC_SUDDA.

·      Lägg till en textruta (Edit Box) med id = IDC_TEXT.

·      Anpassa storleken på kontrollerna och dialogrutan så att alla kanter passar snyggt och prydligt, t.ex. så här:

 

                

 

Just nu kanske det passar att dialogrutan heter ‘Dialog’, men jag kan knappast tänka mig någon större användning av just det namnet. Om man dubbelklickar på dialogrutan, men utanför kontrollerna, så visar egenskapsrutan själva dialogrutans egenskaper. Där kan man ändra en del, bl.a. namnet. (Det räcker med ett enkelt klick om egenskapsrutan är fastnålad.)


CDialog.

 

Dialogrutan måste representeras av ett objekt som innehåller de funktioner etc. som den behöver. Objektet skapas efter en mall, en klass, som vanligt. Vi skapar klassen genom att ärva från MFC-klassen CDialog. Man kan när som helst lägga till en klass, och vill vi lägga till en till vår dialogruta är det speciellt fördelaktigt att starta ClassWizard nu, för då kommer allt att vara förberett för det vi vill göra:

 

                

 

Vi behöver skapa en ny klass, så det är bara att klicka på ‘OK’:

 


Övningsuppgift:

·      Ändra dialogrutans id till IDD_MINDIALOG.

·      Skapa en klass till dialogrutan.

·      Kalla klassen CMinDialog.

·      Läs informationen i ClassWizards Class Info-flik.

·      Stäng ClassWizard.

·      Kontrollera i FileView att de nya filerna har skapats.

·      Kontrollera att klassen har lagts till i ClassView.

 

 

 

 

I klassen CMinDialog finns enligt ClassView två funktioner: konstruktorn samt DoDataExchange(). Den senare har samma typ av makron som vi känner igen från de andra klasserna. Varje objekt har sin egen fönsterprocedur registrerad, och detta gäller även vår nya dialogruta:

 

 

 

 

void CMinDialog::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CMinDialog)

       // NOTE: the ClassWizard will add DDX and DDV calls here

    //}}AFX_DATA_MAP

}

 

 

Vid kommentaren...

 

// NOTE: the ClassWizard will add DDX and DDV calls here

 

...lägger class wizard automatiskt in de kopplingar som behövs mellan våra variabler och dialogrutans kontroller, vilka egentligen är ‘child windows’ till dialogrutan, och har egna fönsterprocedurer.

 

ClassWizard lägger in speciella anrop här vilka kopplar kontrollerna till variabler, s.k. DDE-anrop, Dynamic Data Exchange. Dessa administreras av AFX och aktiveras av funktionen DoDataExchange(). Olika typer av kontroller har olika typer av variabler. En del kontroller kan ha flera variabler, en del inga alls, medan åter andra har en. Det är här som de variabler vi kan se och manipulera i ClassWizards andra flik kommer in i bilden. Vi ska dock använda en genväg för att deklarera variablerna.


I resurseditorn dubbelklickar man på en kontroll samtidigt som man håller Ctrl-tangenten ned­tryckt. Då öppnar ClassWizard en speciell dialogruta för tillägg av medlems­variabel för kontrollen i fråga. Så här kan det se ut när man vill lägga till en variabel som är avsedd att innehålla den text som ska synas i vår textruta:

 

 

 

 

 

 

 

 

 

 


Variabelns namn föreslås börja på ‘m_’, vilket är det vi vant oss vid när det gäller medlemsvariabler. Man kan skapa en variabel av två olika kategorier, ‘Value’ eller ‘Control’. ‘Value’ ger oss det vi nu behöver, en variabel att innehålla texten. ‘Control’ använder man endast om det inte räcker med en standardhantering av kontrollen, utan man vill han tillgång till kontrollens objekt direkt. Observera att det finns en funktion i CDialog som ger oss adressen till valfri kontroll, så att man kan nå den via pekare, utan att skapa ett objekt.

 

Variabeln kan vara av olika typ. Tidigare versioner av Visual C++ understödde endast text i en textruta, men nu har vi tillgång till omvandling mellan olika datatyper. Text hanteras i en klass som heter CString, liknande den vi själva skapade i förra häftet (CText), och det är den datatypen vi ska välja.

 

Övningsuppgift:

·      Koppla en variabel m_Text till textkontrollen.

·      Stäng dialogeditorn.

·      Öppna dialogrutans implementeringsfil.

·      Kontrollera de olika id som finns tillgängliga, känns de igen?

·      Observera att det finns ett antal olika meddelanden knutna till en textruta, medan en knapp har bara två.

·      Koppla funktioner till knapparna IDC_SKRIV och IDC_SUDDA, meddelande BN_CLICKED.


UpdateData().

 

Automatiken vi förväntar oss när vi kopplar en medlemsvariabel till en kontroll kräver en åtgärd från oss. Vi måste anropa en funktion vi ärvt från CDialog. Funk­tionen heter UpdateData() och har ansvar för uppdatering mellan dialogrutan och vår variabel. Den tar ett argument av typen BOOL. Denna typ finns definier­ad i MFC och kan anta två värden vilka även de finns definierade i MFC: TRUE och FALSE.

 

Anger man argumentet TRUE hämtas data från dialogrutan och sparas i medlems­variabeln. Argumentet FALSE har motsatt effekt, det som finns i variabeln syns på skärmen. Detta kan vi testa i våra nyskapade funktioner.

 

Övningsuppgift:

·      Lägg in följande två programsatser i funktionen OnSkriv():

·      En sats som tilldelar m_Text texten ”Nu tryckte du på skrivknappen!”.

·      En sats som anropar UpdateData() med argumentet FALSE.

·      Lägg in följande två programsatser i funktionen OnSudda():

·      En sats som tilldelar m_Text texten ””.

·      En sats som anropar UpdateData() med argumentet FALSE.


DoModal().

 

Vi kan fortfarande inte testa dialogrutan. Vi har nämligen inte lagt till någon möj­lig­het att öppna den i vårt program. Det finns en funktion i CDialog även för det­ta, DoModal(). Men innan vi kan anropa den måste vi göra ett objekt av vår nya klass CMinDialog.

 

Slå först upp klassen CDialog i hjälpen, och läs om dess medlemmar. Läs om hur man anropar DoModal().

 

Man skapar objektet där man har mest nytta av det. Om dialogrutan innehåller till exempel inställningar som behövs i dokumentet är det bäst att deklarera objektet globalt i dokumentklassen. I vårt fall lägger vi det till att börja med lokalt i en funktion i vyn. För att kunna använda klassen CMinDialog i vyn måste vi lägga till satsen ‘#include "MinDialog.h"’ i början av HelloView.h.

 

Övningsuppgift:

·      Lägg till ett menyval i File-menyn under kommandot ‘Hello’. Kalla det ‘Visa Min Dialog’.

·      Koppla menyvalet till en funktion i vyn.

·      Skapa ett lokalt objekt ‘dia’ av typen CMinDialog i funktionen.

·      Anropa DoModal() för objektet dia med hjälp av elementoperatorn.

·      Skriv in #include-satsen enligt ovan.

·      Kompilera, länka och testa. Så här ska det bli:

 


Globalt objekt.

 

Om vi testar att stänga dialogrutan medan texten ‘Nu tryckte du på skrivknapp­en!’ syns i textrutan, och sedan öppna den igen, ser vi att texten försvunnit. Oav­sett om vi avslutar med ‘OK’ eller ‘Cancel’ öppnas alltid dialogrutan i ett initial­tillstånd varje gång. Anledningen till detta är att objektet ligger lokalt i en funk­tion. Vill vi att den ska ‘komma i håg’ sitt tidigare tillstånd, det vill säga variablerna ska behålla sina värden, behöver vi bara se till att objektet existerar så länge vi be­höv­er det.

 

Därför testar vi att deklarera det globalt i stället. Flytta satsen CMinDialog dia; till HelloView.h och lägg den där under attributes (public;). Om detta ska bli godkänt måste ‘#include Mindialog.h’ göras på rätt ställe. Vi lägger den i början av HelloView.h. Man skulle kunna tycka att det räcker med att man ser till att den står före ‘#include HelloView.h’ i HelloView.cpp, men HelloView.h finns med i flera andra implementeringsfiler, så då skulle CMinDialog vara okänd i de filsam­man­hangen, och vi skulle få ‘Error: missing dekl. Specifiers’.

 

Övningsuppgift:

·      Flytta objektdeklarationen till vyns klassdeklaration enligt ovan.

·      Kompilera, länka och testa så att dialogrutan kan komma ihåg sitt tidigare tillstånd mellan anropen.

 

Nyss nämndes ‘initialt tillstånd’. Var har egentligen m_Text blivit initierat? Titta i MinDialog.cpp så får du se.

 

Övningsuppgift:

·      Initiera m_Text till ”Initial text.”

·      Kompilera, länka och testa. Man ska inte kunna få tillbaka ”Initial text.” När man väl tryckt på någon av knapparna.

 

Varför är det ingen skillnad på knapparna ‘OK’ och ‘Cancel’? Vi har här en dialogruta som ändrar sin variabel direkt. Vi kommer senare att skapa en dialog där variabeln ändras först när vi avslutar dialogen. Då kan man byta ut ha­nte­ring­en av ‘OK’-knappen och kopiera in rätt värde i variabeln där. Däremot på­ver­kas ingenting om man väljer ‘Cancel’, och det är väl det som är meningen? I detta enkla exempel vi har nu är det ingen mening med att skilja på knapparna.


Övningsuppgift:

·      Om du arbetat med samma projekt utan att skapa om det är det dags att du suddar det nu, och skapar ett nytt projekt. Du kommer väl ihåg hur man använder AppWizard? Kalla projektet Nej.

·      Ta bort ‘Edit’-menyn och ändra ‘File’-menyn så att den innehåller endast ‘Visa Dialog’ och ‘Avsluta’, åtskilt med en separator. (Ta inte bort ‘Exit’, ändra bara ‘Caption’.) Ändra ‘Caption’ för ‘File’-menyn till ‘Arkiv’.

·      Skapa en dialogruta med ett textfält och en jättestor knapp enligt nedan­stående bild:

 

 

·      Om man ändå trycker på knappen ska följande ske:

·      Första gången skrivs texten: ‘Du skulle ju inte trycka på knappen!’ i textrutan.

·      Andra gången (du behöver en medlemsvariabel eller en statisk variabel att räkna antalet tryckningar med) skrivs texten:
‘Vad nu, kan du inte läsa va?’

·      Därefter väljs fyra meddelanden om och om igen (3, 4, 5, 6, 3, 4, 5, 6…):
‘Tyckte du att du var rolig nu va? Jag kan också trycka på knappar!’
‘Tafsar du mer på min knapp så skriker jag! IIIIIIIIIIIIIIII…’
‘Jag undrar om du inte har lite svårt att fatta vad jag menar: TRYCK INTE!’
‘Det här är inte kul längre, men du kan ju knappast trycka på ‘OK’!’

·      För att kunna göra detta måste du titta på egenskaperna för dialogrutan, knappen och textrutan. Observera att jag har valt en font som endast visar versaler (Algerian 48). Du väljer själv efter vad som finns på din dator.

·      Textrutan ska bl.a. vara flerradig och endast till för utmatning av text.


Överkursuppgift:

·      Försök att hitta något ställe i projektet Nej där man kan lägga in objektet för dialogrutan, och visa den, så att den visas automatiskt när man startar programmet. Ta inte bort den gamla koden, kopiera den bara. (Observera att objektet skapas direkt innan DoModal() anropas, vi har inte ett objekt som deklarerats i Vy-klassen denna gång.)

 

Överkursuppgift:

·      Slå upp ‘rand’ i hjälpen. (Se hjälpanvisning nedan).

·      Bygg en klass ‘CSlump’ avsedd att generera slumptal.

·      Inkludera headerfilen Stdafx.h

·      Konstruktorn ska ta ett heltal som argument. Detta sparas i medlemsvariabeln m_Range. Konstruktorn ska även initiera slumptalssekvensen (se hjälpen!).

·      När du läst hjälpen vill du säkert veta värdet på RAND_MAX. Hur kan du ta reda på det, när det nu inte står i hjälpen?

·      Det ska finnas en metod ‘Nasta’ som genererar och returnerar nästa slumptal. Slumptalet som genereras ska ligga inom området 1 till m_Range.

·      Vill man sedan skapa t.ex. en tärning kan man deklarera ett objekt:
‘CSlump Tarning(6);’ och sedan hämta slumptal inom området 1 - 6 till en egen variabel med följande syntax: ‘slumtal = Tarning.Nasta();’, om den egna variabeln heter slumptal.

·      Spara denna klass för framtida bruk i en separat katalog!

·      Kopiera in den och använd den i projektet Nej enligt följande: I stället för att de fyra sista meddelandena upprepas i sekvens väljer slumptalsgeneratorn bland alla sex meddelanden.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

? Visual C++ Books - C/C++ - Run-Time Library Reference - Alphabetic Function Reference - P through R - rand.