C++ 启动屏幕使等待框移动

C++ 启动屏幕使等待框移动,c++,gdi,C++,Gdi,我有下面的代码,应该画一个位于窗口左下角的小框,每200毫秒向右移动50个像素,然后在它到达右侧后重新出现在左侧 为什么我的小长方形不动?它一直在同一个位置绘制 case WM_PAINT: if (hBitmap != NULL) { // Paint the bitmap. PAINTSTRUCT ps; HDC hdc; HDC

我有下面的代码,应该画一个位于窗口左下角的小框,每200毫秒向右移动50个像素,然后在它到达右侧后重新出现在左侧

为什么我的小长方形不动?它一直在同一个位置绘制

    case WM_PAINT:
    if (hBitmap != NULL)
    {
        // Paint the bitmap.            
        PAINTSTRUCT    ps;
        HDC            hdc;         
        HDC            hdcMem;
        HGDIOBJ        oldBitmap;
        //
        hdc = BeginPaint(hwnd, &ps);
        // Create a dc in memory to paint on.
        hdcMem = CreateCompatibleDC(hdc);
        // Select the bitmap.
        oldBitmap = SelectObject(hdcMem, hBitmap);          
        // Copy bitmap to splash screen window.
        BitBlt(hdc, 0, 0, bmWidth, bmHeight, hdcMem, 0, 0, SRCCOPY);
        // Fill rectangle.
        HBRUSH hbr = CreateSolidBrush(RGB(42, 59, 87));
        SelectObject(hdc, hbr);            
        FillRect(hdc, &rc, hbr);
        // Cleanup.         
        SelectObject(hdcMem, oldBitmap);
        DeleteObject(hbr);
        DeleteObject(oldBitmap);
        DeleteDC(hdcMem);
        EndPaint(hwnd, &ps);            
    }
    break;
case WM_TIMER:
    timeCount++;
    addLeft += 50;
    if (addLeft == 300)
    {
        addLeft = 0;
    }
    // Move rectangle.
    rc.left += addLeft; 
    rc.right += addLeft;
    // Refresh the window.
    UpdateWindow(hwnd);



   // Timer and RECT from the top of the code page, and WinMain:
      UINT_PTR ptrTimer;
      const int TIMER_INTERVAL = 200;
      const int MAX_TIME_COUNT = 100;
      int timeCount;

   // the timer works, but here's the code anyway.
     ptrTimer = SetTimer(hwnd, 1, TIMER_INTERVAL, (TIMERPROC)NULL);

    RECT rc;
rc.left = 141;
rc.top = 232;
rc.right = rc.left + 15;
rc.bottom = rc.top + 15;
谢谢你的回复

马特

编辑:感谢hf.enigma的回复。这就是我在读你的文章之前所做的。如果其他人想这样做,这是可行的,但是还有几个句柄和GDI对象需要清除。我是C++新手,所以如果有人看到内存泄漏,请告诉我。谢谢

case WM_PAINT:
    if (hBitmap != NULL)
    {
        // Paint the bitmap.            
        PAINTSTRUCT    ps;
        HDC            hdc;         
        HDC            hdcMem;
        HGDIOBJ        oldBitmap;
        //
        hdc = BeginPaint(hwnd, &ps);
        hdcMem = CreateCompatibleDC(hdc); // a device context (dc) in memory to paint on.
        oldBitmap = SelectObject(hdcMem, hBitmap);          
        // Copy bitmap to splash screen window.
        BitBlt(hdc, 0, 0, bmWidth, bmHeight, hdcMem, 0, 0, SRCCOPY);
        EndPaint(hwnd, &ps);
        // Cleanup.         
        SelectObject(hdcMem, oldBitmap);
        DeleteObject(oldBitmap);
        DeleteDC(hdcMem);           
        HBRUSH hbr ;            
        // Fill rectangle.
        RECT f;
        GetClientRect(hwndBox, &f);
        hdc = BeginPaint(hwndBox, &ps);         
        hdcMem = CreateCompatibleDC(hdc);
        hbr = CreateSolidBrush(RGB(42, 59, 87));
        SelectObject(hdc, hbr);  
        FillRect(hdc, &f, hbr);
        EndPaint(hwnd, &ps);        
        // Cleanup.         
        SelectObject(hdcMem, oldBitmap);
        DeleteObject(oldBitmap);
        DeleteDC(hdcMem);
        DeleteObject(hbr);
    }




case WM_TIMER:      
    timeCount++;        
    if (addLeft == 60)
    {
        addLeft = 10000;
        ival = 2;
    }
    // 'Hide' the box for 2/3 of timer interval when
    // it reaches the right side.
    if (addLeft == 10000)
        {           
            addLeft = 0;
            ival = 1;
        }
    //      
    switch (ival)
    {       
    case 2:
        addLeft += 12;          
        break;
    case 3:
        ival = 0;
        break;
    }
    ival++;
    if (ival == 2)
    {           
        // Move rectangle.
        MoveWindow(hwndBox, rcleft + addLeft, rctop, 12, 12, true);
    }       
    if (timeCount == MAX_TIME_COUNT)
    {
        DestroyWindow(hwnd);
    }       
    break;

完成绘制后,必须复制位图,并且应使用hdcMem绘制,如下所示:

...

// Fill rectangle.
HBRUSH hbr = CreateSolidBrush(RGB(42, 59, 87));
SelectObject(hdcMem, hbr);            
FillRect(hdcMem, &rc, hbr);

// Copy bitmap to splash screen window.
BitBlt(hdc, 0, 0, bmWidth, bmHeight, hdcMem, 0, 0, SRCCOPY);

// Cleanup.
....

这可以像hf.enigma所说的那样进行绘制,但是必须为每个绘制事件调用两次FillRect()。在不“擦除”上一个块的情况下,窗口的底部有一个长矩形,类似于进度条

最后,我制作了一个子窗口,大小与我想要的块一样,并调用MoveWindow()函数。对我来说,这是实现这一点的最简单和最可维护的方法,而无需使用MFC或CLI

如果这可以帮助其他人,下面是我用于此的所有代码

//This displays a splash screen, and starts
//another application that takes a long time
//to load.

#pragma once
#include "resource.h"
#include "PathStatus.h"
#include "StartApp.h"
#include "CenterWindow.h"
#include <string>
#include <stdlib.h>
#include <iostream>
using namespace std;
const LPWSTR CLASS_NAME(L"TMS_Logs");
const LPWSTR PATH_SUFFIX (L"\\bin\\tl.exe");
const int LEN_APP_NAME = 12; // length of "TMS_Logs.exe".
bool b;
int ival;
char *appPath;
HWND hwnd; // Main window.
HBITMAP hBitmap = NULL; // Bitmap painted in window.
HWND hwndBox; // Moving box shows app. is loading.
HWND hwndButton; // Close box.
int bmWidth;
int bmHeight;
UINT_PTR ptrTimer;
const int TIMER_INTERVAL = 50;
const int MAX_TIME_COUNT = 650;
int timeCount;
int addLeft;
int rcleft, rctop, rcright, rcbottom;
RECT rcMover;
RECT rcMover2;
bool exitApp = false;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{   
rcleft = 157;
rctop = 220;
rcright = rcleft + 15;
rcbottom = rctop + 15;
//
rcMover.left = rcleft;
rcMover.bottom = rcbottom;
rcMover.top = rctop;
rcMover.right = rcright;
//
rcMover2.bottom = rcbottom;
rcMover2.top = rctop;
rcMover.left + rcleft + 50;
rcMover.right = rcleft + 50 + 15;

// Get the commandline.
const wchar_t *args = GetCommandLineW();    
wstring s(args);       
// With no external arguments, GetCommandLineW() returns the
// full path with quotes around it, plus one space after the
// end qoute, e.g., '"c:\fullpath.exe" '.
// Remove the starting and ending quote chars, the space at
// the end, and and the exe path.   
// 
int len = s.length();
s = s.substr(1, len - 3 - LEN_APP_NAME) + PATH_SUFFIX;  
// Convert the wide string to a regular char array. 
// Convert the wstring to c-string.
const wchar_t *path = s.c_str();
// Convert the WCHAR to char* and store it in the 
// 'appPath' variable.
const size_t BUFFER_SIZE = 200;
size_t i;
appPath = (char*)malloc(BUFFER_SIZE);
wcstombs_s(&i, appPath, BUFFER_SIZE, path, BUFFER_SIZE);
// Create window class objects.
WNDCLASSEX wc;
MSG msg;    
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc; // Sets callback function.
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDICN_WSDOT));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME; 
wc.hIconSm = wc.hIcon;
if (!RegisterClassEx(&wc))
{
    MessageBox(NULL, L"Window Registration Failed!", L"Error!",
        MB_ICONEXCLAMATION | MB_OK);        
    return -1;
}

