Also thanks to Dominic for the excellent reference to the container control of the textbox and lookup button. The different approaches contributed for DDT and SDK warrant study.
Bob Mechler
Announcement
Collapse
No announcement yet.
Superclassed Ownerdrawn Button
Collapse
X
-
Before I saw your post I came up with this. It seems to work ok. Not sure I needed all the parameters but I did get gradient ownerdrawn buttons.
Code:CASE %WM_DRAWITEM lDisPtr = CBLPARAM IF @lDisPtr.CtlType = %ODT_BUTTON THEN CALL PaintGRLabelBg(CBHNDL,CBCTL,CBWPARAM,CBLPARAM) FUNCTION = %True END IF
Code:SUB PaintGRLabelBg(pCBHNDL&,pCBCTL&,pCBWPARAM&,pCBLPARAM&,pSelected&) LOCAL lZStr AS ASCIIZ * 64 LOCAL Str AS STRING LOCAL V_hFont& LOCAL V_hCtl& LOCAL V_rc AS Rect LOCAL V_hdc& CONTROL GET TEXT pCBHNDL&,pCBCTL& TO Str CONTROL HANDLE pCBHNDL&,pCBCTL& TO V_hCtl& ' get the handle to the control V_hdc& = GetDc(V_hCtl&) ' this paints the actual label body LOCAL Xin AS LONG LOCAL Yin AS LONG DIM vert(1) AS TRIVERTEX DIM gRect AS GRADIENT_RECT GetClientRect V_hCtl&, V_rc Xin = V_rc.nRight - V_rc.nLeft ' don't want to go all the way to the right, or we'll paint over the border Yin = V_rc.nBottom - V_rc.nTop ' don't want to go all the way to the bottom, or we'll paint over the border Temp& = PB_BACK& cRed& = Temp& MOD 256 cGreen& = (Temp& \ 256) MOD 256 cBlue& = ((Temp& \ 256) \ 256) MOD 256 'cRed& = 192 'cGreen& = 192 'cBlue& = 60 vert(0).x = 0 ' start at pixel 2 so we don't paint over the border vert(0).y = 0 ' start at pixel 22 so that we don't paint over the tabs vert(0).Red = SetColor(cRed&) vert(0).Green = SetColor(cGreen&) vert(0).Blue = SetColor(cBlue&) vert(0).Alpha = &h0000 vert(1).x = Xin vert(1).y = Yin vert(1).Red = SetColor(cRed& - 60) vert(1).Green = SetColor(cGreen& - 60) vert(1).Blue = SetColor(cBlue& - 60) vert(1).Alpha = &h0000 gRect.UpperLeft = 0 gRect.LowerRight = 1 RoundRect V_hdc&,V_rc.nLeft - 1,V_rc.nTop - 1,V_rc.nRight + 1,V_rc.nBottom + 1,4,4 GradientFill V_hdc&, vert(0), 2, gRect, 1, %GRADIENT_FILL_RECT_v SelectObject V_hdc&,V_hFontCap& lZstr = Str ' copy the text to the nul terminated string SetBkMode V_hdc&, %Transparent ' set the bg for transparent SetTextColor V_hdc&, %BLACK 'GetSysColor(%COLOR_BTNTEXT) ' set the foreground color to black TextOut V_hdc&, V_rc.nLeft + 4 , V_rc.nTop + 3 , lZStr, LEN (lZStr) 'draw the text END SUB
Leave a comment:
-
I like the idea mentioned about reflecting (forwarding) the WM_DRAWITEM message to the controls window procedure (if superclassed).
ie.
%BM_MyDraw = %WM_USER + 400
Then in response to the WM_DRAWITEM message do this:
Code:CASE %WM_DRAWITEM LOCAL pDI AS DRAWITEMSTRUCT PTR pDI = CBLPARAM IF @pDI.CtlType = %ODT_BUTTON THEN FUNCTION=SendMessage(@pDI.hwnditem, %WM_DRAWITEM, CBWPARAM, CBLPARAM) EXIT FUNCTION END IF
Leave a comment:
-
Originally posted by Dominic Mitchell View PostThis stuff has been discussed at length before, see for example
http://www.powerbasic.com/support/pb...custom+control
Originally posted by Dominic Mitchell View PostIf the control is subclassed/superclassed, and if you don't want to use a container, you can
also use message reflection. That is, the WM_DRAWITEM message is sent from the parent window procedure to the subclassed/superclassed procedure for the control.
Leave a comment:
-
GetClassName
You can test any window handle to see what window class it is. It is a great way to test in WM_DRAWITEM what class generated the message.
member of the DRAWITEMSTRUCT struct. GetClassName fails if the control is superclassed, this
test does not.
Leave a comment:
-
This stuff has been discussed at length before, see for example
http://www.powerbasic.com/support/pb...custom+control
If the control is subclassed/superclassed, and if you don't want to use a container, you can
also use message reflection. That is, the WM_DRAWITEM message is sent from the parent window
procedure to the subclassed/superclassed procedure for the control.
Leave a comment:
-
Code:LOCAL pDI AS DRAWITEMSTRUCT PTR ..... CASE %WM_DRAWITEM pDI = CBLPARAM SELECT CASE @pDI.CtlId CASE %BUTTON_1 CALL ButtonOneProc CASE %BUTTON_2 CALL ButtonTwoProc .....
Leave a comment:
-
Bob,
A very useful API function is:
GetClassName
You can test any window handle to see what window class it is. It is a great way to test in WM_DRAWITEM what class generated the message.
Leave a comment:
-
I like it Chris.
I'll also need to add a test for buttons since WM_DRAWITEM handles ownerdrawing of several other controls.
IF @lDisPtr.CtlType = %ODT_BUTTON for the drawing routine since I also want to owerdraw the tab labels on my tab control.
Bob Mechler
Leave a comment:
-
Bob,
An even simpler method would be to simply write a subroutine which does the drawing for ownerdraw buttons which can be called in the Dialogs WM_DRAWITEM message. That message will only be sent for ownerdraw controls and not other controls.
ie.
Code:CASE %WM_DRAWITEM FUNCTION=MyButtonDrawRoutine(CBWPARAM, CBLPARAM) EXIT FUNCTION
To make it more powerful, have the routine read back the text from the button control (send WM_GETTEXT to the control).
You can parse out the text and embed macros to define the drawing process.
For example embed macros like this:
"My Buttons Text {{RED}}"
By embeding macros in double brackets, you can parse out any macros and leave only the text. This way you can then define the macros for each button, such as colors, font, etc. in the buttons text . This makes it easy to use PBForms to design the dialog. You simply write the buttons text plus macros in the designers text field for the controls.
Leave a comment:
-
ahead and try it for a normal(e.g. BS_PUSHBUTTON) button. I guarantee you are in for a shock.
Shock? No.
Chagrin at forgetting that when you try to "make your own button" control a lot of the info you need to make it act like a button is not readily available? Yes.
While the focus rectangle handling is the same for BS_OWNERDRAW 'standard' buttons and "superclass-created" buttons, with the latter you have to keep track of the "pushed state" yourself, which necessitates processing the WM_LBUTTONUP notification, as well as WM_Keyup/keydown looking for <spacebar> and storing that current pushed state.. as well as send notifications to the parent for some of those actions.
On the plus side, I think its only the pushed state is what you have to monitor, as you can always ask for the size and location (GetWindowRect) and the focused state (compare GetFocus() with this hwnd).
Darned, I should have (but didn't) try BM_GETSTATE message. I wonder if that might not make life easier. I'll try that later today or maybe tomorrow and see if I can post a little baby demo.
Ok, so the button is a bad example. Let's go back to the label, that's a lot cleaner.
MCM
Leave a comment:
-
The container class? Is there an example? I've never used one.
I didn't have any luck using WM_PAINT in the SuperClass of the button or label. It either GPF'd or drew it partially.
There are some really nice examples I've found of gradient buttons (which is what I really want). None of them are superclassed though.
I want to superclass a gradient button in order to give it additional default functionality. One would be to call a function I'll call ValidateForm(param,param,....) which will have the same name in all programs just code that returns the id's of fields not yet matching that program's needs or that it's ready to save the record or do the processing. That way the SuperClassed button will look exactly the same and be reusable by just supplying the location and size.
I'll look for some container class examples next.
Bob Mechler
Leave a comment:
-
When superclassing a control (a new class based on an existing class, which is different than subclassing) you have to be careful in how you process the window procedure messages. You have to make sure you don't work against the original class and how it works.
If you want to build a custom class using ownerdraw, it may be better to build your own custom class (not a superclass) which acts as a container. Then have the container control create the ownerdraw control as a child of itself. Then the container class can handle the ownerdraw messages from its ownerdrawn child control.
So the child control can get messages sent to its container, you can have the container class forward messages to the child control. This way the container could support all the messages of the child.
Leave a comment:
-
Don't use OwnerDraw style and just do it on WM_PAINT in superclass procedure.
This is kind of the whole idea behind superclassing... "It's just like <something> except for (in this case, the WM_PAINT processing).
Go ahead and try it for a normal(e.g. BS_PUSHBUTTON) button. I guarantee you are in for a shock.
Leave a comment:
-
Depends on what you are trying to accomplish with that label.
Not that you can do a hell of a lot with a label anyway, but hey, it's your label.
Leave a comment:
-
Thanks. And probably switch to a Superclassed Label instead of a button, right?
Bob Mechler
Leave a comment:
-
Don't use OwnerDraw style and just do it on WM_PAINT in superclass procedure.
This is kind of the whole idea behind superclassing... "It's just like <something> except for (in this case, the WM_PAINT processing).
No, I have no clue if using 'DDT' is going to interfere with this, but it will work just fine with SDK-style windows.
Leave a comment:
-
Superclassed Ownerdrawn Button
What event in the SuperClass CallBack procedure can be used to draw it?
I know how to use WM_DRAWITEM in a dialog callback. Do owernerdrawn buttons, even if superclassed, have to rely on the parent control's WM_DRAWITEM event?
Bob MechlerTags: None
Leave a comment: