Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Resize Borderless form

Status
Not open for further replies.

stefanodam78

Programmer
Mar 1, 2014
9
IT
Hi,
I need to resize a borderless form , I used the bindevent command on WM_NCHITTEST . But the resize does not work properly, it always run the resize bottomright even if I drag one of the edges ...
I return the correct value of WM_NCHITTEST but always starts the same resize ...
BorderStyle property is 3 otherwise does not resize (vfp problem)
I remove the border by changing the style of the form (WS_THICKFRAME off)

Example
shape1 identifies the virtual edge
x1 and y1 identify the coordinates of the form than the screen

proc NCHitTestCallback
LPARAMETERS Hwnd , uMsg , wParam , lParam
    LOCAL nXCoord , nYCoord , NRET
    
    * Low -order word : cursor x - coordinates
    nXCoord = BITAND ( m.lParam , 0x0000FFFF ) - this.x1
    * High -order word : cursor y- coordinates
    nYCoord = BITRSHIFT ( BITAND ( m.lParam , 0xFFFF0000 ) , 16) - this.y1
* Bottom edge
    IF !( m.nXCoord < this.shape1.Left OR m.nXCoord > this.shape1.Left + this.shape1.Width OR;
         m.nYCoord < this.shape1.top OR m.nYCoord > this.shape1.top + this.shape1.height )
         RETURN 15
    endif
RETURN CallWindowProc ( THIS.hOrigProc , m.Hwnd , m.uMsg , m.wParam , m.lParam )

Dest regards
(sorry for my english :) )
 
> it always run the resize bottomright even if I drag one of the edges

Well,you only have one NCHitTestCallback, you have to find out which edge or corner was dragged. I don't see your code even trying to determine that.

>BorderStyle property is 3 otherwise does not resize
You can always setform.width and height

How about this solution?
thread184-1034603

Bye, Olaf.
 
> it always run the resize bottomright even if I drag one of the edges

Well,you only have one NCHitTestCallback, you have to find out which edge or corner was dragged. I don't see your code even trying to determine that.

>BorderStyle property is 3 otherwise does not resize
You can always setform.width and height

How about this solution?
thread184-1034603

Bye, Olaf.
 
> it always run the resize bottomright even if I drag one of the edges

Well,you only have one NCHitTestCallback, you have to find out which edge or corner was dragged. I don't see your code even trying to determine that.

>BorderStyle property is 3 otherwise does not resize
You can always setform.width and height

How about this solution?
thread184-1034603

Bye, Olaf.
 
Thank you for your replay

Try this...

Public myForm
myForm = Createobject("myForm")
myForm.Show

Define Class myForm As Form
TitleBar=0
BorderStyle=3
x1=0
y1=0
hOrigProc = 0

Add Object btnClose As CommandButton With Caption="Close"

Procedure btnClose.Click()
Unbindevents(Thisform.HWnd, 0x0084)
Thisform.Release()

Procedure Init()

This.btnClose.Move(5,35)

Declare Integer GetWindowRect In user32;
INTEGER hWindow,;
STRING @lpRect
Declare Integer CallWindowProc In user32;
INTEGER lpPrevWndFunc, Integer hWindow, Long Msg,;
INTEGER wParam, Integer Lparam
Declare Integer GetWindowLong In user32;
INTEGER HWnd, Integer nIndex

Declare Integer SetWindowLong In user32;
INTEGER HWnd,;
INTEGER nIndex,;
INTEGER dwNewLong

Declare Integer SetWindowPos In user32;
INTEGER HWnd,;
INTEGER hWndInsertAfter,;
INTEGER x,;
INTEGER Y,;
INTEGER cx,;
INTEGER cy,;
INTEGER wFlags

*--- Remove Border
#Define GWL_STYLE -16
nStyle = GetWindowLong(This.HWnd,;
GWL_STYLE)
#Define WS_THICKFRAME 0x00040000
= SetWindowLong(This.HWnd, GWL_STYLE ,;
BITAND(m.nStyle, Bitnot(WS_THICKFRAME)))
#Define HWND_TOP 0
#Define SWP_FRAMECHANGED 0x0020
SetWindowPos(This.HWnd, HWND_TOP, This.Left, This.Top, This.Width, This.Height, SWP_FRAMECHANGED)

#Define GWL_WNDPROC -4
This.hOrigProc = GetWindowLong(This.HWnd, GWL_WNDPROC)

Bindevent(This.HWnd, 0x0084, This, 'NCHitTestCallback', 6)
Endproc

Procedure NCHitTestCallback
Lparameters HWnd, uMsg, wParam, Lparam
Local nXCoord, nYCoord, nRet

