Vorheriges Kapitel:  Erstellen Ihrer ersten Anwendung    Nächstes Kapitel: Menüs       Inhaltsverzeichnis Inhaltsverzeichnis       Die Downloadseite Download       Kontakt Kontakt

 

Standardsteuerelemente

 

Radio Buttons(Optionsfelder)
Listboxen(Listenfelder)
Comboboxen(Kombinationsfelder)
Slider(Regler,Poti)
Spinbuttons(Drehfelder)
Listcontrol(Listenelement)
Treecontrol(Strukturansicht)
Property Sheet(Registerkarte)

 

 

 

Im folgenden werden Sie die meisten Standardsteuerelemente, die Sie zum Windows-Programmieren brauchen, kennenlernen. Wie Sie wissen, befinden sich die Standardsteuerelemente für eine Dialogseite auf der Werkzeugleiste des Rsource-Editors. Sie klicken einfach auf ein gewünschtes Steuerelement und positionieren es auf Ihre Dialogseite. Das ist aber leider nicht alles. Sie müssen die Funktionsweise dieser Elemente selbst programmieren. Alle Steuerelemente, die hier behandelt werden, sind in dem Beispielprogramm Controls zu einer Property Sheet gebaut worden, wo Sie ihre Funktionalität testen können. Damit die Übersicht nicht ganz verloren geht, befindet sich der Quellcode für jedes einzelne Steuerelement in einer separaten Datei.

 

 

 

Der komplette Quellcode zu diesem Steuerelement befindet sich in Radio.cpp.

Radio Buttons eignen sich am besten dazu, eine Option unter vielen für eine Anwendung zu wählen. Sie positionieren zuerst mit Hilfe von Resource-Editor eine Anzahl von Radio Buttons auf Ihre Dialogseite und dann bezeichnen(ID) die einzelnen Rodio Buttons dementsprechend. Sie können dann mit einem Groupbox (Gruppenfeld) diesen Buttons einen Obertitel geben.


Abbildung
Noch haben Sie kein Optionsfeld. Starten Sie ClassWizard und gehen Sie zum Register Member Variablen und deklarieren Sie für den ersten Radio Button eine int Variable.

Abbildung
Diese Variable hat im Konstruktor der Dialogklasse den Wert (-1) . Initialisieren Sie diese mit Wert 0. Wenn Sie auf ein Radio Button klicken, dann ändert sich der Wert dieser Variable entsprechend der Reihenfolge des Radio Buttons. Im Beispielprogramm Controls ist noch für die Aktualisierung des Wertes der Variable von der Nachrichten-Funktion OnCmdMsg Gebrauch gemacht worden, die den Wert der Variable an die Editbox automatisch transportiert. Sonst hätten wir eine zusätzliche Aktion - z.B. Aktivierung einer Schaltfläche - für die Darstellung des Wertes der Radiobutton- Variable gebraucht. Der Quellcode für den Konstruktor sieht wie folgt aus:

CRadio::CRadio() : CPropertyPage(CRadio::IDD)
{
//{{AFX_DATA_INIT(CRadio)
m_radio = 0;
m_edit_radio = _T("");
//}}AFX_DATA_INIT
} 

m_radio hatte ursprünglich den Wert (-1). Ihr Wert wurde auf 0 gesetzt.

 

BOOL CRadio::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
// Ab hier:
UpdateData(TRUE);
   switch(m_radio)
              {
       case 0: m_edit_radio="Eins"; break;
       case 1: m_edit_radio="Zwei"; break;
       case 2: m_edit_radio="Drei"; break;
              }
UpdateData(FALSE); 
return CPropertyPage::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

Um das Ergebnis testen zu können, wird der aktuelle Wert in eine Editbox ausgegeben, m_edit_radio ist die variable, die mit diser Editbox verknüpft ist. Sie werden auch bei den folgenden Steuerelementen eine derartige Variable sehen, die Sie nicht verwirren sollte.

 

 

