梦想CAD控件关于曲线问题

IMxDrawCurve 接口

控件中的曲线接口,实现了曲线的相关操作,如求曲线的长度,最近点,面积,曲线上任一点在曲线上的长度 切向方向,曲线交点,坐标变换,打断,偏移,离散等功能。

一、返回曲线组成的闭合区域面积

IMxDrawCurve::GetArea

返回曲线组成的闭合区域面积,具体详细如下:

参数 说明

[out] DOUBLE* pArea


返回闭合区域面积

C#代码计算闭合区域面积:


        MxDrawPolyline pl = new MxDrawPolyline();

        MxDrawPoint pt1 = new MxDrawPoint();

        pt1.x = 10;

        pt1.y = 10;

        MxDrawPoint pt2 = new MxDrawPoint();

        pt2.x = 20;

        pt2.y = 20;

        MxDrawPoint pt3 = new MxDrawPoint();

        pt3.x = 30.5;

        pt3.y = 10;

        pl.AddVertexAt(pt1);

        pl.AddVertexAt(pt2);

        pl.AddVertexAt(pt3);

        pl.IsClosedStatus = true;        

        double dArea = 0.0;

        pl.GetArea(out dArea);

IMxDrawCurve::GetArea2

返回曲线组成的闭合区域面积。

js代码计算闭合区域面积:

将此段代码放入鼠标事件中:


// 得到鼠标位置

var point = mxOcx.NewPoint();

point.x = dX;

point.y = dY;

// 构造择集,得到鼠标所在闭合区域。

// 设置过滤条件

var filter = mxOcx.NewResbuf();

// 设置PL线为过滤条件

filter.AddStringEx("LWPOLYLINE", 5020);

// 选择范围左下角

var pt1 = mxOcx.NewPoint();

pt1.x = point.x - 100;

pt1.y = point.y - 100;

// 选择范围右上角

var pt2 = mxOcx.NewPoint();

pt2.x = point.x + 100;

pt2.y = point.y + 100;

// 选择pt1,pt2所在范围内的对象.

var ss =mxOcx.NewSelectionSet();

ss.Select(1, pt1, pt2, filter);

for (var i = 0; i < ss.Count; i++)

{

    // 遍历所有对象,看当前点是在那个闭合区域内

    var pl =ss.Item(i);

    var dArea = pl.GetArea2 ();

    alert("面积为:" + dArea.toString());

}

二、打断曲线

主要用到函数说明:

IMxDrawCurve::SplitCurves

打断曲线,详细说明如下:

参数 说明

[in] IMxDrawResbuf* aryParam


打断位置参数数组,或打断的点数组,是个MxDrawResbuf对象


[out] IMxDrawResbuf** aryNewId


返回打断后生成的新曲线id,是个MxDrawResbuf对象

c#代码实现如下:


    private void DoSplitCurves()

    {

        MxDrawUtility mxUtility = new MxDrawUtility();

        object getPt;

        MxDrawEntity ent = mxUtility.GetEntity(out getPt, "选择打断的曲线:");        

        if (ent == null)            

        return;

        MxDrawCurve curve;        

        if (ent is MxDrawCurve)

        {

            curve = (MxDrawCurve)ent;

        }        

        else

        {

            MessageBox.Show("实体类型不对");            

            return;

        }

        MxDrawPoint getPt1 = (MxDrawPoint)(mxUtility.GetPoint(null"点取打断位置:"));        

        if (getPt1 == null)

        {

            MessageBox.Show("用户取消..");            

            return;

        }

        MxDrawResbuf param = new MxDrawResbuf();

        param.AddPoint(getPt1, -10);

        object objId;        

        if (curve.SplitCurves(param,out objId))

        {

            MxDrawResbuf rbId = (MxDrawResbuf)objId;

            MessageBox.Show("打断成功,生成的曲线个数:" + rbId.Count);            

            // 把以前的删除掉。

            ent.Erase();

        }        

        else

        {

            MessageBox.Show("打断失败");

        }

    }