// Load the resource bitmap.
hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDBMP_TL7));
// Make a bitmap to hold the returned width and height.
// This bitmap will be deleted when DeleteObject is called
// for the hBitmap handle.
BITMAP bm;  
if (hBitmap != NULL && GetObject(hBitmap, sizeof(bm), &bm))
{   
    bmWidth = bm.bmWidth;
    bmHeight = bm.bmHeight;     
}
else
{
    MessageBox(hwnd, L"Error loading splash screen bitmap.",
        L"Error", MB_ICONEXCLAMATION | MB_OK);
    return -1;
}
// Center the window on the monitor
// where the mouse is.
RECT rc;
CenterRectToMonitor(&rc, bmWidth, bmHeight);
//
hwnd = CreateWindowEx(WS_EX_PALETTEWINDOW, wc.lpszClassName, // Uses the properties set in Window Class wc.
    L"TMS Logs", WS_POPUP, rc.left, rc.top, bmWidth, bmHeight, NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
    MessageBox(NULL, L"Error creating Window.", L"Error",
        MB_ICONEXCLAMATION | MB_OK);
    return -1;
}   
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
//bool started = true;
bool started = false;
bool ret;
int x, w, y, h;
x = 369;
y = 10;
w = 19;
h = 19;
// Make close box in upper-right corner.
hwndButton = CreateWindow( 
    L"BUTTON",  // Predefined class.
    L"X",      // Button text 
    WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
    369,         // x position 
    10,          // y position 
    19,        // Button width
    19,        // Button height
    hwnd,     // Parent window
    NULL,       // No menu.
    (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), 
    NULL);      // Pointer not needed.

