6. Listrutan

 

 

·     Programmet.

 

·     Variablerna.

 

·     Använda vald detalj.

 

·     Att hitta rätt detalj.

 

·     Listrutans inbyggda textvariabler.

 

·     Component Gallery.

 

·     SendDlgItemMessage().

 

 

 

 

 

 

 

 

 

 

 

 

 


Programmet.

 

Vi ska prova att använda en listruta. Programmet ska ha en dialogruta som vi förutom ‘OK’ förser med en listruta. (‘Cancel’ tar vi bort.) Tanken är att man ska kunna välja mellan ett antal namn, och genom att dubbelklicka på ett namn ska man få information om personens telefonnummer, vilket visas i en AfxMessageBox. Så här ska det se ut:

 

 

 

 

 

 

 

 

 

 

Man skapar en listruta genom att använda -knappen. Läs om egenskaperna, och anpassa listrutan på lämpligt sätt!

 

 

 

 

 

 

 

 

? Tryck på ?-knappen i egenskapsrutan, en gång för varje valdflik.


Variablerna.

 

Vi kommer i första version att använda två CString-listor med 15 element var. Den ena ska innehålla namnen och den andra motsvarande telefonnummer. Dek­larera listan globalt i dialogrutans klass, och initiera med 15 namn i konstruktorn.

 

När dialogrutan sedan initieras ska vi kopiera in namnen i listrutan. Till detta kan vi använda funktionen AddString() som finns i CListBox. Det enklaste är att skap en kontrollvariabel till listrutan och anropa funktionen på denna variabel. Kalla variabeln m_ListKontroll. Se till så att du verkligen skapar en kontrollvariabel och ingenting annat.

 

Därefter kan vi lägga till en funktion för WM_INITDIALOG, och göra en pro­gramloop som fyller i listrutan:

 

    for(int i = 0; i < 15; i++)

    {

        m_ListKontroll.AddString(m_Namn[i]);

    }

 

När vi kompilerat, länkat och testar dialogrutan kommer den att se ut så här:

 

 

 

           

 

 

 

Lägg speciellt märke till att inte alla namn fick plats. Därigenom fick vi automa­tiskt en rullningslist i högerkanten, om du inte valt bort den bland egenskaperna vill säga. Observera också att listan är sorterad i bokstavsordning, under samma förutsättning.

 

? CListBox::AddString().


Använda vald detalj.

 

När man dubbelklickar på en rad ska en AfxMessageBox() berätta vilket telefon­nummer som motsvarar det valda namnet. Därför måste vi även ha en lista över dessa. Skapa en telefonnummerlista på samma sätt som namnlistan.

 

Lägg en ‘handler’ till listrutans meddelande för dubbelklick. I den funktionen kan man använda listruteobjektets GetCurSel() för att få reda på vilken rad användaren har klickat på:

 

void CNamnDialog::OnDblclkList()

{

    int i = m_ListKontroll.GetCurSel();

    CString csText = m_Namn[i] + ": " + m_Nummer[i];

    AfxMessageBox(csText,MB_ICONINFORMATION);

}

 

 

Så här kan det se ut när vi testar:

 

 

         

 

 

Nästan fint. Tyvärr blev det fel information, eftersom listrutan innehåller vår listas innehåll efter sortering i bokstavsordning. Radnummer är alltså inte lika med ind­ex till vår lista.

 

? CListBox::GetCurSel().


Att hitta rätt detalj.

 

Alltså får vi på något sätt skaffa oss tillgång till rätt index. Nu är det så att listrut­an för utom text kan innehålla en information på varje rad, ett så kallad ‘item data’. Detta data kan vi sätta efter att vi lagt in en text, och det vi vill märka raden med är naturligtvis det index vi behöver till listan.

 

När vi lagrar en text i listrutan m.h.a. AddString() vet vi inte var den hamnar, eftersom den sorteras in i bokstavsordning. Därför ska vi genast leta upp den igen, och märka den med det index som gäller för vår text. I den programslinga som lägger in texterna i listboxen lägger vi till två saker: Leta upp den rad som innehåller texten vi just lagrat med hjälp av funktionen FindStringExact() och märk raden med indexet ‘i’ med hjälp av funktionen SetItemData(). Slå upp funktionerna i hjälpen för att se hur de används.

 

Sedan gäller det att använda den informationen i OnDblclkList(). Som alla säkert förväntat sig kan man nu åter hämta sitt index genom funktionen GetItemData(), och när vi testar ser det ut så här:

 

 

         

 

 

 

? CListBox::FindStringExact(), CListBox::SetItemData() samt CListBox::GetItemData().


Övningsuppgift:

·      Skapa ovanstående projekt och kalla det ListBox.

·      Du bör kunna göra detta utan att titta i häftet, men väl i hjälpen.

 

Övningsuppgift:

·      Öppna projektet ListBox om det inte redan är öppet.

·      Ändra meddelanderutan så att den ser ut så här:

                

 

·      Om man klickar på ‘Ja’ ska naturligtvis motsvarande uppgift tas bort från listrutan. För att kunna göra detta måste du slå upp en funktion i hjälpen.

 

Övningsuppgift:

·      Lägg till en knapp för borttagning av rad i dialogrutan:

 

 

·      Man ska kunna klicka på en rad så att den markeras, och sedan ta bort den med hjälp av ‘Ta bort’.

·      Innan raden tas bort ska en meddelanderuta fråga om man verkligen vill ta bort raden.

·      Om ingen rad markerats ska knappen ‘Ta bort’ vara passiv!

