Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > ListView сортировка


Автор: neosapient 23.1.2008, 19:09
Вопрос: как отсортировать поля в ListView.
В приложении мой пример, не могу понять что не работает?

Помогите найти ошибку. 
Диагноз такой, когда человек щелкает по шапке столбца, то начинает вызываться моя функция сравнения ListSort(...)
Последний параметр воспринимаю бес проблем. А вот в два других ничего не передается. Почему? немогу понять...
Код

// точка входа

#include <windows.h>
#include "resource.h"
// подключаем нестандартные контролы
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
#include <stdio.h>

HINSTANCE hInst;
LRESULT CALLBACK Proc (HWND, UINT, WPARAM, LPARAM);
void massageprocess ();
BOOL InitListViewColumns(HWND hWndListView);
int CALLBACK ListSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

WINAPI WinMain // точка входа в Windows программу
(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPSTR lpCmdLine, int nCmdShow)
{
    HWND hDlg;
    // сохраняем индентификатор приложения
    hInst=hInstance;
    // инициализация дополнительных компонентов
    InitCommonControls (); 
    // создаем диалог
    hDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DIALOG1),0,(DLGPROC)Proc);
    // показать диалог
    ShowWindow(hDlg, SW_SHOW);
    // обрабатываем очередь сообщений
    massageprocess ();
    return 0;
}

// оконная процедура для обработки сообщений
LRESULT CALLBACK Proc
(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{
    NMLISTVIEW *lpNm;
    LPNMHDR pnmh;
    switch(msg)
    {
    case WM_INITDIALOG :  
        InitListViewColumns(GetDlgItem(hDlg,IDC_LIST1));
        break;
    case WM_COMMAND:  
        switch (LOWORD(wParam))
        {
        case IDCANCEL:
            EndDialog(hDlg, LOWORD(wParam));
            PostQuitMessage(0);
            return TRUE;
        case IDOK:
            break;         
        }
        break;
    case WM_NOTIFY:
        pnmh = (LPNMHDR)lParam;
        switch (pnmh->code)
        {
        case LVN_COLUMNCLICK:
            lpNm = (NMLISTVIEW *)lParam;
            ListView_SortItems(lpNm->hdr.hwndFrom, (PFNLVCOMPARE)ListSort, (LPARAM)(lpNm));

            break;
        }
        break;         
    case WM_KEYDOWN:  
        switch (wParam) 
            { 
                case VK_ESCAPE:
                    PostQuitMessage(0);
                    break;
            }
        break;

    case WM_DESTROY: //сообщение уничтожения окна 
        PostQuitMessage(0);
        break;
    }
return 0;
}

void massageprocess()
{MSG msg;
// получаем в цикле следующее сообщение из очереди
// сообщений
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

BOOL InitListViewColumns(HWND hWndListView) 
{ 
    char szText[256];     // temporary buffer 
    LVCOLUMN lvc; 
    int i; 
    char localbuf[80];
    char *mas[]={"first","second"};
    char *mas1[]={"3","1","5","2","4"};
    char *mas2[]={"third","first","fifth","second","fourth"};

    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT |LVCF_SUBITEM; 
    for (i = 0; i < 2; i++) 

    { 
        lvc.iSubItem = i;
        lvc.pszText = mas[i];    
        lvc.cx = 90;     // width of column in pixels
        lvc.fmt = LVCFMT_CENTER;  // left-aligned column
        if (ListView_InsertColumn(hWndListView, i,&lvc) == -1) 
            return FALSE; 
    } 

    LVITEM lvI;
    lvI.mask = LVIF_TEXT | LVIF_STATE ; 
    lvI.state = 0; 
    lvI.stateMask = 0; 

    // Initialize LVITEM members that are different for each item. 
    for (int index = 0; index < 5; index++)
    {
        lvI.iItem = index;
        lvI.iSubItem = 0;
        lvI.pszText =  mas1[index];
        lvI.cchTextMax = strlen(mas1[index]);
        ListView_InsertItem(hWndListView, &lvI);

        lvI.iItem = index;
        lvI.iSubItem = 1;
        lvI.pszText =  mas2[index];
        lvI.cchTextMax = strlen(localbuf);
        ListView_SetItem(hWndListView, &lvI);
        //ListView_InsertItem(hWndListView, &lvI);
    }
    return TRUE; 
} 


int CALLBACK ListSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    NMLISTVIEW *lpNm = NULL;
    HWND hList = NULL;
    TCHAR pszBuff0[256]={0};
    TCHAR pszBuff1[256]={0};
    int iSubItem=0;

    lpNm = (NMLISTVIEW*)lParamSort;
    hList = lpNm->hdr.hwndFrom;
    iSubItem = lpNm->iSubItem;
    ListView_GetItemText(hList,lParam1,iSubItem,pszBuff0,256);
    ListView_GetItemText(hList,lParam2,iSubItem,pszBuff1,256);
    return strcmp(pszBuff0, pszBuff1);
}

Автор: Earnest 23.1.2008, 19:55
 smile 
Цитата

The comparison function has the following form: 

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); 

