Thank you!
I also have some code that subclasses an edit control to allow it
to use the mouse wheel. This only works with numerical edit boxes
but It does save on keyboard typing. Just click on the control and
scroll the mouse wheel and watch the numbers roll up and down.
If anybody is interested please let me know and I'll be happy to
post the code here!
------------------
Cheers
Announcement
Collapse
No announcement yet.
Custom Controls/Sub Classing
Collapse
X
-
Guest replied
-
-
Compliments Mark,
A nicely done piece of code, we need a custom control expert floating
around here as a lot of people are interested in this type of code
so keep up the good work.
regards,
[email protected]
------------------
Leave a comment:
-
-
Guest repliedHey Jules!
I just remembered these from the MSDN...
Code:CopyRect rc2, rc OffsetRect rc2, 2, 2
and OffsetRect to offse the text RECT. I was using them before to
do what you suggested but I got lazy when I redid the control (smile).
There are a couple of reasons for going with a DLL for my controls.
1. Very easy to update the controls without having to recompile all
the source code.
2. If I want to try a "new look" with my application all I have to
do is change the DLL to one with diffrent button drawing code.
3. Just becuase I wanted to learn about DLL's.
I am really happy that I can finally give somthing back to this
forum instead of always being the one to ask questions!
------------------
Cheers
Leave a comment:
-
-
Mark,
Nice code example to which we can build on, Thank You! The fact you are using it
for your own use 'vs' distributing the DLL, I personally feel that this
would be better served if it was an include file. The code is small, why
have an extra DLL. I have already cut and pasted it into my include
file and made some modifications to it.
To give the button a nicer effect when the button is depressed, offset the
text by a couple of pixels.
<edited, added some more effects to make it look like a real normal button>
<from here you can modify color,font,add bitmap etc, good starting point >
Code:'---------------------------------------------------------------------------- 'rem custom control handler '---------------------------------------------------------------------------- function StrataButtonProc(byval hWnd as long, byval message as long, byval wParam as long, byval lParam as long) export as long local szMessage as asciiz * 64 local ps as PAINTSTRUCT local rc as RECT local rc2 as RECT local hdc as long static fDown as long static fGotFocus as long local pt as POINTAPI select case (message) case %WM_KILLFOCUS 'remove focus band InvalidateRect hWnd, byval %NULL, %TRUE fGotFocus = 0 function = 0 exit function case %WM_MOUSEMOVE pt.x = LOWRD( lParam) pt.y = HIWRD( lParam) 'is the mouse still inside our button while SetCapture if fDown = 1 Then GetClientRect hWnd, rc IF PtInRect( rc, pt.x,pt.y ) = %FALSE THEN ReleaseCapture fDown = 0 InvalidateRect hWnd, byval %NULL, %TRUE End IF end if case %WM_LBUTTONDOWN SetCapture hWnd fDown = 1 fGotFocus = 1 SetFocus hWnd InvalidateRect hWnd, byval %NULL, %TRUE function = 0 exit function case %WM_LBUTTONUP ReleaseCapture fDown = 0 InvalidateRect hWnd, byval %NULL, %TRUE SendMessage GetParent(hWnd), %WM_COMMAND, maklng(GetWindowLong(hWnd,%GWL_ID),%BN_CLICKED), hWnd function = 0 exit function case %WM_ERASEBKGND FUNCTION = 0 EXIT FUNCTION case %WM_PAINT hdc = BeginPaint(hWnd, ps) GetWindowText hWnd, szMessage, sizeof(szMessage) GetClientRect hWnd, rc GetClientRect hWnd, rc2 SelectObject hdc, SendMessage(GetParent(hWnd),%WM_GETFONT,0,0) SetTextColor hdc, GetSysColor(%COLOR_BTNTEXT) SetBkColor hdc, GetSysColor(%COLOR_BTNFACE) FillRect hdc, rc, GetSysColorBrush(%COLOR_BTNFACE) if fDown = 1 Then 'button down rc2.nLeft = rc.nLeft +2 rc2.nTop = rc.nTop +2 DrawText hdc, szMessage, len(szMessage), rc2, %DT_CENTER or %DT_SINGLELINE or %DT_VCENTER DrawEdge hDC, rc, %EDGE_SUNKEN , %BF_RECT else 'button up DrawText hdc, szMessage, len(szMessage), rc, %DT_CENTER or %DT_SINGLELINE or %DT_VCENTER DrawEdge hDC, rc, %EDGE_RAISED , %BF_RECT end if If fGotFocus = 1 Then InflateRect rc,-4,-4 DrawFocusRect hDC,rc End IF EndPaint hWnd, ps function = 0 exit function end select 'rem call default window procedure function = DefWindowProc(hWnd, message, wParam, lParam) end function
Best regards, Jules
mailto:[email protected][email protected]</A>
[This message has been edited by Jules Marchildon (edited November 24, 2000).]
Leave a comment:
-
-
Guest repliedthanks!
*constructive* comments well taken! in our application, screen space
is at a premium so i have to make new controls for every thing in
order to reclame as much space as possible. for example, my button
uses only a single line border verses the normal inner and outer lines.
because this control is only going to be used for its original purpose
i have kept the "styles" and "features" to a minimum. this is my first
crack at custom controls and it seems to be going well. i really
appreciate all the advice i've been given in these forums. i feel
like i should be paying you all tuition fees!
btw: did any of you see my contribution to the source code forum?
"convert vs resource.h files" http://www.powerbasic.com/support/pb...ad.php?t=22838
this utility converts the resource.h files generated by visualstudio
into a powerbasic resource.inc file. i made it because i was sick
of editing every time i made a change. now all i have to do is...
rc [resource.rc]
pbres [resource.res]
makinc [resource.h]
wish: maybe the nice powerbasic people will put this into there compiler?
------------------
cheers
Leave a comment:
-
-
Neat code! However, I have a couple of points for you to ponder... please think of these as *constructive* comments!
1. I don't believe it is necessary to unregister the window class when a thread detaches, and likewise when a thread attaches. Window classes are process-local, not thread-local. Other than those issues, the rest of the code looks fairly thread safe (although I;ve not gone through it thoroughly). You should definitely test any custom control in a multi-threaded app before unleashing it upon the world...
For the lurkers: While Windows automatically unregisters window classes on app termination, it is good that you have handled this in your code because DLL's that register window classes MUST unregister their window classes during process detach under Windows 2000/NT.
2. Your custom control callback returns zero (by default) for several messages - this may or may not need to be addressed.
3. Your control does not support disabled/grayed state.
4. There is no handling for "external" code to query the state of the custom control (ie, query whether the control is Pressed, Normal or Disabled, etc).
5. You could add support for %WM_SETREDRAW - handling this may be overkill, so YMMV.
6. You could add support for double clicks and "pushlike" styles.
7. There is no error checking in your code at all.
8. You are selecting a font into the devioce context during %WM_PAINT but do not restore the original font handle.
9. When painting the button, you could send a %WM_CTLCOLORBUTTON message to the parent window procedure - that way you could allow the user to customize the control's color scheme. Since standard buttons do not actually allow the color scheme to change, you'll add an "important" feature the overcomes the standard buttons' limitation.
I hope that these ideas are of some help. Remember, I said they were *constructive* comments!If you can cater to all of these, you'll have a great custom button control!
PS: did I mention support for BMP images? <cheeky grin!>
------------------
Lance
PowerBASIC Support
mailto:[email protected][email protected]</A>
Leave a comment:
-
-
Guest repliedHello All!
I have already made my custom button control from scratch and here
is the code for it. The big thing is that I wish I didn't have to
select the font or setup the colors each time WM_PAINT rolls around
Code:#compile dll #register none #include "win32api.inc" rem function declares declare function RegisterCustomControls(byval hInstance as long) as long declare function UnregisterCustomControls(byval hInstance as long) as long declare function InitStrataControls() as long rem main dll entry point function LibMain(byval hInstance as long, byval fwdReason as long, byval lpvReserved as long) export as long select case (fwdReason) case %DLL_PROCESS_ATTACH function = RegisterCustomControls(hInstance) case %DLL_PROCESS_DETACH function = UnregisterCustomControls(hInstance) case %DLL_THREAD_ATTACH function = RegisterCustomControls(hInstance) case %DLL_THREAD_DETACH function = UnregisterCustomControls(hInstance) end select end function function InitStrataControls() export as long end function rem register custom classes function RegisterCustomControls(byval hInstance as long) as long local szClassName as asciiz * 80 local wcex as WNDCLASSEX rem setup class name szClassName = "StrataButton" rem setup class structure wcex.cbSize = sizeof(wcex) wcex.style = %CS_HREDRAW or %CS_VREDRAW or %CS_GLOBALCLASS or %CS_PARENTDC wcex.lpfnWndProc = codeptr(StrataButtonProc) wcex.cbClsExtra = 0 wcex.cbWndExtra = 0 wcex.hInstance = hInstance wcex.hIcon = %NULL wcex.hIconSm = %NULL wcex.hCursor = LoadCursor(%NULL, byval %IDC_ARROW) wcex.hbrBackground = %COLOR_APPWORKSPACE wcex.lpszClassName = varptr(szClassName) wcex.lpszMenuName = %NULL rem register control class function = RegisterClassEx(wcex) end function rem unregister custom classes function UnregisterCustomControls(byval hInstance as long) as long local szClassName as asciiz * 80 rem setup class name szClassName = "StrataButton" rem unregister control classes function = UnregisterClass(szClassName, hInstance) end function rem custom control handler function StrataButtonProc(byval hWnd as long, byval message as long, byval wParam as long, byval lParam as long) export as long local szMessage as asciiz * 64 local ps as PAINTSTRUCT local rc as RECT local hdc as long select case (message) case %WM_LBUTTONDOWN SetCapture hWnd SetWindowLong hWnd, %GWL_USERDATA, %TRUE InvalidateRect hWnd, byval %NULL, %TRUE exit function case %WM_LBUTTONUP ReleaseCapture SetWindowLong hWnd, %GWL_USERDATA, %FALSE InvalidateRect hWnd, byval %NULL, %TRUE SendMessage GetParent(hWnd), %WM_COMMAND, maklng(GetWindowLong(hWnd,%GWL_ID),%BN_CLICKED), hWnd exit function case %WM_PAINT hdc = BeginPaint(hWnd, ps) GetWindowText hWnd, szMessage, sizeof(szMessage) GetClientRect hWnd, rc SelectObject hdc, SendMessage(GetParent(hWnd),%WM_GETFONT,0,0) SetTextColor hdc, GetSysColor(%COLOR_BTNTEXT) SetBkColor hdc, GetSysColor(%COLOR_BTNFACE) FillRect hdc, rc, GetSysColorBrush(%COLOR_BTNFACE) DrawText hdc, szMessage, len(szMessage), rc, %DT_CENTER or %DT_SINGLELINE or %DT_VCENTER if GetWindowLong(hWnd,%GWL_USERDATA) then DrawEdge hDC, rc, %BDR_SUNKENINNER, %BF_RECT else DrawEdge hDC, rc, %BDR_RAISEDINNER, %BF_RECT end if EndPaint hWnd, ps exit function end select rem call default window procedure function = DefWindowProc(hWnd, message, wParam, lParam) end function
Does anybody have any pointers for me on this code?
------------------
Cheers
Leave a comment:
-
-
Mark,
I can post you the code for subclassing a windows control but I have a toy
on my web site that does it correctly so a download of about 12k will solve
that one.
http://www.pbq.com.au/home/hutch/pbdll50.htm
The file is subclass.zip
For a button replacement control, starting from scratch is a lot more
profitable where modifying an existing control (superclassing) definitely
has its limitations.
CreateWindowEx() and a normal WndProc style message handling procedure
give you the maximum control when designing custom controls. The main trick
is to use the extra window memory to store settings for each control called
from the app that uses it.
You will need to get the swing of SetCapture() / ReleaseCapture() when
handling button up & down states from any of the WM_(mouse) messages but
it is reasonably straight forward stuff. You normally send a WM_COMMAND
message back to the parent so it knows when the button has been pressed
ands you can dial in more or less any variation you want to get the effect
you like.
You have a number of options when drawing the UP and DOWN states of the button,
roll your own GDI line function to frame the window, BitBlt() bmp images
for the 2 states, you can use either DrawText() or TextOut() to display text
on the button face in any color or font you like.
Once you get the swing of this stuff, you have got under the interface of
windows and can do basically anything you like.
Regards,
[email protected]
------------------
Leave a comment:
-
-
Mark,
Since you have Newcomer and Rector hop over to page 225.
Unfortunately, when a control class is set to CS_PARENTDC
the only thing it inherits from the parent class is the clipping
region(client area). What a joke!
This is actually very eay to test using what I like to call lazy
controls(e.g. groupbox). Put the groupbox in a window then use a
large bitmap or large font for its caption. Now select a small
bitmap or font for it caption(do not redraw the entire window just
the groupbox). You should now be left with a messed up window.
------------------
Dominic Mitchell
Leave a comment:
-
-
Guest repliedHello Chris!
I am making a button replacment control and I want the font to be
the same as the dialogs. It states in the Win32 (Rector/Newcomer)
book that each device context has a default font,brush,pen,etc...
so if I use the same DC as the controls parent by specifing
CS_PARENTDC then I should get the same font right? I have tried
the above and it doesn't work.
------------------
Cheers
Leave a comment:
-
-
Mark;
(1) I believe the custom controls do NOT use CS_OWNDC. They use the
parent windows DC which means when you draw into the controls DC
you need to restore the attributes of the DC when you are done.
(2) You should use GetWindowLong to get the controls original
window procedure (callback). If the control was already subclassed
(ie. A tooltip control will subclass controls it is attached to)
you will get the "current" window procedure address, not the original
, but this is proper because if you used GetClassLong to get the
"original" Window procedure, and used it in your subclass routine,
you would "override" any other subclassing that may previously have
implimented. By using GetWindowLong, you can subclass a control multiple
times with no problem.
(3) The original Dialog Editor (that comes with PB) does have
special functions that must be defined in a custom control for
the custom controls to be recognized by the Editor. I do not
know if Visual Studio still supports those functions.
For more info see the book :
Windows Custom Controls
By William Smith and Robert Ward
Published by R&D Publications, Inc.
USA
The book is about 16 bit Windows, but the majority
of info is still the same for 32 bit windows. There
are just a few differences in 32 bit windows.
I couldn't find any books for 32 bit windows about
building custom controls that are not ActiveX, but
simply DLLs.
------------------
Leave a comment:
-
-
Custom Controls/Sub Classing
Hello Everybody!
I have a few questions about windows control classes and
subclassing, so here's the questions.
1. Can I assume that all windows controls (EDIT,BUTTON...) where
created with the class style CS_OWNDC?
2. When subclassing a control is it propper to get the original
controls callback pointer from GetClassLong?
3. Is there any way to get a custom control created with PBDLL
to show up in VisualStudio? I have asked this before but I could
figure out what the answer ment.
------------------
CheersTags: None
-
Leave a comment: