学习C#操纵Visio之三:移动Shape位置

移动形状

         在实际应用中,我们还需要将Shape进行移动。将Shape进行移动的方法有两种。首先我们讲最简单的移动方式:选中à移动。

         选中移动是指先把被移动的Shape进行选择,然后再进行移动处理。在ApplicationClass中,有一个Window成员,叫做ActiveWindow,当前活跃窗口。通过ActiveWindow可以选择Shape,就像用鼠标在屏幕上选中对象一样。然后在通过ActiveWindowSelectionMove来进行移动,非常简单!

         代码:

 

/* ------------------------------------------------------------------ */

/* 使用Select的方式进行的移动                                         */

private void f_part3_move_shape_by_select(string sShape,double DeltaX,double DeltaY)

{

    Shape sp;

    Window aw;

 

    sp = findshapebyid(sShape);

    if (sp == null)

        return;

 

    aw = m_App.ActiveWindow;

    aw.Select(sp, (short)VisSelectArgs.visSelect);

    aw.Selection.Move(DeltaX, DeltaY, (VisUnitCodes.visCentimeters));

}

         需要注意的是,移动时有一个参数,叫做单位,这里用的是VisUnitCodes.visCentlmeters,也可以用毫米等等单位。移动的时候,都是以偏移量作为参数的。如果需要定位到某绝对位置,还需要更高深的技巧,比如要知道本形状当前的绝对位置等等。(看起来获得形状的当前绝对位置不难,其实还挺复杂,关键是要理解)。

 

         使用选择à移动的方式是我一开始使用的方法。当我逐渐深入了解visio之后,可以使用另外的方式进行移动。这就需要大家仔细去理解Cell,理解Row,理解Column,理解Visio的组织结构。

         下一种移动位置的方法是更改Shape中的位置资料。Shape中的位置资料是保存在Cell中的。要理解如何设置Cell,如何获得Cell,那就需要下边讲述的知识了。

         VisioSDK中,大量提及使用CellCellsSRC等等方式进行操作,但却基本没有提及Visio的形状大小、颜色等等。CellRowColumn一开始总是困扰着我,比如最开始设置一个形状数据,为啥是取自CellsSRCVisSectionProperty00)第0行第0列?

         Visio保存成为XML后,发现每一个形状都是使用XML进行描述的。这很重要,也就是说,Cell代表了XML中的一个叶子节点。比如形状数据中的值等等。根据保存的值,一个形状数据有很多属性,一个”CUSTID1”就有这么多内容:

<Prop NameU='Row_1' ID='1'>

<Value Unit='STR'>CUSTID1</Value>

<Prompt F='No Formula'/>

<Label>ID</Label>

<Format F='No Formula'/>

<SortKey F='No Formula'/>

<Type>0</Type>

<Invisible F='No Formula'>0</Invisible>

<Verify F='No Formula'>0</Verify>

<LangID>1033</LangID>

<Calendar F='No Formula'>0</Calendar>

</Prop>

我们取得的Value这个Cell来定位Shape的。我们还可以取这个CUSTID1Prompt,只需要用CellsSRC(VisSectionProperty,0, visCustPropsPrompt),注意,其实VisCustPropsPrompt的值是1visCustPropsLabel的值是2。这暗示了一件事,也就是说,Column,列,意味着在XML中的位置,比如我们看到Value Prop中的第一行,哪么,它对应的Column就是0,我们数到Type是第6行,对应的Column就是5,这是真的吗?当然,不信去查visCustPropsType,它就是5

哪么Row又是怎么回事呢?Row,在这里就是第几个Prop的意思。一个形状可以定义多个形状数据,哪么第一个形状数据就是Row 0,第二个就是Row1。这个可以用来枚举的。

哪么第一个参数Section是啥意思呢?因为我们是取形状数据,也就是CustProperty,因此第一个参数我们用的是visSectionProp

XML里边一个Shape可以有好多好多类的SectionProp只是其中之一而已。

 

言归正传,我们要设置Shape的位置,我们根据保存的XML可以很容易看出,Shape的位置信息似乎是在XForm这个Section里边的。

<XForm>

<PinX>1.771653543307088</PinX>

<PinY>10.23622047244095</PinY>

<Width>0.78740157480315</Width>

<Height>0.78740157480315</Height>

<LocPinX F='Inh'>0.393700787401575</LocPinX>

<LocPinY F='Inh'>0.393700787401575</LocPinY>

<Angle F='Inh'>0</Angle>

<FlipX F='Inh'>0</FlipX>

<FlipY F='Inh'>0</FlipY>

<ResizeMode F='Inh'>0</ResizeMode>

</XForm>

按照我们一般的思想,Shape总归有一个左上角的坐标,其实我没找到。PinXPinY,是旋转的中心点。LocPinXLocPinY是这个Shape自身的中心点。后来我想啊想啊的就想明白了,Shape(形状)可能是不规则的,虽然可以获得包容Shape的最小矩形框,但是毕竟不是规则的,也就是说,可能没有左上角的含义。所谓Shape中心点,也就是以左上角定义的中心点。(真的是左上角坐标系吗?呵呵)