#Define CaptionHeight 30
#Define BorderWidth 5

cBuffer = Replicate(Chr(0), 16)
GetWindowRect( This.HWnd, @cBuffer )

This.x1 = CToBin( Substr(cBuffer, 1, 4),"SR" )
This.y1= CToBin( Substr(cBuffer, 5, 4),"SR" )

* low-order word: cursor x-coordinate
nXCoord = Bitand(m.lParam, 0x0000ffff) - This.x1
* high-order word: cursor y-coordinate
nYCoord = Bitrshift(Bitand(m.lParam, 0xffff0000), 16) - This.y1

*--- TopLeft corner
If m.nYCoord>=0 And m.nYCoord<=BorderWidth And m.nXCoord>=0 And m.nXCoord<=BorderWidth
Return 13 &&HTTOPLEFT
Endif
*--- TopRight corner
If m.nYCoord>=0 And m.nYCoord<=BorderWidth And m.nXCoord>=This.Width-BorderWidth And m.nXCoord<=This.Width
Return 14 &&HTTOPRIGHT
Endif
*--- BottomLeft corner
If m.nYCoord>=This.Height-BorderWidth And m.nYCoord<=This.Height And m.nXCoord>=0 And m.nXCoord<=BorderWidth
Return 16&&HTBOTTOMLEFT
Endif
*--- BottomRight corner
If m.nYCoord>=This.Height-BorderWidth And m.nYCoord<=This.Height And m.nXCoord>=This.Width-BorderWidth And m.nXCoord<=This.Width
Return 17 &&HTBOTTOMRIGHT
Endif

*--- Top Border
If m.nYCoord>=0 And m.nYCoord<=BorderWidth
Return 12 &&HTTOP
Endif

*--- Left Border
If m.nXCoord>=0 And m.nXCoord<=BorderWidth
Return 10 &&HTLEFT
Endif

*--- Bottom Border
If m.nYCoord>=This.Height-BorderWidth And m.nYCoord<=This.Height
Return 15 &&HTBOTTOM
Endif

*--- Right Border
If m.nXCoord>=This.Width-BorderWidth And m.nXCoord<=This.Width
Return 10 &&HTLEFT
Endif

*--- Caption
If m.nYCoord>=BorderWidth And m.nYCoord<=CaptionHeight
Return 2 &&HTCAPTION
Endif

Return CallWindowProc(This.hOrigProc, HWnd,;
m.uMsg, m.wParam, m.lParam)

I drag any corner or edge ... always the same result ... bottomright resize :(
 
Right border must be 11 &&HTRIGHT... sorry
...however it does not work [thumbsdown]
 
Yes and no. The form always is resized, but your code returns 10 &&HTLEFT. This has not the effect you think it should have.

Read
It has the return values you mention. But it's documenting the return values of a call to DefWindowProc. That is, if you would call into DefWindowProc, you'd get these return values. Returning any of this value will not trigger the form resize differently than a bottom right resize.

It's not working the way you think, but it's not there to let the window resize in different ways, as far as I see. Why still stuck with this?

Bye, Olaf.
 
I solved my problem [thumbsup2]

WM_NCLBUTTONDOWN is catched by vfp, I solved the problem by using DefWindowProc. I now have to handle WM_SETCURSOR message... :)

Code:
Public myForm
myForm = Createobject("myForm")
myForm.Show