选择曲线,把曲线从中间1/4 到 3/ 4处断开:


           MxDrawUtility mxUtility = new MxDrawUtility();

         object getPt;

         MxDrawEntity ent = mxUtility.GetEntity(out getPt, "选择打断的曲线:");         

         if (ent == null)             

             return;

         MxDrawCurve curve;         

         if (ent is MxDrawCurve)

         {

             curve = (MxDrawCurve)ent;

         }         

         else

         {

             MessageBox.Show("实体类型不对");             

             return;

         }         

         double dLen = 0.0;

         curve.GetDistAtParam(curve.GetEndParam(),out dLen);

         object pt1;         

         if (!curve.GetPointAtDist(dLen / 4.0, out pt1))             

         return;

         object pt2;         

         if (!curve.GetPointAtDist(dLen * 3.0 / 4.0, out pt2))             

         return;

         MxDrawPoint breakPt1 = (MxDrawPoint)pt1;

         MxDrawPoint breakPt2 = (MxDrawPoint)pt2;         

         if (breakPt1 == null || breakPt2 == null)             

         return;

         MxDrawResbuf param = new MxDrawResbuf();

         param.AddPoint(breakPt1, -10);

         param.AddPoint(breakPt2, -10);

         object objIds;         

         if (curve.SplitCurves(param, out objIds))

         {

             MxDrawResbuf rbId = (MxDrawResbuf)objIds;             

             if(rbId.Count == 3)

             {

                 axMxDrawX1.Erase(rbId.AtLong(1));

             }             

             // 把以前的删除掉。

             ent.Erase();

         }

js代码打断曲线实现如下:


    var ent = mxOcx.GetEntity("选择打断的曲线:");

    if (ent == null)

        return;

    

    var curve;

    if (ent.ObjectName == "McDbSpline")

    {

        curve =ent;

    }

    else

    {

        alert("实体类型不对");

        return;

    }

         

    var getPt1 = mxOcx.GetPoint(false,0,0,"\n 点取打断位置:");

           

    if (getPt1 == null)

    {

        alert("用户取消..");

        return;

    }

    var param = mxOcx.NewResbuf();

    param.AddPoint(getPt1);

    var objId = mxOcx.NewResbuf();

         

    if (curve.SplitCurves(param ,objId))

    {

        var rbId = objId;

        alert("打断成功");

        // 把以前的删除掉。

        ent.Erase();

    }

    else

    {

        alert("打断失败");

    }

三、得到曲线长度

主要用到函数说明:

IMxDrawCurve::GetLength2

返回曲线长度

js代码得到曲线长度实现如下:


    function GetCLength() {

        var ent = mxOcx.GetEntity("选择曲线:");

        if (ent == null)

            return;

    

        var curve;

        if (ent.ObjectName == "McDbSpline")

        {

            curve =ent;

        }

        else

        {

            alert("实体类型不对");

            return;

        }

        var curvelen = curve.GetLength2();

    

        alert(curvelen);

    }

四、得到两曲线的交点

IMxDrawEntity::IntersectWith

求两个实体的交点,具体详细如下:

参数 说明

[in] IDispatch* pIntersectObject


另一个求交实体


[in] MCAD_McExtendOption exOption


求交方式,现在不支持延伸实体求交点


[out,retval] IMxDrawPoints** intersectPoints


返回实体的相交点

js代码得到两曲线的交点:


    //求曲线的交点    

    function  IntersectPoint() {

        var ent1 = mxOcx.GetEntity("选择曲线1:");

        if (ent1 == null)

            return;

    

        var curve;

        if (ent1.ObjectName == "McDbSpline")

        {

            curve =ent1;

        }

        else

        {

            alert("实体类型不对");

            return;

        }

        var ent2 = mxOcx.GetEntity("选择曲线2:");

        if (ent2 == null)

            return;

    

        var curve1;

        if (ent2.ObjectName == "McDbSpline")

        {

            curve1 =ent2;

        }

        else

        {

            alert("实体类型不对");

            return;

        }

    

        var points = curve.IntersectWith(curve1, 1);

        if(points.Count == 0)

        {

            alert("没有求到交点");

        }

        else

        {

            var pt = points.Item(0);

            alert("交点为:" + pt.x + "," + pt.y);

        }

    }

四、曲线周围一点到曲线上的最近点

主要用到函数说明:

IMxDrawCurve::GetClosestPointTo2

返回曲线长度,具体说明如下:

参数 说明

[in] IMxDrawPoint* givenPnt


任一点


[in] VARIANT_BOOL isExtend


暂不支持


[out,retval] IMxDrawPoint** pPointOnCurve