实际上,Visio采用的坐标系是左下角坐标系,也就是说,以页面左下角为0,0,页面左上端为0,MaxY,页面右上端是MaxX,MaxY

 

Ok,移动一个Shape,也就是设置<XForm><PinX><PinY>就可以了。根据上边我们对Cell的理解,也就是设置PinX,PinY这两个Cell就可以了。

get_CellsSRC的三个参数怎么填写呢?首先是Section节,Visio没有对XForm定义单独的Section,它把它归在了VisSectionIndices.visSectionObject中,也就是说SectionObject,它需要使用Row来确定是取XForm节,我猜了一下,是(short)VisRowIndices.visRowXFormOut节。其实还有一个,叫visRowXFormInvisRowXFormOutvisRowXFormIn这两个参数定义都是0,为啥呢?因为<XForm><Shape>的第一个定义,按照VisioCellRowColumn的参数定义,第一个就是0嘛。

第三个参数Column就很简单,取PinX就填写0,取PinY就填写1,实际上VisioSDK的参数中也是这样定义的,visXFormPinX = 0visXFormPinY = 1

        

看起来似乎一切正常。我们取得了表示位置中心的PinXPinY Cell,只需要动动小手指,改一下这两个Cell的值,就可以搞定移动了。根据我们前边的知识,只需要设置Formula(汗死)就可以了。

实际上我第一次也这样干的,傻呗。正确的做法是使用set_Resultget_Result,如下所示:

m_Cell = sp.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowXFormOut,

      (short)VisCellIndices.visXFormPinX);

m_Cell.set_Result(VisUnitCodes.visCentimeters, m_Cell.get_Result(VisUnitCodes.visCentimeters) + DeltaX);

m_Cell = sp.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowXFormOut,

      (short)VisCellIndices.visXFormPinY);

m_Cell.set_Result(VisUnitCodes.visCentimeters, m_Cell.get_Result(VisUnitCodes.visCentimeters) + DeltaY);

 

 

/* ------------------------------------------------------------------ */

/* 打开D:/TestVisio/TestCase01.vsd,移动CUSTID1的图像,本次实现的移动  */

/* 不是使用Select的方式进行的,尝试通过修改ParentShape的属性实现 */

private void f_part3_move_shape(string sShape,double DeltaX,double DeltaY)

{

    Shape sp;

    short iRet;

    Cell m_Cell;

    /* ------------------------------------------------------------------ */

   /*  <XForm>

           <PinX>1.771653543307088</PinX>

           <PinY>10.23622047244095</PinY>

           ...

    *   PinX是指的形状的中心点。

    */

   sp = findshapebyid(sShape);

    if (sp == null)

        return;

    iRet = sp.get_CellsSRCExists((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowXFormOut,

                    (short)VisCellIndices.visXFormPinX, (short)1);

    if (iRet == 0)

    {

        Console.WriteLine("Internal error? can't find <XForm> <PinX>?");

        return;

    }

   

    m_Cell = sp.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowXFormOut,

            (short)VisCellIndices.visXFormPinX);

   m_Cell.set_Result(VisUnitCodes.visCentimeters, m_Cell.get_Result(VisUnitCodes.visCentimeters) + DeltaX);

    m_Cell = sp.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowXFormOut,

                    (short)VisCellIndices.visXFormPinY);

    m_Cell.set_Result(VisUnitCodes.visCentimeters, m_Cell.get_Result(VisUnitCodes.visCentimeters) + DeltaY);

}

 

当然还免不了有测试代码,动画效果哦。

public void TestCase01Part3()

{

    bool m_bRet;

    int  i;

 

    m_Gvar = new CGvars();

    m_bRet = m_Gvar.OpenVisioDocument("D://TestVisio//TestCase01.vsd", (short)Microsoft.Office.Interop.Visio.VisOpenSaveArgs.visOpenCopy);

    if (m_bRet == false)

        return;

    m_App = m_Gvar.GetApplicationClass();

    m_Doc = m_Gvar.GetDocument();

    try

    {

        /* 切换到全屏 */

        m_App.DoCmd((short)VisUICmds.visCmdFullScreenMode);

        for (i = 0; i < 10; i++)

        {

            f_part3_move_shape("/"CUSTID1/"", 0.2, 0);

            Thread.Sleep(20);

        }

        for (i = 0; i < 10; i++)

        {

            f_part3_move_shape_by_select("/"CUSTID2/"", 0.2, 0);

            Thread.Sleep(20);

        }

  Thread.Sleep(3000);                         /* 3秒之后程序退出 */

        m_Doc.Saved = true;                         // 防止关闭弹出保存对话框

    }

    finally

    {

        m_Doc.Close();

        m_App.Quit();

    }

}

 

 

 

你可能感兴趣的:(xml,String,object,C#,null,visio)