Open Cascade MFC应用程序中使用AIS_Rubbe

2019-04-16  本文已影响0人  yumxuanyi

@版权声明:本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出,
本文链接https://www.jianshu.com/p/1d566a1445bc
如有问题, 可邮件(yumxuanyi@qq.com)咨询。


关键字:OpenCascade、MFC、AIS_RubberBand

问题描述

在使用MFC创建的Opeen Cascade项目中,可以使用AIS_RubberBand来创建选择框。
现在需要达到如下效果:

  1. down-move-up模式:鼠标左键按下 开始绘制矩形框, 左键保持按下状态随着鼠标移动不断更新矩形框 ,鼠标左键弹起矩形框绘制结束。
  2. 单击 - move - 单击 模式:鼠标左键单击(连续的down -up)开始绘制矩形框-随着鼠标移动矩形框不断更新-鼠标左键再次单击结束绘制
  3. 双击 - move - 双击 模式:同上单击模式,只是单击改双击。

但在MFC中区分鼠标单击、双击、左键按下、左键抬起是比较困难的一件事。因为无论单击还是双击始终会先触发down 。

解决方法

不处理双击还是单击,仅仅在buttonDown 和buttonUp中进行判断
因此将以上过程简化为:

  1. 仅仅在鼠标左键按下LeftButton中决定是否开始绘制矩形框或结束矩形框的绘制
  2. 在鼠标左键抬起时,判断是否结束绘制。
  3. 鼠标移动过程中 ,如果开始绘制就不断的更新矩形框。

通过以上处理。我们将决定是否开始绘制矩形框的条件完全放在LeftButtonDown中,这样只用判断鼠标是否为down 还是up来终止和结束绘制。

需要定义的变量

  1. Handle(AIS_RubberBand) mySelectionRectangle;//选择框对象
  2. Mouse_SelectionState mySelectionState;//用于记录当前的绘制状态 是开始还是结束。
    enum Mouse_SelectionState
    {
    Mouse_StartSelection,//表示当前状态为已经开始了矩形框的绘制
    Mouse_EndSelection,//表示当前矩形框绘制结束
    Mouse_SelectionNormal//正常状态
    };
    当然你也可以直接用Standard_Boolean来记录。
  3. DWORD myStartSelectionTime;//用于记录开始选择框的时间。
  4. Standard_Integer myFirstCursorX;//用于记录矩形框起点坐标X
  5. .Standard_Integer myFirstCursorY;//用于记录矩形框起点坐标Y
  6. Standard_Integer mySecondCursorX;//用于记录矩形框终点坐标X
  7. Standard_Integer mySecondCursorY;//用于记录矩形框终点坐标Y

在View类构造函数中进行初始化

      CMyView::CMyView()
     {
       // TODO: 在此处添加构造代码
      this->mySelectionRectangle = new AIS_RubberBand();//初始化选择框
       mySelectionState = Mouse_SelectionNormal; //设置初始选择状态
     }

在View类的析构函数中删除

   CMyView::~CMyView()
   {
      this->mySelectionRectangle.Nullify();
   }

具体实现

OnLButtonDown事件处理方法

在OnLButtonDown中进行开始绘制或结束绘制的判断,如果没有开始绘制 就要开始绘制,如果已经开始了绘制 就要结束绘制(检查不重合后)

void CMyView::OnLButtonDown(UINT nFlags,CPoint point)
{
 // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (mySelectionState == Mouse_StartSelection)//表示已经开始了矩形框的绘制
    {
        //如果矩形框的绘制已经开始,需要检查如果当前鼠标点击点point ,       
        //如果不与开始绘制点重合(不落在开始绘制点的范围内时)就要结束矩形框的绘制       
        //如果重合(落在开始点的tol范围内)将保持绘制状态
        Standard_Boolean inRect = JudgeMouseInRect(CPoint(myFirstCursorX, myFirstCursorY), point);//用于判断当前点point是否落在开始绘制点的范围内
        if (inRect == Standard_False)//不重合结束绘制
        {
            mySecondCursorX = point.x;//记录结束的x坐标
            mySecondCursorY = point.y;//记录结束的y坐标
            mySelectionState = Mouse_EndSelection;//将状态标记为结束
            DrawSelectionRectangle(Standard_False);//结束矩形框绘制 参数False表示不绘制矩形框
        }
    }
    else//表示没有开始绘制 这时就要开始绘制矩形框了
    {
        myFirstCursorX = point.x;//记录开始绘制的位置
        myFirstCursorY = point.y;
        mySecondCursorX = point.x;//同时也重置一下这个位置
        mySecondCursorY = point.y;
        mySelectionState = Mouse_StartSelection;//记录状态为开始绘制
        DrawSelectionRectangle(Standard_True);//开始绘图啦
        myStartSelectionTime = ::GetTickCount();//这里记录开始绘制的时间
    }
   CView::OnLButtonDown(nFlags,point);
}  

OnLButtonUp事件处理方法

