how i can move my window when middle mouse button pressed?
in case with left mouse button it would be
case WM_LBUTTONDOWN:
{
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
return 0;
but it does not work with middle button
case WM_MBUTTONDOWN:
{
SendMessage(hwnd, WM_NCMBUTTONDOWN, HTCAPTION, 0);
}
return 0;
but i am not sure about WM_NCMBUTTONDOWN
i`m out of variants, need help please
You have to do this the hard way I'm afraid. I tried all the obvious things and WM_NCHITTEST doesn't cut it if you want to drag the window with anything other than the left mouse button.
Here's some code that works for me (tested on Windows 10). I've excluded error checking for brevity:
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
// WndProc
LRESULT CALLBACK MyWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static int xClick, yClick;
switch (uMsg)
{
case WM_NCMBUTTONDOWN:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
{
SetCapture (hWnd);
POINT pt = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) };
if (uMsg == WM_NCMBUTTONDOWN)
ScreenToClient (hWnd, &pt);
xClick = pt.x;
yClick = pt.y;
return 0;
}
case WM_LBUTTONUP:
case WM_MBUTTONUP:
ReleaseCapture ();
return 0;
case WM_MOUSEMOVE:
{
if (GetCapture() == hWnd)
{
RECT wr;
GetWindowRect (hWnd, &wr);
int xMouse = GET_X_LPARAM (lParam);
int yMouse = GET_Y_LPARAM (lParam);
int xWindow = wr.left + xMouse - xClick;
int yWindow = wr.top + yMouse - yClick;
SetWindowPos (hWnd, NULL ,xWindow, yWindow, 0, 0 , SWP_NOSIZE | SWP_NOZORDER);
}
return 0;
}
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}
// WinMain
int CALLBACK _tWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
HINSTANCE hInstance = NULL;
WNDCLASS wc = { };
wc.lpszClassName = __T ("MyWindowClass");
wc.lpfnWndProc = MyWndProc;
RegisterClass (&wc);
HWND hWnd = CreateWindow (wc.lpszClassName, __T ("My Window"),
WS_CAPTION | WS_BORDER | WS_VISIBLE, 100, 100, 200, 200, NULL, NULL, hInstance, 0);
MSG msg;
while (GetMessage (&msg, NULL, 0, 0))
DispatchMessage (&msg);
return 0;
}
Hope this helps.
Related
I've started Direct2D from a very simple example.
Acquire the factory and ID2D1HwndRenderTarget, then handle WM_PAINT message to draw just a background with a solid color using "Clear" function.
It's work fine, until I start to move the window. When the window is moving it turns gray like nothing is drawing. I've tried to draw an ellipse, and the result is the same.
How could one present the window content with the window moving?
P.S. In case the code is needed
#include <Windows.h>
#include <d2d1_1.h>
#pragma comment(lib,"d2d1")
ID2D1Factory * d2factory_ptr = NULL;
ID2D1HwndRenderTarget * renderTarget_ptr = NULL;
LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(
HINSTANCE hInstance
, HINSTANCE prevInstance
, LPWSTR cmd
, int nCmdShow
) {
WNDCLASSEX wndClassStruct;
ZeroMemory(&wndClassStruct, sizeof(WNDCLASSEX));
wndClassStruct.cbSize = sizeof(WNDCLASSEX);
wndClassStruct.hbrBackground = (HBRUSH)COLOR_WINDOW;
wndClassStruct.style = CS_HREDRAW | CS_VREDRAW;
wndClassStruct.hInstance = hInstance;
wndClassStruct.lpfnWndProc = mainWinProc;
wndClassStruct.lpszClassName = TEXT("MainWnd");
RegisterClassEx(&wndClassStruct);
RECT windowRect = { 0,0,640,480};
AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, 0, WS_EX_APPWINDOW);
HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, TEXT("MainWnd"), TEXT("Direct 2D Test Window"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, CW_USEDEFAULT, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, NULL, NULL, hInstance, 0);
{
D2D1_FACTORY_OPTIONS fo;
ZeroMemory(&fo, sizeof(D2D1_FACTORY_OPTIONS));
IID const factoryIID = IID_ID2D1Factory1;
HRESULT res = S_OK;
if (S_OK != (res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factoryIID, &fo, &d2factory_ptr))) {
return 0;
}
RECT clientRect;
GetClientRect(hWnd, &clientRect);
D2D1_RENDER_TARGET_PROPERTIES renderTargetProps;
ZeroMemory(&renderTargetProps, sizeof(D2D1_RENDER_TARGET_PROPERTIES));
renderTargetProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
renderTargetProps.pixelFormat = (D2D1_PIXEL_FORMAT) { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED };
renderTargetProps.dpiX = 0;
renderTargetProps.dpiY = 0;
renderTargetProps.usage = D2D1_RENDER_TARGET_USAGE_FORCE_BITMAP_REMOTING;
renderTargetProps.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
D2D1_HWND_RENDER_TARGET_PROPERTIES hwndRenderProps;
ZeroMemory(&hwndRenderProps, sizeof(D2D1_HWND_RENDER_TARGET_PROPERTIES));
hwndRenderProps.hwnd = hWnd;
hwndRenderProps.pixelSize = (D2D1_SIZE_U) { clientRect.right - clientRect.left, clientRect.bottom - clientRect.top };
hwndRenderProps.presentOptions = D2D1_PRESENT_OPTIONS_NONE;
if (S_OK != (res = d2factory_ptr->lpVtbl->CreateHwndRenderTarget(d2factory_ptr, &renderTargetProps, &hwndRenderProps, &renderTarget_ptr))) {
return 0;
}
}
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DestroyWindow(hWnd);
if(NULL != renderTarget_ptr)
renderTarget_ptr->lpVtbl->Base.Base.Base.Release((IUnknown*)renderTarget_ptr);
if (NULL != d2factory_ptr)
d2factory_ptr->lpVtbl->Base.Release((IUnknown*)d2factory_ptr);
return 0;
}
LRESULT onPaintMainWindow() {
ID2D1RenderTargetVtbl renderTargetFuncs = renderTarget_ptr->lpVtbl->Base;
ID2D1RenderTarget * This = (ID2D1RenderTarget*)renderTarget_ptr;
D2D1_TAG tag1, tag2;
D2D1_COLOR_F backgroundClr = (D2D1_COLOR_F) { 0.0, 0.5, 1.0, 1.0 };
renderTargetFuncs.BeginDraw(This);
renderTargetFuncs.Clear(This, &backgroundClr);
renderTargetFuncs.EndDraw(This, &tag1, &tag2);
return 0;
}
LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (WM_PAINT == uMsg)
return onPaintMainWindow();
if (WM_DESTROY == uMsg) {
PostQuitMessage(0); return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Configure your WNDCLASSEX to not have a background brush.
Replace this line:
wndClassStruct.hbrBackground = (HBRUSH)COLOR_WINDOW;
With this:
wndClassStruct.hbrBackground = GetStockObject(NULL_BRUSH);
Alternatively, you can modify mainWndProc to swallow the WM_ERASEBKGND messages. It achieves the same effect by not allowing the window to erase itself before issuing a WM_PAINT.
LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (WM_PAINT == uMsg)
return onPaintMainWindow();
if (uMsg == WM_ERASEBKGND)
{
// ignore requests to erase the background since the wm_paint
// handler is going to redraw the entire window.
return 0;
}
if (WM_DESTROY == uMsg) {
PostQuitMessage(0); return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Here is my code. I'm trying to create an edit control. It's not showing, however. Can some take a look at my code and point out the errors please. I can't figure out where the error is. I feel It might have something to do with the parent child relationship.
#include <cstdlib>
#include <windows.h>
#define MAINWINDOW_CLASS_ID 140;
const char* MAINWINDOW_CLASS_NAME = "Main Window";
const char* TEXTAREA_CLASS_NAME = "EDIT";
using namespace std;
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam);
/*
* Initialize the window class and register it.
*/
BOOL initInstance(HINSTANCE hInstance);
/*
* Create and show the window
*/
HWND initWindow(HINSTANCE hInstance);
HWND createTextArea(HWND hParent);
/*
*
*/
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, LPSTR lpCmdline, INT cmdlShow)
{
if (!initInstance(hInstance))
return 0;
HWND hwndMain = initWindow(hInstance);
ShowWindow(hwndMain, cmdlShow);
MSG msg = {} ;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BOOL initInstance(HINSTANCE hInstance)
{
WNDCLASS wc = {};
wc.lpfnWndProc = WinProc;
wc.hInstance = hInstance,
wc.lpszClassName = MAINWINDOW_CLASS_NAME;
return RegisterClass(&wc);
}
HWND initWindow(HINSTANCE hInstance)
{
HWND hwndMain = CreateWindow(
MAINWINDOW_CLASS_NAME, // The class name
"Text Editor", // The window name
WS_OVERLAPPEDWINDOW,// The window style
CW_USEDEFAULT, // The x pos
CW_USEDEFAULT, // The y pos
CW_USEDEFAULT, // The width
CW_USEDEFAULT, // The height
(HWND) NULL, // Handle to parent
(HMENU) NULL, // Handle to the menu
hInstance, // Handle to the instance
NULL // Window creation data
);
if (!hwndMain) {
return NULL;
}
else {
return hwndMain;
}
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) {
HWND htextArea;
char sztestText[] = "I should be able to see this text.";
switch (uMsg) {
case WM_CREATE:
htextArea = createTextArea(hwnd);
SendMessage(htextArea, WM_SETTEXT, 0, (LPARAM) sztestText);
break;
case WM_PAINT:
break;
case WM_CLOSE:
break;
case WM_SIZE:
RECT rectMainWindow;
GetWindowRect(hwnd, &rectMainWindow);
INT x = rectMainWindow.right - rectMainWindow.left + 50;
INT y = rectMainWindow.bottom - rectMainWindow.top + 50;
MoveWindow(htextArea, 0, 0, x, y, TRUE);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
/*******************************************************************/
HWND createTextArea(HWND hParent) {
return CreateWindow(
TEXTAREA_CLASS_NAME, // Class control name
NULL, // Title
WS_CHILD | WS_VISIBLE | ES_MULTILINE, // Styles
0, 0, 0, 0, // Sizing and position
hParent,
(HMENU) MAKEINTRESOURCE(100),
(HINSTANCE) GetWindowLong(hParent, GWL_HINSTANCE),
NULL
);
}
You've defined htextArea as a local variable in WinProc and so every time your window procedure is called its value will be uninitialized. You should make it static or move it to global data outside the function.
(The actual problem is that when you get a WM_SIZE message, you've lost the handle to the edit control, and so its size remains as 0,0).
I want to make a TreeView's item dynamically create its children when the item is expanding. According to http://support.microsoft.com/kb/130697, I wrote the following code:
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <windowsx.h>
#include <CommCtrl.h>
#pragma comment(lib, "ComCtl32.Lib")
#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL MainWindow_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct);
void MainWindow_OnDestroy(HWND hWnd);
void MainWindow_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify);
LRESULT MainWindow_OnNotify(HWND hWnd, int idFrom, NMHDR *pnmhdr);
#define ID_TREEVIEW 100
#define ID_EXPAND 101
HTREEITEM root_item;
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
WNDCLASSEX wcex = { sizeof(wcex) };
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
LoadIconMetric(NULL, IDI_APPLICATION, LIM_LARGE, &wcex.hIcon);
wcex.hCursor = static_cast<HCURSOR>(LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED));
wcex.lpszClassName = TEXT("MainWindow");
LoadIconMetric(NULL, IDI_APPLICATION, LIM_SMALL, &wcex.hIconSm);
RegisterClassEx(&wcex);
HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("TreeView Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hWnd, WM_CREATE, MainWindow_OnCreate);
HANDLE_MSG(hWnd, WM_DESTROY, MainWindow_OnDestroy);
HANDLE_MSG(hWnd, WM_NOTIFY, MainWindow_OnNotify);
HANDLE_MSG(hWnd, WM_COMMAND, MainWindow_OnCommand);
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
BOOL MainWindow_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
HWND h_treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, TEXT("TreeView"), WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_LINESATROOT, 10, 10, 400, 400, hWnd, reinterpret_cast<HMENU>(ID_TREEVIEW), GetModuleHandle(NULL), NULL);
TVINSERTSTRUCT tvis = { TVI_ROOT, TVI_LAST, { TVIF_TEXT | TVIF_CHILDREN } };
tvis.item.pszText = TEXT("Root");
tvis.item.cChildren = 1;
root_item = TreeView_InsertItem(h_treeview, &tvis);
CreateWindow(WC_BUTTON, TEXT("Expand"), WS_CHILD | WS_VISIBLE, 420, 10, 75, 23, hWnd, reinterpret_cast<HMENU>(ID_EXPAND), GetModuleHandle(NULL), NULL);
return TRUE;
}
void MainWindow_OnDestroy(HWND hWnd)
{
PostQuitMessage(0);
}
LRESULT MainWindow_OnNotify(HWND hWnd, int idFrom, NMHDR *pnmhdr)
{
switch (pnmhdr->code)
{
case TVN_ITEMEXPANDING:
{
LPNMTREEVIEW pnmtv = reinterpret_cast<LPNMTREEVIEW>(pnmhdr);
if (pnmtv->action == TVE_EXPAND)
{
LPCTSTR items[] = { TEXT("Item 1"), TEXT("Item 2"), TEXT("Item 3") };
for (LPCTSTR item : items)
{
TVINSERTSTRUCT tvis = { pnmtv->itemNew.hItem, TVI_LAST, { TVIF_TEXT } };
tvis.item.pszText = const_cast<LPTSTR>(item);
TreeView_InsertItem(pnmhdr->hwndFrom, &tvis);
}
}
break;
}
case TVN_ITEMEXPANDED:
{
LPNMTREEVIEW pnmtv = reinterpret_cast<LPNMTREEVIEW>(pnmhdr);
if (pnmtv->action == TVE_COLLAPSE)
{
TreeView_Expand(pnmhdr->hwndFrom, pnmtv->itemNew.hItem, TVE_COLLAPSE | TVE_COLLAPSERESET);
}
break;
}
}
return 0;
}
void MainWindow_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify)
{
if (id == ID_EXPAND)
{
TreeView_Expand(GetDlgItem(hWnd, ID_TREEVIEW), root_item, TVE_EXPAND);
}
}
The code creates a Window with a TreeView and a Button. When the button is clicked, the TreeView's root item should be expanded.
I can expand the root item for the first time. Either click the "Expand" button or click the "+" sign beside the root item is OK. But if I collapsed the root item, I can't expand it again by click the "Expand" button again, while the "+" sign still works. I noticed that although I've used the TVE_COLLAPSERESET flag to clear the TVIS_EXPANDEDONCE flag, it still has the flag before the TreeView_Expand call. Accroding to MSDN, I think I'll need the TVIS_EXPANDEDONCE flag to remain unset. Where am I doing it wrong?
Use PostMessage to reset the TVE_COLLAPSERESET flag:
PostMessage(pnmhdr->hwndFrom, TVM_EXPAND, TVE_COLLAPSE | TVE_COLLAPSERESET, reinterpret_cast<LPARAM>(pnmtv->itemNew.hItem));
To my understanding, the TreeView send the TVN_ITEMEXPANDED notification, which send message back to the TreeView, which may cause the problem. We may need to delay the message until the current message has been processed.
I have simple win32 application (not dialog box), and treeview in this application.
All works, but if I have selected item in the treeview, and I minimize and restore application, selected item changes blue higlighting color to grayed color.
How to correct this without using custom draw?
If I have treeview in the dialog box, selected item has always blue color.
CODE:
HWND g_hTree;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG Msg;
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return (int) Msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TREEVIEWTEST));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TREEVIEWTEST);
wcex.lpszClassName = L"TreeViewTestClass";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
InitCommonControls();
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(L"TreeViewTestClass", L"Tree View Test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
void AddItems();
#define TVS_STYLES (TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_INFOTIP | TVS_TRACKSELECT | WS_VSCROLL | WS_TABSTOP)
#define ID_TREEVIEW 505
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_CREATE:
{
g_hTree = CreateWindowEx(0, WC_TREEVIEWW, L"Test_Tree_View", WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_STYLES, 10, 10, 240, 480, hWnd, (HMENU)ID_TREEVIEW, NULL, NULL);
AddItems();
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void AddItems()
{
TVITEM tvi;
HTREEITEM htSelected;
TVINSERTSTRUCT tvinsert; // struct to config out tree control
HTREEITEM htParent; // Tree item handle
HTREEITEM htBefore; // .......
HTREEITEM htRoot;
tvinsert.hParent=NULL; // top most level no need handle
tvinsert.hInsertAfter=TVI_ROOT; // work as root level
tvinsert.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
tvinsert.item.pszText=L"Parent1";
tvinsert.item.iImage=0;
tvinsert.item.iSelectedImage=1;
htParent = TreeView_InsertItem(g_hTree, &tvinsert);
htRoot = htParent;
htBefore = htParent;
tvinsert.hParent=htParent; // handle of the above data
tvinsert.hInsertAfter=TVI_LAST; // below parent
tvinsert.item.pszText=L"Child 1";
htParent = TreeView_InsertItem(g_hTree, &tvinsert);
tvinsert.hParent=htParent;
tvinsert.item.pszText=L"Child Of Child 1";
htParent = TreeView_InsertItem(g_hTree, &tvinsert);
tvinsert.hParent=htBefore; // handle of the above data
tvinsert.hInsertAfter=TVI_LAST; // below parent
tvinsert.item.pszText=L"Child 2";
htParent = TreeView_InsertItem(g_hTree, &tvinsert);
tvinsert.hParent=NULL; // top most level no need handle
tvinsert.hInsertAfter=TVI_LAST; // work as root level
tvinsert.item.pszText=L"Parent2";
htParent = TreeView_InsertItem(g_hTree, &tvinsert);
}
It seems your tree-view control is losing focus when the window is minimized. You can try handling WM_ACTIVATE and using SetFocus to manually set focus to the tree-view control.
MSDN doc's for MoveWindow() says:
"If the bRepaint parameter is TRUE, the system sends the WM_PAINT message to the window procedure immediately after moving the window (that is, the MoveWindow function calls the UpdateWindow function)."
But when I call GetUpdateRect() after MoveWindow(), while processing the WM_LBUTTONDOWN message in the parent, I get a beep, which shows that the child is invalid. What is the explanation ???
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
HINSTANCE ghInstance;
LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, UINT wParam, LONG lParam);
LRESULT CALLBACK ChildProc (HWND hwnd, UINT message, UINT wParam, LONG lParam);
int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASSEX wndclassx;
ghInstance = hInstance;
wndclassx.cbSize = sizeof(WNDCLASSEX);
wndclassx.style = 0;
wndclassx.lpfnWndProc = WindowProc;
wndclassx.cbClsExtra = 0;
wndclassx.cbWndExtra = 0;
wndclassx.hInstance = hInstance;
wndclassx.hIcon = 0;
wndclassx.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclassx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclassx.lpszMenuName = NULL;
wndclassx.lpszClassName = _T("ParentWindow");
wndclassx.hIconSm = NULL;
if( !RegisterClassEx(&wndclassx) ) return 0;
wndclassx.cbSize = sizeof(WNDCLASSEX);
wndclassx.style = 0;
wndclassx.lpfnWndProc = ChildProc;
wndclassx.cbClsExtra = 0;
wndclassx.cbWndExtra = 0;
wndclassx.hInstance = hInstance;
wndclassx.hIcon = 0;
wndclassx.hCursor = 0;
wndclassx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclassx.lpszMenuName = NULL;
wndclassx.lpszClassName = _T("ChildWindow");
wndclassx.hIconSm = NULL;
if( !RegisterClassEx(&wndclassx) ) return 0;
if( !(hWnd = CreateWindow(_T("ParentWindow"), _T("Parent Window"), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance,
NULL)) ) return 0;
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
HWND hWnd;
switch ( message )
{
case WM_CREATE:
CreateWindow(_T("ChildWindow"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 100, 100, hwnd, (HMENU)0,
ghInstance, NULL);
break;
case WM_LBUTTONDOWN:
hWnd = GetWindow(hwnd, GW_CHILD);
MoveWindow(hWnd, 10, 10, 200, 200, true);
if( GetUpdateRect(hWnd, NULL, FALSE) ) MessageBeep(-1);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ChildProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
The MSDN doc's is wrong. MoveWindow() with TRUE doesn't call UpdateWindow() as the documentation says. It just invalidates the window client area. If I call UpdateWindow() just after MoveWindow() the program runs as expected.
I tried it myself and WM_PAINT is triggered before the if(GetUpdateRect()) is. Also, GetUpdateRect returns FALSE for me.
I'm running Visual Studio 2008 on XP.
I guess it could depend on what compiler you are using, what operating system that is used and whatnot. According to the code you passed everything is done in the same thread, but if it is a multithreaded program I think that this could inflict some issues as well.