 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
Felip Master

Registrado: 09 Jun 2004Mensajes: 200
|
Publicado: Mie 10 Ago, 2022 5:02 pm Asunto: Sincronización de scroll vertical de dos TListViews |
|
|
Busqué en Internet un código que sincronizara el desplazamiento vertical de dos TListViews.
No encontré nada satisfactorio. Traté de adaptar códigos, traté de inventar, en fin, probé un poco de todo, pero si una cosa salía bien en un código, otra siempre salía mal.
Por ejemplo, el siguiente código actualiza el contenido si hacemos clic en la barra de desplazamiento, pero no funciona si arrastramos el botón. Y los botones se desincronizan fácilmente:
| Código: |
#define lv1 GetScrollPos(ListView1->Handle, SB_VERT);
#define lv2 GetScrollPos(ListView2->Handle, SB_VERT);
void __fastcall TForm4::ListView1ScrollBarWinProcs(TMessage &Mes)
{
ListView1ScrollBar(Mes);
if(Mes.Msg==WM_VSCROLL) {
int i = lv1
int k = lv2
if(i != k) {
ListView2->Perform(Mes.Msg,Mes.WParam,Mes.LParam);
}
}
}
|
El siguiente código fue el único que logré sincronizar perfectamente los botones de desplazamiento, pero no funciona para el contenido de las dos TListViews:
| Código: |
void __fastcall TForm4::ListView1ScrollBarWinProcs(TMessage &Mes)
{
ListView1ScrollBar(Mes);
if(Mes.Msg==WM_VSCROLL) {
SCROLLINFO scrInfo = { sizeof(SCROLLINFO), SIF_ALL };
int ratio;
// Get scrollbar position
GetScrollInfo(ListView1->Handle, SB_VERT, &scrInfo);
ratio = scrInfo.nPos;
SetScrollInfo(ListView2->Handle, SB_VERT, &scrInfo, TRUE);
//ScrollWindow(ListView2->Handle,1,ratio,NULL,NULL);
InvalidateRect( ListView2->Handle, NULL, TRUE );
UpdateWindow( ListView2->Handle );
// ListView2->ScrollBy(0, ratio);
// ListView2->Scroll(0, dif);
}
}
|
¿Alguna idea de cómo hacer que esto funcione?
Detalle: ambos TListView son virtuales
Gracias. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Dom 14 Ago, 2022 4:23 pm Asunto: |
|
|
Prueba de esta manera:
| Código: |
void __fastcall TForm4::ListView1ScrollBarWinProcs(TMessage &Mes)
{
if(Mes.Msg == WM_VSCROLL){
SCROLLINFO si = {sizeof(SCROLLINFO), SIF_ALL};
GetScrollInfo(ListView1->Handle, SB_VERT, &si);
if(LOWORD(Mes.WParam) == SB_LINEUP)
ListView2->Scroll(0, -si.nPage);
else if(LOWORD(Mes.WParam) == SB_LINEDOWN)
ListView2->Scroll(0, si.nPage);
else if(LOWORD(Mes.WParam) == SB_THUMBTRACK)
ListView2->Scroll(0, (HIWORD(Mes.WParam)-si.nPos)*si.nPage);
}
ListView1ScrollBar(Mes);
}
|
Saludos. |
|
| Volver arriba |
|
 |
Felip Master

