Open Cascade MFC应用程序中使用AIS_RubberBand绘制矩形选择框的问题及处理方法


@版权声明:本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出,
本文链接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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • DAY1 今日关键词:早起!5:18分 早上好,今天开始第一天的MOS考前学习,制作Exce工作薄,以分析产品销售...
    晨E战到底阅读 360评论 0 1
  • 亲爱的全球易效能教练,大家早上好!又到了我们每周二的教练晨会时间,那在这里温馨提示各位教练请您按编号加姓名的方式修...
    程彦瑞阅读 473评论 0 0
  • 计算机由硬件和软件构成 计算机硬件的五大部件:运算器、控制器、存储器、输入设备、输出设备 计算机软件:系统软件(操...
    Givemeasmi_75e7阅读 338评论 0 0
  • 虽然现在已经是凌晨2点了,为了履行我的承诺,必须写下我今天的成功日记,准确说是昨天的成功日记。今天是我坚持写...
    木子姐陪伴成长阅读 356评论 0 2
  • 金马老师布置作业后的第一时间就在大猫城堡下单了纸质版《刘大猫的财富之旅》,虽然金马老师也同时发了免费电子版,当时想...
    爬树的蜗牛tangbao阅读 333评论 0 2

友情链接更多精彩内容