delphiborderdelphi-7formborderstyle

How to set only 1 specific sizing border edge?


I have some tool-panels made via forms with bsSizeToolWin borders, i have custom handling of window-movement and custom routines for sticking/aligning tool-panels with borders of main form (almost like docking functionality), but the problem that with bsSizeToolWin border-style i have all the corners/sides of border sizeable.

Is it possible to make only one specific border-side sizeable? (e.g. when tool-panel sticked to left border of main form i want only right border of panel sizeable, cuz top and bottom coords of panel getting aligned according to height of client area of main form and left coord sticked to right border of main form)


Solution

  • From a visual standpoint, by default if a window has sizable borders then all edges are drawn sizable, otherwise none of them are, there is no in-between as the Win32 API has no concept of per-edge border styles, only whole-window border styles. If you want the various borders to look different, you would likely have to custom-draw the borders manually by handling the WM_NCCALCSIZE and WM_NCPAINT messages directly.

    From a functional standpoint, it is fairly easy to prevent the user from resizing the window on specific edges. The simplest way is to have the panel handle the WM_NCHITTEST message. Give the panel normal sizing borders (custom drawn if desired), and then have it pass any received WM_NCHITTEST message to the default handler first, and then adjust the result as needed. The benefit of this approach is that the OS will not allow the user to grab any edge that is reported as HTBORDER (non-sizable border), and there will be no visual feedback that the edge is resizable (even if it really is).

    For instance, let's use your panel-aligned-on-the-left example. If the default handler returns either HTBOTTOM, HTBOTTOMLEFT, HTLEFT, HTTOPLEFT, or HTTOP, return HTBORDER instead. If the default handler returns HTBOTTOMRIGHT or HTTOPRIGHT, return HTRIGHT instead. Otherwise return whatever the default handler returned.

    Adjust the values as needed based on which edge of your Panel you want to be sizable.

    For example:

    type
      TMyPanelForm = class(TForm)
      private
        fWhichSideCanBeResized: TAlign;
        procedure WMNCHitTest(var Message: TMessage); message WM_NCHITTEST;
      end;
    
    procedure TMyPanelForm.WMNCHitTest(var Message: TMessage);
    begin
      inherited;
      case fWhichSideCanBeResized of
        alLeft:
        begin
          case Message.Result of
            HTBOTTOM, HTBOTTOMRIGHT, HTRIGHT, HTTOPRIGHT, HTTOP:
              Message.Result := HTBORDER;
            HTBOTTOMLEFT, HTTOPLEFT:
              Message.Result := HTLEFT;
          end;
        end;
        alRight:
        begin
          case Message.Result of
            HTBOTTOM, HTBOTTOMLEFT, HTLEFT, HTTOPLEFT, HTTOP:
              Message.Result := HTBORDER;
            HTBOTTOMRIGHT, HTTOPRIGHT:
              Message.Result := HTRIGHT;
          end;
        end;
        alTop:
        begin
          case Message.Result of
            HTLEFT, HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT, HTRIGHT:
              Message.Result := HTBORDER;
            HTTOPLEFT, HTTOPRIGHT:
              Message.Result := HTTOP;
          end;
        end;
        alBottom:
        begin
          case Message.Result of
            HTLEFT, HTTOPLEFT, HTTOP, HTTOPRIGHT, HTRIGHT:
              Message.Result := HTBORDER;
            HTBOTTOMLEFT, HTBOTTOMRIGHT:
              Message.Result := HTBOTTOM;
          end;
        end;
      end;
    end;
    

    Alternatively:

    procedure TMyPanelForm.WMNCHitTest(var Message: TMessage);
    begin
      inherited;
      case Message.Result of
        HTLEFT:
          if fWhichSideCanBeResized <> alLeft then
            Message.Result := HTBORDER;
        HTRIGHT:
          if fWhichSideCanBeResized <> alRight then
            Message.Result := HTBORDER;
        HTTOP:
          if fWhichSideCanBeResized <> alTop then
            Message.Result := HTBORDER;
        HTBOTTOM:
          if fWhichSideCanBeResized <> alBottom then
            Message.Result := HTBORDER;
        HTTOPLEFT:
          case fWhichSideCanBeResized of
            alTop: Message.Result := HTTOP;
            alLeft: Message.Result := HTLEFT;
          else
            Message.Result := HTBORDER;
          end;
        HTBOTTOMLEFT:
          case fWhichSideCanBeResized of
            alBottom: Message.Result := HTBOTTOM;
            alLeft: Message.Result := HTLEFT;
          else
            Message.Result := HTBORDER;
          end;
        HTTOPRIGHT:
          case fWhichSideCanBeResized of
            alTop: Message.Result := HTTOP;
            alRight: Message.Result := HTRIGHT;
          else
            Message.Result := HTBORDER;
          end;
        HTBOTTOMRIGHT:
          case fWhichSideCanBeResized of
            alBottom: Message.Result := HTBOTTOM;
            alRight: Message.Result := HTRIGHT;
          else
            Message.Result := HTBORDER;
          end;
      end;
    end;