Win32 Want marquee-able empty space in a listview (Iconview)

ぐ巨炮叔叔 提交于 2020-08-10 19:18:14

问题


In a Listview I am looking to have a marquee-able empty space of about 20 pixels above the first row of items and below the last row of items. Also to the left of the left-most items and the right of the right-most items.

I am setting the item positions manually by using LVM_SETITEMPOSITION. Trying to place them at an offset of 20 pixels doesn't seem to work.

I have supplied a simple code sample below. For some reason intially there actually is a marquee-able empty space to the top but once you scroll down and back up this space is gone.

#include <Windows.h>
#include <CommCtrl.h>
#include <gdiplus.h>

#include <string>
#include <codecvt>

#pragma comment(lib,"comctl32.lib")
#pragma comment(lib,"gdiplus.lib")

::HINSTANCE g_hInstance;

// controls
::HWND g_hMainWindow;
::HWND g_hListview;
::HWND g_hButton;

// img list(s)
::HIMAGELIST g_hImageListNormal;

::HWND CreateBasicWindow();
::HWND CreateListview(::HWND hParentWnd, ::HIMAGELIST hImageList);
::HWND CreateButton(::HWND hParentWnd);

LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void Listview_insertItem(::HWND hListview, std::string text, int imageIndex);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* szCmdLine, int iCmdShow) {

    g_hInstance = hInstance;

    g_hMainWindow = CreateBasicWindow();
    g_hListview   = CreateListview(g_hMainWindow, g_hImageListNormal);
    g_hButton      = CreateButton(g_hMainWindow);

    ::ShowWindow(g_hListview, SW_SHOW);
    ::UpdateWindow(g_hListview);

    ::ShowWindow(g_hButton, SW_SHOW);
    ::UpdateWindow(g_hButton);

    ::ShowWindow(g_hMainWindow, SW_SHOW);
    ::UpdateWindow(g_hMainWindow);

    for (int i = 0; i < 5; i++) {

         Listview_insertItem(g_hListview, "item", 0);

    }

    MSG msg = { 0 };

    while (true) {

        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

            if (msg.message == WM_QUIT) {
                return 1;
            }

            TranslateMessage(&msg);
            DispatchMessage(&msg);

        }
    }

    return 1;
}

::HWND CreateBasicWindow() {

    ::WNDCLASS wndClass = { };

    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = 0;
    wndClass.hbrBackground = (HBRUSH)::GetStockObject(GRAY_BRUSH);
    wndClass.hCursor       = ::LoadCursor(NULL, IDC_ARROW);
    wndClass.hIcon         = ::LoadIcon(NULL, IDC_ICON);
    wndClass.hInstance     = g_hInstance;
    wndClass.lpfnWndProc   = WindowProcedure;
    wndClass.lpszClassName = "Window1";
    wndClass.lpszMenuName  = NULL;
    wndClass.style         = CS_HREDRAW | CS_VREDRAW/* | CS_OWNDC | CS_PARENTDC*/;

    if (!::RegisterClass(&wndClass)) {
        return 0;
    }

    ::RECT rect;

    rect.left   = 100;
    rect.right  = 900;
    rect.top    = 100;
    rect.bottom = 900;

    ::HWND hWnd = ::CreateWindowEx(0,
                                   "Window1",
                                   "Window1",
                                   WS_OVERLAPPEDWINDOW,
                                   rect.left,
                                   rect.top,
                                   rect.right - rect.left,
                                   rect.bottom - rect.top,
                                   NULL,
                                   0,
                                   g_hInstance,
                                   NULL);

    return hWnd;
    
}