The lParam1 parameter is the value associated with the first item being compared; and the lParam2 parameter is the value associated with the second item. These are the values that were specified in the lParam member of the items' LVITEM structure when they were inserted into the list. The lParamSort parameter is the same value passed to the LVM_SORTITEMS message. 

Что положил в итемы, то и передается... А ты, насколько я вижу, ничего туда не положил...

Автор: neosapient 24.1.2008, 12:01
Я ни на английском, ни на русском не могу понять алгоритма мох действий по продготовке и проведению поиска.
У меня в голове лежит следующий стериотип.

Я вызываю макрос 
Код

BOOL ListView_SortItemsEx(
    HWND hwnd,
    PFNLVCOMPARE pfnCompare,
    LPARAM lParamSort
);


В первый параметр передаю хендл ListView
Во второй параметр указатель на функцию сравнения двух элементов.
В третий параметр - четырехбайтное значение, которое будет передано моей функции, в моем случае это указатель на структуру.
Управление берет на себя винда. Она по какому то алгоритму (думаю qsort) начинает попарное сравнение, всех элементов.
Далее сортировка. Выбираются два элемента, и передаются в функцию сравнения (вместе с третим, в котором управляющие параметры передаем себе)

Код

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);  


Я не понимаю на каком шаге и где, мною что то кладется?

Хотелось бы рабочий пример или этот подправить.

Автор: Earnest 24.1.2008, 12:20
lParam1 и 2 это lParam из элемента лист-вью (из структуры LVITEM), который ты туда помещаешь (можешь поместить) в момент наполнения лист-вью. Пример сейчас не найду, но помню, что была тема про сортировку в лист вью, поищи.

Автор: neosapient 24.1.2008, 14:40
Вроде разобрался.
Помещаю на момент заполнения ListView в переменную LVITEM::lParam свои значения (уменя отличные от нуля - соответствующие пересчету) и добавляю флаг LVITEM::mask |= LVIF_PARAM.

затем в функции сравнения получаю входные LVITEM::lParam 


Начало сортировать )
Вот только второй столбец исчез когда я сменил стиль на LVITEM::mask |= LVIF_PARAM.

Как исправить это недоразумение? )

Автор: neosapient 24.1.2008, 15:33
Вроде разобрался
Рабочий вариант

Код

// точка входа

#include <windows.h>
#include "resource.h"
// подключаем нестандартные контролы
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
#include <stdio.h>

HINSTANCE hInst;
LRESULT CALLBACK Proc (HWND, UINT, WPARAM, LPARAM);
void massageprocess ();
BOOL InitListViewColumns(HWND hWndListView);
int CALLBACK ListSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

WINAPI WinMain // точка входа в Windows программу
(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPSTR lpCmdLine, int nCmdShow)
{
    HWND hDlg;
    // сохраняем индентификатор приложения
    hInst=hInstance;
    // инициализация дополнительных компонентов
    InitCommonControls (); 
    // создаем диалог
    hDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DIALOG1),0,(DLGPROC)Proc);
    // показать диалог
    ShowWindow(hDlg, SW_SHOW);
    // обрабатываем очередь сообщений
    massageprocess ();
    return 0;
}