Define Class myForm As Form
    TitleBar=0
    BorderStyle=3
    x1=0
    y1=0
    hOrigProc = 0

    Add Object btnClose As CommandButton With Caption="Close"

    Procedure btnClose.Click()
        Unbindevents(Thisform.HWnd, 0x0084)
        Unbindevents(Thisform.HWnd, 0xA1)
        Thisform.Release()

    Procedure Init()

        This.btnClose.Move(5,35)

        Declare Integer GetWindowRect In user32;
            INTEGER hWindow,;
            STRING @lpRect
        Declare Integer CallWindowProc In user32;
            INTEGER lpPrevWndFunc, Integer hWindow, Long Msg,;
            INTEGER wParam, Integer Lparam
        Declare Integer GetWindowLong In user32;
            INTEGER HWnd, Integer nIndex

        Declare Integer SetWindowLong In user32;
            INTEGER HWnd,;
            INTEGER nIndex,;
            INTEGER dwNewLong

        Declare Integer SetWindowPos In user32;
            INTEGER HWnd,;
            INTEGER hWndInsertAfter,;
            INTEGER x,;
            INTEGER Y,;
            INTEGER cx,;
            INTEGER cy,;
            INTEGER wFlags

        Declare Integer DefWindowProc In user32;
            LONG HWnd,;
            LONG Msg,;
            INTEGER wParam,;
            INTEGER Lparam

        *--- Remove Border
        #Define GWL_STYLE -16
        nStyle = GetWindowLong(This.HWnd,;
            GWL_STYLE)
        #Define WS_THICKFRAME 0x00040000
        = SetWindowLong(This.HWnd, GWL_STYLE ,;
            BITAND(m.nStyle, Bitnot(WS_THICKFRAME)))
        #Define HWND_TOP 0
        #Define SWP_FRAMECHANGED 0x0020
        SetWindowPos(This.HWnd, HWND_TOP, This.Left, This.Top, This.Width, This.Height, SWP_FRAMECHANGED)

        #Define GWL_WNDPROC -4
        This.hOrigProc = GetWindowLong(This.HWnd, GWL_WNDPROC)

        Bindevent(This.HWnd, 0x0084, This, 'NCHitTestCallback', 6)
        #Define WM_NCLBUTTONDOWN 0xA1
        Bindevent(This.HWnd, 0xA1, This, 'NCLButtonDownCallback', 6)
    Endproc

    Procedure NCLButtonDownCallback
        Lparameters HWnd, uMsg, wParam, Lparam
        Return DefWindowProc(m.HWnd, m.uMsg, m.wParam, m.lParam)

    Procedure NCHitTestCallback
        Lparameters HWnd, uMsg, wParam, Lparam
        Local nXCoord, nYCoord, nRet

        #Define CaptionHeight 30
        #Define BorderWidth 5

        cBuffer = Replicate(Chr(0), 16)
        GetWindowRect( This.HWnd, @cBuffer )

        This.x1 = CToBin( Substr(cBuffer, 1, 4),"SR" )
        This.y1= CToBin( Substr(cBuffer, 5, 4),"SR" )

        * low-order word: cursor x-coordinate
        nXCoord = Bitand(m.lParam, 0x0000ffff) - This.x1
        * high-order word: cursor y-coordinate
        nYCoord = Bitrshift(Bitand(m.lParam, 0xffff0000), 16) - This.y1

        *--- TopLeft corner
        If m.nYCoord>=0 And m.nYCoord<=BorderWidth And m.nXCoord>=0 And m.nXCoord<=BorderWidth
            Return 13 &&HTTOPLEFT
        Endif
        *--- TopRight corner
        If m.nYCoord>=0 And m.nYCoord<=BorderWidth And m.nXCoord>=This.Width-BorderWidth And m.nXCoord<=This.Width
            Return 14 &&HTTOPRIGHT
        Endif
        *--- BottomLeft corner
        If m.nYCoord>=This.Height-BorderWidth  And m.nYCoord<=This.Height And m.nXCoord>=0 And m.nXCoord<=BorderWidth
            Return 16&&HTBOTTOMLEFT
        Endif
        *--- BottomRight corner
        If m.nYCoord>=This.Height-BorderWidth  And m.nYCoord<=This.Height And m.nXCoord>=This.Width-BorderWidth And m.nXCoord<=This.Width
            Return 17 &&HTBOTTOMRIGHT
        Endif

        *--- Top Border
        If m.nYCoord>=0 And m.nYCoord<=BorderWidth
            Return 12 &&HTTOP
        Endif

        *--- Left Border
        If m.nXCoord>=0 And m.nXCoord<=BorderWidth
            Return 10 &&HTLEFT
        Endif

        *--- Bottom Border
        If m.nYCoord>=This.Height-BorderWidth  And m.nYCoord<=This.Height
            Return 15 &&HTBOTTOM
        Endif

        *--- Right Border
        If m.nXCoord>=This.Width-BorderWidth And m.nXCoord<=This.Width
            Return 11 &&HTRIGHT
        Endif

        *--- Caption
        If m.nYCoord>=BorderWidth And m.nYCoord<=CaptionHeight
            Return 2 &&HTCAPTION
        Endif

        Return CallWindowProc(This.hOrigProc, HWnd,;
            m.uMsg, m.wParam, m.lParam)
ENDDEFINE
 
> I now have to handle WM_SETCURSOR message... :)

Well, you rather would need to send this message, to change the cursor to illustrate the resize type.

Code:
DECLARE INTEGER SendMessage IN user32;
    INTEGER hWnd,;
    INTEGER Msg,;
    INTEGER wParam,;
    INTEGER lParam

