Добавление вертикального захвата в диалог - PullRequest
0 голосов
/ 12 июня 2018

Я не уверен, какой код показать вам здесь.В моем приложении MFC есть производный ресурс CDialogEx:

Gripper

. Он поддерживает элементы управления макетом динамического изменения размера, поэтому пользователь может изменять размер окна.Но я хотел бы добавить вертикальный захват (обозначен красным), чтобы пользователь мог увеличить ширину столбца имен.

Я провел некоторое исследование по этому вопросу, и всем статьям уже почти 10 лет, ине учитывайте более новые элементы управления динамическим изменением размера.


Исследовав это больше, я вижу, что термин "захват изменения размера" - это не то, что я имею в виду.Это значок в правом нижнем углу.Я не это имел в виду.

Я уверен, что вы понимаете, о чем я.Возможно ли это?

1 Ответ

0 голосов
/ 13 июня 2018

Добавление пользовательского элемента управления захватом может быть относительно простым.См. 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

IDD_PAGE1 иIDD_PAGE2 - это диалоговые ресурсы со стилем "child" (не всплывающее)

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;
    }
    ...
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...