Datum: 29.04.2008 11:32
Hallo alle zusammen, ich möchte den Inhalt eines *.txt Dokuments als Tabelle in Microsoft Visual C++ darstellen. Das Problem liegt nun aber nicht am einlesen der Daten, sondern an der Darstellung der Tabelle selbst. In Visual C++ hab ich leider nur ein Listfeld, was mir glaub ich nicht viel bringt, da ich mehrere Spalten benötige. Was Eigenschaft "Mehrspaltig" eines Listenfeldes bringt kapier ich auch nicht so richtig^^ Da ändert sich doch nichts oder? Nun bin ich auf die ActivX DataGrid Elemente gestoßen. Ist es sinnvoll da mit ActivX zu arbeiten oder gibts eine gute Alternative?
Datum: 29.04.2008 11:37
Hallo Frank, ich fang grad erst mit Visual C++ an. Soweit ich gelesen hab gibt es neben der "normalen" Listbox noch ein ListControl welches sich dafür besser eignen soll. Leider hab ich weder damit noch mit dienen ActivX Elementen bisher Erfahrung. Aber vielleicht einfach mal in der MSDN Library nach "ListControl" suchen, da findet sich sicher was. Grüße Sebastian
Datum: 29.04.2008 11:50
Du kannst in einer Listbox sehrwohl Spalten generieren. Der Schlüsselbegriff dafür heißt "InsertColumn" bzw. "InsertItem". Hier ein Programmausschnitt : CListCtrl * pListCtrl = (CListCtrl *)GetDlgItem(IDC_LIST_STATISTIK); pListCtrl->InsertColumn(0,"Spalte 1",LVCFMT_LEFT,60,0); pListCtrl->InsertColumn(1,"Spalte 2",LVCFMT_LEFT,80,0); Um in den Spalten Einträge vorzunehmen benötigt man sowas : LV_ITEM item; pListCtrl->InsertItem(0,"Text",0); item.mask = LVIF_TEXT; item.iItem = 0; Einfach mal ausprobieren, wird schon hinhauen.
Datum: 29.04.2008 12:21
> Du kannst in einer Listbox sehrwohl Spalten generieren. > [...] > CListCtrl * pListCtrl = (CListCtrl *)GetDlgItem(IDC_LIST_STATISTIK); Du verwechselst CListBox und CListCtrl. Letzteres, auch als ListView bekannt, kann mehrspaltige Inhalte darstellen, ersteres ist deutlich primitiver und für eine mehrspaltige Darstellung annähernd völlig unbrauchbar.
Datum: 29.04.2008 13:00
M. H. wrote: > Du kannst in einer Listbox sehrwohl Spalten generieren. ListBox != ListCtrl > Der Schlüsselbegriff dafür heißt "InsertColumn" bzw. "InsertItem". > > Hier ein Programmausschnitt : > > CListCtrl * pListCtrl = (CListCtrl *)GetDlgItem(IDC_LIST_STATISTIK); > pListCtrl->InsertColumn(0,"Spalte 1",LVCFMT_LEFT,60,0); > pListCtrl->InsertColumn(1,"Spalte 2",LVCFMT_LEFT,80,0); Sei aber nett zu deinem User und speichere die Spaltenbreite in der Registry ab. Beim Erzeugen der Columns (also typischerweise in der OnInitDialog eines CDialogs):
pListCtrl->InsertColumn(0,"Spalte 1",LVCFMT_LEFT, AfxGetApp()->GetProfileInt( "List", "S1", 60 ), 0); pListCtrl->InsertColumn(1,"Spalte 2",LVCFMT_LEFT, AfxGetApp()->GetProfileInt( "List", "S2", 80 ), 0); |
und im OnClose Handler eines Dialogs
CListCtrl * pListCtrl = (CListCtrl *)GetDlgItem(IDC_LIST_STATISTIK); AfxGetApp()->WriteProfileInt( "List", "S1", pListCtrl->GetColumnWidth( 0 ) ); AfxGetApp()->WriteProfileInt( "List", "S2", pListCtrl->GetColumnWidth( 1 ) ); |
Mich ärgert sowas immer tierisch, wenn sich Programme die GUI Einstellungen nicht merken. Als Benutzer bist du dann immer am ständigen Verschieben von Spalten, um überhaupt arbeiten zu können nur damit dann beim nächsten Programmstart alles wieder von vorne losgeht. Dabei lässt sich das mit einfachsten Mitteln und ohne großen Aufwand abstellen.
Datum: 29.04.2008 13:15
also irgendwie tut das nicht, bisher hab ich das so gemacht Im RessourcenEditor ein "Listenfeld" über meine FormView gelegt, dort bei Eigenschaft "Mehrspaltig" aktiviert. Dann hab ich in der Klassen meiner FormView eine Membervariable vom Typ CListCtrl * definiert. Nun hab ich für meine FormView-Klasse die Funktion "PreCreateWindow" angelegt und führe dort folgenden Code aus. *****************MEIN CODE******************** m_pList = (CListCtrl *)GetDlgItem(IDC_TEST_LIST); m_pList->InsertColumn(0,"Spalte 1",LVCFMT_LEFT,60,0); m_pList->InsertColumn(1,"Spalte 2",LVCFMT_LEFT,80,0); **************MEIN CODE ENDE****************** Wenn das ganze nun gestartet wird erhalte ich eine "DEBUG ASSERTION FAILED" mit nem Fehler in der winocc.cpp. Klicke ich auf "Ignorieren" kommt folgende Fehlermeldung: "Unbehandelte Ausnahme in Test.exe (MFC42D.DLL): 0xC0000005: Access Violation." Ist das mit dem "Listenfeld" überhaupt richtig?
Datum: 29.04.2008 13:31
Frank wrote: > > Wenn das ganze nun gestartet wird erhalte ich eine "DEBUG ASSERTION > FAILED" mit nem Fehler in der winocc.cpp. Klicke ich auf "Ignorieren" > kommt folgende Fehlermeldung: Ignorieren ist bei sowas immer schlecht. Klicke auf "Weiter" und schau dir im Code an, wie es zu dieser Assertion kommt. Das gibt dann normalerweise schnell Auskunft darüber, was schief läuft. > Im RessourcenEditor ein "Listenfeld" Du willst kein Listenfeld (also eine ListBox), du willst ein Listenelement (ein ListControl). Das steht in der Toolbox in der linken Spalte, gleich unter dem Schieberegler. Das setzt du auf den FormView. Danach in die Eigenschaften und umstellen: Unter "Formate" stellst du die 'Ansicht' um auf: Bericht Damit sollte das dann erst mal laufen.
Datum: 29.04.2008 13:36
Übrigens: Diesen HickHack m_pList = (CListCtrl *)GetDlgItem(IDC_TEST_LIST); kannst du dir auch sparen. Lass dir doch vom Resource-Wizard gleich eine Control Variable für dieses Control bauen, dann brauchst du dich nicht selbst drum kümmern, dass du Zugang zum Control hast.
Datum: 29.04.2008 14:00
das mit der Ressource vom Wizard hab ich auch so umgesetzt und die
dazugehörende Zeile im Code dann auch rausgeschmissen.
Aber das Einfügen von Spalten geht trotzdem nicht.
_AFXCMN_INLINE int CListCtrl::InsertColumn(int nCol, const LVCOLUMN*
pColumn)
{ ASSERT(::IsWindow(m_hWnd)); return (int) ::SendMessage(m_hWnd,
LVM_INSERTCOLUMN, nCol, (LPARAM)pColumn); }
Das Problem liegt in dieser Funktion bei "IsWindow(m_hWnd)" da kennt er
kein m_hWnd bzw. hat einen ungültigen Ausdruck darin stehn.
In welcher Funktion lass ich am besten die Spalten einfügen?
Da ich kein Dialog sondern FormViews verwende gibt es leider keine
"OnInit"-Funktion. Bisher füge ich sie in der "OnCreate" ein aber wie
gesagt geht das nicht.
Datum: 29.04.2008 14:06
Frank wrote: > "OnInit"-Funktion. Bisher füge ich sie in der "OnCreate" ein aber wie > gesagt geht das nicht. OnCreate wird zu früh sein. Solche Dinge macht man in der OnInitialUpdate
Datum: 29.04.2008 14:14
bei den ganzen Funktionen blickt doch niemand mehr durch. Leider macht es keinen Unterschied ob ich die InsertColumn in der OnCreate oder in der OnInitialUpdate ausführe. Der Fehler bleibt derselbe.
Datum: 29.04.2008 14:16
Frank wrote: > bei den ganzen Funktionen blickt doch niemand mehr durch. > Leider macht es keinen Unterschied ob ich die InsertColumn in der > OnCreate oder in der OnInitialUpdate ausführe. Der Fehler bleibt > derselbe. Dann machst du irgendetwas falsch. Habe hier ein Testprojekt (VC++ 6.0) mit einem FormView aufgesetzt. Auf die Form ein ListControl gesetzt. In der OnInitialUpdate des Views die InsertColumns und alles funktioniert so wie es soll. Du hast nicht zufällig vergessen, die InsertColumns aus der OnCreate wieder rauszunehmen?
Datum: 29.04.2008 14:18
die Spalten fügst du auch so ein "m_pEmpfList.InsertColumn(1,"Code",LVCFMT_LEFT,60,-1);" rufst du sonst irgendwo irgendwelche Funktionen für die ListCtrl auf?
Datum: 29.04.2008 14:21
Frank wrote: > die Spalten fügst du auch so ein > > "m_pEmpfList.InsertColumn(1,"Code",LVCFMT_LEFT,60,-1);" Yep. > > rufst du sonst irgendwo irgendwelche Funktionen für die ListCtrl auf? Nein. Hier ist meine OnInitialUpdate
void Test::OnInitialUpdate() { CFormView::OnInitialUpdate(); m_ctrlListe.InsertColumn( 0, "Test1",LVCFMT_LEFT,60,-1 ); m_ctrlListe.InsertColumn( 1, "Test2" ); } |
Du hast doch wohl nicht den Aufruf der OnInitialUpdate der Basisklasse rausgeschmissen? Der muss vor deinen eigenen Aufrufen passieren! Erst dort werden die Control Variablen mit den GUI Elementen verknüpft.
Datum: 29.04.2008 14:24
Hab gerade ein neues Projekt gemacht und es dort ausprobiert, dort tut alles ohne Probleme. Keine Ahnung was ich an dem anderen Projekt verbockt hab. Aber da das andere noch nicht wirklich weit war mach ich nun das neue weiter und übertrag kurz die bisher gemachten Änderungen. Dürfte schneller gehn als ne Fehlersuche.
Datum: 29.04.2008 14:37
Frank wrote: > Hab gerade ein neues Projekt gemacht und es dort ausprobiert, dort tut > alles ohne Probleme. Keine Ahnung was ich an dem anderen Projekt > verbockt hab. Könnte irgendein Problem mit dem im Resource-Editor vergebenen ID sein. Sowas kommt schon mal vor. > Aber da das andere noch nicht wirklich weit war mach ich > nun das neue weiter und übertrag kurz die bisher gemachten Änderungen. > Dürfte schneller gehn als ne Fehlersuche. Da ist meist was drann :-)
Datum: 29.04.2008 14:47
Wenn wir schon dabei sind hätte ich noch 2 Sachen^^ Ich füge nun 4 Spalten in die ListCtrl ein, diese Spalten werden auch wunderbar eingefügt. Aber es ist noch eine 5. Spalte ohne Titel dabei, kann ich die rauswerfen? Das 2. wäre die Größe der ListCtrl. Das Projekt läuft als MDI und die ListCtrl werden als Dokumente angezeigt. Wenn ich auf "Maximieren" in dem Dokument klicke, dann maximiert zwar das Dokument aber die ListCtrl behält ihre Größe bei. Ich hätte aber gerne das die Liste immer das komplette Dokument ausfüllt. Wofür ich eigentlcih eine dynamische Spaltengröße bräuchte oder?
Datum: 29.04.2008 15:00
Frank wrote: > Wenn wir schon dabei sind hätte ich noch 2 Sachen^^ > Ich füge nun 4 Spalten in die ListCtrl ein, diese Spalten werden auch > wunderbar eingefügt. Aber es ist noch eine 5. Spalte ohne Titel dabei, > kann ich die rauswerfen? Das müsste dann der Restplatz des Controls, also der Teil ohne Spalten sein. Den wirst du leider nicht los, aber du kannst natürlich die Spalten entsprechend in die Breite ziehen, so dass sie den kompletten Platz einnehmen. Dazu dann noch das Speichern und Wiederherstellen der Spaltenbreite, wie oben schon gezeigt, und dann sollte das kein Problem mehr sein. Edit: hab erst später gelesen, dass du die Spalten per Programm dynamisch größer und kleiner ziehen willst. > Das 2. wäre die Größe der ListCtrl. Das Projekt läuft als MDI und die > ListCtrl werden als Dokumente angezeigt. Wenn ich auf "Maximieren" in > dem Dokument klicke, dann maximiert zwar das Dokument aber die ListCtrl > behält ihre Größe bei. Da musst du dich dann an die WM_SIZE Message hängen und alle Controls auf der FormView resizen. Aber Achtung: Die aus der WM_SIZE Message generierte Funktion OnSize wird ganz am Anfang des Programms schon mal mit Größen von 0 aufgerufen. So einen Aufruf einfach ignorieren
void TestView::OnSize(UINT nType, int cx, int cy) { CFormView::OnSize(nType, cx, cy); if( cx == 0 || cy == 0 ) return; // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen } |
> Ich hätte aber gerne das die Liste immer das > komplette Dokument ausfüllt. Vorsicht: Der Begriff "Dokument" wird in der MFC für etwas anderes benutzt. Was du hast ist ein "View". Dokument: zuständig für das Halten und Verwalten von Daten View: eine Anzeige der, im zugehörigen Dokument, gespeicherten Daten Diese Aufgabentrennung ist wichtig! Wenn du dich nicht daran hältst, kriegst du Probleme mit dem MDI. Unterschiedliche Views zeigen dann dasselbe Dokument in unterschiedlichen Stadien an. > Wofür ich eigentlcih eine dynamische > Spaltengröße bräuchte oder? Ja. SetColumnWidth ist dein Freund.
Datum: 29.04.2008 15:05
Meine Mum hatte doch recht als sie sagte, das ich komische Freunde hab ^^
Datum: 29.04.2008 15:45
Also funktionieren tut soweit alles. Hab das jetzt mal mit dem folgenden
Code gemacht.
void CEmpfangsverlauf::OnSize(UINT nType, int cx, int cy)
{
CFormView::OnSize(nType, cx, cy);
m_cList.MoveWindow(0,0,cx,cy,TRUE);
m_cList.SetColumnWidth(3,LVSCW_AUTOSIZE_USEHEADER);
// TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen
}
Funktionieren tuts, aber beim Kompilieren kommt wieder mal der "DEBUG
ASSERTION FAILED" mit "Ignorieren" durchklicken und es tut. Aber der
Fehler kommt ja sicher nicht ohne Grund. In den CListCtrl Funktionen wie
MoveWindow usw wird ja die Zeile:
"ASSERT(::IsWindow(m_hWnd));"
Dabei hat m_hWnd den Wert 0x00000000
Also falls jmd das gleiche Problem schonmal hatte und nen Tipp zu einer
Lösung parat hätte, wäre ich echt dankbar.
Achja Karl Heinz, das mit dem Aufruf von OnSize mit 0 als Größen war bei
mir nicht so. Das wird gleich mit der richtigen Größe aufgerufen. Aber
lieber zuviel Sicherheitsabfragen als zuwenig ;)
Datum: 29.04.2008 15:54
Frank wrote: > MoveWindow usw wird ja die Zeile: > > "ASSERT(::IsWindow(m_hWnd));" > > Dabei hat m_hWnd den Wert 0x00000000 Was bedeutet, dass das Control noch nicht mit dem GUI Element verknüpft ist. > > Also falls jmd das gleiche Problem schonmal hatte und nen Tipp zu einer > Lösung parat hätte, wäre ich echt dankbar. > > Achja Karl Heinz, das mit dem Aufruf von OnSize mit 0 als Größen war bei > mir nicht so. Das wird gleich mit der richtigen Größe aufgerufen. Aber > lieber zuviel Sicherheitsabfragen als zuwenig ;) Hast du dir auch den 2-ten oder 3-ten Aufruf der OnSize() angeschaut? :-) Zu deinem Problem. Die OnSize wird bereits aufgerufen noch bevor die Controls erstellt wurden. Du kannst das ganz leicht abfangen, die Assertion sagt dir sogar wie. Solange m_hWnd noch keinen gültigen Wert hat, darfst du die MoveWindow nicht aufrufen. Ergo:
void CEmpfangsverlauf::OnSize(UINT nType, int cx, int cy) { CFormView::OnSize(nType, cx, cy); if( ::IsWindow( m_cList.m_hWnd ) ) { m_cList.MoveWindow(0,0,cx,cy,TRUE); m_cList.SetColumnWidth(3,LVSCW_AUTOSIZE_USEHEADER); } } |
Datum: 29.04.2008 16:11
Super funktioniert wunderbar. Hast du zufällig die Funktion im Kopf um die Größe des Views abzufragen? Das würde ich noch für die Initialisierung benötigen, da die Größe der Liste erst nach einer Größenveränderung des Views umgestellt wird. Lässt man das View bei seiner normalen Größe, so kann es sein das die Liste nicht das komplette View ausfüllt.
Datum: 29.04.2008 16:23
PS: Wenn du sowieso nur ein List Control im View hast, warum machst du das dann so kompliziert? Tausch den CFormView gegen einen CListView aus und fertig. * Mit dem Wizard eine neue View Klasse erzeugen Diese von CListView ableiten * In der Applikation bei der Erzeugung des DocumentTemplates die neue Klasse anstelle der FormView angeben (Header File inkludieren nicht vergessen) * In der neuen Klasse die PreCreateWindow überschreiben, damit das List Control auch im Report Modus erzeugt wird
BOOL CMyList::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= LVS_REPORT;
return CListView::PreCreateWindow(cs);
}
|
* In der OnInitialUpdate die Spalten wie gehabt erzeugen. Mittels GetListCtrl() kommt man an das zugrunde liegende List Control heran:
void CMyList::OnInitialUpdate() { CListView::OnInitialUpdate(); GetListCtrl().InsertColumn( 0, "Test" ); } |
Um Größenänderungen oder dgl. brauchst du dich dann nicht selbst kümmern. Erledigt alles der CListView
Datum: 29.04.2008 16:25
Frank wrote: > Super funktioniert wunderbar. > Hast du zufällig die Funktion im Kopf um die Größe des Views abzufragen? Gibt es nicht. Aber nichts und niemand hindert dich daran, in deinen View 2 Variablen einzubauen, die du im OnSize mit Werten versorgst. Edit: OK. Über GetWindowRect könnte man das machen. Die Variante über Speichern der Größe im OnSize ist aber simpler.
Antwort schreiben
Die Angabe einer Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
- Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
- Aussagekräftigen Betreff wählen
- Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
- Groß- und Kleinschreibung verwenden
- Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
- JPEG-Dateien (.jpg) nur für Fotos verwenden, Schaltpläne, Screenshots usw. als PNG oder GIF anhängen
Formatierung (mehr Informationen...)
- [c]C-Code[/c]
- [avrasm]AVR-Assembler-Code[/avrasm]
- [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
- [math]Formel in LaTeX-Syntax[/math]
- [[Titel]] - Link zu Artikel