自己动手把 VTK 封装成 Windows Forms 控件

2024-08-16 16:01:54 浏览数 (2)

虽然 Kitware 提供了 ActiViz 作为 vtk 的 .Net 库,但这是一个收费软件,并且在调试模式下一直存在程序退出时资源无法释放的问题,于是自己动手做了 vtk 的 .Net 封装库。

代码语言:csharp复制
/*
 * 功能:把 VTK 封装成 Windows Forms 控件
 * 作者:秦建辉
 * 微信:splashcn
 * VTK版本:9.3.1
 */ 
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace FirstSolver
{
    /// <summary>
    /// VTK WinForm 控件
    /// </summary>
    public class RenderWindowControl : UserControl
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public RenderWindowControl()
        {   // 设置控件样式
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque | ControlStyles.ResizeRedraw, true);
            InitializeComponent();
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="disposing">true/false:是否释放托管资源</param>
        protected override void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    components?.Dispose();
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
        }

        /// <summary>
        /// 同步窗口大小
        /// </summary>
        internal void SyncRenderWindowSize() => RenderWindow?.SetSize(Size.Width, Size.Height);

        /// <summary>
        /// 引发 HandleCreated 事件
        /// </summary>
        /// <param name="e">包含事件数据的 EventArgs</param>
        protected override void OnHandleCreated(EventArgs e)
        {
            if (!DesignMode)
            {   // 不是处于设计模式
                RenderWindow = vtkRendererWindow.New(); // 渲染窗口

                Renderer = vtkRenderer.New(); // 渲染器
                RenderWindow.AddRenderer(Renderer);

                RenderWindowInteractor = vtkRenderWindowInteractor.New(); // 交互器
                RenderWindowInteractor.SetInteractorStyle(vtkInteractorStyleTrackballCamera.New());
                RenderWindow.SetInteractor(RenderWindowInteractor);

                RenderWindow.SetParentId(Handle); // 控件句柄                
            }
            base.OnHandleCreated(e);
        }

        /// <summary>
        /// 引发 HandleDestroyed 事件
        /// </summary>
        /// <param name="e">包含事件数据的 EventArgs</param>
        protected override void OnHandleDestroyed(EventArgs e)
        {
            if (Renderer != null && Renderer.Handle != IntPtr.Zero)
            {
                Renderer.SetRenderWindow(new vtkRendererWindow(IntPtr.Zero));
                Renderer = null;
            }

            if ((RenderWindowInteractor != null) && (RenderWindowInteractor.Handle != IntPtr.Zero))
            {
                RenderWindowInteractor.SetRenderWindow(new vtkRendererWindow(IntPtr.Zero));
                RenderWindowInteractor = null;
            }

            RenderWindow = null;
            base.OnHandleDestroyed(e);
        }

        #region MouseEvent
        /// <summary>
        /// 引发 MouseDown 事件
        /// </summary>
        /// <param name="e">包含事件数据的 MouseEventArgs</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (RenderWindowInteractor == null || RenderWindowInteractor.Handle == IntPtr.Zero) return;

            RenderWindowInteractor.SetEventInformationFlipY(e.X, e.Y, 0, 0, 0, e.Clicks, null);
            switch (e.Button)
            {
                case MouseButtons.Left:
                    RenderWindowInteractor.LeftButtonPressEvent();
                    break;

                case MouseButtons.Right:
                    RenderWindowInteractor.RightButtonPressEvent();
                    break;

                case MouseButtons.Middle:
                    RenderWindowInteractor.MiddleButtonPressEvent();
                    break;
            }
        }

        /// <summary>
        /// 引发 MouseMove 事件
        /// </summary>
        /// <param name="e">包含事件数据的 MouseEventArgs</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (RenderWindowInteractor == null || RenderWindowInteractor.Handle == IntPtr.Zero) return;

            RenderWindowInteractor.SetEventInformationFlipY(e.X, e.Y, 0, 0, 0, e.Clicks, null);
            RenderWindowInteractor.MouseMoveEvent();
        }

        /// <summary>
        /// 引发 MouseUp 事件
        /// </summary>
        /// <param name="e">包含事件数据的 MouseEventArgs</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (RenderWindowInteractor == null || RenderWindowInteractor.Handle == IntPtr.Zero) return;

            RenderWindowInteractor.SetEventInformationFlipY(e.X, e.Y, 0, 0, 0, e.Clicks, null);
            switch (e.Button)
            {
                case MouseButtons.Left:
                    RenderWindowInteractor.LeftButtonReleaseEvent();
                    break;

                case MouseButtons.Right:
                    RenderWindowInteractor.RightButtonReleaseEvent();
                    break;

                case MouseButtons.Middle:
                    RenderWindowInteractor.MiddleButtonReleaseEvent();
                    break;
            }
        }

        /// <summary>
        /// 引发 MouseWheel 事件
        /// </summary>
        /// <param name="e">包含事件数据的 MouseEventArgs</param>
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            if (RenderWindowInteractor == null || RenderWindowInteractor.Handle == IntPtr.Zero) return;

            RenderWindowInteractor.SetEventInformationFlipY(e.X, e.Y, 0, 0, 0, e.Clicks, null);
            if (e.Delta > 0)
            {   // 前滚
                RenderWindowInteractor.MouseWheelForwardEvent();
            }
            else
            {   // 后滚
                RenderWindowInteractor.MouseWheelBackwardEvent();
            }
        }
        #endregion

        #region KeyEvent
        /// <summary>
        /// 引发 KeyDown 事件
        /// </summary>
        /// <param name="e">包含事件数据的 KeyEventArgs</param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (RenderWindowInteractor == null || RenderWindowInteractor.Handle == IntPtr.Zero) return;

            RenderWindowInteractor.SetKeyEventInformation(e.Control ? 1 : 0, e.Shift ? 1 : 0, (sbyte)e.KeyCode, 1, null);
            RenderWindowInteractor.KeyPressEvent();
        }

        /// <summary>
        /// 引发 KeyPress 事件
        /// </summary>
        /// <param name="e">包含事件数据的 KeyPressEventArgs</param>
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (RenderWindowInteractor == null || RenderWindowInteractor.Handle == IntPtr.Zero) return;

            RenderWindowInteractor.SetKeyEventInformation(0, 0, (sbyte)e.KeyChar, 1, e.KeyChar.ToString());
            RenderWindowInteractor.CharEvent();
        }

        /// <summary>
        /// 引发 KeyUp 事件
        /// </summary>
        /// <param name="e">包含事件数据的 KeyEventArgs</param>
        protected override void OnKeyUp(KeyEventArgs e)
        {
            if (RenderWindowInteractor == null || RenderWindowInteractor.Handle == IntPtr.Zero) return;

            RenderWindowInteractor.SetKeyEventInformation(e.Control ? 1 : 0, e.Shift ? 1 : 0, (sbyte)e.KeyCode, 1, null);
            RenderWindowInteractor.KeyReleaseEvent();
        }
        #endregion

        /// <summary>
        /// 引发 SizeChanged 事件
        /// </summary>
        /// <param name="e">包含事件数据的 EventArgs</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            SyncRenderWindowSize();
            RenderWindowInteractor?.ConfigureEvent();
            base.OnSizeChanged(e);
            Invalidate();
        }

        #region Focus
        [DllImport("user32.dll")]
        internal static extern IntPtr SetFocus(IntPtr hWnd);

        /// <summary>
        /// 引发 GotFocus 事件
        /// </summary>
        /// <param name="e">包含事件数据的 EventArgs</param>
        protected override void OnGotFocus(EventArgs e)
        {
            if (RenderWindow != null && RenderWindow.Handle != IntPtr.Zero)
            {
                IntPtr genericWindowId = RenderWindow.GetGenericWindowId();
                if (genericWindowId != IntPtr.Zero)
                {
                    try
                    {
                        SetFocus(genericWindowId);
                    }
                    catch
                    {
                        // 屏蔽异常
                    }
                }
            }
            base.OnGotFocus(e);
        }
        #endregion

        /// <summary>
        /// 引发 Paint 事件
        /// </summary>
        /// <param name="e">包含事件数据的 PaintEventArgs</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            if (RenderWindow != null && RenderWindow.Handle != IntPtr.Zero)
            {
                if (Visible)
                {
                    SyncRenderWindowSize();
                    if (RenderWindow.GetInteractor().Handle != RenderWindowInteractor.Handle)
                    {   // 设置新的交互器
                        RenderWindow.SetInteractor(RenderWindowInteractor);
                    }
                    RenderWindow.Render();
                }
            }
            base.OnPaint(e);
        }

        /// <summary>
        /// 引发 VisibleChanged 事件
        /// </summary>
        /// <param name="e">包含事件数据的 EventArgs</param>
        protected override void OnVisibleChanged(EventArgs e) => base.OnVisibleChanged(e);

        /// <summary>
        /// 初始化组件
        /// </summary>
        private void InitializeComponent()
        {
            SuspendLayout();
            AutoScaleDimensions = new SizeF(6f, 13f);
            AutoScaleMode = AutoScaleMode.Font;
            Name = "RenderWindowControl";
            Size = new Size(400, 300);
            ResumeLayout(false);
        }

        #region Property
        /// <summary>
        /// 渲染窗口
        /// </summary>
        public vtkRendererWindow RenderWindow { get; protected set; }

        /// <summary>
        /// 渲染器
        /// </summary>
        public vtkRenderer Renderer
        {
            get => _renderer;
            set
            {
                if (_renderer == null)
                {
                    _renderer = value;
                }
                else
                {
                    if (value == null || _renderer.Handle != value.Handle)
                    {
                        _renderer.Delete();
                        _renderer = value;
                    }
                }
            }
        }
        private vtkRenderer _renderer;        

        /// <summary>
        /// 渲染窗口交互器
        /// </summary>
        public vtkRenderWindowInteractor RenderWindowInteractor
        {
            get => _renderWindowInteractor;
            set
            {
                if (_renderWindowInteractor == null)
                {
                    _renderWindowInteractor = value;
                }
                else
                {
                    if (value == null || _renderWindowInteractor.Handle != value.Handle)
                    {
                        _renderWindowInteractor.Delete();
                        _renderWindowInteractor = value;
                    }
                }
            }
        }
        private vtkRenderWindowInteractor _renderWindowInteractor;

        /// <summary>
        /// 设计模式下的容器
        /// </summary>
        private IContainer components = null;
        #endregion
    }
}
vtk

0 人点赞