|
|
|
|
|
| Steuerelemente - Listenelement |
Hier stehen Informationen zum Umgang mit dem Listenelement (ListControl). Die zugehörige Klasse lautet: CListCtrl. Das Listenelement ist ein sehr vielseitiges Steuerlement und wird häufig verwendet. Man kann in einem Listenfeld z.B Icons mit Text oder auch eine tabellenartige Auflistung anzeigen.
Die verschiedenen Anzeigemöglichkeiten lassen sich in den Eigenschaften des Listenelements einstellen. Der passende Menüpunkt heisst Ansicht (View). In Visual C++ 6.0 findet man ihn im Register Formate.
Listenelement in Berichts-Ansicht:
- Ausgewählte Zeile ermitteln - GetNextItem()
- Beispiel mit Listenelement in Berichts-Ansicht
- Daten in ein Listenelement einfügen - InsertItem()/SetItemText()
- Einträge ausrichten
- Laden und Speichern der Daten
- Ganze Zeile markieren - SetExtendedStyle()
- Gitternetzlinien einfügen - SetExtendedStyle()
- Spaltenkopf beschriften - InsertColumn()
- Zeilenanzahl ermitteln - GetItemCount()
- Zeilen löschen - DeleteItem()/DeleteAllItems()
Eine vom Anwender markierte Zeile kann man mit der Funktion GetNextItem() ermitteln. Der Code dazu sieht so aus:
// Ausgewählte Zeile ermitteln
int nZeilenauswahl;
nZeilenauswahl = m_List1.GetNextItem(-1, LVNI_SELECTED);
In der Variablen nZeilenauswahl steht nun die vom Anwender markierte Zeile. Möchte man diese Zeile löschen, kann man die Funktion DeleteItem() verwenden:
// Ausgewählte Zeile löschen
m_List1.DeleteItem(nZeilenauswahl);
m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. Im Beispiel: Beispiel mit Listenelement in Berichts-Ansicht ist der oben gezeigte Code enthalten.
Ein Listenelement welches in der Berichts-Ansicht dargestellt wird, wird oft verwendet. Man bekommt eine geordnete, tabellenartige Darstellung der Inhalte.
Beispiel:
Im folgenden Beispiel wird gezeigt, wie man ein Listenelement in Berichts-Ansicht erstellt und es mit Daten füllt. Wir werden etwas mit dem Ergebnis spielen und verschiedene Styles einbauen. Ausserdem werden wir die Daten am Ende auch noch speichern, laden und drucken können.
- Erstelle eine Dialogfeldbasierte Anwendung mit dem Namen: LElement_Bericht und entferne alle vorhandenen Elemente. Schau dir die unten stehenden Abbildung an, um zu sehen wie die Steuerelemente angeordnet werden
- Füge ein Listenelement ein, vergrössere es etwas und stelle in den Eigenschaften den Menüpunkt Ansicht (View) auf Bericht (Report) um. Aktiviere ausserdem noch Einzelauswahl (Single Selection). In VC++ 6.0 findet man beides im Register Formate
- Füge eine Member-Variable für das Listenelement ein - Kategorie: Control, Variablentyp: CListCtrl, Name: m_List1
- Als nächstes fügen wir erstmal die Bezeichnungen für den Spaltenkopf ein - wir initialisieren das Listenelement. Danach fügen wir gleich ein paar Daten in das Listenelement ein. Füge dazu folgenden Code in die Funktion OnInitDialog() ein:
BOOL CLControl_ReportDlg::OnInitDialog()
{
...
// ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
// Listenelement initialisieren - Spaltenkopf einfügen
m_List1.InsertColumn(0, "Produkt" ,LVCFMT_LEFT, 100);
m_List1.InsertColumn(1, "Hersteller" ,LVCFMT_LEFT, 70);
m_List1.InsertColumn(2, "Preis" ,LVCFMT_LEFT, 50);
m_List1.InsertColumn(3, "Verfügbar" ,LVCFMT_LEFT, 70);
// Elemente einfügen
m_List1.InsertItem(0, "Druckerpatrone");
m_List1.SetItemText(0, 1, "ASE");
m_List1.SetItemText(0, 2, "19,95");
m_List1.SetItemText(0, 3, "Ja");
m_List1.InsertItem(1, "CD-ROM");
m_List1.SetItemText(1, 1, "ASE");
m_List1.SetItemText(1, 2, "14,95");
m_List1.SetItemText(1, 3, "Ja");
m_List1.InsertItem(2, "Scanner");
m_List1.SetItemText(2, 1, "ASE");
m_List1.SetItemText(2, 2, "84,95");
m_List1.SetItemText(2, 3, "Nein");
return TRUE;
}
Beschreibung:
Mit Hilfe der Funktion InsertColumn() haben wir den Spaltenkopf beschriftet. Der erste Parameter steht für die jeweilige Spalte, der zweite Parameter für die anzuzeigende Beschriftung, der dritte Parameter für die Ausrichtung des anzuzeigenden Textes und der letzte Parameter gibt die Spaltenbreite in Pixel an. Der dritte Parameter, welcher für die Ausrichtung des Textes steht, kann folgende Werte annehmen: LVCFMT_LEFT, LVCFMT_RIGHT oder LVCFMT_CENTER.
Danach haben wir Zeilen mit Hilfe der Funktionen InsertItem() und SetItemText() in das Listenelement eingefügt. Jede neue Zeile wird mit der Funktion InsertItem() begonnen. Der erste Parameter steht für die Zeilenzahl und der zweite Parameter für den anzuzeigenden Text. Jedes weitere Element in der Zeile wird mit der Funktion SetItemText() eingefügt. Dabei steht der erste Parameter für die Zeile in die etwas eingefügt werden soll. Der zweite Parameter steht für die Spalte in die geschrieben werden soll und der dritte Parameter steht für den anzuzeigenden Text.
Erweiterung des Beispiels - Zentrieren der Einträge
Wie oben erwähnt ist es möglich die Spalten und die zugehörigen Einträge zu zentrieren. Dies wird durch den dritten Parameter der Funktion InsertColumn() beeinflusst. Man hat die Auswahl zwischen: LVCFMT_LEFT, LVCFMT_RIGHT oder LVCFMT_CENTER. Das probieren wir gleich mal aus.
- Ändere dazu die Zeilen, die den Text in den Spaltenkopf eintragen:
// Listenelement initialisieren - Spaltenkopf einfügen
m_List1.InsertColumn(0, "Produkt" , LVCFMT_CENTER, 100);
m_List1.InsertColumn(1, "Hersteller" , LVCFMT_CENTER, 70);
m_List1.InsertColumn(2, "Preis" , LVCFMT_CENTER, 50);
m_List1.InsertColumn(3, "Verfügbar" , LVCFMT_CENTER, 70);
Beschreibung:
Wir haben jetzt also den dritten Parameter von LVCFMT_RIGHT in LVCFMT_CENTER geändert. Man sieht schön wie die Spalten und die Einträge jetzt zentriert angezeigt werden. Allerdings gibt es eine Ausnahme - die erste Spalte wird leider nicht zentriert dargestellt.
Erweiterung des Beispiels: Gitternetzlinien einfügen
Mit nur einer Zeile kann man das Aussehen des Listenelements stark beeinflussen. Mit der Zeile:
m_List1.SetExtendedStyle(LVS_EX_GRIDLINES);
kann man Gitternetzlinien in das Listenelement einfügen.
- Um Gitternetzlinien im Listenelement anzuzeigen, ändere die Funktion OnInitDialog() etwas ab:
BOOL CLControl_ReportDlg::OnInitDialog()
{
...
// ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
// Gitternetzlinien einfügen
m_List1.SetExtendedStyle(LVS_EX_GRIDLINES);
// Listenelement initialisieren - Spaltenkopf einfügen
m_List1.InsertColumn(0, "Produkt" , LVCFMT_CENTER, 100);
m_List1.InsertColumn(1, "Hersteller" , LVCFMT_CENTER, 70);
m_List1.InsertColumn(2, "Preis" , LVCFMT_CENTER, 50);
m_List1.InsertColumn(3, "Verfügbar" , LVCFMT_CENTER, 70);
// Elemente einfügen
m_List1.InsertItem(0, "Druckerpatrone");
m_List1.SetItemText(0, 1, "ASE");
m_List1.SetItemText(0, 2, "19,95");
m_List1.SetItemText(0, 3, "Ja");
m_List1.InsertItem(1, "CD-ROM");
m_List1.SetItemText(1, 1, "ASE");
m_List1.SetItemText(1, 2, "14,95");
m_List1.SetItemText(1, 3, "Ja");
m_List1.InsertItem(2, "Scanner");
m_List1.SetItemText(2, 1, "ASE");
m_List1.SetItemText(2, 2, "84,95");
m_List1.SetItemText(2, 3, "Nein");
return TRUE;
}
Erweiterung des Beispiels: Ganze Zeile markieren
Das einzigste was sich standardmäßig in einem Listenelement anklicken lässt ist jeweils der Eintrag in der ersten Spalte. Auch die Markierung steht immer nur auf der ersten Spalte:
Mit der Zeile
m_List1.SetExtendedStyle(LVS_EX_FULLROWSELECT);
lässt sich das leicht ändern. Fügt man diese Zeile ein, kann man die ganze Zeile in einem Listenelement markieren. Da uns die Gitternetzlinien erhalten bleiben sollen, kombinieren wir die Styles.
- Ändere dazu die Zeile zum einfügen der Gitternetzlinien etwas ab:
// Gitternetzlinien einfügen und ganze Zeile markieren
m_List1.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
Ausbau des Beispiels: Daten eingeben - Zeilen löschen
Um das Beispiel kompletter werden zu lassen, fügen wir jetzt eine Möglichkeit hinzu während des Programmlaufs Daten einzufügen. Ebenfalls soll es möglich sein eine markierte Zeile per Button löschen zu können.
- Um dies zu realisieren fügen wir ein paar Textfelder, Eingabefelder und zwei Optionsfelder ein. Schau dir die untenstehende Abbildung an, um zu sehen wie die Steuerelemente angeordnet werden
- Füge ein Textfeld ein und beschrifte es mit: Produkt. Füge daneben ein Eingabefeld ein und ändere die ID in: IDC_PRODUKT
- Füge ein Textfeld ein und beschrifte es mit: Hersteller. Füge daneben ein Eingabefeld ein und ändere die ID in: IDC_HERSTELLER
- Füge ein Textfeld ein und beschrifte es mit: Preis. Füge daneben zwei Eingabefelder ein und ändere die IDs in: IDC_EURO und IDC_CENT
- Füge ein Textfeld ein und beschrifte es mit: Verfügbar. Füge daneben zwei Optionsfelder ein, beschrifte sie mit: Ja und Nein und ändere die IDs in: IDC_JA und IDC_NEIN. Gehe in die Eigenschaften des ersten Optionfelds, also das mit der ID: IDC_JA und aktiviere die Eigenschaft: Gruppe (Group). Terminiere die Gruppe, indem du für das Steuerelement das in der Tabulator-Reihenfolge auf das Optionsfeld "Nein" folgt ebenfalls Gruppe aktivierst. Bei mir ist dies das Listenelement. Solltest du hiermit Probleme haben, kannst du alles wichtige hier: Beispiel mit Optionsfelder nachlesen
- Füge jetzt für die eben eingefügten Steuerelemente Member-Variablen nach folgender Tabelle ein:
| Steuerelement |
Variablenname |
Kategorie |
Variablentyp |
| Produkt (IDC_PRODUKT) |
m_strProdukt |
Wert |
CString |
| Hersteller (IDC_HERSTELLER) |
m_strHersteller |
Wert |
CString |
| Preis (IDC_EURO) |
m_nEuro |
Wert |
int |
| Preis (IDC_CENT) |
m_nCent |
Wert |
int |
| Optionsfeld - Ja (IDC_JA) |
m_nVerfuegbar |
Wert |
int |
- Füge jetzt noch zwei Buttons ein und ändere die Beschriftung in: Daten einfügen und Zeile löschen. Ändere die IDs in: IDC_EINFUEGEN und IDC_LOESCHEN
- Klicke doppelt auf jeden Button, um für jeden eine Nachrichtenbehandlungsroutine für die BN_CLICKED-Nachricht einzufügen und füge folgenden Code in die eben erstellten Funktionen ein:
void CLElement_BerichtDlg::OnEinfuegen()
{
// Daten aus Eingabemaske holen (Variablen aktualisieren)
UpdateData(TRUE);
// Fehler in Eingabemaske abfangen
if(m_strProdukt == "")
{
MessageBox("Kein Produkt eingetragen!", "Fehler!", MB_ICONERROR);
return;
}
if(m_strHersteller =="")
{
MessageBox("Kein Hersteller eingetragen!", "Fehler!", MB_ICONERROR);
return;
}
if(m_nEuro <=0)
{
MessageBox("Der eingegeben Betrag ist zu gering!", "Fehler!", MB_ICONERROR);
return;
}
// Auswertung der Optionsfelder
CString str_Verfuegbar;
if(m_nVerfuegbar == 0)
str_Verfuegbar = "Ja";
else
str_Verfuegbar = "Nein";
// int in String wandeln - nötig für den Preis
CString str_Preis;
str_Preis.Format("%d,%d", m_nEuro, m_nCent);
// Ermitteln wieviele Zeilen das Listenelement hat
int nZeilenanzahl;
nZeilenanzahl = m_List1.GetItemCount();
// Zeile in Listenelement einfügen
m_List1.InsertItem(nZeilenanzahl, m_strProdukt);
m_List1.SetItemText(nZeilenanzahl, 1, m_strHersteller);
m_List1.SetItemText(nZeilenanzahl, 2, str_Preis);
m_List1.SetItemText(nZeilenanzahl, 3, str_Verfuegbar);
}
void CLElement_BerichtDlg::OnLoeschen()
{
// Ausgewählte Zeile ermitteln
int n_Zeilenauswahl;
n_Zeilenauswahl = m_List1.GetNextItem(-1, LVNI_SELECTED);
// Ausgewählte Zeile löschen
m_List1.DeleteItem(n_Zeilenauswahl);
}
- Jetzt müssen wir nur noch die Variable des Optionfelds initialisieren, damit beim Programmstart direkt schon ein Optionsfeld ausgewählt ist. Wir müssen dazu nur eine Zeile Code in die Funktion OnInitDialog() einfügen. Zur Vollständigkeit folgt nochmal unser kompletter Code incl. die Initialisierung des Optionsfelds:
BOOL CLControl_ReportDlg::OnInitDialog()
{
...
// ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
// Radio Button initialisieren
m_nVerfuegbar = 0;
UpdateData(FALSE);
// Gitternetzlinien einfügen und ganze Zeile markieren
m_List1.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
// Listenelement initialisieren - Spaltenkopf einfügen
m_List1.InsertColumn(0, "Produkt" , LVCFMT_CENTER, 100);
m_List1.InsertColumn(1, "Hersteller" , LVCFMT_CENTER, 70);
m_List1.InsertColumn(2, "Preis" , LVCFMT_CENTER, 50);
m_List1.InsertColumn(3, "Verfügbar" , LVCFMT_CENTER, 70);
// Elemente einfügen
m_List1.InsertItem(0, "Druckerpatrone");
m_List1.SetItemText(0, 1, "ASE");
m_List1.SetItemText(0, 2, "19,95");
m_List1.SetItemText(0, 3, "Ja");
m_List1.InsertItem(1, "CD-ROM");
m_List1.SetItemText(1, 1, "ASE");
m_List1.SetItemText(1, 2, "14,95");
m_List1.SetItemText(1, 3, "Ja");
m_List1.InsertItem(2, "Scanner");
m_List1.SetItemText(2, 1, "ASE");
m_List1.SetItemText(2, 2, "84,95");
m_List1.SetItemText(2, 3, "Nein");
return TRUE;
}
 |