Den kompletten Quellcode zur Listbox finden Sie unter Lstbox.cpp.

Nachdem Sie mit dem Resource-Editor eine Listbox auf die Dialogseite positioniert haben, rufen Sie ClassWizard auf und gehen Sie zum Register Member Variablen. Deklarieren Sie eine Variable m_list vom Typ CListBox. Nun müssen Sie mit Hilfe von ClassWizard auch noch zwei Nachrichten-Funktionen deklarieren. Zum einen muß der Inhalt der Listbox initialisiert werden und zum zweiten muß die Nachricht von der Wahl eines neuen Elementes in der Listbox weitergeleitet werden.


Abbildung
Zur Initialisierung des Inhalts dient die Nachricht WM_INITDIALOG, zu der Sie eine Funktion OnInitDilaog() mit Hilfe von ClassWizard hinzufügen:

BOOL CLstbox::OnInitDialog() 
{
int index ;
m_list.AddString("Mathematik");
m_list.AddString("Physik");
m_list.AddString("Informatik");
m_list.AddString("Chemie");
m_list.SelectString(index,"Chemie");
m_list_show="Chemie"; 
UpdateData(FALSE);
return TRUE ; // return TRUE unless you set the focus to a control
} 

Die Funktionen AddString(.....) und SelectString(.....) gehören der MFC Klasse CListBox an. Da Sie die Variable m_list vom Typ CListBox deklariert haben, stehen auch Ihnen diese Funktionen zur Verfügung. Damit Ihr Programm benachrichtigt wird, wenn Sie ein neues Element in der Listbox wählen, müssen Sie im ClassWizard die Nachricht LBN_SELCHANGE wählen, und eine Nachrichten-Funktion dafür hinzufügen. Die Nachricht LBN_SELCHANGE steht Ihnen dann zur Verfügung, wenn Sie bei Object-IDs die Bezeichnung Ihrer Listbox, z.B. IDC_LISTBOX markieren. Der Quellcode sieht wie folgt aus:

void CLstbox::OnSelchangeList() 
{
int index;
CString Str;
index= m_list.GetCurSel();
m_list.GetText(index,Str);
m_list_show=Str;
UpdateData(FALSE);
}

Die Funktion GetCurSel() liefert den Index des gewählten Elements in der Listbox. GetText(.....) liefert die Zeichenkette Str anhand des vorher ermittelten Indexes. Es stehen Ihnen natürlich viele weitere Funktionen zur Verfügung, die Sie sich in die Online-Hilfe Visual C++ ansehen können.

 

 

Den kompletten Quellcode finden Sie unter combo.cpp.

Eine Combobox kann genau so wie eine Listbox programmiert werden. Sie finden hier die beiden Nachrichten-Funktionen OnInitDialog() und OnSelChange().


Abbildung
Die Erläuterungen dazu finden Sie unter dem Steuerelement Listbox.

BOOL CCombo::OnInitDialog() 
{ 
int index;
m_combo.AddString("Ahmad");
m_combo.AddString("Susan");
m_combo.AddString("Müller");
m_combo.AddString("Memet");
m_combo.SelectString(index,"Ahmad");
m_show= "Ahmad";
UpdateData(FALSE); 
}

 

void CCombo::OnSelchangeCombo1() 
{
int index; CString Str;
index=m_combo.GetCurSel();
m_combo.GetLBText(index,Str);
m_show=Str;
UpdateData(FALSE); 
}

 

 

Den kompletten Quellcode zu diesem Steuerelement finden Sie unter Slider.cpp.

Wir werden hier zwei Arten von Schiebereglern programmieren, den stetigen und den schrittweisen Regler:

Zuerst müssen Sie zwei Regler auf Ihre Dialogseite positionieren. Bezeichnen Sie den ersten IDC_SLIDER1 und den zweiten IDC_SLIDER2. IDC_SLIDER1 wird als stetiger und IDC_SLIDER2 als schrittweiser Regler dienen.


