[ AlwaysLearningNewStuff @ 04.07.2015. 05:58 ] @
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. |