Listboxen - synchron scrollbar ?
-
habs mitlerweile rausgefunden, und zwar
ON_EN_HSCROLL gibt es fuer die listboxen nicht, dh man muss es umgehen
ich hab eine zusaetzliche scrollbar eingefuegt, und deren range {mit .SetScrollRange()} eingegeben anhand der ".GetScrollRange()" von der listbox, sofern mehr als 0 dann anzeigen ansonsten nicht
nu kann ich die methoden "ON_WM_HSCROLL" und "ON_WM_VSCROLL" ueberschreiben
dort hab ich dann die entsprechenden aktionen gemacht mit:
m_ListA.SetScrollPos();
das reicht aber noch nicht, die scrollbars der listboxen wandern zwar richtig, aber der inhalt nicht, dh ich hab noch ein SendMessage gebraucht
nu n bissl code womit es ging
ON_WM_VSCROLL() ON_WM_HSCROLL()if((max = m_ListA.GetScrollLimit(SB_VERT))>0) { m_ScrollBar.ShowWindow(TRUE); m_ScrollBar.SetScrollRange(0, max); } else m_ScrollBar.ShowWindow(FALSE);unsigned int i=0; int first=0; void COwnDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int CurPos = m_ScrollBar.GetScrollPos(); if(first=0){ i=nPos; first=1; } switch (nSBCode) { case SB_LINELEFT: m_ListA.PostMessage(WM_VSCROLL, SB_LINEUP); m_ListB.PostMessage(WM_VSCROLL, SB_LINEUP); CurPos--; break; case SB_LINERIGHT: m_ListA.PostMessage(WM_VSCROLL, SB_LINEDOWN); m_ListB.PostMessage(WM_VSCROLL, SB_LINEDOWN); CurPos++; break; case SB_THUMBTRACK: case SB_THUMBPOSITION: CurPos = nPos; if(i<nPos){ m_ListA.PostMessage(WM_VSCROLL, SB_LINEDOWN); m_ListB.PostMessage(WM_VSCROLL, SB_LINEDOWN); i=nPos; } else{ m_ListA.PostMessage(WM_VSCROLL, SB_LINEUP); m_ListB.PostMessage(WM_VSCROLL, SB_LINEUP); i=nPos; } break; } m_ScrollBar.SetScrollPos(CurPos); m_ListA.SetScrollPos(SB_VERT, CurPos); m_ListB.SetScrollPos(SB_VERT, CurPos); }
-
Man kann auch direkt mit Get/SetTopIndex arbeiten. Dann löst man auch das Problem, wenn mal eine Scrollnachricht irgendwie sich verhaspelt.
-
das SetTopIndex verwirrt mich eher mehr als das ich damit irgendetwas hin bekomm /=
in der msdn steht das man {glaub ich so verstanden zu haben} das ein zu den angegebenen item gescrollt wird
haste ma n beispiel ?
ich hab grad gelesen mit - "GetTopIndex" bekommt man immer das erste sichtbare element zurueck
das bringt mir gar nichts, der inhalt der liste ist mir immer unbekannt, auch die anzahl - kann 1 bis 3000 sein
ich denk mir mit der message "LINEUP" und "LINEDOWN" fahr ich am besten, bisher beim test nie ein fehler gehabt, und wenn die liste am anfang ist und LINEUP bekommt, oder am ende ist und LINEDOWN bekommt, gibts auhc kein fehler, das wird einfach missachtet
-
Der Name sagt doch alles: Durch diese Funktion wird ermitelt, welches Item das erste ist, bzw. es wird bestimmt welches das erste Item sein soll.
Was verwirrt Dich?
-
es verwirrt mich wo ich das nutzen kann zum scrollen
-
Fange WM_VSCROLL ab.
Führe den Default durch.
Besorge die den neuen Top Index (GetTopIndex), setzte den neuen top Index in dem anderen Control.
-
tut mir leid, aber ich versteh das nicht
was meinst du mit "fuehre default durch" ?
so wie ich das hab find ich das logisch, wenn zeile hoch, dann an beiden listboxen ein lineup senden, genauso mit linedown
-
@Mr Evil,
meintest du so etwas ???
http://ramveg1.100webspace.net
download: test_clistbox.rarEingaben/Bewegungen an der internen Scrollbar der linken Listbox werden an die rechte Listbox weitergegeben !!!
cu veganza
-
genau - ohne das ich eine eigene progressbar erstellen muss - so hab ich das bisher geloest
-
und wo genau hast du jetzt die Probleme ???
ich habe einfach ein neue Klasse erstellt, diese von CListBox abgeleitet und darin dann die OnVScroll() überschrieben und reagiere auf momentan 3 Messages ( SB_LINEDOWN, SB_LINEUP, SB_THUMBTRACK ).
In der abgeleiteten Klasse habe ich dann nur noch eine Funktion implementiert mit der du ein CWnd* übergeben kannst ( für die zweite Listbox ), um auf die andere ( die rechte ) Listbox zugreifen zu können.
die linke Listbox ist "ge-subclassed" mit der abgeleiteten CListBox Klasse, die rechte Listbox ist eine "normale" CListBox.
benutze mal Spy++ um zu schauen was da genau abgeht ( MESSAGES )... denn Dein Dialog bekommt von den Bewegungen an der "internen Scrollbar" nur sehr bedingt was mit !!!
du mußt also eine eigene Klasse von CListBox ableiten und darin Deine Auswertung/Funktionen implementieren...
versuchs mal selbst zu implementieren... wenn Du Probleme hast melde dich wieder

