Конференция "WinAPI" » Перемещение элементов в ListView (LVN_BEGINDRAG).
 
  • Maksim (07.01.16 14:55) [0]
    Здравствуйте.
    Не могу разобраться в перемещение элементов. В LVN_BEGINDRAG номер ITEMa, а как быть дальше не знаю.
    В справке MSDN не примера на эту тему.

    Помогите пожалуйста.

    Создание окна и ListView.


    unit Unit1;

    interface

    uses
     Windows, Messages, CommCtrl, SysUtils;

     Function WinProc(Wnd: hwnd; Msg : UINT; WParam : WPARAM; LParam: LPARAM): lresult; Stdcall;
     Procedure WinMain;

    var
     WndClassEx : TWndClassEx;
     FormMy, LV : HWND;
     MMsg: Msg;
     XScreen, YScreen : Integer;

    implementation

    var
      FormRect : TRect;

    Const
     LVID = 13;

    Function WinProc(Wnd: HWND; Msg : UINT; WParam : WPARAM; LParam: LPARAM): lresult; Stdcall;
    Var
     lvc : TLVColumn;
     I, B : Integer;
     Item : TLVItem;
    Begin
     Result := 0;
     Case Msg Of
       WM_CREATE:
         begin

           LV := CreateWindowEx(WS_EX_CLIENTEDGE,'SysListView32', '1', WS_CHILD or WS_VISIBLE or LVS_REPORT or LVS_SHOWSELALWAYS
                                 or LVS_SINGLESEL, 0, 0, FormRect.Right, FormRect.Bottom,Wnd, LVID, HInstance, nil);

           SendMessage(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_DOUBLEBUFFER or LVS_EX_HEADERDRAGDROP or LVS_EX_BORDERSELECT or LVS_EX_FULLROWSELECT or LVS_EX_GRIDLINES or LVS_EX_INFOTIP);
           SendMessage(LV, LVM_SETTEXTBKCOLOR, 0, 12632256);
           SendMessage(LV, LVM_SETBKCOLOR, 0, 12632256);

           lvc.fmt := LVCFMT_CENTER;
           lvc.mask := LVCF_TEXT or LVCF_WIDTH;
           lvc.pszText := '0';
           lvc.cx := 70;
           lvc.iSubItem := 0;
           ListView_InsertColumn(lv, 0, lvc);

           lvc.mask := lvc.mask or LVCF_FMT or LVCF_SUBITEM or LVCF_ORDER;

           for I := 1 to 7 do
             begin
               lvc.pszText := PChar(IntToStr(I));
               lvc.iSubItem := I;
               lvc.iOrder := I;
               ListView_InsertColumn(LV, I, lvc);
             end;

            for I := 0 to 6 do
             begin
               FillChar(Item, sizeof(Item), 0 );
               Item.mask := LVIF_TEXT;
               Item.iItem := ListView_GetItemCount(LV);
               Item.pszText := PChar(IntToStr(I));
               ListView_InsertItem(LV, Item);
               for b := 0 to {Header_GetItemCount(ListView_GetHeader(LV)) -2}6 do
                 begin
                   Item.iSubItem := B + 1;
                   Item.pszText  := PChar(IntToStr(Random(100)));
                   ListView_SetItem(LV, Item);
                 end;
             end;
         end;

        WM_NOTIFY:
         begin
           if PNMHDR(lParam).hwndFrom = LV then
             case PNMHDR(lParam).code of
               LVN_BEGINDRAG:
                 begin
                   SetWindowText(Wnd, IntToStr(PNMListView(LParam).iItem)); //PNMListView(LParam).ptAction.X) + ' ' + IntToStr(PNMListView(LParam).ptAction.Y)) ;
                 end;
             end;
         end;

       WM_SIZE:
         Begin
           if WParam <> SIZE_MINIMIZED then
             begin
               GetClientRect(Wnd, FormRect);
               SetWindowPos(LV, 0, 0, 0, FormRect.Right, FormRect.Bottom - 50, SWP_NOZORDER);
             end;
         End;

       WM_CLOSE:
         begin
           DestroyWindow(LV);
           DestroyWindow(Wnd);
         end;

       WM_DESTROY: PostQuitMessage(0);
       Else
         Result := DefWindowProc(Wnd, Msg, WParam, LParam);
     End;
    End;

    Procedure WinMain;
    Begin

     XScreen := (GetSystemMetrics(SM_CXSCREEN));// shr 1;
     YScreen := (GetSystemMetrics(SM_CYSCREEN));// shr 1;

     FillChar(WndClassEx, SizeOf(TWndClassEx), 0);
     WndClassEx.cbSize := SizeOf(TWndClassEx);
     WndClassEx.lpszClassName := 'APIWindow';
     WndClassEx.style := CS_HREDRAW Or CS_VREDRAW;
     WndClassEx.hInstance := HInstance;
     WndClassEx.lpfnWndProc := @WinProc;
     WndClassEx.cbClsExtra := 0;
     WndClassEx.cbWndExtra := 0;
     WndClassEx.hIcon := LoadIcon(HInstance, MakeIntResource('MAINICON'));
     WndClassEx.hIconSm := LoadIcon(HInstance, MakeIntResource('MAINICON'));
     WndClassEx.hCursor := LoadCursor(0, IDC_ARROW);
     WndClassEx.hbrBackground := GetStockObject(LTGRAY_BRUSH);
     WndClassEx.lpszMenuName := NIL;

     If RegisterClassEx(WndClassEx) = 0 Then
       MessageBox(0, 'Невозможно зарегистрировать класс окна', 'Ошибка', MB_OK Or MB_ICONHAND)
     Else
       Begin
         FormMy := CreateWindowEx(0 , WndClassEx.lpszClassName, 'ListView', WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW,
               (XScreen - 500) div 2, (YScreen - 300) div 2, 500, 300, 0, 0, HInstance, NIL);

         If FormMy = 0 Then
           MessageBox (0, 'Окно не создано!', 'Ошибка', MB_OK Or MB_ICONHAND)
         Else
           Begin
             ShowWindow(FormMy, SW_SHOWNORMAL);
             UpdateWindow(FormMy);

             While GetMessage(MMsg, 0, 0, 0) Do
               Begin
                 TranslateMessage(MMsg);
                 DispatchMessage(MMsg);
               End;
             Halt(MMsg.WParam);
             UnregisterClass(WndClassEx.lpszClassName, HInstance);
           End;
       End;
    End;

    end.

  • Maksim (07.01.16 17:48) [1]
    нашел На C++.
    Переделал. Но не работает , т.е. зажимаю лкм, начинаю ташить, появл. картинка с элементом и сдвигается немного и все. Мышью можно двигать бесконечно, картинка застывает.
    Сабклассировал WM_MOUSEMOVE для ListView для получения координат мыши относительно ListView, но при зажатой мыши координаты не меняются:


    var
      FormRect : TRect;

      iHeight, iPos, iRet : Integer;
      hDragImageList : HIMAGELIST;
      hOneImageList, hTempImageList : HIMAGELIST;
      bDragging, bFirst : BOOL;
      lvhti : tLVHITTESTINFO;
     imf : IMAGEINFO;     Item : TLVItem;
     P, pt : TPoint;
     buf : PChar;



    Function LVWinProc(Wnd: THandle; Msg: Cardinal;
     WParam, LParam: Integer): Cardinal; Stdcall;
    Begin    
     Case Msg Of
        WM_MOUSEMOVE:
         begin
           if bDragging then
               Exit;

           p.x := LOWORD(lParam);
           p.y := HIWORD(lParam);
           ImageList_DragMove(p.x, p.y);
          SetWindowText(FormMy, PChar(IntToStr(p.y)));
           Exit;
         end;
     End;
     Result := CallWindowProc(Pointer(GetWindowLong(Wnd, GWL_USERDATA)),
       wnd, Msg, WParam, LParam);
    End;


    После создания ListView:

    SetWindowLong(LV, GWL_USERDATA, SetWindowLong(LV, GWL_WNDPROC, LongInt(@LVWinProc)));

    И WM_NOTIFY


    WM_NOTIFY:
         begin
           if PNMHDR(lParam).hwndFrom = LV then
             case PNMHDR(lParam).code of
               LVN_BEGINDRAG:
                 begin    // {  ListView_CreateDragImage(LV, 1, fff);
                 //  SetWindowText(Wnd, IntToStr({PNMListView(LParam).iItem)); //}PNMListView(LParam).ptAction.X) + ' ' + IntToStr(PNMListView(LParam).ptAction.Y)) ;

                 p.x := 8;
                 p.y := 8;

                 // Ok, now we create a drag-image for all selected items
                 bFirst := TRUE;
                 iPos := ListView_GetNextItem(LV, -1, LVNI_SELECTED);
                 while (iPos <> -1) do
                   begin
                     if bFirst then
                       begin
                         // For the first selected item,
                         // we simply create a single-line drag image
                         hDragImageList := ListView_CreateDragImage(LV, iPos, p);
                         ImageList_GetImageInfo(hDragImageList, 0, imf);
                         iHeight := imf.rcImage.Bottom;
                         bFirst := FALSE;
                       //  Break;
                       end
                     else
                       begin
                         // For the rest selected items,
                         // we create a single-line drag image, then
                         // append it to the bottom of the complete drag image
                         hOneImageList := ListView_CreateDragImage(LV, iPos, p);
                         hTempImageList := ImageList_Merge(hDragImageList,
                                          0, hOneImageList, 0, 0, iHeight);
                         ImageList_Destroy(hDragImageList);
                         ImageList_Destroy(hOneImageList);
                         hDragImageList := hTempImageList;
                         ImageList_GetImageInfo(hDragImageList, 0, imf);
                         iHeight := imf.rcImage.bottom;
                        // Break;
                       end;

                     iPos := ListView_GetNextItem(LV, iPos, LVNI_SELECTED);

                   end;

                 // Now we can initialize then start the drag action
                 ImageList_BeginDrag(hDragImageList, 0, 0, 0);

                 pt := PNMListView(LParam).ptAction;
               //  ClientToScreen(LV, pt);

                 ImageList_DragEnter({GetDesktopWindow()} LV, p.x, pt.y);

                 bDragging := TRUE;
               //  ImageList_EndDrag();
                 // Don't forget to capture the mouse
                 SetCapture(Wnd);

                   Exit;
                 end;

             end;
         end;

     WM_LBUTTONUP:
         begin //  MessageBox(Wnd,'','',0);
           // End the drag-and-drop process
           bDragging := FALSE;
           ImageList_DragLeave(LV);
           ImageList_EndDrag();
           ImageList_Destroy(hDragImageList);

           ReleaseCapture();

           // Determine the dropped item

         {  lvhti.pt.x := LOWORD(lParam);
           lvhti.pt.y := HIWORD(lParam);
           ClientToScreen(Wnd, &lvhti.pt);
           ScreenToClient(LV, &lvhti.pt);
           ListView_HitTest(LV, &lvhti);

           // Out of the ListView?
           if lvhti.iItem = -1 then
               Exit;
           // Not in an item?
           if ((lvhti.flags and LVHT_ONITEMLABEL = 0) and (lvhti.flags and LVHT_ONITEMSTATEICON = 0)) then
               Exit;

           // Dropped item is selected?
           Item.iItem := lvhti.iItem;
           Item.iSubItem := 0;
           Item.mask := LVIF_STATE;
           Item.stateMask := LVIS_SELECTED;
           ListView_GetItem(LV, Item);

           if (Item.state = LVIS_SELECTED) then
               Exit;

           // Rearrange the items
           iPos := ListView_GetNextItem(LV, -1, LVNI_SELECTED);
           while iPos <> -1 do
             begin
               // First, copy one item
               Item.iItem := iPos;
               Item.iSubItem := 0;
               //Item.cchTextMax := MAX_TARGET_LEN;
               Item.pszText := buf;
               Item.stateMask := LVIS_SELECTED;
               Item.mask := LVIF_STATE or LVIF_IMAGE
                           or LVIF_INDENT or LVIF_PARAM or LVIF_TEXT;
               ListView_GetItem(lv, Item);
               Item.iItem := lvhti.iItem;
               // Insert the main item
               iRet := ListView_InsertItem(LV, Item);
               if Item.iItem < iPos then
                   inc(lvhti.iItem);
               if (iRet <= iPos) then
                   inc(iPos);
               // Set the subitem text
               for i := 1 to 6 do
                 begin
                   ListView_GetItemText(lv, iPos,
                                  i, buf, SizeOf(Buf));
                   ListView_SetItemText(LV, iRet, i, buf);
                 end;

               // Delete from original position
               ListView_DeleteItem(LV, iPos);
               iPos := ListView_GetNextItem(LV, -1, LVNI_SELECTED);
             end;  }

        //   Exit;
         end;
  • Maksim (07.01.16 18:18) [2]
  • Maksim (07.01.16 20:37) [3]
    Вроде Получилось.

    Перемещение элемента вверх работает.
    А вот вниз нет, голова уже не соображает.
    Может кто увидит проблему и подскажет ее решение.


    unit Unit1;

    interface

    uses
     Windows, Messages, CommCtrl, SysUtils;

     Procedure WinMain;

    var
     WndClassEx : TWndClassEx;
     FormMy, LV : HWND;
     MMsg: Msg;
     XScreen, YScreen : Integer;

    implementation

    var
      FormRect : TRect;

      iHeight, iPos, iRet : Integer;
      hDragImageList : HIMAGELIST;
      hOneImageList, hTempImageList : HIMAGELIST;
      bDragging, bFirst : BOOL;
      lvhti : tLVHITTESTINFO;
     imf : IMAGEINFO;     Item : TLVItem;
     P, pt : TPoint;
     Buf : array [0..MAX_PATH] of Char;

    Const
     LVID = 13;

    Function WinProc(Wnd: HWND; Msg : UINT; WParam : WPARAM; LParam: LPARAM): lresult; Stdcall;
    Var
     lvc : TLVColumn;
     I, B : Integer;

    Begin
     Result := 0;
     Case Msg Of
       WM_CREATE:
         begin

           LV := CreateWindowEx(WS_EX_CLIENTEDGE,'SysListView32', '1', WS_CHILD or WS_VISIBLE or LVS_REPORT or LVS_SHOWSELALWAYS
                                 , 0, 0, FormRect.Right, FormRect.Bottom,Wnd, LVID, HInstance, nil);

           SendMessage(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_DOUBLEBUFFER or LVS_EX_HEADERDRAGDROP or LVS_EX_BORDERSELECT or LVS_EX_FULLROWSELECT or LVS_EX_GRIDLINES or LVS_EX_INFOTIP);
           SendMessage(LV, LVM_SETTEXTBKCOLOR, 0, 12632256);
           SendMessage(LV, LVM_SETBKCOLOR, 0, 12632256);

           lvc.fmt := LVCFMT_CENTER;
           lvc.mask := LVCF_TEXT or LVCF_WIDTH;
           lvc.pszText := '0';
           lvc.cx := 70;
           lvc.iSubItem := 0;
           ListView_InsertColumn(lv, 0, lvc);

           lvc.mask := lvc.mask or LVCF_FMT or LVCF_SUBITEM or LVCF_ORDER;

           for I := 1 to 7 do
             begin
               lvc.pszText := PChar(IntToStr(I));
               lvc.iSubItem := I;
               lvc.iOrder := I;
               ListView_InsertColumn(LV, I, lvc);
             end;

            for I := 0 to 6 do
             begin
               FillChar(Item, sizeof(Item), 0 );
               Item.mask := LVIF_TEXT;
               Item.stateMask := LVIS_DROPHILITED;
               Item.iItem := ListView_GetItemCount(LV);
               Item.pszText := PChar(IntToStr(I));
               ListView_InsertItem(LV, Item);
               for b := 0 to {Header_GetItemCount(ListView_GetHeader(LV)) -2}6 do
                 begin
                   Item.iSubItem := B + 1;
                   Item.pszText  := PChar(IntToStr(Random(100)));
                   ListView_SetItem(LV, Item);
                 end;
             end;
         end;
       WM_MOUSEMOVE:
         begin
           if not bDragging then
               Exit;

           p.x := LOWORD(lParam);
           p.y := HIWORD(lParam);
           ImageList_DragMove(p.x, p.y);

           Exit;
         end;
        WM_NOTIFY:
         begin
           if PNMHDR(lParam).hwndFrom = LV then
             case PNMHDR(lParam).code of
               LVN_BEGINDRAG:
                 begin  
                 p.x := 8;
                 p.y := 8;

                 bFirst := TRUE;
                 iPos := ListView_GetNextItem(LV, -1, LVNI_SELECTED);
                 while (iPos <> -1) do
                   begin
                     if bFirst then
                       begin
                         hDragImageList := ListView_CreateDragImage(LV, iPos, p);
                         ImageList_GetImageInfo(hDragImageList, 0, imf);
                         iHeight := imf.rcImage.Bottom;
                         bFirst := FALSE;
                       end
                     else
                       begin
                         hOneImageList := ListView_CreateDragImage(LV, iPos, p);
                         hTempImageList := ImageList_Merge(hDragImageList,
                                          0, hOneImageList, 0, 0, iHeight);
                         ImageList_Destroy(hDragImageList);
                         ImageList_Destroy(hOneImageList);
                         hDragImageList := hTempImageList;
                         ImageList_GetImageInfo(hDragImageList, 0, imf);
                         iHeight := imf.rcImage.bottom;
                       end;

                     iPos := ListView_GetNextItem(LV, iPos, LVNI_SELECTED);

                   end;
                 
                 ImageList_BeginDrag(hDragImageList, 0, 0, 0);

                 pt := PNMListView(LParam).ptAction;

                 ImageList_DragEnter({GetDesktopWindow()} LV, pt.x, pt.y);

                 bDragging := TRUE;
                 SetCapture(Wnd);
                   Exit;
                 end;
             end;
         end;

     WM_LBUTTONUP:
         begin
           bDragging := FALSE;
           ImageList_DragLeave(LV);
           ImageList_EndDrag();
           ImageList_Destroy(hDragImageList);

           ReleaseCapture();

           FillChar(lvhti, sizeof(lvhti), 0 );
           lvhti.pt.x := LOWORD(lParam);
           lvhti.pt.y := HIWORD(lParam);
           ClientToScreen(Wnd, lvhti.pt);
           ScreenToClient(LV, lvhti.pt);
           ListView_HitTest(LV, lvhti);

           if lvhti.iItem = -1 then
               Exit;
           if ((lvhti.flags and LVHT_ONITEMLABEL = 0) and (lvhti.flags and LVHT_ONITEMSTATEICON = 0)) then
               Exit;
           FillChar(Item, sizeof(Item), 0 );

           Item.iItem := lvhti.iItem;
           Item.iSubItem := 0;
           Item.mask := LVIF_STATE;
           Item.stateMask := LVIS_SELECTED;
           ListView_GetItem(LV, Item);

           if (Item.state = LVIS_SELECTED) then
               Exit;

           iPos := ListView_GetNextItem(LV, -1, LVNI_SELECTED);
          // while iPos <> -1 do
             begin
               // First, copy one item
               FillChar(Item, sizeof(Item), 0 );
               Item.iItem := iPos;
               Item.iSubItem := 0;
               Item.cchTextMax := MAX_PATH;
               Item.pszText := buf;
               Item.stateMask := LVIS_SELECTED;
               Item.mask := LVIF_STATE or LVIF_IMAGE or LVIF_INDENT or LVIF_PARAM or LVIF_TEXT;
               ListView_GetItem(lv, Item);
               Item.iItem := lvhti.iItem;
               // Вставьте пункт главного
               iRet := ListView_InsertItem(LV, Item);
         
               if Item.iItem < iPos then
                   inc(lvhti.iItem) ;

               if (iRet <= iPos) then
                   inc(iPos);

               for i := 0 to 7 do
                 begin
                   ListView_GetItemText(lv, iPos, i, buf, SizeOf(Buf));
                   ListView_SetItemText(LV, iRet, i, buf);
                 end;
               ListView_DeleteItem(LV, iPos);
               iPos := ListView_GetNextItem(LV, -1, LVNI_SELECTED);
             //      Break;
             end;

           Exit;
         end;

       WM_SIZE:
         Begin
               GetClientRect(Wnd, FormRect);
               SetWindowPos(LV, 0, 0, 0, FormRect.Right, FormRect.Bottom - 50, SWP_NOZORDER);
         End;

       WM_CLOSE:
         begin
           DestroyWindow(LV);
           DestroyWindow(Wnd);
         end;

       WM_DESTROY: PostQuitMessage(0);
       Else
         Result := DefWindowProc(Wnd, Msg, WParam, LParam);
     End;
    End;

  • Maksim (07.01.16 22:35) [4]
    Есть кто живой?
 
Конференция "WinAPI" » Перемещение элементов в ListView (LVN_BEGINDRAG).
Есть новые Нет новых   [134427   +34][b:0][p:0.003]