Registrado: 09 Jun 2004Mensajes: 200
|
Publicado: Lun 15 Ago, 2022 9:15 pm Asunto: |
|
|
¡Gracias por responder, escafandra!
El código movió ListView2 pero no se sincronizó con ListView1. Tal vez porque es un TListView virtual. No sé.
Adapté un código que funcionó, pero es un código muy feo. Funcionó, pero lleva tiempo actualizar la sincronización si hay muchos datos en listview:
| Código: |
void __fastcall TForm4::ListView1ScrollBarWinProcs(TMessage &Mes)
{
ListView1ScrollBar(Mes);
if(Mes.Msg==WM_VSCROLL) {
ListView2->Items->BeginUpdate();
SCROLLINFO scrInfo = { sizeof(SCROLLINFO), SIF_ALL };
GetScrollInfo(ListView1->Handle, SB_VERT, &scrInfo);
int lv1 = scrInfo.nPos;
int lv2 = GetScrollPos(ListView2->Handle, SB_VERT);
while(lv2<lv1) {
ListView2->Perform(WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
lv2 = GetScrollPos(ListView2->Handle, SB_VERT);
}
while(lv2>lv1) {
ListView2->Perform(WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
lv2 = GetScrollPos(ListView2->Handle, SB_VERT);
}
ListView2->Items->EndUpdate();
}
}
|
no tengo mas ideas |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mar 16 Ago, 2022 8:19 pm Asunto: |
|
|
No dispongo de TVirtualListView así que lo Hice con TListView realizando un Subclassing con el código que te expuse. El resultado es el siguiente:
Saludos |
|
| Volver arriba |
|
 |
Felip Master

Registrado: 09 Jun 2004Mensajes: 200
|
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mie 17 Ago, 2022 9:03 pm Asunto: |
|
|
He probado haciendo virtuales los ListView con 3500 elementos y me funciona igual que en el caso de no virtuales.
Para el SubClassing he escrito esta función:
| Código: |
typedef void __fastcall(__closure *PWndProc)(Messages::TMessage &Message);
//---------------------------------------------------------------------------
void __fastcall SetSubCass(TWinControl *WC, PWndProc newProc, PWndProc *oldProc)
{
*oldProc = WC->WindowProc;
WC->WindowProc = newProc;
}
|
y la uso así:
| Código: |
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
SetSubCass(ListView1, SubClassLV1WndProc, &LV1WndProc);
SetSubCass(ListView2, SubClassLV2WndProc, &LV2WndProc);
}
//---------------------------------------------------------------------------
|
Siendo LV1WndProc y LV2WndProc punteros a los WndProc originales de cada ListView.
Cada SubClass realiza lo mismo que el otro referenciando a su ListView contrario:
| Código: |
void __fastcall TForm1::SubClassLV1WndProc(TMessage& Mes)
{
if(Mes.Msg == WM_VSCROLL){
SCROLLINFO si = {sizeof(SCROLLINFO), SIF_ALL};
GetScrollInfo(ListView1->Handle, SB_VERT, &si);
if(LOWORD(Mes.WParam) == SB_LINEUP)
ListView2->Scroll(0, -si.nPage);
else if(LOWORD(Mes.WParam) == SB_LINEDOWN)
ListView2->Scroll(0, si.nPage);
else if(LOWORD(Mes.WParam) == SB_THUMBTRACK)
ListView2->Scroll(0, (HIWORD(Mes.WParam)-si.nPos)*si.nPage);
}
LV1WndProc(Mes);
}
void __fastcall TForm1::SubClassLV2WndProc(TMessage& Mes)
{
if(Mes.Msg == WM_VSCROLL){
SCROLLINFO si = {sizeof(SCROLLINFO), SIF_ALL};
GetScrollInfo(ListView2->Handle, SB_VERT, &si);
if(LOWORD(Mes.WParam) == SB_LINEUP)
ListView1->Scroll(0, -si.nPage);
else if(LOWORD(Mes.WParam) == SB_LINEDOWN)
ListView1->Scroll(0, si.nPage);
else if(LOWORD(Mes.WParam) == SB_THUMBTRACK)
ListView1->Scroll(0, (HIWORD(Mes.WParam)-si.nPos)*si.nPage);
}
LV2WndProc(Mes);
}
|
Lo que falta por implementar es la rueda del ratón y el movimiento con teclado.
Pero ahora se me ocurre preguntarte si en tu caso ambos ListView tienen los mismos elementos o no. En mis pruebas ambos tenían los mismos.
Saludos. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Jue 18 Ago, 2022 8:39 pm Asunto: |
|
|
Experimentando con ListView vritual con diferente número de elementos, he escrito un código que asegure que el primer elemento visible de la lista esté sincronizado y funciona bastante bien:
| Código: |
void Listview_SetTopIndex(HWND hListView, int index)
{
SendMessage(hListView, WM_SETREDRAW, 0, 0);
ListView_EnsureVisible(hListView, ListView_GetItemCount(hListView)-1, true);
ListView_EnsureVisible(hListView, index, true);
SendMessage(hListView, WM_SETREDRAW, 1, 0);
}
void __fastcall TForm1::SubClassLV1WndProc(TMessage& Mes)
{
LV1WndProc(Mes);
if(Mes.Msg == WM_VSCROLL || Mes.Msg == WM_MOUSEWHEEL || Mes.Msg == WM_KEYDOWN ){
int Top = ListView_GetTopIndex(ListView1->Handle);
Listview_SetTopIndex(ListView2->Handle, Top);
}
}
|
Saludos. |
|
| Volver arriba |
|
 |
Felip Master

Registrado: 09 Jun 2004Mensajes: 200
|
Publicado: Vie 19 Ago, 2022 3:21 am Asunto: |
|
|
¡Simplemente perfecto!
Muchas gracias  |
|
| Volver arriba |
|
 |
|
|
No puedes publicar temas nuevos en este foro No puedes responder a temas en este foro No puedes editar tus mensajes en este foro No puedes borrar tus mensajes en este foro No puedes votar en las encuestas de este foro
|
© 2002–2026 Club Builder · Funciona con phpBB.
|