Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Visual C++ / MFC / WTL > Direct2D


Автор: Black_Dragon 20.05.20, 05:18
Начал изучать. Надо рисовать схемы с прокруткой и масштабированием.
Для основы взял:
https://docs.microsoft.com/ru-ru/cpp/mfc/wa...ct?view=vs-2019
Используются костыли в коде для его корректной работе в двух разных примерах
Гугл на Direct2D дает только разные примеры (ну и топиики с проблемами), как рисовать и т.д. в виде полноценной документации у меня не находится.

VS 2019
I Первая проблема
Создал проект MFC с одним документов без Document/View

При изменении размера окна, по факту, сперва вызывается OnDraw2D, а потом OnSize.
Хотя, если смотреть пример из документации, то по логике, должно быть на оборот, так как в OnSize меняются настройки Градиента от размера окна (в коде перенесено в OnDraw2D).

CScrollGraph
Скрытый текст
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    class CScrollGraph : public CScrollView
    {
        DECLARE_DYNCREATE(CScrollGraph)
     
        CD2DTextFormat          *m_pTextFormat = nullptr;
        CD2DSolidColorBrush     *m_pBlackBrush = nullptr;
        CD2DLinearGradientBrush *m_pLinearGradientBrush = nullptr;
     
    public:
        CScrollGraph();           // защищенный конструктор, используемый при динамическом создании
        virtual ~CScrollGraph();
     
    public:
    #ifdef _DEBUG
        virtual void AssertValid() const;
    #ifndef _WIN32_WCE
        virtual void Dump(CDumpContext& dc) const;
    #endif
    #endif
     
    protected:
        virtual void OnDraw(CDC* pDC);      // для отрисовки этого представления
        virtual void OnInitialUpdate();     // впервые после создания
     
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
        virtual void OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/);
    protected:
        afx_msg LRESULT OnDraw2D(WPARAM wParam, LPARAM lParam);
        void InitObj1();
    public:
        afx_msg void OnSize(UINT nType, int cx, int cy);
    };

