向对话框添加垂直抓手

时间:2018-06-12 15:30:56

标签: mfc

我不确定在这里向您展示什么代码。我的MFC应用程序中有一个CDialogEx派生资源:

Gripper

如果支持动态调整大小布局控件,则用户可以调整窗口大小。但我想添加一个垂直抓手(用红色表示),这样用户就可以使名称列的宽度更大。

我已经对此进行了一些研究,所有文章都已有近10年的历史,并且没有考虑到新的动态调整大小控件。

对此进行了更多的研究后,我发现"调整大小的抓手"术语不是我的意思。这是右下角的图标。我不是这个意思。

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

1 个答案:

答案 0 :(得分:4)

添加自定义抓手控件可能相对容易。请参阅下面的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的静态控件,并按如下方式使用。

以下代码的主对话CMyDialogIDD_DIALOG,正常对话

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

IDD_PAGE1IDD_PAGE2是&#34; child&#34;的对话框资源。风格(不弹出)

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;
    }
    ...
};