返回曲线上的最近点

js代码求曲线周围一点到曲线上的最近点实现如下:


    var ent = mxOcx.GetEntity("选择曲线:");

    if (ent == null)

        return;

    

    var curve;

    if (ent.ObjectName == "McDbSpline")

    {

        curve =ent;

    }

    else

    {

        alert("实体类型不对");

        return;

    }

    

    var getPt1 = mxOcx.GetPoint(false,0,0,"\n 点取一个点:");

         

    if (getPt1 == null)

    {

        alert("用户取消..");

        return;

    }

    

    var ClosestPoint = curve.GetClosestPointTo2(getPt1,false);

    

    var grtClosestPointx = ClosestPoint.x;

    

    var grtClosestPointy = ClosestPoint.y;

         

    alert(grtClosestPointx);

    alert(grtClosestPointy);

五、离散曲线

主要用到函数说明:

IMxDrawCurve::GetSamplePoints

离散曲线,具体说明如下:

参数 说明

[in] DOUBLE dApproxEps


离散后的曲线的最大弧高


[out,retval] IMxDrawPoints** ppPointArray


返回离散的点数组

js代码实现如下:


    var ent = mxOcx.GetEntity("选择需要离散的曲线:");

    if (ent == null)

        return;

    

    var curve;

    if (ent.ObjectName == "McDbSpline")

    {

        curve =ent;

    }

    else

    {

        alert("实体类型不对");

        return;

    }

    var curvelen = curve.GetSamplePoints(1);

    if (curvelen == null) {

        return;

    }

    var pt = curvelen.Item(0);

    console.log(pt)

    mxOcx.PathMoveTo(pt.x, pt.y);

    for(var i = 1; i < curvelen.Count;i++)

    {

        pt = curvelen.Item(i);

        mxOcx.PathLineTo(pt.x,pt.y)

    }

    

    mxOcx.LineWidth = 10;

    mxOcx.DrawPathToPolyline();

六、偏移

主要用到函数说明:

IMxDrawCurve::OffsetCurves

曲线偏移,具体说明如下:

参数 说明

[in] DOUBLE dOffsetDist


偏移距离


[in] IMxDrawPoint* ptOffsetRef


偏移方向参考点,曲线向该点所在位置偏移


[out] IMxDrawResbuf** aryNewId


返回偏移后新生成的曲线id数组

c#代码实现如下:


    private void OffsetCurves()

    {

        MxDrawUtility mxUtility = new MxDrawUtility();

        object getPt;

        MxDrawEntity ent = mxUtility.GetEntity(out getPt,"选择编移的曲线:");        

        if (ent == null)            

        return;

        MxDrawCurve curve;        

        if(ent is MxDrawCurve)

        {

            curve = (MxDrawCurve)ent;

        }        else

        {

            MessageBox.Show("实体类型不对");            

            return;

        }

        MxDrawPoint getPt1 = (MxDrawPoint)(mxUtility.GetPoint(null"点取偏移位置:"));        

        if (getPt1 == null)

        {

            MessageBox.Show("用户取消..");            

            return;

        }

        MxDrawPoint getPt2 = (MxDrawPoint)(mxUtility.GetPoint(getPt1, "点取偏移距离:"));        

        if (getPt2 == null)

        {

            MessageBox.Show("用户取消..");            

            return;

        }

        Double dis = (getPt1.x - getPt2.x) * (getPt1.x - getPt2.x) + (getPt1.y - getPt2.y) * (getPt1.y - getPt2.y);

        dis = Math.Sqrt(dis);

        object objId;        

        if(curve.OffsetCurves(dis, getPt1, out objId) )

        {

            MxDrawResbuf rbId = (MxDrawResbuf)objId;

            MessageBox.Show("偏移生成的曲线个数:" + rbId.Count);

        }

    }

js代码实现如下:


var ent = mxOcx.GetEntity("选择偏移的曲线:");

if (ent == null)

    return;

var curve;