Otherwise the example already is usable, yes.
Has already been done his way, too:
What's so wrong with normal windows forms? On what Windows version are you? Win8? Missing aero style? Want to emulate Win8 app style? WPF?

Bye, Olaf.
 
I need create custom caption forms, Win8 style may be an idea... :)
My problem with the resize and mousepointer I solved in this way:

BorderStyle=0 &&Mousepointer is corrent now (I remove the WS_THICKFRAME code)
...
#Define WM_NCLBUTTONDOWN 0x00A1
Bindevent(This.HWnd, WM_NCLBUTTONDOWN, This, 'NCLButtonDownCallback') &&Work resize
...

Procedure NCLButtonDownCallback
Lparameters HWnd, uMsg, wParam, Lparam
CallWindowProc(This.hOrigProc, m.HWnd, m.uMsg, m.wParam, m.lParam) &&For activate form on click
= ReleaseCapture()
* Complete left click by sending 'left button up' message
= SendMessage(m.HWnd, 0x00A2, 0x0, 0x0)
RETURN DefWindowProc(m.HWnd, m.uMsg, m.wParam, m.lParam)
...

within a few days I could post my class code :)

Thank you Olaf for your help
 
Well, up to now your code does not change the mouse pointer to resize arrows. I updated with the additional code you provided.

If it's all about custom captions only, you could do this using gdiplus to draw within the title bar. Samples are in the solution samples application.

No need to reinvent the wheel, still. But if it's fun to you.

It's fine anyway, to share this.

Bye, Olaf.
 