·      Observera att när man tagit bort en rad så är ingen rad markerad, och knappen ska åter bli passiv, oavsett vilken av de två metoderna man använt till att ta bort raden.

·      Använd en objektvariabel för knappen, så är det enklare att byta status på den.

 

 


Listrutans inbyggda textvariabler.

 

Man behöver inte ha separata variabler som innehåller de texter som visas i text­rutan. Om man till exempel matar in texter efter hand, räcker det med att de lagras i listrutan. Tryck på frågetecknet i egenskapsrutan och läs noga om denna egenskap! Om vi tänker oss att vi skapar ett program med en tom listruta, i vilken det finns möjlighet att lägga till texter:

 

 

Om man klickar på ‘Lägg Till...’ ska man få följande dialogruta där man kan mata in uppgifter för en rad i listrutan:

 

        

 

Gör en sammansatt textsträng av typen CString som innehåller både namn och nummer. Denna läggs sedan till i listrutan. ‘Ta Bort’ ska fungera som tidigare, men ‘Töm Listan’ kräver lite läsning i hjälp­en. Det finns en funktion som tar bort alla rader i listan.

 

Listans innehåll finns bara tillgängligt så länge dialogrutan är öppen, så denna applikation är inte särskilt användbar om man inte sparar uppgifterna på annat sätt. Stänger man dialogrutan och sedan öppnar den igen, så har listan tömts. Vi kommer senare att se hur man kan lägga kontroller i programfönstret, och i ett sådant fall har man listrutans innehåll intakt hela programkörningen. I ännu ett senare kapitel kommer vi att arbeta med länkade listor och se hur man lätt kan spara innehållet på disken, så vi gör inte mer av detta exempel.

 

Övningsuppgift:

·      Radera projekt ListBox.

·      Skapa ett nytt projekt ListBox enligt ovanstående exempel.


Component Gallery.

 

Med Developer Studio följer diverse färdiga standardresurser i ‘Component Gallery’. När du sedan  skapar egna resurser har du möjlighet att lägga till dessa i samma samling, när man skapar klassen till en resurs. Låt oss se vad som händer när vi skapar en klass till en dialogruta:

 

 

 

       

 

 

 

Se till så att kryssrutan ‘Add to Component Gallery’ är förkryssad, så hamnar den nya resursen där inklusive de filer som beskriver klassen. Gör man sedan tillägg i dessa filer kommer även dessa att finnas med i Component Gallery .


När vi senare har ett nytt projekt där vi vill skapa en liknande dialogruta kan vi klicka på knappen för Component Gallery:         eller välja [Insert - Component]

 

 

 
Varvid dess dialogruta visas:

 

 

 

 

 

 

Här kan man välja bland flikar för diverse standardkomponenter, men även tidigare projekt finns med bland flikarna. Låt oss välja vårt projekt, och bland de resurser som visas välja vår nya dialogruta ‘Ny Dialog’:

 

 

                                  

 

 

När vi klickar på ‘Ja’ läggs resursen till vårt projekt. Det är bara att modifiera om så önskas, och att använda den.


SendDlgItemMessage().

 

Före MFC var man hänvisad till att skicka meddelanden till kontrollerna i en dialog i stället för att använda de funktioner vi sett ovan. Det finns fortfarande möjlighet att göra detta. Funktionen som skickar meddelanden liknar Windows standardfunktion Send­Message(), och heter SendDlgItemMessage().

 

Funktionen behöver till skillnad från SendMessage() inget handtag till ägar­fön­s­t­­ret, men i stället id för den kontroll som ska ha meddelandet. Annars fungerar den på samma sätt. Ett argument är själva meddelandet, och de två övriga är data som ska följa med meddelandet, vilket naturligtvis är olika för olika meddelanden.

 

I MFC har man bakat in dessa anrop till SendMessage() i diverse funktioner, varav vi sett en del, och dessa funktioner har ett namn som motsvarar medde­lan­dets namn, så att LB_ADDSTRING skickas med hjälp av funktionen AddString(). Därigenom slipper vi dessutom att översätta de två parametrarna till relevant data. Ibland ska en parameter delas upp i två delar (ett word blir två bytes till exempel) eller typomvandlas till till exempel char*.

 

När vi fyllde i listrutan enligt detta kapitels första exempel använde vi Add­String():

 

m_ListKontroll.AddString(m_Namn[i]);

 

Förr var man tvungen att använda SendDlgItemMessage():

 

SendDlgItemMessage(IDC_LIST, LB_ADDSTRING, 0,

                   (LPARAM)(LPSTR)(const char*) m_Namn[i]);

 

Bara den sista typomvandlingen kunde vara en mardröm att försöka klura ut. Observera att alla meddelanden börjar med en förkortning som återspeglar var meddelandet hör hemma, som till exempel LB_ indikerar att detta hör hemma i en ListBox. Se efter vilka övriga meddelanden som finns. Varje meddelande finns beskriven i hjälpen med avseende på parametrarnas användning.

 

Övningsuppgift:

·      Radera tidigare version av ListBox och skapa ett nytt projekt med samma namn.

·      Skapa inga kontrollvariabler denna gång.

·      Slå upp SendDlgItemMessage() i hjälpen och läs hur den fungerar.

·      Slå upp erforderliga meddelanden för att kunna lösa uppgiften på detta sätt i stället, med bibehållen funktionalitet enligt första varianten.

 

? CWnd::SendDlgItemMessage(), Win32 SDK: Win32, Reference, Messages.