Комментарий к шагу 197

Здравствуй Артем.

Предлагаю другой вариант перетаскивания у меня есть список который я сам прорисовываю каждой записи сопоставлен указатель на структуру с данными список со стилем has_string none поэтому каждый раз удалять и добавлять запись по крайней мере трудоемко. Что делаю я.

1. OnLButtonDown я запоминаю текущую позицию если она не -1.

2. OnMouseMove я проверяю если запомненная позиция не равна текущей то просто обменять указатели на структуры перерисовать две записи. Присвоить запомненной текущую.

3. Все

Вот полный готовый пример перетаскивания списка без MFC на чистом С. На MFC практически не пишу.

#include <windows.h>

typedef struct
{
char title[20];
// ... здесь может быть произвольная информация например сведения о второй
//колонке или чикбоксе и т.п.
}*LPPLITEM, PLITEM;


LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK ListBoxProc (HWND, UINT, WPARAM, LPARAM);
WNDPROC fnOldScr ; // Указатель на системную процедуру обработки сообщений ListBox


int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "Environ" ;
HWND hwnd ;
MSG msg ;
WNDCLASSEX wndclass ;

wndclass.cbSize = sizeof (wndclass) ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;

RegisterClassEx (&wndclass) ;

hwnd = CreateWindow (szAppName, "List Box Dragging demo programm",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HWND hwndList ;
LPPLITEM lpItem ;
switch (iMsg)
{
case WM_CREATE :
hwndList = CreateWindow ("listbox", NULL,
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | WS_BORDER | LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED ,
0, 0, 200, 80, hwnd, (HMENU) 1,
(HINSTANCE) GetWindowLong (hwnd,GWL_HINSTANCE),
NULL) ;
fnOldScr=(WNDPROC)SetWindowLong(hwndList, GWL_WNDPROC,(LONG)ListBoxProc ) ; 

lpItem = new PLITEM ;
strcpy(lpItem->title, "Item 1");
SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) lpItem) ;

lpItem = new PLITEM ;
strcpy(lpItem->title, "Item 2");
SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) lpItem) ;

lpItem = new PLITEM ;
strcpy(lpItem->title, "Item 3");
SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) lpItem) ;

lpItem = new PLITEM ;
strcpy(lpItem->title, "Item 4");
SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) lpItem) ;
return 0 ;

case WM_DRAWITEM :
{
LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;
COLORREF clrBackground, clrForeground;
TEXTMETRIC tm;
int y;
LPPLITEM lpItem;

clrForeground = SetTextColor(lpdis->hDC, lpdis->itemState & ODS_SELECTED
? GetSysColor(COLOR_HIGHLIGHTTEXT) : GetSysColor(COLOR_MENUTEXT));
clrBackground = SetBkColor(lpdis->hDC, lpdis->itemState & ODS_SELECTED ?
GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_WINDOW));

GetTextMetrics(lpdis->hDC, &tm);
y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2 ;

lpItem=(LPPLITEM)SendMessage(lpdis->hwndItem, LB_GETITEMDATA ,lpdis->itemID, 0);
ExtTextOut(lpdis->hDC, 2 , y, ETO_CLIPPED | ETO_OPAQUE, &lpdis->rcItem,
lpItem->title, lstrlen(lpItem->title), NULL);

SetTextColor(lpdis->hDC, clrForeground);
SetBkColor(lpdis->hDC, clrBackground);
return 0;
}

case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}

LRESULT CALLBACK ListBoxProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static bool flag;
static int iPos;

switch(iMsg)
{
case WM_LBUTTONDOWN:
CallWindowProc (fnOldScr, hwnd, iMsg, wParam, lParam) ;
iPos=SendMessage(hwnd, LB_GETCURSEL, 0, 0);
if(iPos>=0) flag=true;
return 0;

case WM_MOUSEMOVE:
if(flag)
{
int iCurPos;

CallWindowProc (fnOldScr, hwnd, iMsg, wParam, lParam) ;
iCurPos=SendMessage(hwnd, LB_GETCURSEL, 0, 0);
if(iCurPos!=iPos && iCurPos>=0)
{
LPPLITEM lpItem, lpCurItem;

lpItem = (LPPLITEM)SendMessage(hwnd, LB_GETITEMDATA, iPos, 0);
lpCurItem = (LPPLITEM)SendMessage(hwnd, LB_GETITEMDATA, iCurPos, 0);
SendMessage(hwnd, LB_SETITEMDATA, iCurPos, (LPARAM)lpItem);
SendMessage(hwnd, LB_SETITEMDATA, iPos, (LPARAM)lpCurItem);
InvalidateRect(hwnd, NULL, true);  //Здесь можно выщитать координаты iPos и апдейтить только ее
iPos = iCurPos;
}
return 0;
}
break;
case WM_LBUTTONUP:
flag=false;
}
return CallWindowProc (fnOldScr, hwnd, iMsg, wParam, lParam) ;
}

PS. При использовании стиля extended select наблюдается визуальный глюк весь путь от старого положения до нового становится выделением как избавиться не знаю, пробовал на время убирать стиль мультиселект но как выяснилось после создания менять стиль Listbox-а нельзя:)

Автор : Куроедов Д. В.

Hosted by uCoz