Artrm Kovalchuk
Artrm Kovalchuk

Reputation: 73

Scrollbar duplicate winapi c++

I am making a scrollbar for the first time and don't understand why I have a duplicate of my scrollbar when content is scrollable. Here is how it looks, I don't know if you can see it good enough but here's a screenshot; one scrollbar is the thick gray one (the one a want to keep, looks more like the classic scrollbar), and one is a little gray rectangle to the left of it. Both of these scrollbars work and scroll my program. :

Double scroll

But when content is not scrollable then it looks like this:

enter image description here

Here is my ScrollBar.cpp if this will help:

#include "ScrollBar.h"

ScrollBar::ScrollBar(){}

ScrollBar::~ScrollBar(){
    RemoveWindowSubclass(hWnd, scrollProc, IDC_STATIC);
    delete con;
}


ScrollBar::ScrollBar(HWND hWnd, HINSTANCE hInst) : hWnd(hWnd),hInst(hInst) {
    this->hWndParent = GetParent(hWnd);
    con = new Controls(hWndParent);
}

void ScrollBar::createScroll(int x, int y, int w, int h, bool stickRight, bool stickBottom) {
    this->x = x;
    this->y = y;
    this->width = w;
    this->height = h;

    hScroll = con->create("scrollbar", WS_VISIBLE | WS_CHILD | SBS_VERT, x, y, width, height,"scrollBar","",0, stickRight, stickBottom);
    //Creates like this
    /// CreateWindowEx(0, type, text, styles, cData.x, cData.y, cData.width, cData.height, hWnd, (HMENU)id, NULL, (LPVOID)lParam);

    SetWindowSubclass(hScroll, scrollProc, IDC_STATIC, (DWORD_PTR)this);
    SetWindowSubclass(hWndParent, scrollProc, IDC_STATIC, (DWORD_PTR)this);

    con->setEventListener();
}


void ScrollBar::setScrollRange(int scrollMaxHeight) {
    scrollMaxH = scrollMaxHeight == -1 ? scrollMaxH : scrollMaxHeight;
    SCROLLINFO si = { 0 };
    si.cbSize = sizeof(si);
    si.fMask = SIF_RANGE;
    si.nMin = 0;
    si.nMax = scrollMaxH;

    SetScrollInfo(hScroll, SB_VERT, &si, false);

}


void ScrollBar::setScrollSize() {

    SCROLLINFO oSi = { 0 };
    oSi.cbSize = sizeof(oSi);
    oSi.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
    GetScrollInfo(hScroll, SB_VERT, &oSi);


    RECT rect = GetLocalCoordinates(hWnd);
    int width = rect.right - rect.left;
    int height = rect.bottom - rect.top;



    SCROLLINFO si = { 0 };

    si.cbSize = sizeof(si);
    si.fMask = SIF_PAGE;
    si.nPage = height;

    SetScrollInfo(hScroll, SB_VERT, &si, TRUE);

    si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;

    GetScrollInfo(hScroll, SB_VERT, &si);

    int res = oSi.nPos - si.nPos;

    if (res > 0) {

        setChildScrollOffset(hWnd, res);
    }
}


void ScrollBar::handleVScroll(int action,int thum) {
    int nPos;
    int nOldPos;

    SCROLLINFO si = { 0 };

    si.cbSize = sizeof(si);
    si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
    GetScrollInfo(hScroll, SB_VERT, &si);

    nOldPos = si.nPos;

    switch (action)
    {
    case SB_TOP:
        nPos = si.nMin;
        break;

    case SB_BOTTOM:
        nPos = si.nMax;
        break;

    case SB_LINEUP:
        nPos = si.nPos - 30;
        break;

    case SB_LINEDOWN:
        nPos = si.nPos + 30;
        break;

    case SB_PAGEUP:
        nPos = si.nPos - 30;
        break;

    case SB_PAGEDOWN:
        nPos = si.nPos + 30;
        break;

    case SB_THUMBTRACK:
        nPos = thum;
        break;

    default:
        nPos = si.nPos;
        break;
    }

    SetScrollPos(hScroll, SB_VERT, nPos, TRUE);

    nPos = GetScrollPos(hScroll, SB_VERT);


    if (nOldPos != nPos) {
        ScrollWindowEx(hWnd, 0, nOldPos - nPos, NULL, NULL, NULL, NULL,
            SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
        UpdateWindow(hWnd);
        setChildScrollOffset(hWnd, nOldPos - nPos);
    }
}

void ScrollBar::setChildScrollOffset(HWND h, int offset) {
    Controls* childsCon = reinterpret_cast<Controls*>(GetWindowLongPtr(h, GWLP_USERDATA));
    for (auto it : childsCon->sControls)
    {
        childsCon->getControlItem(it.first)->y += offset;
    }
}

LRESULT CALLBACK ScrollBar::scrollProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
    ScrollBar* lpData = (ScrollBar*)dwRefData;

    HDC hdc = (HDC)wParam;
    PAINTSTRUCT ps;
    HBRUSH hbrBackground;


    switch (uMsg) {
    
    case WM_SIZE:
    {
        lpData->setScrollSize();
        break;
    }
    case WM_VSCROLL:
    {
        lpData->handleVScroll(LOWORD(wParam), HIWORD(wParam));
        return true;
    }
    case WM_MOUSEWHEEL:
    {

        short zDelta = (short)(0xFFFF & (wParam >> 16));
        if (zDelta > 0)
            PostMessage(lpData->hScroll, WM_VSCROLL, SB_LINEUP, NULL);
        else
            PostMessage(lpData->hScroll, WM_VSCROLL, SB_LINEDOWN, NULL);
        return 0;
    }
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

Upvotes: 1

Views: 268

Answers (2)

Jeaninez - MSFT
Jeaninez - MSFT

Reputation: 4017

You need to distinguish between Standard Scroll Bars and Scroll Bar Controls. A scroll bar control is a control window that belongs to the SCROLLBAR window class.

For more details about how to Create Scroll Bar, I suggest you could refer to the Doc: How to Create Scroll Bars

According to the code, you want to create a Scroll Bar Controls. So you should creates a window without standard horizontal and vertical scroll bars and then use the CreateWindowEx function to create a scroll bar by specifying the SCROLLBAR window class.

Could you please show a minimal, reproducible sample?

Upvotes: 0

SoronelHaetir
SoronelHaetir

Reputation: 15162

I am blind and so can't see your screen shots but does your parent window have WS_VSCROLL? (you don't show the styles associated with that window). If so remove it, the WS_VSCROLL adds a scrollbar that is not control-based to the window's non-client area.

Upvotes: 1

Related Questions