// оконная процедура для обработки сообщений
LRESULT CALLBACK Proc
(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{
    NMLISTVIEW *lpNm;
    LPNMHDR pnmh;
    switch(msg)
    {
    case WM_INITDIALOG :  
        InitListViewColumns(GetDlgItem(hDlg,IDC_LIST1));
        break;
    case WM_COMMAND:  
        switch (LOWORD(wParam))
        {
        case IDCANCEL:
            EndDialog(hDlg, LOWORD(wParam));
            PostQuitMessage(0);
            return TRUE;
        case IDOK:
            break;         
        }
        break;
    case WM_NOTIFY:
        pnmh = (LPNMHDR)lParam;
        switch (pnmh->code)
        {
        case LVN_COLUMNCLICK:
            lpNm = (NMLISTVIEW *)lParam;
            ListView_SortItems(lpNm->hdr.hwndFrom, (PFNLVCOMPARE)ListSort, (LPARAM)(lpNm));

            break;
        }
        break;         
    case WM_KEYDOWN:  
        switch (wParam) 
            { 
                case VK_ESCAPE:
                    PostQuitMessage(0);
                    break;
            }
        break;

    case WM_DESTROY: //сообщение уничтожения окна 
        PostQuitMessage(0);
        break;
    }
return 0;
}

void massageprocess()
{MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

BOOL InitListViewColumns(HWND hWndListView) 
{ 
    char szText[256];     // temporary buffer 
    LVCOLUMN lvc; 
    int i; 
    char localbuf[80];
    char *mas[]={"first","second"};
    char *mas1[]={"3","1","5","2","4"};
    char *mas2[]={"third","first","fifth","second","fourth"};
    DWORD style;

    style = ListView_GetExtendedListViewStyle(hWndListView);
    style |= LVS_REPORT|LVS_EX_FULLROWSELECT ;
    ListView_SetExtendedListViewStyle (hWndListView,style);

    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT |LVCF_SUBITEM; 
    for (i = 0; i < 2; i++) 

    { 
        lvc.iSubItem = i;
        lvc.pszText = mas[i];    
        lvc.cx = 90;     // width of column in pixels
        lvc.fmt = LVCFMT_CENTER;  // left-aligned column
        if (ListView_InsertColumn(hWndListView, i,&lvc) == -1) 
            return FALSE; 
    } 

    LVITEM lvI;
    lvI.mask = LVIF_TEXT | LVIF_STATE; 
    lvI.state = 0; 
    lvI.stateMask = 0; 

    // Initialize LVITEM members that are different for each item. 
    for (int index = 0; index < 5; index++)
    {

        //---- ссылка для сортировки
        lvI.lParam = atoi(mas1[index]);
        lvI.mask |= LVIF_PARAM; 

        //---- заполнение 0 столбца (создание элемента)
        lvI.iItem = index;
        lvI.iSubItem = 0;
        lvI.pszText =  mas1[index];
        lvI.cchTextMax = strlen(mas1[index]);
        ListView_InsertItem(hWndListView, &lvI);

        //---- убираем ссылку для сортировки (в остальных полях не нужна)
        lvI.mask = lvI.mask&(~LVIF_PARAM); 

        //---- заполнение 1 столбца
        lvI.iItem = index;
        lvI.iSubItem = 1;
        lvI.pszText =  mas2[index];
        lvI.cchTextMax = strlen(mas2[index]);
        ListView_SetItem(hWndListView, &lvI);
    }
    return TRUE; 
} 


int CALLBACK ListSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    NMLISTVIEW *lpNm = NULL;
    HWND hList = NULL;
    TCHAR pszBuff0[256]={0};
    TCHAR pszBuff1[256]={0};
    int iSubItem=0;

    return lParam1>lParam2;
}


Для ListView есть ещё макросы ListView_SortItemsEx и ListView_SortGroups 
Чем эти сортиовки отличаются?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)