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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

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