Abbildung
Rufen Sie ClassWizard auf und deklarieren Sie jeweils eine Variable vom Typ CSliderCtrl für die beiden Regler. Der Stetige Regler hat demnach die Variable m_slider1 und der schrittweise hat die Variable m_slider2. Zuerst müssen die beiden Variablen initialisiert werden. Wir wissen bereits, daß dies für eine Dialogseite in OnInitDialog() stattfindet. Der Quellcode dafür sieht wie folgt aus:

BOOL CSlider::OnInitDialog() 
{
m_slider1.SetRange(0,50);
m_slider1.SetTicFreq(5);
SetDlgItemText(IDC_EDIT_POTI1,"0");
m_slider2.SetRange(0,5);
SetDlgItemText(IDC_EDIT_POTI2,"0");
return TRUE;
}

Mit SetRange legen Sie die Anzahl der Schritte fest. Der stetige Regler soll von 0 bis 50 stetig zählen. Der zweite Regler hat insgesamt 5 Schritte. Da die beiden Editboxen, die zum Testen dienen, ihre Variablen vom Typ CString haben, werden sie mit der MFC Funktion SetDlgItemText(.....) mit dem Wert 0 initialisiert. Damit Ihr Programm auch benachrichtigt wird, wenn Sie den Kopf des Reglers nach rechts oder links schieben, müssen Sie von der Nachricht WM_HSCROLL Gebrauch machen.


Abbildung
WM_HSCROLL bemerkt die horizontale Bewegungsrichtung. Fügen Sie mit Hilfe von ClassWizard die dazugehörige Nachrichten-Funktion hinzu. Der Quellcode der Nachrichten-Funktion sieht wie folgt aus:

void CSlider::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
// Stetiger Regler: 
CString str1;
str1.Format("%d",m_slider1.GetPos());
SetDlgItemText(IDC_EDIT_POTI1,str1);
//Schrittweiser Regler:
int wert[6]={0,5,10,15,20,25};
CString str2;
str2.Format("%d",wert[m_slider2.GetPos()]);
SetDlgItemText(IDC_EDIT_POTI2,str2);
CPropertyPage::OnHScroll(nSBCode, nPos, pScrollBar);
}

Die Funktion GetPos() liefert die aktuelle Position des Reglers. Die Funktion Format(.....), die der MFC Klasse CString gehört, Schreibt den dezimalen Wert, den die Funktion GetPos() liefert, in die CString Variablen str1 und str2 um. Als Test werden die Werte von str1 und str2 mit der MFC Funktion SetDlgItemText(.....) in den beiden Editboxen geschrieben. Zu dem schrittweisen Regler ist noch zu erwähnen, daß wir zuerst ein Array von fünf Werten definiert haben und mit GetPos(), den entsprechenden Wert des Arrays wieder zurückbekommen.

 

 


Abbildung

Positionieren Sie zuerst einmal mit Hilfe des Resource-Editors ein Spinbutton auf Ihre Dialogseite und bezeichnen(ID) Sie es. Rufen Sie dann ClassWizard auf, deklarieren Sie eine Variable des Typs CSpinButtonCtrl z.B. m_spin, die mit dem Spinbutton in Verbindung steht und fügen Sie der Nachricht WM_INITDIALOG die Funktion OnInitDialog() hinzu. Initialisieren darin den Spinbutton. Der Quellcode dazu würde folgendermaßen aussehen:

BOOL CSpin::OnInitDialog() 
{
m_spin.SetRange(0,100);
m_spin.SetPos(0);
SetDlgItemText(IDC_EDIT_SPIN,"0");
return TRUE;
}