// Make a box that moves along the bottom of 
// the window while the other app. loads.       
x = rcleft;
y = rctop;
w = 10;
h = 10; 
hwndBox = CreateWindow(L"static", 0, WS_CHILD | WS_VISIBLE, x, y, w, h, hwnd, NULL,
    (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL); 
// Create a timer to close this window after
// several seconds, in case the main app. does
// not send the close window message to this app.
// the WM_TIMER message is handled in the WndProc
// callback function.
ptrTimer = SetTimer(hwnd, 1, TIMER_INTERVAL, (TIMERPROC)NULL);
// Start message Loop.
while ((ret = GetMessage(&msg, NULL, 0, 0)) !=  0)
{
    if (ret == -1)
    {                  
        MessageBox(NULL,
            L"Error in Splash screen window message loop, at:\n\n'GetMessage(&msg, NULL, 0, 0))'.\n\nMessage return value was -1.",
            L"TMS Logs", MB_ICONEXCLAMATION | MB_OK);
        // Exit this app.
        return -1;
    }
    // TranslateMessage(&Msg); // Not needed with what I have here.
    DispatchMessage(&msg);
    // Check app. path and start the other app.     
    if (!started)
    {           
        started = true;
        if (Path_Accessible(appPath))
        {
            // Start the main app.
            if (!StartApplication(appPath))
            {
                // The folder or file is missing, or
                // the user does not have security
                // permissions to the sub-folder.
                MessageBox(hwnd, L"Unexpected error at: StartApplication().",
                    L"Error", MB_ICONEXCLAMATION | MB_OK);
                if (appPath)
                {
                    free(appPath);
                }
                return -1;
            }
        }
        else
        {               
            // Display an error message.                
            char msg[350];
            char* prefix = "Error: Can't find 'tl.exe'.\n\n It's missing from: '";
            //char* suffix = " '\ncannot be accessed, or does not exist.";
            int count = sizeof(msg);
            strncpy(msg, prefix, count);
            strncat(msg, appPath, count);
            //strncat(msg, suffix, count);              
            // Convert c-string to wide char. string.
            count = strlen(msg) + 1;
            wchar_t* wMsg = new wchar_t[count];
            size_t returnCount;
            int ret = mbstowcs_s(&returnCount, wMsg, count, msg, _TRUNCATE);
            if (ret == 0 && returnCount == count)
            {
                MessageBox(hwnd, wMsg, L"Error", MB_ICONEXCLAMATION | MB_OK);               
            }
            else
            {
                // Error
                MessageBox(hwnd, L"Error: The application path cannot be accessd, or does not exist.", L"Error", MB_ICONEXCLAMATION | MB_OK);
            }
            delete[] wMsg;
            if (appPath)
            {
                free(appPath);
            }
            return -1;
        }
    }
}
if (appPath)
{
    free(appPath);      
}       
return msg.wParam;
}

// Process messages.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
    // The close button is the only child window,
    // so no need to check wparam.
    DestroyWindow(hwnd);
    break;
case WM_CLOSE:
    DestroyWindow(hwnd);
    break;
case WM_DESTROY:                
    DestroyWindow(hwndButton);
    DestroyWindow(hwndBox);
    if (hBitmap != NULL)
    {
        if (!DeleteObject(hBitmap))
        {
            MessageBox(hwnd, L"Error at: WndProc(). Failed to delete the application bitmap.",
                L"Error", MB_OK);
        }
    }
    if (ptrTimer)
    {   
        if (!KillTimer(hwnd, ptrTimer))
        {
            MessageBox(hwnd, L"Error at :WndProc(). Failed to free the application timer.",
                L"Error", MB_OK);
        }
    }
    PostQuitMessage(0);
    break;
case WM_PAINT:
    if (hBitmap != NULL)
    {
        // Paint the bitmap.            
        PAINTSTRUCT    ps;
        HDC            hdc;         
        HDC            hdcMem;
        HGDIOBJ        oldBitmap;
        //
        hdc = BeginPaint(hwnd, &ps);
        hdcMem = CreateCompatibleDC(hdc); // a device context (dc) in memory to paint on.
        oldBitmap = SelectObject(hdcMem, hBitmap);          
        // Copy bitmap to splash screen window.
        BitBlt(hdc, 0, 0, bmWidth, bmHeight, hdcMem, 0, 0, SRCCOPY);
        EndPaint(hwnd, &ps);
        // Cleanup.         
        SelectObject(hdcMem, oldBitmap);
        DeleteObject(oldBitmap);
        DeleteDC(hdcMem);           
        HBRUSH hbr ;            
        // Fill rectangle.
        RECT f;
        GetClientRect(hwndBox, &f);
        hdc = BeginPaint(hwndBox, &ps);         
        hdcMem = CreateCompatibleDC(hdc);
        hbr = CreateSolidBrush(RGB(42, 59, 87));
        SelectObject(hdc, hbr);  
        FillRect(hdc, &f, hbr);
        EndPaint(hwnd, &ps);        
        // Cleanup.         
        SelectObject(hdcMem, oldBitmap);
        DeleteObject(oldBitmap);
        DeleteDC(hdcMem);
        DeleteObject(hbr);
    }
    break;
case WM_TIMER:      
    timeCount++;        
    if (addLeft == 60)
    {
        addLeft = 10000;
        ival = 2;
    }
    // 'Hide' the box for 2/3 of timer interval when
    // it reaches the right side.
    if (addLeft == 10000)
        {           
            addLeft = 0;
            ival = 1;
        }
    //      
    switch (ival)
    {       
    case 2:
        addLeft += 12;          
        break;
    case 3:
        ival = 0;
        break;
    }
    ival++;
    if (ival == 2)
    {           
        // Move rectangle.
        MoveWindow(hwndBox, rcleft + addLeft, rctop, 12, 12, true);
    }       
    if (timeCount == MAX_TIME_COUNT)
    {
        DestroyWindow(hwnd);
    }       
    break;
default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
路径状态.H

#include <sys/stat.h>
const int SUCCESS = 0; // Indicates stat buffer was successfully set.

// Method to check if a file or folder
// exists and is accessible, using the stat
// structure and stat function, ref: 
// http://pubs.opengroup.org/onlinepubs/009695399/functions/stat.html
bool Path_Accessible(const char* path)
{
if (path == 0)
{
    return false;
}

struct stat path_status;    
int result = stat(path, &path_status);
// 
// The _S_IFREG flag indicates the path is a
// regular file and not a directory.
//
// To check for a directory, use '_S_IFDIR'.    
return result == SUCCESS &&
    (path_status.st_mode & _S_IFREG);
}
#包括
const int SUCCESS=0;//表示已成功设置统计缓冲区。
//方法来检查文件或文件夹
//存在并且可以使用stat访问
//结构和统计功能,参考:
// http://pubs.opengroup.org/onlinepubs/009695399/functions/stat.html
布尔路径可访问(常量字符*路径)
{
如果(路径==0)
{
返回false;
}
结构状态路径\状态;
int result=stat(路径和路径状态);
// 
//_S_IFREG标志表示路径为
//常规文件而不是目录。
//
//要检查目录,请使用“\u S\u IFDIR”。
返回结果==成功&&
(path_status.st_mode&_S_IFREG);
}
这就是我的启动屏幕的样子。请注意,小框从现在的位置向左移动一点,向右移动一点,然后重复这个过程,直到另一个应用程序出现。此启动将WM_CLOSE消息发送到此窗口


谢谢。我最后做的是创建一个小的方形子窗口,并在其上调用MoveWindow(刷新标志设置为true)API,然后用我想要的颜色填充该子窗口。它的开销稍微大一点,但它工作得很好。当我有更多的时间时,我会尝试你的代码。
void CenterRectToMonitor(LPRECT prc, int rcWidth, int rcHeight)
{
POINT pt;   
GetCursorPos(&pt);
HMONITOR mon;
mon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(mon, &mi);
*prc = mi.rcMonitor;
//
// Center the window rectangle to the monitor rectangle.
prc->left   = prc->left + (prc->right  - prc->left - rcWidth) / 2;
prc->top    = prc->top  + (prc->bottom - prc->top  - rcHeight) / 2;
prc->right  = prc->left + rcWidth;
prc->bottom = prc->top  + rcHeight;     
}
#include <sys/stat.h>
const int SUCCESS = 0; // Indicates stat buffer was successfully set.

// Method to check if a file or folder
// exists and is accessible, using the stat
// structure and stat function, ref: 
// http://pubs.opengroup.org/onlinepubs/009695399/functions/stat.html
bool Path_Accessible(const char* path)
{
if (path == 0)
{
    return false;
}

struct stat path_status;    
int result = stat(path, &path_status);
// 
// The _S_IFREG flag indicates the path is a
// regular file and not a directory.
//
// To check for a directory, use '_S_IFDIR'.    
return result == SUCCESS &&
    (path_status.st_mode & _S_IFREG);
}