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 :P
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!!!