Beschreibung
Das Beispiel beinhaltet jetzt eine Eingabemöglichkeit, um auch Elemente in das Listenelement während des Programmlaufs einzufügen und auch wieder zu löschen. Optimal wäre hier noch eine Abfrage, bevor eine Zeile gelöscht wird.
Erweiterung des Beispiels - Laden und Speichern der Daten
Jetzt bauen wir noch eine Möglichkeit ein alle Artikel des Listenelements zu speichern und wieder zu laden.
- Füge dazu zwei weitere Buttons ein und ändere die Beschriftung in: Laden und Speichern. Ändere die IDs in: IDC_LADEN und IDC_SICHERN
- Klicke doppelt auf jeden Button, um für jeden eine Nachrichtenbehandlungsroutine für die BN_CLICKED-Nachricht einzufügen und füge folgenden Code in die eben erstellten Funktionen ein:
void CLElement_BerichtDlg::OnLaden()
{
CString strLesePuffer, strDateiName, strPfad;
CStdioFile DateiLesen;
int i=0;
// Holt Pfad und Name mit .exe
strPfad = GetCommandLine();
// Dateierweiterung abschneiden
int nPos = strPfad.ReverseFind( '\\');
strPfad = strPfad.Mid(1, nPos-1);
// Ermittelten Pfad + Dateiname in strDateiName schreiben
strDateiName = strPfad +"//text.txt";
// Kompletten Inhalt des Listenelements löschen
m_List1.DeleteAllItems();
// Datei auslesen
if (DateiLesen.Open(strDateiName, CFile::modeRead))
{
while(DateiLesen.ReadString(strLesePuffer))
{
// Datei zeilenweise auslesen
m_List1.InsertItem(i, strLesePuffer);
DateiLesen.ReadString(strLesePuffer);
m_List1.SetItemText(i, 1, strLesePuffer);
DateiLesen.ReadString(strLesePuffer);
m_List1.SetItemText(i, 2, strLesePuffer);
DateiLesen.ReadString(strLesePuffer);
m_List1.SetItemText(i, 3, strLesePuffer);
i++;
}
}
else
MessageBox ("Fehler beim Laden der Datei", "Fehler", MB_ICONINFORMATION);
}
void CLElement_BerichtDlg::OnSichern()
{
CString m_strPreis, m_strVerfuegbar, strDateiName, strPfad;
CStdioFile DateiSpeichern;
int i, nZeilenanzahl;
// Holt Pfad und Name mit .exe
strPfad = GetCommandLine();
// Dateierweiterung abschneiden
int nPos = strPfad.ReverseFind( '\\');
strPfad = strPfad.Mid(1, nPos-1);
// Ermittelten Pfad + Dateiname in strDateiName schreiben
strDateiName = strPfad +"//text.txt";
// Daten in Datei sichern
if (DateiSpeichern.Open(strDateiName, CFile::modeCreate | CFile::modeWrite ))
{
// Anzahl der Zeilen im Listenfeld holen
nZeilenanzahl = m_List1.GetItemCount();
for(i=0; i < nZeilenanzahl; i++)
{
m_strProdukt = m_List1.GetItemText(i, 0);
m_strHersteller = m_List1.GetItemText(i, 1);
m_strPreis = m_List1.GetItemText(i, 2);
m_strVerfuegbar = m_List1.GetItemText(i, 3);
DateiSpeichern.WriteString (m_strProdukt+"\n" + m_strHersteller+"\n" + m_strPreis+"\n" + m_strVerfuegbar +"\n" ) ;
}
DateiSpeichern.Close ();
MessageBox ("Daten wurden gespeichert", "Daten gespeichert", MB_ICONINFORMATION);
}
else
MessageBox ("Fehler beim Öffnen der Datei - Speichern wurde abgebrochen", "Fehler", MB_ICONINFORMATION);
}
 |
