cutepig123 / gitblog

MIT License
0 stars 0 forks source link

CDiagramEditor #76

Open cutepig123 opened 3 months ago

cutepig123 commented 3 months ago

簡介:

https://www.codeproject.com/Articles/6607/CDiagramEditor-DIY-vector-and-dialog-editor

1722611147984

代碼實現原理

每個控件需要從CDiagramEntity繼承并且實現相關函數用來支持

而框架呢支持

class CDiagramButton : public CDiagramEntity
{
// Construction
public:
    CDiagramButton();

    static  CDiagramEntity* CreateFromString( const CString& str );

// Overrides
    virtual CDiagramEntity* Clone();
    virtual void            Draw( CDC* dc, CRect rect );
    virtual CString Export( UINT format = 0 ) const;

private:
    CButtonPropertyDlg  m_dlg;
};

按鈕如何畫自己

Q:每個對象的拖動,大小調整之類的動作

void CDiagramEditor::OnLButtonDown( UINT nFlags, CPoint point ) 

Q: 如何畫選中的物體?


void CDiagramEntity::DrawSelectionMarkers( CDC* dc, CRect rect ) const
{

    // Draw selection markers 畫8個小正方形
    CRect rectSelect;

    dc->SelectStockObject( BLACK_BRUSH );
    rectSelect = GetSelectionMarkerRect( DEHT_TOPLEFT, rect );
    dc->Rectangle( rectSelect );

    rectSelect = GetSelectionMarkerRect( DEHT_TOPMIDDLE, rect );
    dc->Rectangle( rectSelect );

    rectSelect = GetSelectionMarkerRect( DEHT_TOPRIGHT, rect );
    dc->Rectangle( rectSelect );

    rectSelect = GetSelectionMarkerRect( DEHT_BOTTOMLEFT, rect );
    dc->Rectangle( rectSelect );

    rectSelect = GetSelectionMarkerRect( DEHT_BOTTOMMIDDLE, rect );
    dc->Rectangle( rectSelect );

    rectSelect = GetSelectionMarkerRect( DEHT_BOTTOMRIGHT, rect );
    dc->Rectangle( rectSelect );

    rectSelect = GetSelectionMarkerRect( DEHT_RIGHTMIDDLE, rect );
    dc->Rectangle( rectSelect );

    rectSelect = GetSelectionMarkerRect( DEHT_LEFTMIDDLE, rect );
    dc->Rectangle( rectSelect );

}

QA

Q:What is SetPanning?

設置平移

Q: What is ScreenToVirtual?

Q:WHat is SetCapture?

查MSND,对SetCapture()函数的说明为:“该函数在属于当前线程的指定窗口里设置鼠标捕获。一旦窗口捕获了鼠标,所有鼠标输入都针对该窗口,无论光标是否在窗口的边界内。同一时刻只能有一个窗口捕获鼠标。如果鼠标光标在另一个线程创建的窗口上,只有当鼠标键按下时系统才将鼠标输入指向指定的窗口。”一开始我看这个解释误认为了只要在属于窗口里的一个线程调用了SetCapture(hWnd)把hWnd设为当前的窗口句柄,那么以后的所有窗口消息都会发到我们指定的那个窗口消息队列中。这样的理解是错误的!!!在你调用SetCapture(hWnd)函数后,只是能够捕获onmousedown、onmouseup、onmousemove、onclick、ondblclick、onmouseover和onmouseout鼠标消息,但是一般我们是捕获onmousemove和onmouseup两个消息。需要只注意最后一句“如果鼠标光标在另一个线程创建的窗口上,只有当鼠标键按下时系统才将鼠标输入指向指定的窗口”的解释,就是即使你在一个窗口线程里对了了SetCapture(),但你在别的窗口的上点击了同样会把鼠标消息发个这个窗口而是我们通过调用SetCapture()设定那个窗口。因为当鼠标在窗口外面点击的时候,被点击的窗口获得焦点,原来的SetCapture()也就失效了。

当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉,否则别的线程想调用就会失败。记住:SetCapture()和ReleaseCapture()必须成对呈现。

————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/lanyzh0909/article/details/5543399

Q: RedrawWindow vs invalidate?

感覺主要分別是否進入事件隊列

InvalidateRect does not immediately redraw the window.

It simply "schedules" a future redraw for a specific rectangular area of the window. Using InvalidateRect you may schedule as many areas as you want, making them accumulate in some internal buffer. The actual redrawing for all accumulated scheduled areas will take place later, when the window has nothing else to do. (Of course, if the window is idle at the moment when you issue the InvalidateRect call, the redrawing will take place immediately).

You can also force an immediate redraw for all currently accumulated invalidated areas by calling UpdateWindow. But, again, if you are not in a hurry, explicitly calling UpdateWindow is not necessary, since once the window is idle it will perform a redraw for all currently invalidated areas automatically.

RedrawWindow, on the other hand, is a function with a much wider and flexible set of capabilities. It can be used to perform invalidation scheduling (i.e. the same thing InvalidateRect does) or it can be used to forcefully perform immediate redrawing of the specified area, without doing any "scheduling". In the latter case calling RedrawWindow is virtually equivalent to calling InvalidateRect and then immediately calling UpdateWindow.

Q:What is RUBBERBANDING?

它允许用户通过在要选择的项目周围拖动一个尺寸矩形来选择多个 OLE 项目。当用户释放鼠标左键时,用户选择的区域内的项目将被选中,并且可以由用户操作

Q:更簡單的方式實現RUBBERBANDING?

MFC有一個現成的class

用法1:

CRectTracker trackerRubber;
if (trackerRubber.TrackRubberBand(this, point, TRUE))

用法2:鼠標在裏面選中了才能

// track之前必須設置rect和style,因爲他只有鼠標選中物體才能觸發track動作
    trackerRubber.m_rect.SetRect(0, 0, 100, 100);
    trackerRubber.m_nStyle = CRectTracker::dottedLine | CRectTracker::resizeInside;
    CClientDC dc(this);
    trackerRubber.Draw(&dc);
    trackerRubber.Track(this, point);
    trackerRubber.Draw(&dc);

它的工作原理?

他的關鍵代碼是在BOOL CRectTracker::TrackHandle

for (;;)
        VERIFY(::GetMessage(&msg, NULL, 0, 0));

        switch (msg.message)
        {
        // handle movement/accept messages
        case WM_LBUTTONUP:
        case WM_MOUSEMOVE:
            。。DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd); // 内部調用pDC->DrawDragRect(rect, size, m_rectLast, m_sizeLast);
        default:
            DispatchMessage(&msg);

而DrawDragRect内部使用擦除老區域,然後畫出新區域 PatBlt 使用 PatBlt,您可以重复使用单色图案画笔并设置不同的颜色,只需更改 DC 中的文本和背景颜色即可。 使用 BitBlt,您必须先更新内存 DC 中的位图。   dwRop:指定光栅操作码。该操作码可以取下列值,这些值的含义如下:   PATCOPY:将指定的模式拷贝到目标位图中。   PATINVERT:使用布尔OR(或)操作符将指定模式的颜色与目标矩形的颜色进行组合。   DSTINVERT:将目标矩形反向。   BLACKNESS:使用物理调色板中与索引0相关的颜色填充目标矩形。(对于缺省的物理调色板而言,该颜色为黑色)。   WHITENESS:使用物理调色板中与索引1有关的颜色来填充目标矩形。(对于缺省的物理调色板而言,该颜色为白色) ————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/yjkwf/article/details/5287186 Q: When will windows send WM_SETCURSOR message

cutepig123 commented 3 months ago

AVSLib.zip