代码之家  ›  专栏  ›  技术社区  ›  Andrew Truckle

将垂直夹持器添加到对话框

mfc
  •  2
  • Andrew Truckle  · 技术社区  · 6 年前

    我不知道给你看什么代码。我有一个 CDialogEx MFC应用程序中的派生资源:

    Gripper

    它支持动态调整布局控件,以便用户可以调整窗口的大小。但是我想添加一个垂直的夹持器(用红色表示),这样用户可以使names列的宽度变大。

    我对此做了一些研究,所有的文章都有将近10年的历史了,没有考虑到更新的动态调整大小控件。


    经过更多的研究,我发现“调整夹持器大小”这个词并不是我的意思。这是右下角的图标。我不是这个意思。

    我相信你知道我的意思。有可能吗?

    1 回复  |  直到 5 年前
        1
  •  4
  •   Barmak Shemirani    6 年前

    添加自定义夹持器控件相对容易。见 CMySplitter 下级。

    但是,如果所有控件都在一个对话框中,将很难逐个重新定位/调整单个控件的大小。

    理想情况下,使用两个子对话框。在资源编辑器中设置单个控件的“调整大小/重新定位”属性。将夹点控件放在两个对话框之间并根据需要调整大小。

    夹持器控制等级:

    #include <functional>
    
    class CMySplitter : public CStatic
    {
    public:
        class CPopup : public CWnd
        {
        public:
            CMySplitter *parent;
            int offset;
            void OnMouseMove(UINT flag, CPoint pt);
            void OnLButtonUp(UINT flag, CPoint pt);
            DECLARE_MESSAGE_MAP()
        };
    
        std::function<void(int)> callback;
        CRect boundary;
        CPopup popup;
        void OnLButtonDown(UINT flag, CPoint point);
        void PreSubclassWindow();
        void SetRange(int left, int right);
        DECLARE_MESSAGE_MAP()
    };
    
    //create splitter control from a static control in dialog
    void CMySplitter::PreSubclassWindow()
    {
        CStatic::PreSubclassWindow();
    
        //modify static control's style (must have SS_NOTIFY)
        SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_VISIBLE | SS_GRAYRECT | WS_CHILD | SS_NOTIFY);
    
        //create a popup window with transparency
        static CString classname =
            AfxRegisterWndClass(0, 0, (HBRUSH)GetStockObject(BLACK_BRUSH));
        popup.CreateEx(WS_EX_LAYERED | WS_EX_PALETTEWINDOW | WS_EX_NOACTIVATE,
            classname, NULL, WS_POPUP, CRect(0, 0, 0, 0), this, 0);
    
        popup.SetLayeredWindowAttributes(0, 128, LWA_ALPHA);
        popup.parent = this;
    }
    
    //when user click the static control, show a popup window
    void CMySplitter::OnLButtonDown(UINT flag, CPoint pt)
    {
        CStatic::OnLButtonDown(flag, pt);
    
        GetCursorPos(&pt);
    
        CRect rc;
        GetWindowRect(&rc);
    
        popup.offset = pt.x - rc.left;
        popup.SetWindowPos(NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_SHOWWINDOW);
        popup.SetCapture();
    }
    
    //how far to the left and right the splitter can go
    void CMySplitter::SetRange(int left_, int right_)
    {
        CRect rc;
        GetParent()->GetWindowRect(&rc);
        boundary.left = rc.left + left_;
        boundary.right = rc.right - right_;
    }
    
    //move this popup window
    void CMySplitter::CPopup::OnMouseMove(UINT flag, CPoint pt)
    {
        CWnd::OnMouseMove(flag, pt);
        GetCursorPos(&pt);
        CRect rc;
        GetWindowRect(&rc);
    
        int x = pt.x - offset;
        if (x > parent->boundary.left && x < parent->boundary.right)
            SetWindowPos(NULL, x, rc.top, 0, 0, SWP_NOSIZE);
    }
    
    //hide popup window, let the parent dialog know
    void CMySplitter::CPopup::OnLButtonUp(UINT flag, CPoint pt)
    {
        CWnd::OnLButtonUp(flag, pt);
        ReleaseCapture();
        ShowWindow(SW_HIDE);
    
        CRect rc;
        GetWindowRect(&rc);
        parent->callback(rc.left);
    }
    
    BEGIN_MESSAGE_MAP(CMySplitter::CPopup, CWnd)
        ON_WM_CREATE()
        ON_WM_LBUTTONDOWN()
        ON_WM_LBUTTONUP()
        ON_WM_MOUSEMOVE()
    END_MESSAGE_MAP()
    
    BEGIN_MESSAGE_MAP(CMySplitter, CWnd)
        ON_WM_LBUTTONDOWN()
    END_MESSAGE_MAP()
    

    用途:

    添加静态控件 IDC_STATIC1 并按如下方式使用。

    下面的代码有一个主对话框 CMyDialog 具有 IDD_DIALOG ,正常对话框

    它有两个子对话框,child1和child2 IDD_PAGE1 IDD_PAGE2

    IDD1页1 IDD2页2 是具有“子”样式的对话框资源(不是弹出式)

    class CMyDialog : public CDialogEx
    {
    public:
        class CChild1 : public CDialogEx
        {
        };
    
        class CChild2 : public CDialogEx
        {
        };
    
        CChild1 child1;
        CChild1 child2;
    
        //respond to gripper resize
        void respond(int position)
        {
            CRect rs;
            m_splitter.GetWindowRect(&rs);
            rs.MoveToX(position);
            ScreenToClient(&rs);
    
            CRect rc;
            GetClientRect(&rc);
    
            CRect r1(0, 0, rs.left, rc.bottom);
            CRect r2(rs.right, 0, rc.right, rc.bottom);
    
            child1.MoveWindow(r1, TRUE);
            child2.MoveWindow(r2, TRUE);
            m_splitter.MoveWindow(rs, TRUE);
    
            m_splitter.Invalidate(TRUE);
        }
    
        CMySplitter m_splitter;
        BOOL OnInitDialog()
        {
            CDialogEx::OnInitDialog();
            child1.Create(IDD_PAGE1, this);
            child2.Create(IDD_PAGE2, this);
    
            m_splitter.SubclassDlgItem(IDC_STATIC1, this);
            m_splitter.SetRange(50, 50);
            m_splitter.callback = std::bind(&CMyDialog::respond, this, std::placeholders::_1);
    
            //width for splitter
            int dx = 10;
    
            CRect rc;
            GetClientRect(&rc);
            CRect r1(0, 0, 200, rc.bottom);
            CRect r2(r1.right + dx, 0, rc.right, rc.bottom);
            CRect rs(r1.right, 10, r2.left, rc.bottom - 10);
    
            child1.MoveWindow(r1);
            child2.MoveWindow(r2);
            m_splitter.MoveWindow(rs);
    
            child1.ShowWindow(SW_SHOW);
            child2.ShowWindow(SW_SHOW);
    
            return TRUE;
        }
        ...
    };