A solution of this kind gives me a lot more power... I can handle that part of the form is enabled to control the window and I have no problems with the textbox using the valid (like in my sample, valid check doesn't fire when I click on caption)
I can insert vfp controls in my caption, like DWM (Vista style)

Code:
Public myForm
myForm = Createobject("myForm")
myForm.Show

Define Class myForm As Form
    TitleBar=0
    BorderStyle=0
    hOrigProc = 0
    BackColor=Rgb(255,255,255)
    bNCLBtn = .T.
    nBorderWidth = 5
    Caption  = "MyForm"

    Add Object btnClose As CommandButton With Caption="Close"
    Add Object TextChk As TextBox
    Add Object oCaption As Shape With BorderStyle=0
    Add Object LblCaption As Label With BackStyle=0, Top = 6, Left=10, FontSize=10, FontName="Arial"

    Procedure TextChk.Valid
        If Empty(This.Value)
            Messagebox("Is empty")
            Return 0
        Endif

    Procedure btnClose.Click()
        Unbindevent(Thisform.HWnd)
        Thisform.Release()

    Procedure Init()
        This.btnClose.Move(5,35)
        This.TextChk.Move(200,35)
        This.oCaption.Move(0,5,This.Width,20)
        This.oCaption.Anchor=11

        Declare Integer GetWindowRect In user32;
            INTEGER hWindow,;
            STRING @lpRect
        Declare Integer CallWindowProc In user32;
            INTEGER lpPrevWndFunc, Integer hWindow, Long Msg,;
            INTEGER wParam, Integer Lparam
        Declare Integer GetWindowLong In user32;
            INTEGER HWnd, Integer nIndex

        Declare Integer DefWindowProc In user32;
            LONG HWnd,;
            LONG Msg,;
            INTEGER wParam,;
            INTEGER Lparam

        Declare Integer ReleaseCapture In user32
        Declare Long SendMessage In WIN32API ;
            Long HWnd, Long wMsg, Long wParam, Long Lparam

        Declare SHORT PostMessage In user32;
            INTEGER   HWnd,;
            INTEGER   Msg,;
            Long      wParam,;
            Long      Lparam

        Declare Integer GetFocus In user32

        #Define GWL_WNDPROC -4

        This.hOrigProc = GetWindowLong(This.HWnd, GWL_WNDPROC)
        Bindevent(Thisform.HWnd , 0x0084, Thisform, 'NCHitTestCallback', 6)
        #Define WM_NCLBUTTONDOWN 0x00A1
        Bindevent(This.HWnd, WM_NCLBUTTONDOWN, This, 'NCLButtonDownCallback')
        Bindevent(This, "Caption", This, "OnCaption")
        *--- Border
        This.AddObject("oBorderTop", "my_Border", 0)
        This.AddObject("oBorderLeft", "my_Border", 1)
        This.AddObject("oBorderRight", "my_Border", 2)
        This.AddObject("oBorderBottom", "my_Border", 3)
        This.OnCaption()
    Endproc

    Procedure OnCaption()
        This.LblCaption.Caption=This.Caption
    Endproc

    Procedure NCLButtonDownCallback
        Lparameters HWnd, uMsg, wParam, Lparam
        If This.bNCLBtn
            This.bNCLBtn = .F.
            nRet = CallWindowProc(This.hOrigProc, m.HWnd, m.uMsg, m.wParam, m.lParam)
            *--- If Focused
            If m.HWnd==GetFocus()
                This.bNCLBtn = .F.
                = ReleaseCapture()
                * Complete left click by sending 'left NC button up' message
                = SendMessage(m.HWnd, 0x202, m.wParam, m.lParam)
                *--- Metto nella coda nuovamente WM_NCLBUTTONDOWN per eseguire la DefWindowProc
                = PostMessage(m.HWnd, m.uMsg, m.wParam, m.lParam)
            Endif
        Else
            This.bNCLBtn = .T.
            nRet =DefWindowProc(m.HWnd, m.uMsg, m.wParam, m.lParam)
        Endif
        Return nRet

    Procedure NCHitTestCallback
        Lparameters HWnd, uMsg, wParam, Lparam
        Local nXCoord, nYCoord, nRet, cBuffer

        cBuffer = Replicate(Chr(0), 16)
        GetWindowRect( This.HWnd, @cBuffer )
        * low-order word: cursor x-coordinate
        nXCoord = Bitand(m.lParam, 0x0000ffff) - CToBin( Substr(cBuffer, 1, 4),"SR" )
        * high-order word: cursor y-coordinate
        nYCoord = Bitrshift(Bitand(m.lParam, 0xffff0000), 16) - CToBin( Substr(cBuffer, 5, 4),"SR" )

        *--- TopLeft corner
        If m.nYCoord>=0 And m.nYCoord<=This.nBorderWidth And m.nXCoord>=0 And m.nXCoord<=This.nBorderWidth
            Return 13 &&HTTOPLEFT
        Endif
        *--- TopRight corner
        If m.nYCoord>=0 And m.nYCoord<=This.nBorderWidth And m.nXCoord>=This.Width-This.nBorderWidth And m.nXCoord<=This.Width
            Return 14 &&HTTOPRIGHT
        Endif
        *--- BottomLeft corner
        If m.nYCoord>=This.Height-This.nBorderWidth  And m.nYCoord<=This.Height And m.nXCoord>=0 And m.nXCoord<=This.nBorderWidth
            Return 16&&HTBOTTOMLEFT
        Endif
        *--- BottomRight corner
        If m.nYCoord>=This.Height-This.nBorderWidth  And m.nYCoord<=This.Height And m.nXCoord>=This.Width-This.nBorderWidth And m.nXCoord<=This.Width
            Return 17 &&HTBOTTOMRIGHT
        Endif

        *--- Top Border
        If m.nYCoord>=0 And m.nYCoord<=This.nBorderWidth
            Return 12 &&HTTOP
        Endif

        *--- Left Border
        If m.nXCoord>=0 And m.nXCoord<=This.nBorderWidth
            Return 10 &&HTLEFT
        Endif

        *--- Bottom Border
        If m.nYCoord>=This.Height-This.nBorderWidth  And m.nYCoord<=This.Height
            Return 15 &&HTBOTTOM
        Endif

        *--- Right Border
        If m.nXCoord>=This.Width-This.nBorderWidth And m.nXCoord<=This.Width
            Return 11 &&HTRIGHT
        Endif

        *--- Caption
        If m.nYCoord>=This.nBorderWidth And m.nYCoord<=This.oCaption.Height
            Return 2 &&HTCAPTION
        Endif

        Return CallWindowProc(This.hOrigProc, HWnd,;
            m.uMsg, m.wParam, m.lParam)
Enddefine

*--- cp_Border
Define Class my_Border As Line
    BorderWidth = 1
    Visible=.T.
    Procedure Init(pType)
        With This
            Do Case
                Case m.pType = 0
                    *--- Top
                    .Move(0, 2, .Parent.Width, 0)
                    .BorderWidth = 4
                    .Anchor = 11
                Case m.pType = 1
                    *--- Left
                    .Move(0, 0, 0, .Parent.Height)
                    .Anchor = 7
                Case m.pType = 2
                    *--- Right
                    .Move(.Parent.Width-.BorderWidth, 0, 0, .Parent.Height)
                    .Anchor = 13
                Case m.pType = 3
                    *--- Bottom
                    .Move(0, .Parent.Height-.BorderWidth, .Parent.Width, 0)
                    .Anchor = 14
            Endcase
            .BorderColor = Rgb(161,161,161)
        Endwith
    Endproc

Enddefine
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top