Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

Pomozite mi da implementiram drag & drop u listview kontroli ( C/C++ i WinAPI )

[es] :: C/C++ programiranje :: Pomozite mi da implementiram drag & drop u listview kontroli ( C/C++ i WinAPI )

[ Pregleda: 1149 | Odgovora: 0 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

AlwaysLearningNewStuff
nezaposlen
Beograd, Srbija

Član broj: 329753
Poruke: 2
*.dynamic.isp.telekom.rs.



Profil

icon Pomozite mi da implementiram drag & drop u listview kontroli ( C/C++ i WinAPI )04.07.2015. u 05:58 - pre 56 meseci
Poštovani,

Ovo mi je prvi post, pa Vas molim da imate razumevanja.

Radim u MS Visual Studiju 2013, koristeći C++ i čist WinAPI.
Treba da napravim listview u report modu koji dozvoljava preuredjivanje itema.
Korisnici traže da se ova funkcionalnost izvodi poput uobičajenog drag / drop-a.

Ja sam ovaj zadatak u velikoj meri uspešno rešio, ali mi treba pomoc oko implementacije autoscroll-ovanja.
Vidite, autoscrol-ovanje treba da se izvrši kada korisnik pomeri miš van listview kontrole.
Na taj način se prikazuje item koji je do tada bio nevidljiv.

Dole Vam je demo aplikacija koja ilustruje o čemu govorim. Priložen je minimalan kod.

Iako je moja implementacija autoscroll-ovanja neispravna, primer dobro ilustruje o čemu govorim.
Izvinjavam se za komentare na Engleskom, na brzinu sam sastavljao ovaj post pa nisam stigao da ih prevedem na srpski.

Još jedna stvar, glavni deo čini subclass procedura DragAndDrop, i WM_NOTIFY hendler u proceduri glavnog prozora.
Sve ostalo se može ignorisati.

UPUTSTVO: Napravite prazan C++ projekat, kopirajte ovaj kod i to je to. Ne zaboravite da podesite projekat na UNICODE.

Code:
#include <windows.h>
#include <windowsx.h>   // various listview macros etc
#include <CommCtrl.h>
#include <stdio.h>      // swprintf_s()

// enable Visual Styles
#pragma comment( linker, "/manifestdependency:\"type='win32' \
                         name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
                         processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
                         language='*'\"")

// link with Common Controls library
#pragma comment( lib, "comctl32.lib")  

//============ global variables
HINSTANCE hInst; 
BOOL g_bDrag;  // did user start drag and drop?
POINT ptOld;   // needed to calculate to scroll up or down 

// subclass procedure for listview -> implements drag and drop
LRESULT CALLBACK DragAndDrop(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam,
    UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (message)
    {
    case WM_CAPTURECHANGED:  // in case user ALT+TAB to another window, for example
    {
        g_bDrag = FALSE;
        // do other cleanup, omitted for brevity
    }
        return DefSubclassProc(hwnd, message, wParam, lParam);
    case WM_LBUTTONUP:
    {
        if (g_bDrag)
        {
            // we release the capture now and update relevant variables
            g_bDrag = FALSE;
            ReleaseCapture();
            // perform item rearrangement, omitted for brevity
        }
    }
        return DefSubclassProc(hwnd, message, wParam, lParam);
    case WM_MOUSEMOVE:
    {
        if (g_bDrag)
        {
            // extract the coordinate from the LPARAM
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            // check if we are under item
            LVHITTESTINFO lvhti = { 0 };
            lvhti.pt = pt;
            ListView_HitTest(hwnd, &lvhti);
            // if outside listview, autoscroll
            if (lvhti.iItem == -1)
            {
                // index of the top fully visible item
                int topIndex = ListView_GetTopIndex(hwnd);
                // we need item rectangle for scrolling calculations
                RECT rcTopIndex = { 0 };
                ListView_GetItemRect(hwnd, topIndex, &rcTopIndex, LVIR_BOUNDS);
                // currentPoint - oldPoint determines scroll direction
                // we just need to multiply it with item's rectangle height
                // to get proper scrolling amount
                ListView_Scroll(hwnd, 0, (pt.y - ptOld.y) * (rcTopIndex.bottom - rcTopIndex.top));
                // update previous point
                ptOld = pt;
            }
            else  // we are inside listview, reset old point
                ptOld = { 0 };
        }
    }
        return DefSubclassProc(hwnd, message, wParam, lParam);
    case WM_NCDESTROY:
        ::RemoveWindowSubclass(hwnd, DragAndDrop, uIdSubclass);
        return DefSubclassProc(hwnd, message, wParam, lParam);
    }
    return ::DefSubclassProc(hwnd, message, wParam, lParam);
}