Скрытый текст
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    IMPLEMENT_DYNCREATE(CScrollGraph, CScrollView)
     
    CScrollGraph::CScrollGraph()
    {
     
    }
     
    CScrollGraph::~CScrollGraph()
    {
    }
     
     
    BEGIN_MESSAGE_MAP(CScrollGraph, CScrollView)
        ON_WM_CREATE()
        ON_REGISTERED_MESSAGE(AFX_WM_DRAW2D, &CScrollGraph::OnDraw2D)
        ON_WM_SIZE()
    END_MESSAGE_MAP()
     
     
    // Рисование CScrollGraph
     
    void CScrollGraph::OnInitialUpdate()
    {
        CScrollView::OnInitialUpdate();
     
        CSize sizeTotal;
        // TODO: рассчитайте полный размер этого представления
        sizeTotal.cx = sizeTotal.cy = 1000;
        SetScrollSizes(MM_TEXT, sizeTotal);
    }
     
    void CScrollGraph::OnDraw(CDC* pDC)
    {
        CDocument* pDoc = GetDocument();
        // TODO: добавьте код отрисовки
    }
     
    // Диагностика CScrollGraph
     
    #ifdef _DEBUG
    void CScrollGraph::AssertValid() const
    {
        CScrollView::AssertValid();
    }
     
    #ifndef _WIN32_WCE
    void CScrollGraph::Dump(CDumpContext& dc) const
    {
        CScrollView::Dump(dc);
    }
    #endif
    #endif //_DEBUG
     
    // Обработчики сообщений CScrollGraph
     
    int CScrollGraph::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        if (CScrollView::OnCreate(lpCreateStruct) == -1)
            return -1;
     
        // TODO:  Добавьте специализированный код создания
     
        // Enable D2D support for this window:
        EnableD2DSupport();
     
        InitObj1();
     
        return 0;
    }
     
    void CScrollGraph::OnUpdate(CView *pSender, LPARAM lHint, CObject *pHint)
    {
        // TODO: добавьте специализированный код или вызов базового класса
        CScrollView::OnUpdate(pSender, lHint, pHint);
    }
     
    afx_msg LRESULT CScrollGraph::OnDraw2D(WPARAM wParam, LPARAM lParam)
    {
        CHwndRenderTarget* pRenderTarget = (CHwndRenderTarget*) lParam;
        ASSERT_VALID(pRenderTarget);
        if (pRenderTarget->IsValid())
        {
            if (1)
            {
     
                //GetClientRect(rect);
                //m_pLinearGradientBrush->SetEndPoint(CPoint(rect.right, rect.bottom));
     
                int nMapMode;
                SIZE sizeTotal;
                SIZE sizePage;
                SIZE sizeLine;
                GetDeviceScrollSizes(nMapMode, sizeTotal, sizePage, sizeLine);
                //CPoint pos1 = GetScrollPosition();
                //CPoint pos2 = GetDeviceScrollPosition();
                //CSize sss = GetTotalSize();
     
                // apply translation transform according to view's scroll position
                CPoint point = GetScrollPosition();
                D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation((float) -point.x, (float) -point.y);
                pRenderTarget->SetTransform(matrix);
     
                CRect rect(0, 0, sizeTotal.cy, sizeTotal.cx);
                m_pLinearGradientBrush->SetEndPoint(CPoint(sizeTotal.cx, sizeTotal.cy));
                pRenderTarget->FillRectangle(rect, m_pLinearGradientBrush);
     
                pRenderTarget->DrawText(
                    _T("Hello, World!"),
                    rect,
                    m_pBlackBrush,
                    m_pTextFormat);
            }
        }
     
        return TRUE;
    }
     
    void CScrollGraph::InitObj1()
    {
        // Initialize D2D resources:
        m_pBlackBrush = new CD2DSolidColorBrush(
            GetRenderTarget(),
            D2D1::ColorF(D2D1::ColorF::Black));
     
        m_pTextFormat = new CD2DTextFormat(
            GetRenderTarget(),
            _T("Verdana"),
            50);
     
        m_pTextFormat->Get()->SetTextAlignment(
            DWRITE_TEXT_ALIGNMENT_CENTER);
     
        m_pTextFormat->Get()->SetParagraphAlignment(
            DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
     
        D2D1_GRADIENT_STOP gradientStops[2];
     
        gradientStops[0].color =
            D2D1::ColorF(D2D1::ColorF::White);
     
        gradientStops[0].position = 0.f;
        gradientStops[1].color =
            D2D1::ColorF(D2D1::ColorF::Indigo);
     
        gradientStops[1].position = 1.f;
     
        m_pLinearGradientBrush = new CD2DLinearGradientBrush(
            GetRenderTarget(),
            gradientStops,
            ARRAYSIZE(gradientStops),
            D2D1::LinearGradientBrushProperties(
                D2D1::Point2F(0, 0),
                D2D1::Point2F(0, 0)));
    }
     
    void CScrollGraph::OnSize(UINT nType, int cx, int cy)
    {
        CScrollView::OnSize(nType, cx, cy);
     
        // TODO: добавьте свой код обработчика сообщений
    }

CChildView
Скрытый текст
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    class CChildView : public CWnd
    {
        CScrollGraph    *m_Graph = nullptr;
    // Создание
    public:
        CChildView();
     
    // Атрибуты
    public:
     
    // Операции
    public:
     
    // Переопределение
        protected:
        virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
     
    // Реализация
    public:
        virtual ~CChildView();
     
        // Созданные функции схемы сообщений
    protected:
    //  afx_msg void OnPaint();
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnSize(UINT nType, int cx, int cy);
    };

Скрытый текст
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    CChildView::CChildView()
    {
    }
     
    CChildView::~CChildView()
    {
    }
     
     
    BEGIN_MESSAGE_MAP(CChildView, CWnd)
    //  ON_WM_PAINT()
        ON_WM_CREATE()
        ON_WM_SIZE()
    END_MESSAGE_MAP()
     
     
     
    // Обработчики сообщений CChildView
     
    BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
    {
        if (!CWnd::PreCreateWindow(cs))
            return FALSE;
     
        cs.dwExStyle |= WS_EX_CLIENTEDGE;
        cs.style &= ~WS_BORDER;
        cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
            ::LoadCursor(nullptr, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), nullptr);
     
        return TRUE;
    }
     
    //void CChildView::OnPaint()
    //{
    //  CPaintDC dc(this); // контекст устройства для рисования
    //  
    //  // TODO: Добавьте код обработки сообщений
    //  
    //  // Не вызывайте CWnd::OnPaint() для сообщений рисования
    //}
     
     
     
    int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        if (CWnd::OnCreate(lpCreateStruct) == -1)
            return -1;
     
        m_Graph = new CScrollGraph();
        m_Graph->Create(nullptr, nullptr, AFX_WS_DEFAULT_VIEW, { 100, 100 }, this, 1, nullptr);
     
        return 0;
    }
     
     
    void CChildView::OnSize(UINT nType, int cx, int cy)
    {
        CWnd::OnSize(nType, cx, cy);
        if (m_Graph->GetSafeHwnd()) m_Graph->MoveWindow(0, 0, cx, cy);
        // TODO: добавьте свой код обработчика сообщений
    }