Beschreibung
Jetzt ist es auch möglich eingebene Daten zu speichern und wieder herzustellen. In der Funktion OnLaden() wird zuerst der Pfad der Anwendung ermittelt und die Dateierweiterung abgetrennt. Danach wird mit Hilfe der Funktion DeleteAllItems() der komplette Inhalt des Listenelements gelöscht. Falls bereits eine Datei mit Daten vorhanden ist wird diese geöffnet und zeilenweise in das Listenelement eingelesen.
In der Funktion OnSichern() wird wieder zuerst der Pfad der Anwendung ermittelt und die Dateierweiterung abgetrennt. Dann wird eine Textdatei erstellt und zeilenweise in diese Textdatei geschrieben.
Erweiterung des Beispiels - Drucken der Daten
Was jetzt noch dringend fehlt ist eine Möglichkeit die eingegeben Daten auszudrucken.
- Füge dazu einen weiteren Button ein, ändere die Beschriftung in: Drucken und die ID in: IDC_DRUCKEN
- Klicke doppelt auf den Button, um eine Nachrichtenbehandlungsroutine für die BN_CLICKED-Nachricht einzufügen und füge folgenden Code in die eben erstellte Funktion ein:
void CLElement_BerichtDlg::OnDrucken()
{
CPrintDialog dlgPrint(FALSE, PD_ALLPAGES, this);
// GetDefaults liefert den Standarddrucker
dlgPrint.GetDefaults();
// Verbinden des Drucker-DC mit einem CDC-Objekt
CDC dcPrint;
dcPrint.Attach(dlgPrint.GetPrinterDC());
// DOCINFO-Struktur erzeugen (wird für Druck benötigt)
DOCINFO ListControlPrint;
ListControlPrint.cbSize = sizeof(ListControlPrint);
ListControlPrint.lpszDocName = "Listenelement Druck";
ListControlPrint.lpszOutput = NULL;
ListControlPrint.lpszDatatype = NULL;
ListControlPrint.fwType = NULL;
//Maße des druckbaren Bereiches des Papiers ermitteln (in 0,1mm)
dcPrint.SetMapMode(MM_LOMETRIC);
int nLaenge = dcPrint.GetDeviceCaps(VERTSIZE);
int nBreite = dcPrint.GetDeviceCaps(HORZSIZE);
int nRechts = nBreite * 10 - 40;
int nUnten = -nLaenge * 10 + 40;
// Rahmen für Druck festlegen
dcPrint.Rectangle(50, 0, nRechts, nUnten);
// Schriftart und Grösse für die Überschrift festlegen
CFont font, *p_OldFont;
font.CreateFont(-100, 0, 0, 0, 600, 0, 0, 0, ANSI_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Verdana");
p_OldFont= dcPrint.SelectObject(&font);
// Ausdruck des Dokuments starten
if (dcPrint.StartDoc(&ListControlPrint)>=0)
{
// Eine Seite beginnen
dcPrint.StartPage();
// Mit grosser Schrift Überschrift ausgeben
dcPrint.TextOut(450, -100, " Listenelement Druck");
// Standard Font für den Rest benutzen
dcPrint.SelectObject(p_OldFont);
// Obere Linie zeichnen (von links nach rechts)
dcPrint.MoveTo(50, -500);
dcPrint.LineTo(nRechts, -500);
// Header ausgeben
dcPrint.TextOut(200,-530, "Produkt");
dcPrint.TextOut(800,-530, "Hersteller");
dcPrint.TextOut(1350,-530, "Preis");
dcPrint.TextOut(1680,-530, "Verfügbar?");
// Linie unter dem Header zeichnen (von links nach rechts)
dcPrint.MoveTo(50, -600);
dcPrint.LineTo(nRechts, -600);
// Zweite Linie unter dem Header zeichnen (von links nach rechts)
dcPrint.MoveTo(50, -605);
dcPrint.LineTo(nRechts, -605);
// Linie ganz unten zeichnen (von links nach rechts)
dcPrint.MoveTo(50, nUnten+450);
dcPrint.LineTo(nRechts, nUnten+450);
// Ab hier kommen die vertikalen Linien (von oben nach unten)
// Line ganz nRechts zeichnen (von oben nach unten)
dcPrint.MoveTo(nRechts, -500);
dcPrint.LineTo(nRechts, nUnten+450);
// Zweite Linie von rechts zeichnen, also zwischen Preis und Verfügbar
dcPrint.MoveTo(1600, -500);
dcPrint.LineTo(1600, nUnten+450);
// nächste Linie zeichnen, also Linie zwischen Hersteller und Preis
dcPrint.MoveTo(1180, -500);
dcPrint.LineTo(1180, nUnten+450);
// nächste Linie, also zwischen Produkt und Hersteller
dcPrint.MoveTo(630, -500);
dcPrint.LineTo(630, nUnten+450);
// Ganz linke Linie zeichnen
dcPrint.MoveTo(50, -500);
dcPrint.LineTo(50, nUnten+450);
//Zeit und Datum ausgeben
CTime time = CTime::GetCurrentTime();
CString date = time.Format("Datum: %d.%m.%Y ");
CString str_Time = time.Format("Uhrzeit: %H:%M");
dcPrint.TextOut(50, -350, date);
dcPrint.TextOut(50, -400, str_Time);
// Ausgabe der Elemente des Listenelements
CString str, m_strPreis, m_strVerfuegbar;
// Seitenzahl ausgeben
int nSeite= 1;
str.Format("Seite %d ",nSeite);
dcPrint.TextOut(1000, nUnten+250, str);
// Ab hier wird der Ausdruck der Artikel vorbereitet
// Ermitteln der Zeilen des Listenelement
int nAnzahl = m_List1.GetItemCount();
int nLaufendeNr = 0;
for(int i=0; i < nAnzahl; i++)
{
nLaufendeNr++;
// Ausruckbare Artikel auf 20 begrenzen
if(i >= 20)
{
MessageBox("Es werden nur die ersten 20 Artikel ausgedruckt!", "Info!", MB_ICONEXCLAMATION);
break;
}
// Einträge aus Listenelement lesen
m_strProdukt = m_List1.GetItemText(i, 0);
m_strHersteller = m_List1.GetItemText(i, 1);
m_strPreis = m_List1.GetItemText(i, 2);
m_strVerfuegbar = m_List1.GetItemText(i, 3);
// und ausgeben
dcPrint.TextOut(80, -550-nLaufendeNr*80, m_strProdukt);
dcPrint.TextOut(650, -550-nLaufendeNr*80, m_strHersteller);
dcPrint.TextOut(1200, -550-nLaufendeNr*80, m_strPreis);
dcPrint.TextOut(1630, -550-nLaufendeNr*80, m_strVerfuegbar);
}
// Seite auswerfen
dcPrint.EndPage();
// Dokument schließen
dcPrint.EndDoc();
// Druckergerätekontext löschen
dcPrint.DeleteDC();
MessageBox("Daten wurden erfolgreich gedruckt", "Info", MB_ICONEXCLAMATION);
}
else
MessageBox("Fehler! Dokument konnte nicht gedruckt werden", "Fehler!", MB_ICONEXCLAMATION);
}
 |
Beschreibung
Jetzt funktioniert auch der Ausdruck der Daten. Ich denke der Code ist ausreichend kommentiert. Der Ausdruck ist auf 20 Artikel begrenzt, d.h. es kann nur eine Seite gedruckt werden. Was ist wenn mehrere Seiten gedruckt werden sollen? Ganz einfach - füge einfach diese if-Anweisung ans Ende der for-Schleife ein:
if(nLaufendeNr == 20)
{
// Laufende Nr auf 0 setzen, damit die nächste Seite wieder von oben gedruckt wird
nLaufendeNr = 0;
// Gedruckte Seite auswerfen
dcPrint.EndPage();
//Ab hier wiederholt sich der Code zum drucken, also:
// Eine Seite beginnen
dcPrint.StartPage();
.....
// Bis zu dieser Zeile:
// Ab hier wird der Ausdruck der Artikel vorbereitet
Es wiederholt sich in der if-Anweisung also lediglich der Code zum drucken. Idealerweise packt man diesen Code selbstverständlich in eine Funktion, da der gleiche Code ja mehrmals aufgerufen wird. Nicht vergessen dürfen wir diesen Teil der sich in der for-Schleife befindet:
// Ausruckbare Artikel auf 20 begrenzen
if(i >= 20)
{
MessageBox("Es werden nur die ersten 20 Artikel ausgedruckt!", "Info!", MB_ICONEXCLAMATION);
break;
}
Dieser Code-Teil muss komplett entfernt oder auskommentiert werden, da wir sonst die Begrenzung auf 20 Artikel noch haben und nur die Tabelle ohne Inhalt ausgedruckt wird. Somit funktioniert auch der mehrseitige Druck. Wem dies noch nicht so ganz klar ist, findet den vollständigen Code mit Beschreibung im Projekt zu diesem Beispiel. Den Download gibts ein Stück weiter unten.
Um jetzt noch einen Druckdialog aufzurufen, damit ein Drucker ausgewählt werden kann, muss der gesamte Druckcode (ausser die erste Zeile) in einen if-Zweig gepackt werden:
CPrintDialog dlgPrint(FALSE, PD_ALLPAGES, this);
if(dlgPrint.DoModal()==IDOK)
{
... // Kompletter Code zum drucken bis zum 'else'
}
Downloads: Bericht_Beispiel.exe - Gesamtes Projekt
Um den Spaltenkopf zu beschriften verwendet man die Funktion InsertColumn(). Um nun Elemente in die einzelnen Zeilen einzufügen verwendet man für die erste Spalte die Funktion InsertItem() und für alle weiteren Spalten die Funktion SetItemText(). Um z.B ein Listelement beim Start der Anwendung zu initialisieren, also den Spaltenkopf beschriften und ein paar Elemente einzufügen, schreibt man den Code dazu am besten in die OnInitDialog() Funktion. Hier als Beispiel eine Initialisierung eines Listenelements:
BOOL CLControl_ReportDlg::OnInitDialog()
{
...
// ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
// Listenelement initialisieren - Spaltenkopf einfügen
m_List1.InsertColumn(0, "Produkt" ,LVCFMT_LEFT, 100);
m_List1.InsertColumn(1, "Hersteller" ,LVCFMT_LEFT, 70);
m_List1.InsertColumn(2, "Preis" ,LVCFMT_LEFT, 50);
m_List1.InsertColumn(3, "Verfügbar" ,LVCFMT_LEFT, 70);
// Elemente einfügen
m_List1.InsertItem(0, "Druckerpatrone");
m_List1.SetItemText(0, 1, "ASE");
m_List1.SetItemText(0, 2, "19,95");
m_List1.SetItemText(0, 3, "Ja");
m_List1.InsertItem(1, "CD-ROM");
m_List1.SetItemText(1, 1, "ASE");
m_List1.SetItemText(1, 2, "14,95");
m_List1.SetItemText(1, 3, "Ja");
m_List1.InsertItem(2, "Scanner");
m_List1.SetItemText(2, 1, "ASE");
m_List1.SetItemText(2, 2, "84,95");
m_List1.SetItemText(2, 3, "Nein");
return TRUE;
}
Beschreibung:
Mit Hilfe der Funktion InsertColumn() haben wir den Spaltenkopf beschriftet. Der erste Parameter steht für die jeweilige Spalte, der zweite Parameter für die anzuzeigende Beschriftung, der dritte Parameter für die Ausrichtung des anzuzeigenden Textes und der letzte Parameter gibt die Spaltenbreite in Pixel an. Der dritte Parameter, welcher für die Ausrichtung des Textes steht, kann folgende Werte annehmen: LVCFMT_LEFT, LVCFMT_RIGHT oder LVCFMT_CENTER.
Danach haben wir Zeilen mit Hilfe der Funktionen InsertItem() und SetItemText() in das Listenelement eingefügt. Jede neue Zeile wird mit der Funktion InsertItem() begonnen. Der erste Parameter steht für die Zeilenzahl und der zweite Parameter für den anzuzeigenden Text. Jedes weitere Element in der Zeile wird mit der Funktion SetItemText() eingefügt. Dabei steht der erste Parameter für die Zeile in die etwas eingefügt werden soll. Der zweite Parameter steht für die Spalte in die geschrieben werden soll und der dritte Parameter steht für den anzuzeigenden Text.
m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. Im Beispiel: Beispiel mit Listenelement in Berichts-Ansicht ist der oben gezeigte Code enthalten.
Im Beispiel Spaltenkopf beschriften - InsertColumn() steht das der dritte Parameter der Funktion InsertColumn() für die Ausrichtung des Textes zuständig ist. Er kann kann folgende Werte annehmen: LVCFMT_LEFT, LVCFMT_RIGHT oder LVCFMT_CENTER. Die Elemente könnten also folgendermaßen z.B. zentriert werden:
// Listenelement initialisieren - Spaltenkopf einfügen
m_List1.InsertColumn(0, "Produkt" , LVCFMT_CENTER, 100);
m_List1.InsertColumn(1, "Hersteller" , LVCFMT_CENTER, 70);
m_List1.InsertColumn(2, "Preis" , LVCFMT_CENTER, 50);
m_List1.InsertColumn(3, "Verfügbar" , LVCFMT_CENTER, 70);
Beschreibung:
Mit Hilfe des dritten Parameters der Funktion InsertColumn() wird also die Ausrichtung des Textes bestimmt. Man sieht schön wie die Spalten und die Einträge jetzt zentriert angezeigt werden. Allerdings gibt es eine Ausnahme - die erste Spalte wird leider nicht zentriert dargestellt.
m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. Im Beispiel: Beispiel mit Listenelement in Berichts-Ansicht ist der oben gezeigte Code enthalten.
Selbstverständlich will man auch mal vom Anwender eingegebene Daten speichern bzw. wiederherstellen. Das geht ganz leicht und als Code Beispiel kommt der Code aus dem Beispiel mit Listenelement in Berichts-Ansicht zum Einsatz:
void CLElement_BerichtDlg::OnLaden()
{
CString strLesePuffer, strDateiName, strPfad;
CStdioFile DateiLesen;
int i=0;
// Holt Pfad und Name mit .exe
strPfad = GetCommandLine();
// Dateierweiterung abschneiden
int nPos = strPfad.ReverseFind( '\\');
strPfad = strPfad.Mid(1, nPos-1);
// Ermittelten Pfad + Dateiname in strDateiName schreiben
strDateiName = strPfad +"//text.txt";
// Kompletten Inhalt des Listenelements löschen
m_List1.DeleteAllItems();
// Datei auslesen
if (DateiLesen.Open(strDateiName, CFile::modeRead))
{
while(DateiLesen.ReadString(strLesePuffer))
{
// Datei zeilenweise auslesen
m_List1.InsertItem(i, strLesePuffer);
DateiLesen.ReadString(strLesePuffer);
m_List1.SetItemText(i, 1, strLesePuffer);
DateiLesen.ReadString(strLesePuffer);
m_List1.SetItemText(i, 2, strLesePuffer);
DateiLesen.ReadString(strLesePuffer);
m_List1.SetItemText(i, 3, strLesePuffer);
i++;
}
}
else
MessageBox ("Fehler beim Laden der Datei", "Fehler", MB_ICONINFORMATION);
}
void CLElement_BerichtDlg::OnSichern()
{
CString m_strPreis, m_strVerfuegbar, strDateiName, strPfad;
CStdioFile DateiSpeichern;
int i, nZeilenanzahl;
// Holt Pfad und Name mit .exe
strPfad = GetCommandLine();
// Dateierweiterung abschneiden
int nPos = strPfad.ReverseFind( '\\');
strPfad = strPfad.Mid(1, nPos-1);
// Ermittelten Pfad + Dateiname in strDateiName schreiben
strDateiName = strPfad +"//text.txt";
// Daten in Datei sichern
if (DateiSpeichern.Open(strDateiName, CFile::modeCreate | CFile::modeWrite ))
{
// Anzahl der Zeilen im Listenfeld holen
nZeilenanzahl = m_List1.GetItemCount();
for(i=0; i < nZeilenanzahl; i++)
{
m_strProdukt = m_List1.GetItemText(i, 0);
m_strHersteller = m_List1.GetItemText(i, 1);
m_strPreis = m_List1.GetItemText(i, 2);
m_strVerfuegbar = m_List1.GetItemText(i, 3);
DateiSpeichern.WriteString (m_strProdukt+"\n" + m_strHersteller+"\n" + m_strPreis+"\n" + m_strVerfuegbar +"\n" ) ;
}
DateiSpeichern.Close ();
MessageBox ("Daten wurden gespeichert", "Daten gespeichert", MB_ICONINFORMATION);
}
else
MessageBox ("Fehler beim Öffnen der Datei - Speichern wurde abgebrochen", "Fehler", MB_ICONINFORMATION);
}
Beschreibung
m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. In der Funktion OnLaden() wird zuerst der Pfad der Anwendung ermittelt und die Dateierweiterung abgetrennt. Danach wird mit Hilfe der Funktion DeleteAllItems() der komplette Inhalt des Listenelements gelöscht. Falls bereits eine Datei mit Daten vorhanden ist wird diese geöffnet und zeilenweise in das Listenelement eingelesen.
In der Funktion OnSichern() wird wieder zuerst der Pfad der Anwendung ermittelt und die Dateierweiterung abgetrennt. Dann wird eine Textdatei erstellt und zeilenweise in diese Textdatei geschrieben.
Das einzigste was sich standardmäßig in einem Listenelement anklicken lässt ist jeweils der Eintrag in der ersten Spalte. Auch die Markierung steht immer nur auf der ersten Spalte:
Mit der Zeile
m_List1.SetExtendedStyle(LVS_EX_FULLROWSELECT);
lässt sich das leicht ändern. Fügt man diese Zeile ein, kann man die ganze Zeile in einem Listenelement markieren:
Styles können auch kombiniert werden, z.B wie in den hier gezeigten Screenshots. Da wurden zwei Styles kombiniert, damit auch noch Gitternetzlinien sichtbar sind. Das sieht dann so aus:
// Gitternetzlinien einfügen und ganze Zeile markieren
m_List1.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. Im Beispiel: Beispiel mit Listenelement in Berichts-Ansicht ist der oben gezeigte Code enthalten.
Mit nur einer Zeile kann man das Aussehen des Listenelements stark beeinflussen. Mit folgender Zeile fügt man Gitternetzlinien in das Listenelement ein:
m_List1.SetExtendedStyle(LVS_EX_GRIDLINES);
Beschreibung
Das Style LVS_EX_GRIDLINES sorgt also dafür das Gitternetzlinien im Listenelement angezeigt werden. Styles können kombiniert werden, z.B mit LVS_EX_FULLROWSELECT, um eine ganze Zeile zu markieren. Verwendet man mehrere Styles, werden diese mit einem | voneinander getrennt.
m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. Im Beispiel: Beispiel mit Listenelement in Berichts-Ansicht ist der oben gezeigte Code enthalten.
Um den Spaltenkopf zu beschriften verwendet man die Funktion InsertColumn(). Um z.B ein Listelement beim Start der Anwendung zu initialisieren, also den Spaltenkopf beschriften, schreibt man den Code dazu am besten in die OnInitDialog() Funktion. Hier als Beispiel eine Initialisierung eines Listenelements:
BOOL CLControl_ReportDlg::OnInitDialog()
{
...
// ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
// Listenelement initialisieren - Spaltenkopf einfügen
m_List1.InsertColumn(0, "Produkt" ,LVCFMT_LEFT, 100);
m_List1.InsertColumn(1, "Hersteller" ,LVCFMT_LEFT, 70);
m_List1.InsertColumn(2, "Preis" ,LVCFMT_LEFT, 50);
m_List1.InsertColumn(3, "Verfügbar" ,LVCFMT_LEFT, 70);
return TRUE;
}
Beschreibung
Mit Hilfe der Funktion InsertColumn() haben wir den Spaltenkopf beschriftet. Der erste Parameter steht für die jeweilige Spalte, der zweite Parameter für die anzuzeigende Beschriftung, der dritte Parameter für die Ausrichtung des anzuzeigenden Textes und der letzte Parameter gibt die Spaltenbreite in Pixel an. Der dritte Parameter, welcher für die Ausrichtung des Textes steht, kann folgende Werte annehmen: LVCFMT_LEFT, LVCFMT_RIGHT oder LVCFMT_CENTER.
m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. Im Beispiel: Beispiel mit Listenelement in Berichts-Ansicht ist der oben gezeigte Code enthalten.
Um heraus zu finden wieviele Zeilen ein Listenelement hat, kann man die Funktion GetItemCount() verwenden:
// Anzahl der Zeilen im Listenfeld holen
int nZeilenanzahl = m_List1.GetItemCount();
Beschreibung
In der Variablen nZeilenanzahl steht die Anzahl der vorhandenen Zeilen im Listenelement. m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. Im Beispiel: Beispiel mit Listenelement in Berichts-Ansicht ist der oben gezeigte Code enthalten.
Um eine Zeile im Listenelement zu löschen kann man die Funktion DeleteItem() verwenden. Man übergibt ihr die zu löschende Zeilennummer. Möchte man z.B eine vom Anwender markierte Zeile löschen, dann sieht der Code dazu so aus:
// Ausgewählte Zeile ermitteln
int nZeilenauswahl;
nZeilenauswahl = m_List1.GetNextItem(-1, LVNI_SELECTED);
// Ausgewählte Zeile löschen
m_List1.DeleteItem(nZeilenauswahl);
Möchte man alle Zeilen des Listenelements auf einmal löschen, kann man die Funktion DeleteAllItems() verwenden:
// Kompletten Inhalt des Listenelements löschen
m_List1.DeleteAllItems();
m_List1 ist eine Variable des Listenelement und vom Typ CListCtrl. Im Beispiel: Beispiel mit Listenelement in Berichts-Ansicht ist der oben gezeigte Code enthalten.
| Die Vervielfältigung der auf diesen Seiten enthaltenen Informationen und Grafiken ist untersagt, ausgenommen davon ist sämtlicher auf diesen Seiten angezeigter Quellcode. Es wird keinerlei Gewähr für die Richtigkeit und Vollständigkeit der bereitgestellten Informationen übernommen. Haftungsansprüche für Schäden, die durch Nutzung der bereitgestellten Informationen verursacht wurden, sind ausgeschlossen. Für den Inhalt von angegebenen Verweisen wird keine Gewährleistung übernommen.
Copyright © 2005 coding-help.de | |