::HWND CreateListview(::HWND hParentWnd, ::HIMAGELIST hImageList) {

    ::RECT rect;

    rect.left   = 100;
    rect.right  = 500;
    rect.top    = 100;
    rect.bottom = 500;

    ::HWND hWnd = ::CreateWindowEx(0,
                                   WC_LISTVIEW,
                                   WC_LISTVIEW,
                                   WS_CHILD | LVS_ICON,
                                   rect.left,
                                   rect.top,
                                   rect.right - rect.left,
                                   rect.bottom - rect.top,
                                   hParentWnd,
                                   0,
                                   g_hInstance,
                                   NULL);

    ::SIZE iconSize;
    iconSize.cx = 100;
    iconSize.cy = 100;

    // Create imagelist
    hImageList = ::ImageList_Create(iconSize.cx, iconSize.cy, ILC_COLOR32 | ILC_MASK, 0, 0);

    // Bind imagelist to listview
    ListView_SetImageList(hWnd, hImageList, 0);

    std::string imageFileLocation = "image.bmp";

    // Load Image
    ::HBITMAP hBitmap = (::HBITMAP)LoadImage(NULL, imageFileLocation.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);

    if (!hBitmap)
        ::MessageBox(hWnd, std::string("Image " + imageFileLocation + " not found.").c_str(), "Error", MB_OK);

    // Add image to imagelist
    ::ImageList_Add(hImageList, hBitmap, NULL);

    // Set icon spacing
    ListView_SetIconSpacing(hWnd, iconSize.cx + 16, iconSize.cy + 22);

    // enable double buffering and oneclick activate for convenience
    ::SendMessage(hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER, LVS_EX_DOUBLEBUFFER);
    ::SendMessage(hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_ONECLICKACTIVATE, LVS_EX_ONECLICKACTIVATE);

    return hWnd;

}

::HWND CreateButton(::HWND hParentWnd) {

    ::RECT rect;

    rect.left   = 100;
    rect.right  = 200;
    rect.top    = 50;
    rect.bottom = 100;

    ::HWND hWnd = ::CreateWindowEx(0,
                                   WC_BUTTON,
                                   WC_BUTTON,
                                   WS_CHILD,
                                   rect.left,
                                   rect.top,
                                   rect.right - rect.left,
                                   rect.bottom - rect.top,
                                   hParentWnd,
                                   0,
                                   g_hInstance,
                                   NULL);

    ::SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)"Insert Item");

    return hWnd;

}

void Listview_insertItem(::HWND hListview, std::string text, int imageIndex) {

    unsigned int mask = LVIF_TEXT | LVIF_IMAGE;

    ::LVITEM W32LvItem = { 0 };

    W32LvItem.mask       = mask;
    W32LvItem.iItem      = INT_MAX;
    W32LvItem.iSubItem   = 0;
    W32LvItem.pszText    = (char*)text.c_str();
    W32LvItem.cchTextMax = text.length();
    W32LvItem.iImage     = imageIndex;

    // NOTE: LVM_INSERTITEM nor ListView_InsertItem can be used to insert a subitem
    int newItemIndex = ::SendMessage(hListview, LVM_INSERTITEM, 0, (::LPARAM)&W32LvItem);




    // UPDATE ALL ITEM POSITIONS

    ::RECT lvClientRect;
    ::GetClientRect(hListview, &lvClientRect);

    ::SIZE lvClientSize;
    lvClientSize.cx = lvClientRect.right - lvClientRect.left;
    lvClientSize.cy = lvClientRect.bottom - lvClientRect.top;

    ::SIZE itemSize;
    itemSize.cx = 50 + 16;
    itemSize.cy = 50 + 22;

    ::DWORD spacing = ListView_GetItemSpacing(hListview, false);

    ::SIZE itemSpacing;

    itemSpacing.cx = LOWORD(spacing);
    itemSpacing.cy = HIWORD(spacing);

    int itemIndex = 0;

    while (itemIndex != -1) {

        // calculate how many items fit in a row
        int iItemsPerRow = lvClientSize.cx / (itemSize.cx + itemSpacing.cx);

        // calculate in which row, and in which place within that row this icon should be placed
        int itemRowNb    = (int)std::ceil(itemIndex / iItemsPerRow);
        int itemColumnNb = (itemIndex < iItemsPerRow) ? itemIndex : itemIndex % iItemsPerRow;

        int topOffset = 20;

        // calculate destination x/y
        int x = lvClientRect.left + itemColumnNb * (itemSize.cx + itemSpacing.cx);
        int y = lvClientRect.top + topOffset + itemRowNb * (itemSize.cy + itemSpacing.cy);

        // move item to calculated position
        ListView_SetItemPosition(hListview, itemIndex, x, y);

        // get next item
        itemIndex = ListView_GetNextItem(hListview, itemIndex, LVNI_ALL);

    }

}


LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_COMMAND:
        {

            switch (HIWORD(wParam)) {

                case BN_CLICKED:
                {

                    int itemCount = ListView_GetItemCount(g_hListview);

                    Listview_insertItem(g_hListview, "item" + std::to_string(itemCount), 0);

                    break;
                }

            }

            break;

        }

    }

    return DefWindowProc(hWnd, msg, wParam, lParam);

}

来源:https://stackoverflow.com/questions/62708112/win32-want-marquee-able-empty-space-in-a-listview-iconview

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!