// main window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
    {
        ptOld = { 0 };    // user is not dragging listview item
        g_bDrag = FALSE;  // user is not dragging listview item

        //================ create an example listview
        RECT rec = { 0 };
        GetClientRect(hwnd, &rec);

        HWND hwndLV = CreateWindowEx(0, WC_LISTVIEW,
            L"", WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT,
            50, 50, 250, 200, hwnd, (HMENU)2000, hInst, 0);

        // set extended listview styles
        ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);

        // add some columns
        LVCOLUMN lvc = { 0 };

        lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
        lvc.fmt = LVCFMT_LEFT;

        for (long nIndex = 0; nIndex < 5; nIndex++)
        {
            wchar_t txt[50];
            swprintf_s(txt, 50, L"Column %d", nIndex);

            lvc.iSubItem = nIndex;
            lvc.cx = 60;
            lvc.pszText = txt;

            ListView_InsertColumn(hwndLV, nIndex, &lvc);
        }

        // add some items
        LVITEM lvi;

        lvi.mask = LVIF_TEXT;

        for (lvi.iItem = 0; lvi.iItem < 10000; lvi.iItem++)
        {
            for (long nIndex = 0; nIndex < 5; nIndex++)
            {
                wchar_t txt[50];
                swprintf_s(txt, 50, L"Item %d%d", lvi.iItem, nIndex);

                lvi.iSubItem = nIndex;
                lvi.pszText = txt;
                if (!nIndex)  // item 
                    SendDlgItemMessage(hwnd, 2000, LVM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&lvi));
                else          // sub-item
                    SendDlgItemMessage(hwnd, 2000, LVM_SETITEM, 0, reinterpret_cast<LPARAM>(&lvi));
            }
        }

        //============================ subclass it
        SetWindowSubclass(hwndLV, DragAndDrop, 0, 0);
    }
        return 0L;
    case WM_NOTIFY:
    {
        switch (((LPNMHDR)lParam)->code)
        {
        case LVN_BEGINDRAG:  // user started dragging listview item
        {
            g_bDrag = TRUE;
            // listview must capture the mouse
            SetCapture(((LPNMHDR)lParam)->hwndFrom);
        }
            break;
        default:
            break;
        }
    }
        break;
    case WM_CLOSE:
        ::DestroyWindow(hwnd);
        return 0L;
    case WM_DESTROY:
    {
        ::PostQuitMessage(0);
    }
        return 0L;
    default:
        return ::DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

// WinMain

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
    int nCmdShow)
{
    // store hInstance in global variable for later use
    hInst = hInstance;

    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    // register main window class
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;
    wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"Main_Window";
    wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);

    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, L"Window Registration Failed!", L"Error!", MB_ICONEXCLAMATION |
            MB_OK);

        return 0;
    }

    // initialize common controls
    INITCOMMONCONTROLSEX iccex;
    iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    iccex.dwICC = ICC_LISTVIEW_CLASSES;
    InitCommonControlsEx(&iccex);

    // create main window
    hwnd = CreateWindowEx(0, L"Main_Window", L"Listview Drag and Drop",
        WS_OVERLAPPEDWINDOW,
        50, 50, 400, 400, NULL, NULL, hInstance, 0);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    return Msg.wParam;
}


Ukoliko imate dodatna pitanja vrlo rado ću odgovoriti. Ako trebam da dodam još neke informacije nije problem.

Hvala na pažnji, iskreno se nadam da ćete mi pomoći.

Srdačan pozdrav.
 
Odgovor na temu

[es] :: C/C++ programiranje :: Pomozite mi da implementiram drag & drop u listview kontroli ( C/C++ i WinAPI )

[ Pregleda: 1149 | Odgovora: 0 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.