II Вторая проблема
Тот же проект, только с включенным режимом Document/View
Для View (при создании проекта) выбираем базовым классом CScrollView.

OnDraw2D вызывается перед OnInitialUpdate/OnUpdate (дважды) (в коде добавлен костыль для проверки инициализации)
В OnUpdate команда SetScrollSizes инициирует вызов OnDraw2D, т.е. OnDraw2D вложен в OnUpdate , в первом примере этого не происходит.
При изменении размера, так же как в первом примере, OnDraw2D перед OnSize, но OnDraw2D+OnSize вызывается дважды при однократном изменении размера.
ЗЫ: при создании приложения были добавлены дополнительные фреймы в стиле Outlook, не исключаю, что двойные вызовы из-за этого, так как при втором вызове, отличается размер по высоте (с учетом текущего набора фреймов), но хотелось бы и этого избежать.

Скрытый текст
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    class CGraph1View : public CScrollView
    {
        CD2DTextFormat          *m_pTextFormat = nullptr;
        CD2DSolidColorBrush     *m_pBlackBrush = nullptr;
        CD2DLinearGradientBrush *m_pLinearGradientBrush = nullptr;
     
        CD2DBitmap              *m_pBitmap = nullptr;
        //CHwndRenderTarget     *m_renderTarget = nullptr;
     
        bool                    m_Init = false;
     
    protected: // создать только из сериализации
        CGraph1View() noexcept;
        DECLARE_DYNCREATE(CGraph1View)
     
    // Атрибуты
    public:
        CGraph1Doc* GetDocument() const;
     
    // Операции
    public:
     
    // Переопределение
    public:
        virtual void OnDraw(CDC* pDC);  // переопределено для отрисовки этого представления
        virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    protected:
        virtual void OnInitialUpdate(); // вызывается в первый раз после конструктора
        virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
        virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
        virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
     
    // Реализация
    public:
        virtual ~CGraph1View();
    #ifdef _DEBUG
        virtual void AssertValid() const;
        virtual void Dump(CDumpContext& dc) const;
    #endif
     
    protected:
        void InitObj1();
     
     
    // Созданные функции схемы сообщений
    protected:
        afx_msg void OnFilePrintPreview();
        afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
        afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    protected:
        afx_msg LRESULT OnDraw2D(WPARAM wParam, LPARAM lParam);
        virtual void OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/);
    public:
        afx_msg void OnSize(UINT nType, int cx, int cy);
    };
     
    #ifndef _DEBUG  // версия отладки в Graph1View.cpp
    inline CGraph1Doc* CGraph1View::GetDocument() const
       { return reinterpret_cast<CGraph1Doc*>(m_pDocument); }
    #endif

