Page 1 of 1
How to Ownerdraw a Windows Frame?
Posted: Thu Mar 08, 2007 12:06 am
by Konne
Hello, I just don't get it. How do I need to use #WM_NCPAINT, so that I can draw the Window Frame by my own. (There shouldn't be flickering at all) Could someone make a very easy example so that I would understand it?
Hope someone can help me.
Thx
Posted: Thu Mar 08, 2007 12:29 am
by netmaestro
I'm not sure I understand exactly what you're trying to accomplish, but there are several approaches to ownerdrawing a window frame/background. Here is an example of one of the easier ways, just to get a dialog started and hopefully inspire some more responses with alternatives:
Code: Select all
CreateImage(0,640,480,32)
captionfont = FontID(LoadFont(#PB_Any,"Tahoma",10,#PB_Font_Bold))
hDC=StartDrawing(ImageOutput(0))
Box(0,0,640,480,#White)
Box(0,0,640,25,#Blue)
DrawIconEx_(hDC,7,6,LoadIcon_(0,#IDI_ASTERISK),16,16,0,0,#DI_NORMAL|#DI_COMPAT)
DrawingFont(captionfont)
DrawText(32,5,"I can draw my own window!",#White,#Blue)
DrawingMode(#PB_2DDrawing_Outlined)
Box(0,0,640,480,#Black)
StopDrawing()
Global hBrush = CreatePatternBrush_(ImageID(0))
OpenWindow(0,0,0,640,480,"",#PB_Window_ScreenCentered|#PB_Window_BorderLess)
CreateGadgetList(WindowID(0))
ButtonGadget(0,617,3,20,20,"X")
SetGadgetFont(0,captionfont)
SetClassLong_(WindowID(0),#GCL_HBRBACKGROUND, hBrush)
InvalidateRect_(WindowID(0),0,1)
Repeat
EventID = WaitWindowEvent()
Select EventID
Case #WM_LBUTTONDOWN
If WindowMouseY(0)<=25
SendMessage_(WindowID(0),#WM_NCLBUTTONDOWN,#HTCAPTION,0)
EndIf
EndSelect
Until EventID = #PB_Event_Gadget And EventGadget() = 0
DeleteObject_(hBrush)
Posted: Thu Mar 08, 2007 12:52 am
by Joakim Christiansen
I also want to draw a custom border but I need the window menu to be inside it, any ideas?
Posted: Thu Mar 08, 2007 8:05 am
by netmaestro
Here's an alternate way you can draw the window frame by responding to WM_NCPAINT:
Code: Select all
Global frame ; Frame region is persistent
Procedure WNDPROC(hwnd, msg, wparam, lparam)
result = #PB_ProcessPureBasicEvents
Select msg
Case #WM_NCPAINT
hdc = GetWindowDC_(hwnd)
hbr=CreateSolidBrush_(#Green)
SelectObject_(hdc, hbr)
PaintRgn_(hdc,frame)
DrawIconEx_(hDC,7,7,LoadIcon_(0,#IDI_ASTERISK),18,18,0,0,#DI_NORMAL|#DI_COMPAT)
SetBkMode_(hdc, #TRANSPARENT)
SetTextColor_(hdc,#Yellow)
TextOut_(hdc, 32,7, @"I can draw my own window frame!", 31)
ReleaseDC_(hwnd, hdc)
DeleteObject_(hbr)
result = 0
Case #WM_ACTIVATEAPP,#WM_MOUSEACTIVATE, #WM_PAINT, #WM_GETICON, #WM_GETTEXT, #WM_NCACTIVATE, #WM_SYSCOMMAND, #WM_SETFOCUS
RedrawWindow_(WindowID(0), 0, frame, #RDW_INVALIDATE|#RDW_FRAME)
EndSelect
ProcedureReturn result
EndProcedure
OpenWindow(0,0,0,320,240,"",#PB_Window_ScreenCentered)
; Create region for frame area only to be updated in WNDPROC
GetWindowRect_(WindowID(0),@wr.RECT)
ww=wr\right-wr\left
hh=wr\bottom-wr\top
x = GetSystemMetrics_(#SM_CXFRAME)
y = GetSystemMetrics_(#SM_CYCAPTION)+GetSystemMetrics_(#SM_CYFRAME)
cright = ww-GetSystemMetrics_(#SM_CXFRAME)
cbottom = hh-GetSystemMetrics_(#SM_CYFRAME)
whole = CreateRectRgn_(0,0,ww,hh)
frame = CreateRectRgn_(0,0,ww,hh)
client = CreateRectRgn_(x,y,cright,cbottom)
CombineRgn_(frame,whole,client,#RGN_XOR)
DeleteObject_(whole)
DeleteObject_(client)
SetWindowCallback(@WNDPROC())
CreateGadgetList(WindowID(0))
ButtonGadget(0,WindowWidth(0)/2-30,WindowHeight(0)-30,60,20,"Close")
Repeat
ev=WaitWindowEvent()
Until ev=#PB_Event_Gadget And EventGadget() = 0
DeleteObject_(frame)
Posted: Thu Mar 08, 2007 10:39 am
by srod
Nice one.

Posted: Thu Mar 08, 2007 11:00 am
by Joakim Christiansen
Sweet, but if you add a menu to it on Vista it fucks up a little

But I think I should be able to fix it so thanks!
Posted: Thu Mar 08, 2007 11:07 am
by Joakim Christiansen
Code: Select all
DrawIconEx_(hDC,5,3,LoadIcon_(0,#IDI_QUESTION),18,18,0,0,#DI_NORMAL|#DI_COMPAT)
SetBkMode_(hdc, #TRANSPARENT)
SetTextColor_(hdc,#White)
TextOut_(hdc, 32,4, @"I can draw my own window frame!", 31)
Code: Select all
x = GetSystemMetrics_(#SM_CXFRAME)-5
y = GetSystemMetrics_(#SM_CYCAPTION)+GetSystemMetrics_(#SM_CYFRAME)-5
cright = ww-GetSystemMetrics_(#SM_CXFRAME)+5
cbottom = hh-GetSystemMetrics_(#SM_CYFRAME)+5
Code: Select all
ButtonGadget(0,WindowWidth(0)/2-30,WindowHeight(0)-60,60,20,"Close")
Just did these changes and it works fine with and without a menu, but I haven't tested on XP yet.
Posted: Thu Mar 08, 2007 11:53 am
by dell_jockey
Joakim,
it works on XP, with minor alignment problems on the right side of the header bar.
Posted: Thu Mar 08, 2007 12:03 pm
by netmaestro
It's just a start really, I'm sure there's more bases to cover yet. But it gets the topic moving anyway. Anyone makes improvements, be sure to post them.
Posted: Thu Mar 08, 2007 12:08 pm
by Joakim Christiansen
dell_jockey wrote:Joakim,
it works on XP, with minor alignment problems on the right side of the header bar.
Developing a program for Vista that looks the same on XP is like developing a web page for IE and make it look the same in FF. I really hate what Microsoft have done...
Posted: Thu Mar 08, 2007 3:29 pm
by Konne
@netmaestro
Wow best exmaple for this I've ever seen. Thx very much.
There is only one question left. What Event is send when the [X] [_] Buttons etc need to be redrawn?
Posted: Fri Mar 09, 2007 4:39 am
by Rook Zimbabwe
NetMaestro I have done did learnt so much from you!
Now to create a few PNGs and a transparent window and frame it than a few image buttons and I will have my own window!!!