我有以下代码,它应该绘制一个位于窗口左下角的小盒子,每隔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;
答案 0 :(得分:0)
完成绘画后你必须复制位图,你应该用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.
....
答案 1 :(得分:0)
这可以像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文件的代码。
StartApp.H
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude DDE, RPC, Shell, Sockets, etc.
#define NOCOMM // Exclude serial communication APIs.
#include <Windows.h>
#include <cstdlib>
// Calls the CreateProcess function to start another app.
// ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682512(v=vs.85).aspx
bool StartApplication(const char* appPath)
{
// The CreateProcess function requires
// wide char. array, so convert appPath.
size_t count = strlen(appPath) + 1;
wchar_t* path = new wchar_t[count];
size_t returnCount;
int ret = mbstowcs_s(&returnCount, path, count, appPath, _TRUNCATE);
if (ret != 0 || returnCount != count)
{
// Error converting C-string.
delete[] path;
return false;
}
// Required objects.
STARTUPINFO si;
PROCESS_INFORMATION pi;
// Set the size of the objects.
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the program at 'path'.
bool ok = CreateProcess(
path, // module name/app. path.
NULL, // Command line/path, if null app. path is used.
NULL, // Process handle, use null.
NULL, // Thread handle, use null.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi); // Pointer to PROCESS_INFORMATION structure.
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
delete[] path;
return ok;
}
CenterWindow.H
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;
}
PathStatus.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);
}
这就是我的闪屏看起来像。请注意,小盒子在它现在的位置左侧开始,向右移动一点,然后重复直到另一个应用程序。这个开始发送WM_CLOSE消息到这个窗口。