curve =ent;

    var getPt1 = mxOcx.GetPoint(false,0,0,"\n 点取偏移位置:");

    if(getPt1 == null)

    {

        return;

    }

    var getPt2 = mxOcx.GetPoint(true,getPt1.x,getPt1.y,"\n 点取偏移距离:");

    if(getPt2 == null)

    {

        return;

    }

    var dis = (getPt1.x - getPt2.x) * (getPt1.x - getPt2.x) + (getPt1.y - getPt2.y) * (getPt1.y - getPt2.y);

     dis = Math.sqrt(dis);

    //dis = Math.sqrt();

    //var objId;

    var objId = mxOcx.NewResbuf();

    if(curve.OffsetCurves2(dis, getPt1))

    {

        var rbId = objId;

       

        // 把以前的删除掉。

        ent.Erase();

    }

七、绘制pl线

js代码实现如下:


function DrawPolyline()

{

      var mxOcx = document.all.item("MxDrawXCtrl");

              mxOcx.focus();

      var point1 = mxOcx.GetPoint(false,0,0,"\n 点取开始点:");

      if(point1 == null)

      {

             return;

      }

      //mxOcx.PathMoveToEx(point1.x,point1.y,10,10,0.0);

      mxOcx.PathMoveTo(point1.x,point1.y);

             

      var point2 = mxOcx.GetPoint(true,point1.x,point1.y,"\n 点取下一个:");

      if(point2 == null)

      {

             return;

      }

      var tmpobj = new Array();

      //mxOcx.PathLineToEx(point2.x,point2.y,10,10,0.0);

      mxOcx.PathLineTo(point2.x,point2.y);

                var iCount = 0;

      var id = mxOcx.DrawLine(point1.x,point1.y,point2.x,point2.y);

          tmpobj[iCount] = id;

                iCount = iCount + 1;

      point1 = point2;

                while(true)

                {

                       var point2 = mxOcx.GetPoint(true,point1.x,point1.y,"\n 点取下一个:");

         if(point2 == null)

         {

                break;

         }

         mxOcx.PathLineTo(point2.x,point2.y);

         var id = mxOcx.DrawLine(point1.x,point1.y,point2.x,point2.y);

             tmpobj[iCount] = id;

                   iCount = iCount + 1;

         point1 = point2;

                }

                var i = 0;

                for(;i < iCount;i++)

                {

         mxOcx.Erase(tmpobj[i] );

                }

                var lId = mxOcx.DrawPathToPolyline();

      // 把新绘的pl线变成双线。

                var param = mxOcx.Call("Mx_NewResbuf","");

                param.AddLong(lId);

      // 双线的宽度。

                var lineWidth = 2;

                param.AddDouble(lineWidth);

      // 调用变双线函数。

               var ret = mxOcx.CallEx("ExApp_MakeDoubleLine",param);

               

      if(ret.AtString(0) == "Ok")

      {

         // 返回的绘制的双线对象id.

         alert(ret.AtLong(1));

      }

      // 删除旧的pl线。

                mxOcx.Erase(lId);

      

}

八、由曲线上的一点返回该点到曲线开始点的长度

主要用到函数说明:

IMxDrawCurve::GetDistAtPoint

由曲线上的一点返回该点到曲线开始点的长度,具体说明如下:

参数 说明

[in] IMxDrawPoint* point


曲线上的一点


[out] DOUBLE* pDis


返回到开始点的曲线上长度

js代码实现如下:


    var ent = mxOcx.GetEntity("选择曲线:");    

    if (ent == null)

        return;

    var curve;

    if (ent.ObjectName == "McDbSpline")

    {

        curve =ent;

    }

    else

    {

        alert("实体类型不对");

        return;

    }

    var getPt1 = mxOcx.GetPoint(false,0,0,"\n 点取一个点:");

    if (getPt1 == null)

    {

        alert("用户取消..");

        return;

    }

    if (curve.GetDistAtPoint2(getPt1))

    {

        alert(curve.GetDistAtPoint2(getPt1));

    }

    else

    {

        alert("失败");

    }

九、返回指定参数在曲线上,到开始点的曲线上长度

主要用到函数说明:

IMxDrawCurve::GetDistAtParam

返回指定参数在曲线上,到开始点的曲线上长度,具体说明如下:

参数 说明

[in] DOUBLE dParam


曲线参数


[out] DOUBLE* pDis


返回到开始点的曲线上长度