cu veganza
-
irgendwie kapier ich das nicht
also
ich hab mal ein testdialog gemacht, da zwei listboxen erstellt, und die beim oninitidialog fuellen lassen sodass man scrollen kann
dann eine klasse erstellt:
#pragma once #include "afxwin.h" class OwnListBoxes : public CListBox { protected: DECLARE_MESSAGE_MAP() afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar); };und dann die entsprechende cpp dazu:
#include "stdafx.h" #include "TestProj.h" #include "TestProjDlg.h" #include "OwnListBoxes.h" BEGIN_MESSAGE_MAP(OwnListBoxes, CListBox) ON_WM_VSCROLL() END_MESSAGE_MAP() void OwnListBoxes::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) { int i=0; }bei int i=0; hab ich n haltepunkt gesetzt, und ich seh das egal was ich mach das programm nie dahin kommt
als wenn den die klasse voellig egal istich hab auch schon probiert das ich rechtsklick auf die listbox, add class - von CDialog abgeleitet {besseres war ne zur auswahl} dann ne eigene klasse erstellt und da diese neue klasse abgeleitet - in beiden hab ich auch versucht das VScroll abzufangen - ging alles nicht }=
-
ha, ich habs
mein problem war die variable die ich zum fuellen benutzt hatte, das war ne eigene
void CTestProjDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST1, m_myListBox); DDX_Control(pDX, IDC_LIST2, m_List2); }da hab ich es von "m_List1" auf "m_myListBox" geaendert und in meiner haupt dialogklasse
public: CTestProjDlg(CWnd* pParent = NULL); // standard constructor enum { IDD = IDD_TESTPROJ_DIALOG }; COwnListBoxes m_myListBox;
-
nu stellt sich mir die frage wie ich die neue scrollposition in der zweiten liste setz, du hast etwas von einer funktion mit *Wnd geschrieben - da bin ich grad etwas ratlos was ich da zu tun habe
mein erster versuch war, das ich bei ListA::OnVScroll gleich den aufruf zu ListB::OnVScroll mach, das problem hierbei ist der pointer auf die scrollbar, ich braeuchste ja den pointer auf die zweite liste
ps. die zweite liste hab ich auch das OnVScroll ueberschrieben da ich es auch umgekehrt abhaengig machen moechte
dazuedit
ich hab nu in der scroll klasse A eine funktion die die pointer auf die scrollbars annehmen sodass ich das senden kann
aber die sind immer null, auch die in der ersten OnVScroll (pScrollBar) sind immer null, im prinzip isses da egal wie ich es aufruf /=
void OwnListBoxesA::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) { CListBox::OnVScroll(nSBCode, nPos, pScrollBar); // pScrollBar ist immer NULL }
-
naja eigentlich ganz einfach:
1. lege in Deiner abgeleiteten ListBox Klasse eine private Membervariable vom Type CWnd* an
2. implementiere eine Funktion damit diese CWnd* Variable "von außen" gesetzt werden kann
void CMyListbox::SetSlaveLB_Handle(CWnd *pWnd) { m_hLB = pWnd; //m_hLB ist die Membervariable in Deiner CListBox Klasse ( siehe Punkt 1. ) }3. in der OnitDialog() von Deiner Dialoganwendung übergibst du dann den Pointer in die abgeleitete Klasse und kannst dann in der Klasse selbst darauf zugreifen !!!
m_cMyListbox.SetSlaveLB_Handle( GetDlgItem( IDC_LIST1 ) ); // eine Überprüfung ob das Handle "valid" ist wäre nicht schlecht !!!alternativ kannst du Dir natürlich auch über:
AfxGetMainWnd()->GetDlgItem(IDC_LIST1);direkt in Deiner abgeleiteten Klasse Zugriff auf die ListBox holen !!!
hoffe das hilft Dir weiter

cu veganza
-
Kurze Zwischenfrage
Falls du möchtest, dass man Elemente aus zwei Spalten glichzeitig sieht, kann man doch drei andere einfachere Wege gehen:
- Man nehme CListView und fertig - ohne irgendwelche weiteren tiefgehenden Codes
- eine Listbox und CListBox::DrawOwnItem verändern, so dass es zwei Spalten einzeigt
- Diesmal werden drei Steuerelemente benötigt: 2 Listboxen, die keine Scrollbar haben, und eine externe Scrollbar (als Steuerelement direkt auf den Dialogfeld oder sonstwo) dazwischen. (ganz grob, im etwa, in der nähe von dem was ihr hier macht)
Mit freudlichen Grüßen
Rhombicosidodecahedron
-
Rhombicosidodecahedron schrieb:
Kurze Zwischenfrage
Falls du möchtest, dass man Elemente aus zwei Spalten glichzeitig sieht, kann man doch drei andere einfachere Wege gehen:das muß Mr Evil beantworten...
die Problemstellung war das zwei Listboxen über die interne Scrollbar synchron scrollbar sein sollen !!!
cu veganza
-
veganza schrieb:
Rhombicosidodecahedron schrieb:
Kurze Zwischenfrage
Falls du möchtest, dass man Elemente aus zwei Spalten glichzeitig sieht, kann man doch drei andere einfachere Wege gehen:das muß Mr Evil beantworten...
die Problemstellung war das zwei Listboxen über die interne Scrollbar synchron scrollbar sein sollen !!!
Ich meine ja nur, dass man flexibel sein sollte (vor allem beim Lösen von Problemen) und nicht bis "Teufel-komm-raus" einen für einem zu schwierigen Problem sitzt und nicht weiterkommt.
Mit freundlichen Grüßen und hoffend veganza nicht weiter zu verärgern
Rhombicosidodecahedron
-
Rhombicosidodecahedron schrieb:
Ich meine ja nur, dass man flexibel sein sollte (vor allem beim Lösen von Problemen) und nicht bis "Teufel-komm-raus" einen für einem zu schwierigen Problem sitzt und nicht weiterkommt.
hast schon recht... ich hätte Mr Evil mal am Anfang fragen sollen was er genau vor hat ( so wie ich es sonst eigentlich immer mache ). Ich "denke" aber er kennt das CListCtrl ( hoffentlich ) !!!
Rhombicosidodecahedron schrieb:
Mit freundlichen Grüßen und hoffend veganza nicht weiter zu verärgern
Rhombicosidodecahedrondu hast mich nicht verärgert... und sorry wenn es so rübergekommen ist... war nicht meine Absicht

cu veganza
-
also um es mal ein bissl zu verdeutlichen
ich benutz die listboxen um den inhalt eines vectors aufzulisten, dieser ist ein CString vector und pro zeile steht ein text, diesen muss ich einzeln handeln koennen und auhc in der listbox anklicken sodass ich diesen angeklickenten holen kann
zugriffe hab ich solche:
void CFileRenamerDlg::SetListBevoreItems() { int iPos = m_ListBevore.GetCurSel(); m_ListBevore.ResetContent(); CString csTemp = _T(""); for(size_t i=0; i<m_vcsListComplete.size(); i++){ if(m_CBPath.GetCheck() == TRUE) csTemp += m_vcsListPath[i]; csTemp += m_vcsListFile[i]; if(m_CBExtension.GetCheck() == TRUE) csTemp += m_vcsListExtension[i]; m_ListBevore.AddString(csTemp); csTemp = _T(""); } m_ListBevore.SetCurSel(iPos); SetListBevoreScrollBar(); }desweiteren hier und da noch ein paar get item usw
CListCtrl war auch mein erster gedanke, nur da find ich kein addstring oder sonstiges
ich hab mal mein testpeoject wegen den synchronen scrollen hochgeladen, das sind meine bisherigen versuche mit dem ueberschriebenen OnVScroll
Klick
Klick
das zweite, da hatte ich vor die erste ebenfals abhaengig vom zweiten zu machenbtw: das eigentliche problem hatte ich ja schon geloest mit einer zusaetzlichen scrollbar siehe seite 1 - nur das ich das mitlerweile alles auf dieses SetTopIndex geaendert hab
{vielen dank auch dafuer an den ideen-schubser} {=ich hab kein abgabetermin usw, darum kann ich mir zeit lassen und an diesem problem rumprobieren
diese anderen ideen, zb zwei reihen geht nicht, da die listen fast immer unterschiedlichen inhalt haben werden, und auch horizontal scrollbar {einzeln} sein muessen
-
Ehm, kein AddString in einem CListCtrl und du gibst schon auf? ^^
Hier mal ein kleines Beispiel wie man ein CListCtrl füllen kann:CListCtrl* pMyListCtrl; // Dein ListCtrl, welches auch auf etwas zeigen sollte :D // Zuerst mal, falls schon was drin wäre, leeren wir das CListCtrl komplett, samt den Kolonnen // Zuerst alle Items raus. pMyListCtrl->DeleteAllItems(); // Danach alle Kolonnen. while(pMyListCtrl->GetHeaderCtrl()->GetItemCount() > 0) { pMyListCtrl->DeleteColumn(0); } // Wir fügen nun 3 Kolonnen ein. pMyListCtrl->InsertColumn(0, _T("Kolonne 1"), LVCFMT_LEFT, 100); pMyListCtrl->InsertColumn(1, _T("Kolonne 2"), LVCFMT_LEFT, 110); pMyListCtrl->InsertColumn(2, _T("Kolonne 3"), LVCFMT_LEFT, 50); // Wir haben nun ein Array arObject. Jedes Objekt hat 3 CStrings: strA, strB, strC for(int i = 0; i < nCount; ++i) { pMyListCtrl->InsertItem(i, arObject[i].strA); pMyListCtrl->SetItemText(i, 1, arObject[i].strB); pMyListCtrl->SetItemText(i, 2, arObject[i].strC); }Ich hoffe das hilft dir beim Verständnis des CListCtrls und hilft dir bei der Lösung deines Problems.
Edit: Das CListCtrl sollte natürlich dann im Report Style sein! ^^Referenzen
CListCtrl Overview
CListCtrl::DeleteAllItems
CListCtrl::GetHeaderCtrl
CListCtrl::DeleteColumn
CListCtrl::InsertColumn
CListCtrl::InsertItem
CListCtrl::SetItemText
CHeaderCtrl Overview
CHeaderCtrl::GetItemCountGrüssli