Mit SetRange bestimmen Sie die Reichweite des Spinbuttons. Mit SetPos setzen Sie die Anfangsposition. Und mit SetDlgItemText(.....) initialisieren Sie die Editbox mit dem Wert 0. Wie bei den Slidern wird bei der Aktivierung des Spinbuttons eine Nachricht ausgelöst, welche mit einer Nachrichten-Funktion abgefangen werden muß. Da unsere Spinbuttons eine vertikale Ausrichtung haben, müssen wir von der Nachricht WM_VSCROLL Gebrauch machen. Erzeugen Sie mit Hilfe von ClassWizard die zugehörige Nachrichten-Funktion OnVScroll() zu der Nachricht WM_VSCROLL. Der Quellcode würde folgendermaßen aussehen:

void CSpin::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
CString str;
str.Format("%d",nPos);
SetDlgItemText(IDC_EDIT_SPIN,str);
CPropertyPage::OnVScroll(nSBCode, nPos, pScrollBar);
}

Bei nPos handelt es sich um den zweiten Parameter der Nachrichten-Funktion OnVScroll(). Dieser Parameter enthält die Information über die aktuelle Position des Spinbuttons. Die Funktion Format(.....) schreibt den Wert von nPos in die lokale CString Variable str und SetDlgItemText(.....) schreibt str in die Editbox. Es gibt auch eine andere Möglichkeit, den Spinbutton zu programmieren. Man setzt den Editbox als buddy usw., aber es sollte am Anfang alles so einfach wie nur möglich gehalten werden.

 

 

Den kompletten Quellcode finden Sie in Listcont.cpp.

Die Programmierung des Listcontrols eignet sich nicht ganz für den Anfänger. Dies gilt auch für den Treecontrol(Strukturansicht).


Abbildung
Eine Listcontrol ist zwar etwas schwierig zu programmieren, dafür ist sie aber sehr vielseitig. Sie haben die Möglichkeit jedes Element in einer Listcontrol mit einem Icon zu versehen, verschiedene Farben zu wählen, oder mehrerer Spalten mit Titelleiste und vieles mehr zu erzeugen. Wir werden hier eine Listcontrol mit mehren Spalten und einer Titelleiste programmieren.

Positionieren Sie zuerst einmal im Resource-Editor eine Listcontrol auf Ihre Dialogseite, gehen Sie zu den Eigenschaften der Listcontrol, bezeichnen(ID) Sie sie und dann gehen Sie in den Eigenschaften zum Register Formate(Styles) und wählen Sie bei der Ansicht die Option Bericht(Report) aus.


Abbildung
Rufen Sie anschließend ClassWizard auf und deklarieren Sie für die Listcontrol eine Variable des Typs CListCtrl. Nun müssen Sie die Listcontrol in der Funktion OnInitDialog initialisieren: Der Quellcode kann wie folgt aussehen:

BOOL CListcont::OnInitDialog() 
{
char* name[]={"Müller","Schulz","Pascha","Sultan","Pakhtun","Zalem"};
char* nummer[]={"12541","45874","78541","23654","41254","36214"};

LV_ITEM item; 
m_listcont.InsertColumn(0,"Name",LVCFMT_LEFT,150,0);
m_listcont.InsertColumn(1,"Matrikel Nr.",LVCFMT_RIGHT,100,1);
item.mask=LVIF_TEXT;

      for(int j=0; j<6; j++)
          {
          item.iItem=0;
          item.pszText=name[j];
          item.iSubItem=0;
          int itemNr=m_listcont.InsertItem(&item);
          item.iItem=itemNr;
          item.iSubItem=1;
          item.pszText=nummer[j];
          m_listcont.SetItem(&item);
          }
return TRUE; 
}

Die Arrays name[ ] und nummer[ ] bilden die beiden Spalten des Listcontrols. LV_ITEM ist ein Strukt, dessen Elemente mit Listcontrols benutzt werden. Die Anweisung (item.mask=LVIF_TEXT;) bedeutet, daß die Elemente der Listcontrol aus Text und nicht aus Bildern bestehen. Der Ausdruck pszText besagt, daß die Elemente der Listcontros auf eine mit 0\ abgeschlossene Zeichenkette(Null-terminiert) zeigen. Die Elemente sind zeilenweise indiziert, wobei iItem den 0 Index und iSubItem den 1 Index hat. Sie werden den obigen Quellcode am besten dann verstehen, wenn Sie die Listcontrol um eine oder zwei Spalten erweitern. Dann werden Sie nämlich gewisse Regelmäßigkeit erkennen, die eine feste Hierarchie in der Struktur der Listcontrol erkennen lassen.

Nun wie bei einer Listbox, muß die Nachricht weitergeleitet werden, wenn Sie ein neues Element innerhalb der Listcontrol auswählen. Markieren Sie bitte dafür bei Object_ID des ClassWizards auf die ID(Bezeichnung) der Listcontrol und wählen Sie die Nachricht LVN_ITEMCHANGED. Fügen Sie der Nachricht die von ClassWizard vorgeschlagene Nachrichten-Funktion OnItemChangedListcontrol() hinzu. Der Quellcode dazu kann wie folgt aussehen:

void CListcont::OnItemchangedListcontrol(NMHDR* pNMHDR, LRESULT* pResult) 
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
//Ab hier:
int sel; CString str1,str2;
sel=pNMListView->iItem;
str1=m_listcont.GetItemText(sel,0);
str2=m_listcont.GetItemText(sel,1);
m_edit_listcont=str1;
m_edit_listcont2=str2;
UpdateData(FALSE); 
*pResult = 0;
}

Mit der Variable sel erhalten wir den Index des gewählten Elements. Mit GetItemText(.....) haben wir Zugang zu dem Element selbst. Als Test zeigen m_edit_listcont und m_edit_listcont2 die Elemente der beiden Spalten der gewählten Zeile.

 

 

Den kompletten Quellcode finden Sie unter Tree.cpp.

Auch bei Treecontrol haben Sie wie bei einer Listcontrol viele Gestaltungsmöglichkeiten. Im folgenden wird eine Treecontrol mit zwei Wurzeln - Großvater und Großmutter - programmiert.


Abbildung
Wie bei Listcontrol muß zuerst die Treecontrol in OnInitDialog() initialisiert werden. Der Quellcode dazu sieht wie folgt aus:

BOOL CTree::OnInitDialog() 
{
TV_INSERTSTRUCT tvinsert;
tvinsert.hParent=NULL;
tvinsert.hInsertAfter=TVI_LAST;
tvinsert.item.mask=TVIF_TEXT;
tvinsert.item.hItem=NULL;
tvinsert.item.pszText=" Großvater" ;
HTREEITEM hgvat=m_tree.InsertItem(&tvinsert);
tvinsert.item.pszText="Großmutter";
HTREEITEM hgmutt=m_tree.InsertItem(&tvinsert);
tvinsert.hParent=hgvat;
tvinsert.item.pszText="Vater";
m_tree.InsertItem(&tvinsert);
tvinsert.item.pszText="Ich";
m_tree.InsertItem(&tvinsert);
tvinsert.hParent=hgmutt;
tvinsert.item.pszText="Vater";
m_tree.InsertItem(&tvinsert);
tvinsert.item.pszText="Ich";
m_tree.InsertItem(&tvinsert);
return TRUE; 
}

Sie werden den obigen Quellcode am besten verstehen, wenn Sie die Wurzeln um einen Knoten erweitern. Hier werden Sie auch wie bei einer Listcontrol eine gewisse Hierarchie feststellen.Wenn Sie auf ein bestimmtes Element der Treecontrol klicken, wird die Nachricht TVN_SELCHANGED ausgelöst. Damit diese Nachricht von der Anwendung abgefangen werden kann, fügen Sie bitte mit Hilfe von ClassWizard die zugehörige Nachrichten-Funktion OnSelChangedTree() hinzu. Der Quellcode dafür kann wie folgt aussehen:

void CTree::OnSelchangedTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
//Ab hier:
HTREEITEM sel; 
CString str;
sel=pNMTreeView->itemNew.hItem;
str=m_tree.GetItemText(sel);
m_edit_tree=str;
UpdateData(FALSE);
*pResult = 0;
}

 

 

