wpf --自定义控件的transeform

来源:互联网 发布:波粒二象性知乎 编辑:程序博客网 时间:2024/04/30 08:02

 WPF不可以对非WPF控件进行Transform操作,但是对于我们自定义的控件仍然可以曝露消息进行一些Transform 操作,Transform 一般来说就是Matrix的实现,对于Matrix我们先来做道题:

  已知圆心O(0,0) ,在坐标轴上有一点P( x , y ), 逆时针旋转OP a度,使得P点到P1(x1,y1),用x,y表示p1点的坐标。

WPF自定义控件——使用Win32控件

  解:显然P1 O等于 PO,作 X轴上任意一点M,假设我们的角MOP为b度,又已知角P1OP为a度。

  那么得

  x1 = PO * COS(a+b)

  y1=  PO * SIN(a+b)

  展开得

  x1 = PO * COS(a) * COS(b) – PO * SIN(a) * SIN(b)

  y1 = PO * SIN(a)* COS(b) + PO * COS(a) * SIN(b)

  因为

  x = PO * COS(b)

  y = PO * SIN(b)

  代入上式得

  x1 = x * COS(a) – y*SIN(a)

  y1 = y*COS(a) + x*SIN(a)

  如果你对三角函数忘的够彻底的话请看

  http://zh.wikipedia.org/w/index.php?title=三角函数&variant=zh-cn

  用矩阵表示移动前的点

  x1[1*x ,0*y]

  y1[0*x ,1*y]

  移动后转变成了

   x           y

  x1 [COS(a) ,  –SIN(a)]

  y1 [COS(a) ,    SIN(a)]

  当然我们可能还有偏移量,比如向正方向竖移2个单位,向正单位横移1个单位,也就是做了个仿射变换

  x1 [COS(a) ,  –SIN(a)]

  y1 [COS(a) ,    SIN(a)]

  z   [ 1         ,    2       ]

  为了变化方便所以还加了一列,这样的话上面的平移我们还可以这样得到

   [1,0,0] * x1 [COS(a) , –SIN(a) ,0] 

   [0,1,0] * y1 [COS(a) ,   SIN(a) ,0]

   [1,2,1] * z   [0         ,    0       ,1]    

  注意:矩阵的乘法中 A*B 不等于 B * A 。

  http://zh.wikipedia.org/w/index.php?title=变换矩阵&variant=zh-cn#.E4.BB.BF.E5.B0.84.E5.8F.98.E6.8D.A2http://zh.wikipedia.org/w/index.php?title=矩阵&variant=zh-cn

WPF自定义控件——使用Win32控件

  图片看不清楚?请点击这里查看原图(大图)。

   从以上你是感觉Matrix就是一个点的变化么,把图像中的每个点都逆时针旋转下,图像就斜了,或许你可以模拟出WPF中的RotateTransform、ScaleTransform、SkewTransform、TranslateTransform  这些类的效果。

  对于WPF中当前的Matrix可以这样得到 Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;

  四.消息通知

   知道了这些我们就可以把Matrix作为参数发送个win32自定义画图让其也一起旋转,变化.对于非托管控件我们通常使用SendMessage来传递消息,这里用winform来做例子。

   这里我们先来看下http://hi.baidu.com/cyap/blog/item/9aebca0f5e4c612c6159f300.html这个网页对pinvoke中发送消息的一些使用说明;其中我们还要注意SendMessage中的第四个参数如果传递的是int,struct,string,byte类型就相对容易些;在Marshal中便有对应的函数读取Marshal.PtrToStructure,Marshal.PtrToStringAuto处理,假如传递是类的话,先要序列化,转化成2进制之后,因为从指针中并不能知道到这个指针所申请的空间大小,所以需要一个结构体来保存这个2进制数据的指针,以及他的长度。

public struct CopyDataStruct
{
  /// <summary>
  /// 数据长度
  /// </summary>
  public int cbData;
  /// <summary>
  /// 数据首地址指针
  /// </summary>
  public IntPtr lpData;
}

private void SendMessage()
{
  System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix();

  BinaryFormatter formatter = new BinaryFormatter();
  byte[] datas;
  using (System.IO.MemoryStream mStream = new System.IO.MemoryStream())
  {
    formatter.Serialize(mStream, matrix);
    datas = mStream.ToArray();
  }

  int length = datas.Length;
  IntPtr ptr = Marshal.AllocHGlobal(length);
  Marshal.Copy(datas, 0, ptr, length);
  CopyDataStruct data = new CopyDataStruct();
  data.cbData = length;
  data.lpData = ptr;

  SendMessage(hwndListBox, 700, 0, ref data);
  Marshal.FreeHGlobal(ptr);
}

protected override void WndProc(ref Message m)
{
  base.WndProc(ref m);
  if (m.Msg == 700)
  {
    CopyDataStruct data = new CopyDataStruct();
    data = (CopyDataStruct)m.GetLParam(data.GetType());
    byte[] datas = new byte[data.cbData];
    Marshal.Copy(data.lpData, datas, 0, data.cbData);

    BinaryFormatter formatter = new BinaryFormatter();
    using (System.IO.MemoryStream mStream = new System.IO.MemoryStream(datas))
    {
      //得到对象
      object obj = formatter.Deserialize(mStream);
    }
  }
}

 

  当然如果你感觉比较麻烦的话,也可以把这两个值分别放在WParam和LParam传送(这个做法不推荐)。

WPF自定义控件——使用Win32控件