This is a follow up to my previous post. I have 3 statics which I want to change the color on when clicked and maintain it until clicked a second time. The following code will change the color when clicked for each static and all 3 will have the same color until the window loses focus. When the window is restored, only the last clicked window will have the changed color while the others return to their original. Thanks...
.if uMsg==WM_INITDIALOG
invoke Create, hWin ; Creates 3 statics.
invoke CreateSolidBrush, 000FFFFH ; Yellow
mov hBrNorm, eax
invoke CreateSolidBrush, 000FF00h ; Green
mov hBrClk, eax
ret
.elseif uMsg==WM_CTLCOLORSTATIC ; Set backcolor of all statics on load.
mov eax, lParam
.if eax==handle
mov pixel, 000FF00h
mov eax, hBrClk
mov hBrush, eax
.else
invoke GetDC, lParam
invoke GetPixel, eax, 0, 0
cmp eax, pixel
je _bypass
mov eax, hBrNorm
mov hBrush, eax
.endif
invoke SetTextColor,wParam,0
invoke SetBkMode,wParam,TRANSPARENT
mov eax, hBrush
ret
; This point is NEVER reached.
_bypass:
PrintText "Bypassed"
.elseif uMsg==WM_COMMAND
mov ebx, wParam
shr ebx, 16
.if bx==STN_CLICKED
mov eax, lParam
mov handle, eax
invoke InvalidateRect, lParam, NULL, TRUE
.endif
I removed the [SOLVED] from the title, this forum is not a help desk.
I believe that the answer to my own question is that it cannot be done because WM_PAINT is calling WM_ERASEBKGND thereby clearing all but the most recent change. So, what has to happen is that the static has to be saved with its' color. In other words, if I want to maintain the color of more than 1 static, the second static's handle and color must be collected into an arrary (or something) and returned to WM_PAINT via InvalidateRect.
If any pros have a better answer, I would really be interested because this same issue seems to be true for FillRect also. Once the initial messaging is complete, everthing is basically temporary from that point forward. I have not read any documentation to confirm this, but I have made some practical attempts.
A work in progress...
"A static control sends the WM_CTLCOLORSTATIC message to its parent window when the control is about to be drawn". So whatever color your handler is setting should persist.
;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================
IDC_ST1 equ 1001
IDC_ST2 equ 1002
IDC_ST3 equ 1003
;==============================================================================
null EQU NULL
;==============================================================================
.data
hInst dd 0
hWnd dd 0
posx dd 0
posy dd 0
hwndStatic1 dd 0
hwndStatic2 dd 0
hwndStatic3 dd 0
brush1 dd WHITE_BRUSH
brush2 dd LTGRAY_BRUSH
brush3 dd GRAY_BRUSH
wcx WNDCLASSEX <>
msg MSG <>
className db "test_class",0
.code
;==============================================================================
;==============================================================================
WindowProc proc hWin:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
SWITCH uMsg
CASE WM_CREATE
STYLE = WS_CHILD or WS_VISIBLE or SS_CENTER or SS_NOTIFY
invoke CreateWindowEx, WS_EX_CLIENTEDGE,
chr$("STATIC"),
chr$("XXXXX"),
STYLE,
20,
20,
150,
30,
hWin,
IDC_ST1,
hInst,
null
mov hwndStatic1, eax
invoke CreateWindowEx, WS_EX_CLIENTEDGE,
chr$("STATIC"),
chr$("XXXXX"),
STYLE,
20,
70,
150,
30,
hWin,
IDC_ST2,
hInst,
null
mov hwndStatic2, eax
invoke CreateWindowEx, WS_EX_CLIENTEDGE,
chr$("STATIC"),
chr$("XXXXX"),
STYLE,
20,
120,
150,
30,
hWin,
IDC_ST3,
hInst,
null
mov hwndStatic3, eax
CASE WM_CTLCOLORSTATIC
SWITCH lParam
CASE hwndStatic1
invoke SetTextColor, wParam, 0ff0000h
invoke SetBkMode, wParam, TRANSPARENT
invoke GetStockObject, brush1
ret
CASE hwndStatic2
invoke SetTextColor, wParam, 0ff0000h
invoke SetBkMode, wParam, TRANSPARENT
invoke GetStockObject, brush2
ret
CASE hwndStatic3
invoke SetTextColor, wParam, 0ff0000h
invoke SetBkMode, wParam, TRANSPARENT
invoke GetStockObject, brush3
ret
ENDSW
CASE WM_COMMAND
mov eax, wParam
movzx eax, ax
SWITCH eax
CASE IDCANCEL
invoke DestroyWindow, hWin
CASE IDC_ST1
SWITCH brush1
CASE WHITE_BRUSH
mov brush1, LTGRAY_BRUSH
CASE LTGRAY_BRUSH
mov brush1, GRAY_BRUSH
CASE GRAY_BRUSH
mov brush1, WHITE_BRUSH
ENDSW
invoke InvalidateRect, hwndStatic1, null, TRUE
CASE IDC_ST2
SWITCH brush2
CASE WHITE_BRUSH
mov brush2, LTGRAY_BRUSH
CASE LTGRAY_BRUSH
mov brush2, GRAY_BRUSH
CASE GRAY_BRUSH
mov brush2, WHITE_BRUSH
ENDSW
invoke InvalidateRect, hwndStatic2, null, TRUE
CASE IDC_ST3
SWITCH brush3
CASE WHITE_BRUSH
mov brush3, LTGRAY_BRUSH
CASE LTGRAY_BRUSH
mov brush3, GRAY_BRUSH
CASE GRAY_BRUSH
mov brush3, WHITE_BRUSH
ENDSW
invoke InvalidateRect, hwndStatic3, null, TRUE
ENDSW
CASE WM_CLOSE
invoke DestroyWindow, hWin
CASE WM_DESTROY
invoke PostQuitMessage, NULL
return 0
DEFAULT
invoke DefWindowProc, hWin, uMsg, wParam, lParam
ret
ENDSW
return 0
WindowProc endp
;==============================================================================
start:
;==============================================================================
mov hInst, rv(GetModuleHandle, NULL)
mov wcx.cbSize, sizeof WNDCLASSEX
mov wcx.style, CS_HREDRAW or CS_VREDRAW \
or CS_BYTEALIGNWINDOW
mov wcx.lpfnWndProc, offset WindowProc
mov wcx.cbClsExtra, NULL
mov wcx.cbWndExtra, NULL
m2m wcx.hInstance, hInst
mov wcx.hbrBackground, COLOR_BTNFACE + 1
mov wcx.lpszMenuName, NULL
mov wcx.lpszClassName, offset className
mov wcx.hIcon, rv(LoadIcon, NULL, IDI_APPLICATION)
mov wcx.hCursor, rv(LoadCursor, NULL, IDC_ARROW)
mov wcx.hIconSm, 0
invoke RegisterClassEx, addr wcx
;--------------------------------------------------------------
; Specify the window width and height and calc the coordinates
; necessary to center the window on the screen.
;--------------------------------------------------------------
WW = 200
WH = 200
invoke GetSystemMetrics, SM_CXSCREEN
shr eax, 1
sub eax, WW / 2
mov posx, eax
invoke GetSystemMetrics, SM_CYSCREEN
shr eax, 1
sub eax, WH / 2
mov posy, eax
invoke CreateWindowEx, WS_EX_OVERLAPPEDWINDOW,
addr className,
chr$("Test"),
WS_OVERLAPPED or WS_SYSMENU,
posx, posy, WW, WH,
null, null,
null, null
mov hWnd, eax
invoke ShowWindow, hWnd, SW_SHOWDEFAULT
invoke UpdateWindow, hWnd
msgLoop:
invoke GetMessage, addr msg, NULL, 0, 0
.if eax != 0
invoke IsDialogMessage, hWnd, addr msg
.if eax == 0
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
.endif
jmp msgLoop
.ENDIF
exit msg.wParam
;==============================================================================
end start
Thanks again MichaelW. Apparently I keep getting my ducks out of line. Looks like I was trying to make things happen to quickly and failed to notice that I had to be working with single objects instead of a group. MASM is not VB and I have to remember that. Don't go anywhere, I will be back in the ditch again.
Thanks to MichaelW, this is the final code I came up with. The controls are not spelled out in the code thereby making it possible to add more without modification. This code can be condensed more if desired by making a loop to create the statics and puting the handles and IDs into arrays. Any and all comments welcome.
.386
;.model flat,stdcall
option casemap:none
include \masm32\include\masm32rt.inc
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
.const
styleex dd WS_EX_CLIENTEDGE or WS_EX_DLGMODALFRAME
style dd WS_OVERLAPPEDWINDOW
IDC_STC1 equ 1 ; Value is used to index aColor array,
IDC_STC2 equ 2 ; just keep adding in succession.
IDC_STC3 equ 3
.data
ClassName db 'DLGCLASS',0
AppName db 'Change color',0
AboutMsg db 'MASM32 RadASM Dialog as main',13,10,'Copyright © MASM32 2001',0
.data?
hInstance dd ?
CommandLine dd ?
posx dd ?
posy dd ?
hIDC_STC1 HWND ?
hIDC_STC2 HWND ?
hIDC_STC3 HWND ?
hBrushBlue dd ?
hBrushGreen dd ?
hBrushRed dd ?
hBrushYellow dd ?
hDC dd ?
color dd ?
aColor dd 4 dup (?) ; Increase by 1 for each static.
index dd ? ; Keeps track of esi.
.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke GetCommandLine
invoke InitCommonControls
mov CommandLine,eax
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax
;=====================================================================================
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
; Code by MichaelW...
WW = 200
WH = 200
invoke GetSystemMetrics, SM_CXSCREEN
shr eax, 1
sub eax, WW / 2
mov posx, eax
invoke GetSystemMetrics, SM_CYSCREEN
shr eax, 1
sub eax, WH / 2
mov posy, eax
invoke CreateWindowEx,styleex,ADDR ClassName,ADDR AppName,\
style,posx,\
posy,WW,WH,NULL,NULL,\
NULL,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.while TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.break .if (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain endp
;=====================================================================================
CreateStatics proc hWin:DWORD
; Code by MichaelW...
; Keep adding statics here:
STYLE = WS_CHILD or WS_VISIBLE or SS_CENTER or SS_NOTIFY
invoke CreateWindowEx, WS_EX_CLIENTEDGE, chr$("STATIC"), chr$("XXXXX"), STYLE,\
20, 20, 150, 30, hWin, IDC_STC1, hInstance, NULL
mov hIDC_STC1, eax
invoke CreateWindowEx, WS_EX_CLIENTEDGE, chr$("STATIC"), chr$("XXXXX"), STYLE,\
20, 70, 150, 30, hWin, IDC_STC2, hInstance, NULL
mov hIDC_STC2, eax
invoke CreateWindowEx, WS_EX_CLIENTEDGE, chr$("STATIC"), chr$("XXXXX"), STYLE,\
20, 120, 150, 30, hWin, IDC_STC3, hInstance, NULL
mov hIDC_STC3, eax
ret
CreateStatics endp
;=====================================================================================
WndProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
SWITCH uMsg
CASE WM_CREATE
invoke CreateStatics, hWin
mov hIDC_STC1, rv(GetDlgItem, hWin, IDC_STC1)
mov hIDC_STC2, rv(GetDlgItem, hWin, IDC_STC2)
mov hBrushBlue, rv(CreateSolidBrush, 0FF0000h)
mov hBrushGreen, rv(CreateSolidBrush, 000FF00h)
mov hBrushRed, rv(CreateSolidBrush, 00000FFh)
mov hBrushYellow, rv(CreateSolidBrush, 000FFFFh)
mov esi, offset aColor ; 1 based array to hold the color.
push esi
pop index ; Index to colors for individual statics.
mov eax, hBrushYellow ; Going to initialize all statics to yellow.
mov ecx, 3 ; Number of statics to initialize.
_addStatic:
add esi, 4 ; Static IDs are 1 based.
mov [esi], eax
loop _addStatic
ret
CASE WM_COMMAND
invoke GetDlgCtrlID, lParam
mov ebx, 4
mul ebx
mov esi, offset aColor
add esi, eax
mov index, esi
sub index, 4
; Required because the statics are not defined in the code.
mov hDC, rv(GetDC, lParam)
invoke GetPixel, hDC, 10, 10
; Rotate the colors.
SWITCH EAX
CASE 0FF0000h
push hBrushGreen
pop color
CASE 000FF00h
push hBrushRed
pop color
CASE 00000FFh
push hBrushYellow
pop color
CASE 000FFFFh
push hBrushBlue
pop color
ENDSW
mov eax, color
mov [esi], eax
invoke InvalidateRect, lParam, NULL, TRUE
ret
CASE WM_SETFOCUS ; Need to point the statics to the user colors;
mov esi, offset aColor ; otherwise they revert to system colors.
mov index, esi
CASE WM_CTLCOLORSTATIC ; Colors all statics on load.
invoke SetBkMode, wParam, TRANSPARENT
add index, 4 ; Set esi for 1 based index.
mov esi, index
mov eax, [esi]
ret
CASE WM_CLOSE
invoke DeleteObject, hBrushBlue
invoke DeleteObject, hBrushGreen
invoke DeleteObject, hBrushRed
invoke DeleteObject, hBrushYellow
invoke DestroyWindow,hWin
CASE WM_DESTROY
invoke PostQuitMessage,NULL
DEFAULT
invoke DefWindowProc,hWin,uMsg,wParam,lParam
ret
ENDSW
xor eax,eax
ret
WndProc endp
;=====================================================================================
end start