在LButtonUp事件中判断是否结束绘制判断条件

  1. 如果已经开始可绘制 就要比对当前鼠标位置是否与开始绘制的位置是否重合 这里要求不重合
  2. 当前时间与开始时间之差是否大于一个余量(这里给200,防止过快的操作) 这里要求大于余量
  3. 若果以上两个条件都满足 就结束绘制
void CMyView::OnLButtonUp(UINT nFlags,CPoint point)
{
    if (mySelectionState == Mouse_StartSelection)//开始了绘制 就要判断是否去结束绘制
    {
        CPoint center(myFirstCursorX, myFirstCursorY);
        Standard_Boolean inRect = JudgeMouseInRect(center, point);//判断是否重合
        if (inRect == Standard_False)//不重合 进行条件2的判断
        {
            DWORD currentTime = ::GetTickCount();
            if (currentTime - myStartSelectionTime > 200)//起始时间差大于200 结束绘制
            {
                mySecondCursorX = point.x;//记录结束时的坐标
                mySecondCursorY = point.y;
                mySelectionState = Mouse_EndSelection;//标记为结束
                DrawSelectionRectangle(Standard_False);//结束矩形框绘制
            }
        }
    }
     CView::OnLButtonUp(nFlags,point);
}

OnMouseMove事件处理方法

鼠标移动时开始更新矩形框,如果已经开始了绘制 就要在鼠标移动时不断更新矩形框的大小

void CMyView::OnMouseMove(UINT nFlags,CPoint point)
{
       if (mySelectionState == Mouse_StartSelection)
    {
        mySecondCursorX = point.x;
        mySecondCursorY = point.y;
        DrawSelectionRectangle(Standard_True);
    }
    CView::OnMouseMove(nFlags,point);
}

JudgeMouseInRect方法

判断当前坐标是否与center坐标重合
判断方法 mousePoint不落在以center为半径 r=4的范围内 为不重合 否则重合

Standard_Boolean CMyView::JudgeMouseInRect(CPoint center, CPoint mousePoint)
{
    Standard_Real xdis = abs(center.x - mousePoint.x);
    Standard_Real ydis = abs(center.y - mousePoint.y);
    double distance = sqrt(pow(xdis, 2) + pow(ydis, 2));//求距离
    if (distance - 4 <= Precision::Confusion())//这里设置以半径为4的范围 这里给了半径为4个像素
    {
        return Standard_True;
    }
    return Standard_False;
}

DrawSelectionRectangle方法

绘制矩形选择框 isDisplay 表示十分显示 或 不显示矩形框

Standard_Boolean CEquipmentCADView::DrawSelectionRectangle(Standard_Boolean isDisplay)
{
    Handle(AIS_InteractiveContext) hContext = GetDocument()->GetAISContext();
    if (!isDisplay)
    {
        hContext->Remove(this->mySelectionRectangle, Standard_False);
        hContext->CurrentViewer()->RedrawImmediate();
        return Standard_False;
    }
    //获取视口尺寸
    Standard_Integer winViewWidth;//视口窗体宽度
    Standard_Integer winViewHeight;//视口窗体高度
    this->myView->Window()->Size(winViewWidth, winViewHeight);//获取窗体尺寸
     //注意:这里用view的Window的size方法 而不是GetWindowRect()方法 因为GetWindowRect()方法左右上下会少像素

    this->mySelectionRectangle->SetRectangle(myFirstCursorX, winViewHeight - myFirstCursorY, mySecondCursorX, winViewHeight - mySecondCursorY);//设置矩形框的范围

    this->mySelectionRectangle->SetFillTransparency(0.8);//设置矩形填充的透明度为0.8

    //下面判断是全选还是部分选取的矩形框
    //当从左到右选取时为全选 只有物体的包围框完全落在矩形选择框之内才选择
    //当从右到左时为部分选。一旦物体的包围框与矩形选择框有相交就选择
    if (myFirstCursorX <= mySecondCursorX)
    {
        this->mySelectionRectangle->SetLineType(Aspect_TOL_SOLID);//设置边框线型为实线
        this->mySelectionRectangle->SetFillColor(Quantity_NOC_BLUE2);//设置填充颜色为蓝色
    }
    else
    {
        this->mySelectionRectangle->SetLineType(Aspect_TOL_DOT);//设置边框线型为虚点
        this->mySelectionRectangle->SetFillColor(Quantity_NOC_GREEN2);//设置填充颜色为绿色
    }
    this->mySelectionRectangle->SetFilling(Standard_True);//开启矩形填充模式

    //下面判断 如果已经显示了就更新图形
    //没有显示就显示图像
    if (!hContext->IsDisplayed(this->mySelectionRectangle))
    {
        hContext->Display(this->mySelectionRectangle, Standard_False);//显示对象
    }
    else
    {
        hContext->Redisplay(this->mySelectionRectangle, Standard_False);//更新对象显示
    }
    hContext->CurrentViewer()->RedrawImmediate();

    return Standard_True;
}
上一篇 下一篇

猜你喜欢

热点阅读