Petit exemple d'une solution trouvée suite à cette discussion sur le forum:
http://www.cppfrance.com/infomsg/WS_POPUP-FOCUS-0_730993.aspx
Le but est de créer une listbox dans une autre fenêtre, sans que le fenêtre mère ne perde le focus, en vue d'avoir le même comportement que les bouton annuler/refaire de Office ou Visual Studio
Il y a une fenêtre edit qui permet d'entrer le nombre d'items qui seront présent dans la listbox
Source / Exemple :
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0501
#include <windows.h>
HINSTANCE g_hInst;
HWND g_hWnd, g_hListbox;
char g_szAppName[] = "DropDown";
BOOL g_bCapture = FALSE;
WNDPROC defListboxProc;
#define MAX_ITEMS 10
int __fastcall bnatoi(const char* psz)
{
__asm
{
xor eax, eax
push ebx
xor edx, edx
xor ebx, ebx
cmp byte ptr[ecx], '-'
jne short L1
inc ecx
mov edx, 0xFFFFFFFF
L1:
mov bl, byte ptr[ecx]
cmp bl, '0'
jb short L2
cmp bl, '9'
ja short L2
lea eax, dword ptr[eax + 4 * eax]
sub bl, '0'
add eax, eax
inc ecx
add eax, ebx
jmp short L1
L2:
add eax, edx
pop ebx
xor eax, edx
}
}
LRESULT ListBox_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
POINT pt = {LOWORD(lParam), HIWORD(lParam)};
RECT clientRect, screenRect;
POINT screenMousePos;
GetCursorPos(&screenMousePos);
GetWindowRect(hWnd, &screenRect);
GetClientRect(hWnd, &clientRect);
LRESULT l = 0;
if(PtInRect(&screenRect, screenMousePos))
{
if(pt.x > clientRect.right)
{
// Clic dans la fenêtre, mais en dehors de la zone client
// Donc sur la scollbar
g_bCapture = TRUE; // Car la ListBox va recevoir WM_CAPTURECHANGED, mais il ne faut pas la fermer
// On enlève temporairement la capture
ReleaseCapture();
l = CallWindowProc((WNDPROC)GetWindowLongPtr(hWnd, GWL_WNDPROC),
hWnd,
WM_NCLBUTTONDOWN,
HTVSCROLL,
MAKELPARAM(screenMousePos.x, screenMousePos.y));
SetCapture(hWnd);
g_bCapture = FALSE;
}
return l;
}
else DestroyWindow(hWnd); // Clic à coté de la fenêtre
return 0;
}
LRESULT ListBox_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
int sel, count;
POINT pt;
RECT rect;
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
GetClientRect(hWnd, &rect);
if(PtInRect(&rect, pt) || (wParam & MK_LBUTTON))
{
// On prend les mouvements de la souris quand on est au dessus de la listBox,
// ou quand le bouton gauche de la souris est enfoncé
if(pt.y < 0)
PostMessage(hWnd, WM_VSCROLL, SB_LINEUP, 0);
if(pt.y > rect.bottom)
PostMessage(hWnd, WM_VSCROLL, SB_LINEDOWN, 0);
sel = LOWORD(SendMessage(hWnd, LB_ITEMFROMPOINT, 0, lParam));
SendMessage(hWnd, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, sel));
count = (int)SendMessage(hWnd, LB_GETCOUNT, 0, 0);
if(sel != count - 1)
SendMessage(hWnd, LB_SELITEMRANGE, FALSE, MAKELPARAM(sel + 1, count - 1));
}
return 0;
}
LRESULT CALLBACK ListboxProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int sel;
switch(uMsg)
{
case WM_MOUSEMOVE:
return ListBox_OnMouseMove(hWnd, wParam, lParam);
case WM_LBUTTONDOWN:
return ListBox_OnLButtonDown(hWnd, wParam, lParam);
case WM_KEYDOWN:
switch(wParam)
{
case VK_DOWN:
sel = (int)SendMessage(hWnd, LB_GETSELCOUNT, 0, 0);
SendMessage(hWnd, LB_SETSEL, 1, sel);
break;
case VK_UP:
sel = (int)SendMessage(hWnd, LB_GETSELCOUNT, 0, 0);
SendMessage(hWnd, LB_SETSEL, 1, sel - 1);
SendMessage(hWnd, LB_SETSEL, 0, sel - 1);
break;
case VK_RETURN:
goto ok;
case VK_ESCAPE:
DestroyWindow(hWnd);
break;
}
break;
case WM_LBUTTONUP:
ok:
case WM_CAPTURECHANGED:
if(!g_bCapture)
{
DestroyWindow(hWnd);
g_hListbox = 0;
}
}
return CallWindowProc(defListboxProc, hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK AppWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hEdit;
switch(uMsg)
{
case WM_KEYDOWN:
case WM_MOUSEWHEEL:
if(g_hListbox) PostMessage(g_hListbox, uMsg, wParam, lParam);
break;
case WM_CREATE:
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", 0, WS_VISIBLE | WS_CHILD, 0, 0, 200, 25,
hWnd, (HMENU)1000, g_hInst, 0);
CreateWindowEx(0, "Button", "Test", WS_VISIBLE | WS_CHILD, 200, 0, 100, 25,
hWnd, (HMENU)1001, g_hInst, 0);
break;
case WM_COMMAND:
if(LOWORD(wParam) == 1001)
{
char szitems[32];
GetWindowText(hEdit, szitems, 32);
int nItems = bnatoi(szitems);
if(nItems < 1) return 0;
POINT pt = {200, 25}; // Coordonnées dans la fenêtre mère
// Comme on va mettre le bureau en fenêtre mère, il faut transformer les coordonnées
MapWindowPoints(hWnd, HWND_DESKTOP, &pt, 1);
g_hListbox = CreateWindowEx(WS_EX_TOOLWINDOW, "Listbox", 0,
WS_VSCROLL | WS_BORDER | LBS_HASSTRINGS | LBS_MULTIPLESEL |WS_VISIBLE | WS_CHILD,
pt.x, pt.y, 100, 100, hWnd, 0, g_hInst, 0);
int height = (int)SendMessage(g_hListbox, LB_GETITEMHEIGHT, 0, 0);
if(nItems > MAX_ITEMS) height *= MAX_ITEMS;
else height *= nItems;
SetWindowPos(g_hListbox, 0, 0, 0, 100, height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
SetParent(g_hListbox, HWND_DESKTOP);
for(int i = 0; i < nItems; i++)
SendMessage(g_hListbox, LB_ADDSTRING, 0, (LPARAM)"Chaine d'exemple");
// Donne le focus à la fenêtre principale, pour qu'elle puisse rediriger les
// message vers la listbox (WM_KEYDOWN, WM_WOUSEWHEEL...)
SetFocus(hWnd);
SetCapture(g_hListbox);
defListboxProc = (WNDPROC)SetWindowLongPtr(g_hListbox, GWL_WNDPROC, (LONG_PTR)ListboxProc);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
#ifdef _DEBUG
int main()
#else
#pragma comment(linker, "/entry:myWinMain")
int __stdcall myWinMain()
#endif
{
MSG msg;
g_hInst = GetModuleHandle(0);
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof wcex);
wcex.cbSize = sizeof wcex;
wcex.lpfnWndProc = AppWndProc;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = g_hInst;
wcex.lpszClassName = g_szAppName;
wcex.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
wcex.hCursor = LoadCursor(0, IDC_ARROW);
if(!RegisterClassEx(&wcex)) return 1;
g_hWnd = CreateWindowEx(0, g_szAppName, g_szAppName, WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, g_hInst, 0);
if(!g_hWnd) return 1;
ShowWindow(g_hWnd, SW_NORMAL);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#ifdef _DEBUG
return (int)msg.wParam;
#else
ExitProcess(msg.wParam);
#endif
}
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.