js代码实现如下:


    var ent = mxOcx.GetEntity("选择曲线:");

    if (ent == null)

        return;

    var curve;

    if (ent.ObjectName == "McDbSpline")

    {

        curve =ent;

    }

    else

    {

        alert("实体类型不对");

        return;

    }

    var curvelen = curve.GetEndParam();

    

    if (curve.GetDistAtParam2(curvelen))

    {

        var my = curve.GetDistAtParam2(curvelen);

        alert(my);

      

    }

    else

    {

        alert("失败");

    }

十、得到指定参数在曲线上的点坐标

主要用到函数说明:

IMxDrawCurve::GetPointAtParam

得到指定参数在曲线上的点坐标,具体说明如下:

参数 说明

[in] DOUBLE dParam


曲线上的参数


[out] IMxDrawPoint** pPoint


返回曲线的点

js代码实现如下:


    var ent = mxOcx.GetEntity("选择曲线:");

    if (ent == null)

        return;

    var curve;

    if (ent.ObjectName == "McDbSpline")

    {

        curve =ent;

    }

    else

    {

        alert("实体类型不对");

        return;

    }

    var curvelen = curve.GetStartParam();

    

    if (curve.GetPointAtParam2(curvelen))

    {

        var my = curve.GetPointAtParam2(curvelen);

        alert(my.x);

        alert(my.y);

    }

    else

    {

        alert("失败");

    }

十一、返回曲线上一点在曲线上的参数

主要用到函数说明:

IMxDrawCurve::GetParamAtPoint

返回曲线上一点在曲线上的参数,具体说明如下:

参数 说明

[in] IMxDrawPoint* point


曲线的点


[out] DOUBLE* pParam


返回曲线上的参数

js代码实现如下:


    var ent = mxOcx.GetEntity("选择曲线:");

    if (ent == null)

        return;

    var curve;

    if (ent.ObjectName == "McDbSpline")

    {

        curve =ent;

    }

    else

    {

        alert("实体类型不对");

        return;

    }

    var getPt1 = mxOcx.GetPoint(false,0,0,"\n 点取一个点:");

    if (getPt1 == null)

    {

        alert("用户取消..");

        return;

    }

    if (curve.GetParamAtPoint2(getPt1))

    {

        alert(curve.GetParamAtPoint2(getPt1));

    }

    else

    {

        alert("失败");

    }

十二、求曲线参数所在位置的一价导数,这就是切向方向

主要用到函数说明:

IMxDrawCurve::GetFirstDeriv

求曲线参数所在位置的一价导数,这就是切向方向,具体说明如下:

参数 说明

[in] DOUBLE dParam


曲线参数


[out] IMxDrawVector3d** pFirstDeriv


返回切向方向

js代码实现如下:


    var ent = mxOcx.GetEntity("选择曲线:");

    if (ent == null)

        return;

    var curve;

    if (ent.ObjectName == "McDbLine")

    {

        curve =ent;

    }

    else

    {

        alert("实体类型不对");

        return;

    }

    var curvelen = curve.GetEndParam();

    

    if (curve.GetFirstDeriv2(curvelen))

    {

        var my = curve.GetFirstDeriv2(curvelen);

        alert(my.x);

        alert(my.y);

    }

    else

    {

        alert("失败");

    }

十三、返回曲线上到开始点的曲线长度对应的曲线参数

主要用到函数说明:

IMxDrawCurve::GetParamAtDist

返回曲线上到开始点的曲线长度对应的曲线参数,具体说明如下:

参数 说明

[in] DOUBLE dDis


到开始点的曲线上长度


[out] DOUBLE* pParam


返回曲线参数

js代码实现如下:


    var ent = mxOcx.GetEntity("选择曲线:");

    if (ent == null)

        return;

    var curve;

    curve =ent;

    var curvelen = curve.GetLength2();

    

    var my = curve.GetParamAtDist2(0);

    alert(my);

    if (curve.GetParamAtDist2(curvelen))

    {

        alert(curve.GetParamAtDist2(curvelen));

    

    }

    else

    {

        alert("失败");

    }

原文地址:https://www.cnblogs.com/yzy0224/p/10860909.html

时间: 2024-10-09 18:21:20

梦想CAD控件关于曲线问题的相关文章

梦想CAD控件关于比较问题

全图比较 怎么比较两个CAD图纸文件修改前后的不同部分呢?在工程图纸设计中,我们更多情况下可能需要对同一张工程图的前后修改部分进行对比,以确定工程图纸的改动部分及追溯原因,本教程演示了几种常见的比较方法. 实现图纸比较功能,首先将两个控件放入网页中,js代码如下: <p align="center">   <object classid="clsid:74A777F8-7A8F-4e7c-AF47-7074828086E2" id="Mx

