Jump to content
Tuts 4 You

Need help making this starfield animation draggable


Recommended Posts

iamwho
Posted
#include <Windows.h>
#include <iostream>
#include <windowsx.h>

#define IDB_EXIT 102

PAINTSTRUCT ps;
HDC hdc;
RECT starfield_rc;

BOOL g_bDragging = FALSE;
POINT g_ptDragStart;

int WIDTH = 350;
int HEIGHT = 400;

const int numStars = 50;
const int starSpeed = 1;

struct Star
{
    int x, y;
    int speed;
};

const int NUM_STARS = 100;
Star stars[NUM_STARS];

HDC hdcMem;
HBITMAP hbmMem;
HBITMAP hbmOld;

void starfield(HDC hdc, int x, int y, RECT *rc)
{
    int width = 335;
    rc->left = x;
    rc->top = y;
    rc->right = width;
    rc->bottom = 249;

    HDC hdcMem = CreateCompatibleDC(hdc);
    HBITMAP hbmMem = CreateCompatibleBitmap(hdc, width, 215);
    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);

    HBRUSH brush = CreateSolidBrush(RGB(0, 0, 0));
    FillRect(hdcMem, rc, brush);
    DeleteObject(brush);

    for (int i = 0; i < NUM_STARS; i++)
    {
        SetPixel(hdcMem, stars[i].x, stars[i].y, RGB(255, 255, 255));
        stars[i].x = (stars[i].x + stars[i].speed) % width;
    }
    BitBlt(hdc, x, y, width, 215, hdcMem, 0, 0, SRCCOPY);
    SelectObject(hdcMem, hbmOld);
    DeleteObject(hbmMem);
    DeleteDC(hdcMem);
}
// main function
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lparam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{
    for (int i = 0; i < NUM_STARS; i++)
    {
        stars[i].x = rand() % 340;
        stars[i].y = rand() % 249;
        stars[i].speed = rand() % 3 + 1;
    }
    TCHAR appname[] = TEXT("Template");
    WNDCLASS wndclass;
    MSG msg;
    HWND hwnd;

    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hInstance = hInstance;
    wndclass.lpfnWndProc = WndProc;
    wndclass.lpszClassName = appname;
    wndclass.lpszMenuName = NULL;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;

    // check this window class is registered or not
    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("Window class is not registered"), TEXT("Error...."), MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindowEx(0,
                          appname,                            // window name
                          appname,                            // window text
                          WS_VISIBLE | WS_POPUP, // set POPUP window style for no border & controls
                          100,                                // window position x
                          100,                                // window position y
                          WIDTH,                              // width
                          HEIGHT,                             // height
                          NULL,
                          NULL,
                          hInstance,
                          NULL);
    // show & update created window
    SetTimer(hwnd, 1, 10, NULL); // Set a timer to trigger every 100ms
    ShowWindow(hwnd, nCmdShow);

    // get message from queue
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}
bool isSizingOrMoving = false;

// WndProc function
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    HINSTANCE hIns;
    HWND exit_button, gen_button, title, license;
    LRESULT move = NULL;
    static int xClick;
    static int yClick;

    switch (message)
    {
    case WM_CREATE:

    {
        exit_button = CreateWindow(TEXT("BUTTON"), NULL, WS_CHILD | WS_VISIBLE | BS_BITMAP,
                                   250, 360, 70, 30, hwnd, (HMENU)100, hIns, 0);
        HBITMAP exitImg = (HBITMAP)LoadImageA(GetModuleHandleA(nullptr), (LPCSTR)MAKEINTRESOURCE(IDB_EXIT), IMAGE_BITMAP, 0, 0, NULL);

        title = CreateWindow(TEXT("STATIC"), TEXT("Hello"), WS_CHILD | WS_VISIBLE, 150, 5, 120, 20, hwnd, 0, hIns, 0);

        SendMessageW(exit_button, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)exitImg);
    }

    break;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        hdc = BeginPaint(hwnd, &ps);
        starfield(hdc, 6, 31, &starfield_rc);
        EndPaint(hwnd, &ps);
        break;
    }

    case WM_TIMER:
        InvalidateRect(hwnd, &starfield_rc, FALSE);
        break;

    case WM_COMMAND:

        switch (wParam)
        {
        case 100:
            PostQuitMessage(EXIT_SUCCESS);
            return 0;
        }

        break;
    case WM_CTLCOLORSTATIC:

    {
        hdc = (HDC)wParam;

        return (LRESULT)CreateSolidBrush(RGB(0, 0, 0)); // black and white

        break;
    }

    case WM_CTLCOLOREDIT:

    {
        hdc = (HDC)wParam;

        return (LRESULT)CreateSolidBrush(RGB(0, 0, 0)); // black and white

        break;
    }

    case WM_LBUTTONDOWN:
        {
            // Start dragging
            g_bDragging = TRUE;
            g_ptDragStart.x = LOWORD(lParam);
            g_ptDragStart.y = HIWORD(lParam);
            SetCapture(hwnd);
        }
        return 0;

    case WM_MOUSEMOVE:
        {
            if (g_bDragging)
            {
                // Calculate the offset
                int dx = LOWORD(lParam) - g_ptDragStart.x;
                int dy = HIWORD(lParam) - g_ptDragStart.y;

                // Get the current window position
                RECT rc;
                GetWindowRect(hwnd, &rc);
                // Move the window by the offset
                SetWindowPos(hwnd, NULL, rc.left + dx, rc.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
            }
        }
        return 0;

    case WM_LBUTTONUP:
        {
            // Stop dragging
            g_bDragging = FALSE;
            ReleaseCapture();
        }
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

This is my starfield animation. Although you can drag the window. But if you drag it from extreme left or the top area, it gets lost. Can anyone help on how to fix this?

  • Like 2
iamwho
Posted
40 minutes ago, Kurapica said:

What exactly gets lost ?

When you drag it fastly from the title, it gets lost.

  • Like 1
jackyjask
Posted

you could save short video and embed right in the post here

  • Like 1
adoxa
Posted

LOWORD & HIWORD are unsigned, so when the mouse moves outside the window you're getting big values, causing it to go offscreen; use GET_X_LPARAM & GET_Y_LPARAM instead, then it will work fine.

  • Like 1
  • 6 months later...
Posted

 

"Local variables (hdcMem, hbmMem, hbmOld) in the starfield() function conflict with global ones.

The window size (WIDTH = 350, HEIGHT = 400) doesn’t match the starfield size (335 width and 249 height). Make them consistent if intended.

Ensure that IDB_EXIT is properly defined in your resources (e.g., .rc file). If not, the LoadImageA call will fail.

In WM_MOUSEMOVE, SetWindowPos is called every time the mouse moves, which may cause performance issues. "

  • Like 1
Posted (edited)

I would just use case WM_NCHITTEST and in that event check for g_bDragging is true, if so then use SendMessage with WM_NCLBUTTONDOWN and HTCAPTION, that way you will drag the entire window as if it had a caption/titlebar whenever mouse is down.

So I would remove the WM_MOUSEMOVE and add something like this:

    case WM_NCHITTEST:
        {
            if (g_bDragging)
            {
                SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
            }
        }
        return 0;

 

Edited by fearless
  • Like 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...