Den kompletten Quellcode zum Thema Property Sheet finden Sie unter ControlsView.cpp

Eine Property Sheet besteht aus mehren einzelnen Dialogseiten, bzw. Property Pages.


Abbildung
Im Resource-Editor haben Sie direkt die Möglichkeit, Property Pages als Dialogseite zu erzeugen. Sie befinden sich unter dem Resource Dialog. Achten Sie darauf, daß alle Property Pages die gleiche Größe haben. Jede Seite sollte einen Titel haben. Dies können Sie ja bei den Eigenschaften des Dialogs bestimmen. Sie können im linken Fenster des Resource-Editors die einzelnen Seiten markieren und dann auf die rechte Maustaste drücken, die Option Eigenschaften wählen und dort die Sprache ändern. Nachdem Sie die Seite gestaltet haben, rufen Sie ClassWizard auf. Sie müssen wie schon bekannt, für jede Seite eine eigene neue Klasse erzeugen, die Sie nicht von CDialog sondern von CPropertyPage ableiten müssen.

Abbildung

Nun müssen Sie zu Ihrer Ansicht(.....View.cpp) wechseln. Damit auch die Ansicht die neuen Klassen, bzw. Dialogseiten erkennt, müssen Sie die Headerdateien der neuen Klassen mit der #include Direktive am Kopf der View-Datei binden. Sie müssen nun die Registerkarte in der Ansicht initialisieren und gestalten. Sie haben bisher beobachtet, daß wir die Initialisierungen für eine Dialogseite in OnInitDialog() gemacht haben. In der Ansicht übernimmt diese Aufgabe die MFC Funktion OnInitialUpdate(), die Sie mit Hilfe von ClassWizard erzeugen. Diesen Sachverhalt sollten Sie sich gut anmerken. Der Quellcode sieht folgendermaßen aus:

void CControlsView::OnInitialUpdate() 
{
CView::OnInitialUpdate();
//Ab hier:
MessageBox(" Hier sehen Sie eine Demonstration der       Standardsteuerelemente"
" der modalen Dialoge.");
CPropertySheet property(" Steuerelemente ");
CCombo combo;
CRadio radio;
CLstbox listbox;
CSlider slider;
CSpin spin;
CListcont listcont;
CTree tree;
Cinfo info;
property.AddPage(&radio);
property.AddPage(&listbox);
property.AddPage(&combo);
property.AddPage(&slider);
property.AddPage(&spin);
property.AddPage(&listcont);
property.AddPage(&tree);
property.AddPage(&info);
property.DoModal();
exit(0);
}

Der Quellcode oben ist leicht verständlich. Sie deklarieren zuerst ein Objekt der MFC Klasse CpropertySheet und schreiben im Konstruktor den Titel der Registerkarte. Danach deklarieren Sie auch für jede Registerseite ein Objekt und mit AddPage(.....) binden Sie die Seiten in die Registerkarte. Mit der MFC Funktion DoModal() machen Sie die Registerkarte auf den Bildschirm sichtbar. Vielleicht wundern Sie sich was die Funktion exit(0) hier zu suchen hat. Probieren Sie das Programm einmal auch ohne die Funktion exit(0). Dann werden Sie auch die Funktion OnInitialUpdate() besser verstehen. Es ist zu erwähnen, daß OnInitialUpdate() aufgerufen wird, bevor die Seite für das Anwendunsgerüst (Framework) des Programms erzeugt wird. Mit exit(0) unterbinden Sie den ganzen Prozeß, der nach dem Aufruf von OnInitialUpdate() stattfindet.

 

 

      Vorheriges Kapitel:  Erstellen Ihrer ersten Anwendung   Nächstes Kapitel: Menüs       Inhaltsverzeichnis Inhaltsverzeichnis       Die Downloadseite Download       Kontakt Kontakt