梦想CAD控件 2019.01.20更新

下载地址:http://www.mxdraw.com/ndetail_10120.html1. 修改CAD不等比例块保存问题2. 修改CAD捕捉时,Z值对捕捉不准的影响3. 修改图片对象选择后,自动跑到最前面问题4. 增加shx文件搜索路径设置选项:ShxPath5. 增加回车运行前一个命令配制选项6.增加控制那些CAD图层可以用来选择对象的配制选项.7. 增加返回CAD块引用的剪切边界功能8. 增加字典遍历器返回当前对象名称函数.9. 增加服务器后台,静默批量dwg转jpg例程,非常适用.10

梦想CAD控件自定义实体实现

一.增加自定义实体对象 调用DrawCustomEntity函数,绘制一个自定义实体对象. 下面代码绘制一个自定义实体,C#代码实现如下: private void DrawMlineCommand() {     MxDrawUiPrPoint getPt = new MxDrawUiPrPoint();     getPt.message = "点取第一点";     if (getPt.go() != MCAD_McUiPrStatus.mcOk)     {         r

梦想CAD控件 2018.7.26更新

下载地址: http://www.mxdraw.com/ndetail_107.html 1.  增加属性匹配功能 2.  增加List命令 3.  增加CAD图纸审图批注功能 4.  环形阵列功能 5.  修改有些CAD实体镜向不对 6.  修改在有些情况下,TrueType字体编辑后,显示不对问题 7.  增加CAD打印对话框调用时,可以设置打印区域参数 原文地址:https://www.cnblogs.com/yzy0224/p/9395162.html

CAD控件:梦想CAD控件功能更新 清除图上的所有高亮实体

1,修正得组里面的实体,把删除实体也返回的错误 2,修正代理实体改不了颜色问题. 3,修正捕捉块插入点,有时会跑到很远的位置问题. 4.MxDrawChange类增加ToBlockReference函数 5.增加MxDraw::DrawToJpgBase64,Mx_DrawToJpgBase64函数,把图纸上的内容保存为Base64字符编码的jpg图片 6.增加Mx_ClearAllHighlight函数,清除图上的所有高亮实体 7.修改缩放实体命令,在动态输入打开后,不能输入比例

CAD控件,CAD插件使用教程:Android开发使用控件--开发环境的搭建

Android开发使用控件入门--环境搭建 2014-12-24 09:57     14人阅读     评论(0)     收藏         编辑     删除 CAD控件.CAD三维控件,手机控件 Android开发控件 软件名称(,梦,,想.CAD  ,控件) 1. 环境搭建: 3 1.1. 安装Eclipse 3 1.2. 下载JDK 3 1.3. 下载Android SDK 5 1.4. 给Eclipse 安装ADT插件  8 1.5. 运行Eclipse设置Android ADT

高精度快速预览打开dwg文件的CAD控件CAD Image DLL介绍及下载

CAD Image DLL对于DXF格式, DWG格式(AutoCAD R12 到AutoCAD 2004/2005), PLT 以及 HPGL/HPGL2文件都有快速的显示速度和精度,开发者再也不会为如何打开dwg文件?dwg格式用什么打开?犯愁了.CAD Image DLL价格经济,是理想的商业化的程序内置CAD控件,包括Visual Basic, MS Visual C++, MS Visual Studio .NET, Borland Delphi, Borland C++ Builde

手机,平板当中浏览和编辑DWG的CAD控件出来啦!支持ARX二次开发

控件2014.06.30 安卓开发最新更新 发布时间:2014-06-30 22:22:42 开发包下载地址:http://www.mxdraw.com/MxDraw6.0Android(20140630)TryVersion.exe 安卓手机上的apk安装包: http://www.mxdraw.com/MxDrawApp60.apk 安卓快速入门文档: http://www.mxdraw.com/AndroidDev.doc 1. 优化dwg显示速度,现在可以极速显示dwg,比市面上的任何软

CAD控件:界面控制说明和方法

更新时间:2015 年08 月24 日 界面控制说明 目录 1.1 说明: ......................................................................................................................................... 4 1.2 菜单栏 ................................................................