Скрытый текст
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    IMPLEMENT_DYNCREATE(CGraph1View, CScrollView)
     
    BEGIN_MESSAGE_MAP(CGraph1View, CScrollView)
        // Стандартные команды печати
        ON_COMMAND(ID_FILE_PRINT, &CScrollView::OnFilePrint)
        ON_COMMAND(ID_FILE_PRINT_DIRECT, &CScrollView::OnFilePrint)
        ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CGraph1View::OnFilePrintPreview)
        ON_WM_CONTEXTMENU()
        ON_WM_RBUTTONUP()
        ON_WM_CREATE()
        ON_REGISTERED_MESSAGE(AFX_WM_DRAW2D, &CGraph1View::OnDraw2D)
        ON_WM_SIZE()
    END_MESSAGE_MAP()
     
    // Создание или уничтожение CGraph1View
     
    CGraph1View::CGraph1View() noexcept
    {
        // TODO: добавьте код создания
     
    }
     
    CGraph1View::~CGraph1View()
    {
    }
     
    BOOL CGraph1View::PreCreateWindow(CREATESTRUCT& cs)
    {
        // TODO: изменить класс Window или стили посредством изменения
        //  CREATESTRUCT cs
     
        return CScrollView::PreCreateWindow(cs);
    }
     
    // Рисование CGraph1View
     
    void CGraph1View::OnDraw(CDC* /*pDC*/)
    {
        //CGraph1Doc* pDoc = GetDocument();
        //ASSERT_VALID(pDoc);
        //if (!pDoc)
        //  return;
     
        // TODO: добавьте здесь код отрисовки для собственных данных
    }
     
    void CGraph1View::OnInitialUpdate()
    {
        CScrollView::OnInitialUpdate();
    }
     
     
    // Печать CGraph1View
     
     
    void CGraph1View::OnFilePrintPreview()
    {
    #ifndef SHARED_HANDLERS
        AFXPrintPreview(this);
    #endif
    }
     
    BOOL CGraph1View::OnPreparePrinting(CPrintInfo* pInfo)
    {
        // подготовка по умолчанию
        return DoPreparePrinting(pInfo);
    }
     
    void CGraph1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
        // TODO: добавьте дополнительную инициализацию перед печатью
    }
     
    void CGraph1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
        // TODO: добавьте очистку после печати
    }
     
    void CGraph1View::OnRButtonUp(UINT /* nFlags */, CPoint point)
    {
        ClientToScreen(&point);
        OnContextMenu(this, point);
    }
     
    void CGraph1View::OnContextMenu(CWnd* /* pWnd */, CPoint point)
    {
    #ifndef SHARED_HANDLERS
        theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
    #endif
    }
     
     
    // Диагностика CGraph1View
     
    #ifdef _DEBUG
    void CGraph1View::AssertValid() const
    {
        CScrollView::AssertValid();
    }
     
    void CGraph1View::Dump(CDumpContext& dc) const
    {
        CScrollView::Dump(dc);
    }
     
    void CGraph1View::InitObj1()
    {
        // Initialize D2D resources:
        m_pBlackBrush = new CD2DSolidColorBrush(
            GetRenderTarget(),
            D2D1::ColorF(D2D1::ColorF::Black));
     
        m_pTextFormat = new CD2DTextFormat(
            GetRenderTarget(),
            _T("Verdana"),
            50);
     
        m_pTextFormat->Get()->SetTextAlignment(
            DWRITE_TEXT_ALIGNMENT_CENTER);
     
        m_pTextFormat->Get()->SetParagraphAlignment(
            DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
     
        D2D1_GRADIENT_STOP gradientStops[2];
     
        gradientStops[0].color =
            D2D1::ColorF(D2D1::ColorF::White);
     
        gradientStops[0].position = 0.f;
        gradientStops[1].color =
            D2D1::ColorF(D2D1::ColorF::Indigo);
     
        gradientStops[1].position = 1.f;
     
        m_pLinearGradientBrush = new CD2DLinearGradientBrush(
            GetRenderTarget(),
            gradientStops,
            ARRAYSIZE(gradientStops),
            D2D1::LinearGradientBrushProperties(
                D2D1::Point2F(0, 0),
                D2D1::Point2F(0, 0)));
    }
     
    CGraph1Doc* CGraph1View::GetDocument() const // встроена неотлаженная версия
    {
        ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CGraph1Doc)));
        return (CGraph1Doc*)m_pDocument;
    }
    #endif //_DEBUG
     
     
    // Обработчики сообщений CGraph1View
     
    int CGraph1View::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        if (CScrollView::OnCreate(lpCreateStruct) == -1)
            return -1;
     
        // Enable D2D support for this window:
        EnableD2DSupport();
     
        InitObj1();
     
        return 0;
    }
     
    void CGraph1View::OnUpdate(CView *pSender, LPARAM lHint, CObject *pHint)
    {
        
        //CScrollView::OnUpdate(pSender, lHint, pHint);
        CHwndRenderTarget* pRenderTarget = this->GetRenderTarget();
        ASSERT_VALID(pRenderTarget);
        if (pRenderTarget->IsValid())
        {
            if (1)
            {
                CSize size;
                // TODO: рассчитайте полный размер этого представления
                size.cx = size.cy = 1000;
                SetScrollSizes(MM_TEXT, size);
                ScrollToPosition(CPoint(0, 0));
            }
            if (0)
            {
                CSize sizeImage(100, 100);
                delete m_pBitmap;
                m_pBitmap = nullptr;
     
                const CString strFile = L"D:\\Photos\\73030609.jpg";
                if (!strFile.IsEmpty())
                {
     
                    m_pBitmap = new CD2DBitmap(pRenderTarget, strFile);
                    HRESULT hr = m_pBitmap->Create(pRenderTarget);
                    if (m_pBitmap->IsValid())
                    {
                        CD2DSizeF size = m_pBitmap->GetSize();
                        sizeImage.SetSize(static_cast<int>(size.width), static_cast<int>(size.height));
                    }
                }
                SetScrollSizes(MM_TEXT, sizeImage);
                ScrollToPosition(CPoint(0, 0));
            }
            m_Init = true;
        }
    }
     
    afx_msg LRESULT CGraph1View::OnDraw2D(WPARAM wParam, LPARAM lParam)
    {
        CHwndRenderTarget* pRenderTarget = (CHwndRenderTarget*) lParam;
        ASSERT_VALID(pRenderTarget);
        if (m_Init && pRenderTarget->IsValid())
        {
            if (1)
            {
     
                //GetClientRect(rect);
                //m_pLinearGradientBrush->SetEndPoint(CPoint(rect.right, rect.bottom));
     
                int nMapMode;
                SIZE sizeTotal;
                SIZE sizePage;
                SIZE sizeLine;
                GetDeviceScrollSizes(nMapMode, sizeTotal, sizePage, sizeLine);
                //CPoint pos1 = GetScrollPosition();
                //CPoint pos2 = GetDeviceScrollPosition();
                //CSize sss = GetTotalSize();
     
                // apply translation transform according to view's scroll position
                CPoint point = GetScrollPosition();
                D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation((float) -point.x, (float) -point.y);
                pRenderTarget->SetTransform(matrix);
     
                CRect rect(0, 0, sizeTotal.cy, sizeTotal.cx);
                m_pLinearGradientBrush->SetEndPoint(CPoint(sizeTotal.cx, sizeTotal.cy));
                pRenderTarget->FillRectangle(rect, m_pLinearGradientBrush);
     
                pRenderTarget->DrawText(
                    _T("Hello, World!"),
                    rect,
                    m_pBlackBrush,
                    m_pTextFormat);
            }
            if (0)
            {
                D2D1_COLOR_F color = { 1.f, 1.f, 1.f, 1.f }; // r, g, b, a
                pRenderTarget->Clear(color);
                if ((nullptr != m_pBitmap) && m_pBitmap->IsValid())
                {
                    // apply translation transform according to view's scroll position
                    CPoint point = GetScrollPosition();
                    D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation((float) -point.x, (float) -point.y);
                    pRenderTarget->SetTransform(matrix);
                    // draw the bitmap
                    CD2DSizeF size = m_pBitmap->GetSize();
                    pRenderTarget->DrawBitmap(m_pBitmap, CD2DRectF(0, 0, size.width, size.height));
                }
            }
        }
     
        return TRUE;
    }
     
    void CGraph1View::OnSize(UINT nType, int cx, int cy)
    {
        CScrollView::OnSize(nType, cx, cy);
    }

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)