Winform 做一个组织机构思维导图

就是把组织机构图做成思维导图的样子

本文是在别人的工作上进行了一定的更改,但是找不到这个链接了。

注:

1.组织结构图是用Graphics画的,因此他是一个图片。
2.本文给出了对图片进行点击时的一些响应事件。
先看一下结果图:
水平组织结构图(鼠标悬浮北京公司)
鼠标悬浮在北京公司上
垂直组织机构图(鼠标点击上海公司)
这里写图片描述

C# 源代码给出如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace DrawOrgChart
{
    public enum Orientation { Horizontal, Vertical };
    public class Tree<T>
    {
        Tree<T> _Parent = null;
        T _Content;
        List<Tree<T>> _Childs = new List<Tree<T>>();
        SizeF _Size;
        public Rectangle _Rec;
        private bool isHover = false;//指示鼠标是否在组织机构块上
        private bool isClick = false;//指示鼠标是否对组织结构进行了点击
        private int maxWidth;//组织机构图的最大宽度
        private int maxHeight;//组织结构图的最大高度
        private Pen pen = Pens.Blue;//画笔
        private Color clickColor = Color.BlueViolet;
        private int recHeight = 24;//矩形高度
        private int hInterval = 25;//水平间距
        private int vInterval = 16;//垂直间距
        private int borderWidth = 26;//画布两边宽度
        private int borderHeight = 26;//画布上下宽度
        private int verPadding = 5;//文字距边框的垂直距离
        private int horPadding = 10;//文字距边框的水平距离
        public bool IsHover { get { return isHover; } set { isHover = value; } }
        public bool IsClick { get { return isClick; } set { isClick = value; } }
        public int MaxWidth { get { return maxWidth; } set { maxWidth = value; } }
        public int MaxHeight { get { return maxHeight; } set { maxHeight = value; } }
        public int HInterval { get { return hInterval; } set { hInterval = value; } }
        public int VInterval { get { return vInterval; } set { vInterval = value; } }
        public Orientation OrientationMode = Orientation.Vertical;//用来指示组织机构图是水平的还是垂直的   

        public Tree(Tree<T> parent, T content)
        {
            _Parent = parent;
            _Content = content;
        }

        public Tree<T> Add(T content)
        {
            Tree<T> tree = new Tree<T>(this, content);
            _Childs.Add(tree);
            return tree;
        }

        public Tree<T> Parent { get { return _Parent; } }

        public T Content { get { return _Content; } set { _Content = value; } }

        public List<Tree<T>> Childs { get { return _Childs; } }

        public SizeF Size { get { return _Size; } set { _Size = value; } }

        public Rectangle Rec { get { return _Rec; } set { _Rec = value; } }
        /// <summary>
        /// 量测矩形框的完全放置字符串所需的大小
        /// </summary>
        /// <param name="g"></param>
        /// <param name="font"></param>
        /// <param name="addWidth">左右边距</param>
        /// <param name="addHeight">上下边距</param>
        void MeatureAllSize(Graphics g, Font font, int addWidth, int addHeight)
        {
            string s = _Content.ToString();
            SizeF size = g.MeasureString("我爱你中国", font);//用来获取5个字时的边框,水平分布时边框的宽度需要一定
            if (OrientationMode == Orientation.Vertical)//画垂直图时执行
            {
                _Size = g.MeasureString(s, font);
                _Size.Width += addWidth;
            }
            else//画水平图时执行
            {
                StringBuilder sb = new StringBuilder();
                int i=0;
                //将内容按5个字换行
                while (i < s.Length)
                {
                    if (i>0&&i % 5 == 0)
                    {
                        sb.Append("\r\n");
                    }
                    sb.Append(s[i]);
                    i++;
                }
                if (s.Length > 5)
                {
                    _Size = g.MeasureString(sb.ToString(), font);
                }
                else
                {
                    _Size = size;//小于5个字的情形
                }
                _Size.Width += addWidth;
                _Size.Height += addHeight;
            }
            foreach (Tree<T> tree in Childs)
                tree.MeatureAllSize(g, font, addWidth,addHeight);//为所有节点计算边框
        }
        /// <summary>
        /// 获取扁平化结构,画图的思想是将组织机构图的每一代节点放在一个列表里面,然后一个列表一个列表画
        /// </summary>
        /// <returns></returns>
        List<List<Tree<T>>> GetTreeLayers()
        {
            List<List<Tree<T>>> layers = new List<List<Tree<T>>>();
            GetTreeLayers(layers, new List<Tree<T>>(new Tree<T>[] { this }), 0);

            return layers;
        }

        void GetTreeLayers(List<List<Tree<T>>> layers, List<Tree<T>> childs, int level)
        {
            if (childs.Count == 0) return;
            if (layers.Count <= level) layers.Add(new List<Tree<T>>());

            for (int i = 0; i < childs.Count; i++)
            {
                layers[level].Add(childs[i]);
                GetTreeLayers(layers, childs[i].Childs, level + 1);
            }
        }
        /// <summary>
        /// 设置显示区域(从最后一层最左或最后一列最上开始)
        /// </summary>
        /// <param name="level"></param>
        /// <param name="height"></param>
        /// <param name="interval"></param>
        /// <param name="left"></param>
        void SetRectangle(int level, int height, int hInterval, int vInterval, int leftOrTop, Orientation orientation)
        {
            int index = 0;
            if (Parent != null) index = Parent.Childs.IndexOf(this);
            if (orientation == Orientation.Vertical)//垂直时
            {
                int left = leftOrTop;
                if (Childs.Count == 0)
                {
                    // 没有儿子,就向前靠
                    if (left > 0) left += hInterval;
                }
                else
                {
                    // 有儿子,就在儿子中间
                    int centerX = (Childs[0].Rec.Left + Childs[Childs.Count - 1].Rec.Right) / 2;
                    left = centerX - (int)_Size.Width / 2;

                    // 并且不能和前面的重复,如果重复,联同子孙和子孙的右边节点右移
                    if (Parent != null && index > 0)
                    {
                        int ex = (Parent.Childs[index - 1].Rec.Right + hInterval) - left;
                        if (index > 0 && ex > 0)
                        {
                            for (int i = index; i < Parent.Childs.Count; i++)
                                Parent.Childs[i].RightChilds(ex);
                            left += ex;
                        }
                    }
                }
                _Rec = new Rectangle(left, (height + vInterval) * level, (int)_Size.Width, height);
            }
            else//水平时
            {
                int top = leftOrTop;
                if (Childs.Count == 0)
                {
                    // 没有儿子,就向前靠
                    if (top > 0) top += vInterval;
                }
                else
                {
                    // 有儿子,就在儿子中间
                    int centerX = (Childs[0].Rec.Top + Childs[Childs.Count - 1].Rec.Bottom) / 2;
                    top = centerX - (int)_Size.Height / 2;

                    // 并且不能和前面的重复,如果重复,联同子孙和子孙的右边节点右移
                    if (Parent != null && index > 0)
                    {
                        int ex = (Parent.Childs[index - 1].Rec.Bottom + vInterval) - top;
                        if (index > 0 && ex > 0)
                        {
                            for (int i = index; i < Parent.Childs.Count; i++)
                                Parent.Childs[i].DownChilds(ex);
                            top += ex;
                        }
                    }
                }
                _Rec = new Rectangle(((int)_Size.Width+hInterval)*level, top, (int)_Size.Width, (int)_Size.Height);
            }
        }

        /// <summary>
        /// 所有子孙向右平移
        /// </summary>
        /// <param name="ex"></param>
        void RightChilds(int ex)
        {
            Rectangle rec;
            for (int i = 0; i < _Childs.Count; i++)
            {
                rec = _Childs[i].Rec;
                rec.Offset(ex, 0);
                _Childs[i].Rec = rec;
                _Childs[i].RightChilds(ex);
            }
        }
        /// <summary>
        /// 所有子孙向下平移
        /// </summary>
        /// <param name="ex"></param>
        void DownChilds(int ex)
        {
            Rectangle rec;
            for (int i = 0; i < _Childs.Count; i++)
            {
                rec = _Childs[i].Rec;
                rec.Offset(0, ex);
                _Childs[i].Rec = rec;
                _Childs[i].DownChilds(ex);
            }
        }

        void Offset(int x, int y)
        {
            _Rec.Offset(x, y);
            for (int i = 0; i < _Childs.Count; i++)
                _Childs[i].Offset(x, y);
        }

        public Bitmap DrawAsImage()
        {
            return DrawAsImage(pen, new Font("宋体", 10.5f), recHeight, horPadding,verPadding, hInterval, vInterval, borderWidth, borderHeight,OrientationMode);
        }

        public Bitmap DrawAsImage(Pen pen, Font font, int h, int horPadding,int verPadding,
            int horInterval, int verInterval, int borderWidth,int borderHeight,Orientation orientation)
        {
            Bitmap bmp = new Bitmap(1, 1);
            Graphics g = Graphics.FromImage(bmp);
            // 把树扁平化
            List<List<Tree<T>>> layers = GetTreeLayers();
            // 算出每个单元的大小
            MeatureAllSize(g, font, horPadding,verPadding);
            g.Dispose();
            bmp.Dispose();
            if (OrientationMode == Orientation.Vertical)//水平时
            {
                // 从最后一层开始排列
                //int left = 0;
                for (int i = layers.Count - 1; i >= 0; i--)
                {
                    int left = 0;
                    for (int j = 0; j < layers[i].Count; j++)
                    {
                        layers[i][j].SetRectangle(i, h, horInterval, verInterval, left, OrientationMode);
                        left = layers[i][j].Rec.Right;
                    }
                }

                Offset(borderWidth, borderWidth);

                // 获取画布需要的大小
                maxHeight = (h + verInterval) * layers.Count - verInterval + borderWidth * 2;
                maxWidth = 0;
                for (int i = layers.Count - 1; i >= 0; i--)
                {
                    for (int j = 0; j < layers[i].Count; j++)
                    {
                        if (layers[i][j].Rec.Right > maxWidth)
                            maxWidth = layers[i][j].Rec.Right;
                    }
                }
                maxWidth += borderWidth; // 边宽
                // 画
                bmp = new Bitmap(maxWidth, maxHeight);
            }
            else//水平时
            {
                // 从最后一列开始排列
                for (int i = layers.Count - 1; i >= 0; i--)
                {
                    int top = 0;
                    for (int j = 0; j < layers[i].Count; j++)
                    {
                        layers[i][j].SetRectangle(i, h, horInterval, verInterval, top, OrientationMode);
                        top = layers[i][j].Rec.Bottom;
                    }
                }

                Offset(borderWidth, borderWidth);

                // 获取画布需要的大小
                maxHeight=0;
                maxWidth = 0;
                for (int i = layers.Count - 1; i >= 0; i--)
                {
                    for (int j = 0; j < layers[i].Count; j++)
                    {
                        if (layers[i][j].Rec.Right > maxWidth)
                            maxWidth = layers[i][j].Rec.Right;
                        if(layers[i][j].Rec.Bottom>maxHeight)
                            maxHeight = layers[i][j].Rec.Bottom;
                    }
                }
                maxWidth += borderWidth; // 边宽
                maxHeight += borderHeight;
                // 画
                bmp = new Bitmap(maxWidth, maxHeight);
            }
            g = Graphics.FromImage(bmp);
            //这里主要针对贝塞尔曲线的抗锯齿,但是效果不怎么理想
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;  //图片柔顺模式选择            
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;//高质量
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;//再加一点
            g.Clear(Color.White);
            StringFormat format = (StringFormat)StringFormat.GenericDefault.Clone();
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Far;

            Rectangle rec, recParent;
            for (int i = 0; i < layers.Count; i++)
            {
                for (int j = 0; j < layers[i].Count; j++)
                {
                    // 画字
                    rec = (Rectangle)layers[i][j].Rec;
                    //矩形内矩形
                    Rectangle rec2 = new Rectangle(rec.Left + 2, rec.Top + 2, rec.Width - 4, rec.Height - 4);
                    g.DrawRectangle(pen, rec);
                    //画阴影
                    g.DrawLine(Pens.DimGray, new Point(rec.Left + 1, rec.Bottom + 1), new Point(rec.Right + 1, rec.Bottom + 1));
                    g.DrawLine(Pens.DimGray, new Point(rec.Right + 1, rec.Top + 1), new Point(rec.Right + 1, rec.Bottom + 1));
                    g.DrawLine(Pens.Gray, new Point(rec.Left + 2, rec.Bottom + 2), new Point(rec.Right + 2, rec.Bottom + 2));
                    g.DrawLine(Pens.Gray, new Point(rec.Right + 2, rec.Top + 2), new Point(rec.Right + 2, rec.Bottom + 2));
                    //g.DrawEllipse(pen, rec);
                    if (layers[i][j].isHover && !layers[i][j].isClick)//进入矩形时执行
                    {
                        g.FillRectangle(new LinearGradientBrush(rec, Color.White, Color.LightBlue, LinearGradientMode.ForwardDiagonal), rec);
                        //g.FillEllipse(new SolidBrush(hoverColor), rec);
                    }
                    if (layers[i][j].isHover && layers[i][j].isClick)//点击矩形时执行
                    {
                        g.DrawRectangle(Pens.Black, rec2);
                        g.FillRectangle(new LinearGradientBrush(rec, Color.White, Color.AliceBlue, LinearGradientMode.ForwardDiagonal), rec2);
                        //g.FillEllipse(new SolidBrush(hoverColor), rec);
                    }
                    g.DrawString(layers[i][j].Content.ToString(), font, new SolidBrush(pen.Color),
                        rec, format);
                    // 画到父亲的线
                    if (layers[i][j].Parent != null)
                    {
                        recParent = layers[i][j].Parent.Rec;                        
                        //画贝塞尔线
                        if (orientation == Orientation.Vertical)
                        {
                            g.DrawBezier(pen, new Point(rec.Left + rec.Width / 2, rec.Top), new Point(rec.Left + rec.Width / 2, rec.Top - verInterval / 2), new Point(recParent.Left + recParent.Width / 2, recParent.Bottom + verInterval / 2), new Point(recParent.Left + recParent.Width / 2, recParent.Bottom));
                        }
                        else
                        {
                            g.DrawBezier(pen, new Point(rec.Left, rec.Top + rec.Height / 2), new Point(rec.Left - horInterval / 2, rec.Top + rec.Height / 2), new Point(recParent.Right + horInterval / 2, recParent.Bottom - recParent.Height / 2), new Point(recParent.Right, recParent.Bottom - recParent.Height / 2));
                        }
                    }
                }
            }
            g.Flush();
            g.Dispose();
            return bmp;
        }
    }
}

form程序如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DrawOrgChart
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        List<Tree<string>> nodes = new List<Tree<string>>();
        Tree<string> tree;
        private void Form1_Load(object sender, EventArgs e)
        {
            cmbOrientation.SelectedIndex = 0;
            tree = new Tree<string>(null, "董事会");
            nodes.Add(tree);
            nodes.Add(tree.Add("董事秘书室特殊机构"));
            nodes.Add(tree.Add("北京公司"));

            nodes.Add(tree.Add("上海公司"));
            nodes.Add(tree.Add("山西公司"));

            nodes.Add(tree.Childs[1].Add("总经理办公室"));
            nodes.Add(tree.Childs[1].Add("财务部"));
            nodes.Add(tree.Childs[1].Add("销售部"));

            nodes.Add(tree.Childs[2].Add("上海销售部"));
            nodes.Add(tree.Childs[2].Add("上海秘书处"));

            nodes.Add(tree.Childs[3].Add("太原分部"));


        }      

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            Point p = e.Location;
            double scaleX = (double)tree.MaxWidth / pictureBox1.Width;
            double scaleY = (double)tree.MaxHeight / pictureBox1.Height;
            switch (pictureBox1.SizeMode)
            {
                case PictureBoxSizeMode.Zoom:
                    double scale = scaleX < scaleY ? scaleY : scaleX;
                    if (scale == scaleX)
                    {
                        p.Y = (int)((p.Y - (pictureBox1.Height - tree.MaxHeight / scale) / 2) * scale);
                        p.X = (int)(p.X * scale);
                    }
                    else
                    {
                        p.X = (int)((p.X - (pictureBox1.Width - tree.MaxWidth / scale) / 2) * scale);
                        p.Y = (int)(p.Y * scale);
                    }
                    break;
                case PictureBoxSizeMode.StretchImage:

                    p.X = (int)(p.X * scaleX);
                    p.Y = (int)(p.Y * scaleY);
                    break;
            }
            bool changed = false;
            foreach (var node in nodes)
            {
                if (node.Rec.Contains(p))
                {
                    if (!node.IsHover)
                    {
                        node.IsHover = true;
                        changed = true;
                    }
                    break;
                }
                else
                {
                    if (node.IsHover)
                    {
                        node.IsHover = false;
                        changed = true;
                    }
                }
            }
            if (changed)
            {
                Bitmap bmp = tree.DrawAsImage();
                pictureBox1.Image = bmp;
                pictureBox1.Refresh();
            }
        }

        private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
        {            
            Point p = pictureBox1.PointToClient(MousePosition);
            double scaleX = (double)tree.MaxWidth / pictureBox1.Width;
            double scaleY = (double)tree.MaxHeight / pictureBox1.Height;
            switch (pictureBox1.SizeMode)
            {
                case PictureBoxSizeMode.Zoom:
                    double scale = scaleX < scaleY ? scaleY : scaleX;
                    if (scale == scaleX)
                    {
                        p.Y = (int)((p.Y - (pictureBox1.Height - tree.MaxHeight / scale) / 2) * scale);
                        p.X = (int)(p.X * scale);
                    }
                    else
                    {
                        p.X = (int)((p.X - (pictureBox1.Width - tree.MaxWidth / scale) / 2) * scale);
                        p.Y = (int)(p.Y * scale);
                    }
                    break;
                case PictureBoxSizeMode.StretchImage:

                    p.X = (int)(p.X * scaleX);
                    p.Y = (int)(p.Y * scaleY);
                    break;
            }
            Tree<string> nodeB = null;
            bool rectClicked = false;
            foreach (var node in nodes)
            {
                if (node.Rec.Contains(p))
                {
                    nodeB = node;                    
                    rectClicked = true;
                    break;
                }
            }            
            if (e.Button == MouseButtons.Left && e.Clicks == 1)
            {
                if (rectClicked)
                {
                    Form2 frm = new Form2();
                    frm.Text = nodeB.Content.ToString();
                    frm.Show();
                    //MessageBox.Show(nodeB.Content.ToString());
                }
            }
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            pictureBox1.ContextMenuStrip.Enabled = true;
            Point p = pictureBox1.PointToClient(MousePosition);
            double scaleX = (double)tree.MaxWidth / pictureBox1.Width;
            double scaleY = (double)tree.MaxHeight / pictureBox1.Height;
            switch (pictureBox1.SizeMode)
            {
                case PictureBoxSizeMode.Zoom:
                    double scale = scaleX < scaleY ? scaleY : scaleX;
                    if (scale == scaleX)
                    {
                        p.Y = (int)((p.Y - (pictureBox1.Height - tree.MaxHeight / scale) / 2) * scale);
                        p.X = (int)(p.X * scale);
                    }
                    else
                    {
                        p.X = (int)((p.X - (pictureBox1.Width - tree.MaxWidth / scale) / 2) * scale);
                        p.Y = (int)(p.Y * scale);
                    }
                    break;
                case PictureBoxSizeMode.StretchImage:

                    p.X = (int)(p.X * scaleX);
                    p.Y = (int)(p.Y * scaleY);
                    break;
            }
            bool rectClicked = false;            
            foreach (var node in nodes)
            {
                if (node.Rec.Contains(p))
                {
                    rectClicked = true;
                    break;
                }
            }
            if (!rectClicked)
            {
                contextMenuStrip1.Items[0].Enabled = true;
                contextMenuStrip1.Items[1].Enabled = false;
                contextMenuStrip1.Items[2].Enabled = false;
            }
            else
            {
                contextMenuStrip1.Items[0].Enabled = true;
                contextMenuStrip1.Items[1].Enabled = true;
                contextMenuStrip1.Items[2].Enabled = true;
            }
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Point p = pictureBox1.PointToClient(MousePosition);
                double scaleX = (double)tree.MaxWidth / pictureBox1.Width;
                double scaleY = (double)tree.MaxHeight / pictureBox1.Height;
                switch (pictureBox1.SizeMode)
                {
                    case PictureBoxSizeMode.Zoom:
                        double scale = scaleX < scaleY ? scaleY : scaleX;
                        if (scale == scaleX)
                        {
                            p.Y = (int)((p.Y - (pictureBox1.Height - tree.MaxHeight / scale) / 2) * scale);
                            p.X = (int)(p.X * scale);
                        }
                        else
                        {
                            p.X = (int)((p.X - (pictureBox1.Width - tree.MaxWidth / scale) / 2) * scale);
                            p.Y = (int)(p.Y * scale);
                        }
                        break;
                    case PictureBoxSizeMode.StretchImage:

                        p.X = (int)(p.X * scaleX);
                        p.Y = (int)(p.Y * scaleY);
                        break;
                }
                Tree<string> nodeB = null;
                bool rectClicked = false;
                foreach (var node in nodes)
                {
                    if (node.Rec.Contains(p))
                    {
                        nodeB = node;
                        rectClicked = true;
                        break;
                    }
                }
                if (rectClicked)
                {
                    nodeB.IsClick = true;
                    Bitmap bmp = tree.DrawAsImage();
                    pictureBox1.Image = bmp;
                    pictureBox1.Refresh();
                }
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Point p = pictureBox1.PointToClient(MousePosition);
                double scaleX = (double)tree.MaxWidth / pictureBox1.Width;
                double scaleY = (double)tree.MaxHeight / pictureBox1.Height;
                switch (pictureBox1.SizeMode)
                {
                    case PictureBoxSizeMode.Zoom:
                        double scale = scaleX < scaleY ? scaleY : scaleX;
                        if (scale == scaleX)
                        {
                            p.Y = (int)((p.Y - (pictureBox1.Height - tree.MaxHeight / scale) / 2) * scale);
                            p.X = (int)(p.X * scale);
                        }
                        else
                        {
                            p.X = (int)((p.X - (pictureBox1.Width - tree.MaxWidth / scale) / 2) * scale);
                            p.Y = (int)(p.Y * scale);
                        }
                        break;
                    case PictureBoxSizeMode.StretchImage:

                        p.X = (int)(p.X * scaleX);
                        p.Y = (int)(p.Y * scaleY);
                        break;
                }
                Tree<string> nodeB = null;
                bool rectClicked = false;
                foreach (var node in nodes)
                {
                    if (node.Rec.Contains(p))
                    {
                        nodeB = node;
                        rectClicked = true;
                        break;
                    }
                }
                if (rectClicked)
                {
                    nodeB.IsClick = false;
                    Bitmap bmp = tree.DrawAsImage();
                    pictureBox1.Image = bmp;
                    pictureBox1.Refresh();
                }
            }
        }

        private void btn1_Click(object sender, EventArgs e)
        {
            switch (cmbOrientation.SelectedItem.ToString()) 
            {
                case "水平":
                    foreach(var tree in nodes)
                    tree.OrientationMode = Orientation.Horizontal;
                    break;
                case "垂直":
                    foreach(var tree in nodes)
                    tree.OrientationMode = Orientation.Vertical;
                    break;
            }
            int hinterval,vinterval;
            if (!int.TryParse(txtHinterval.Text, out hinterval) || !int.TryParse(txtVinterval.Text, out vinterval))
            {
                MessageBox.Show("横向间距和纵向间距只能设置为整数");
                return;
            }
            else {
                tree.HInterval = hinterval;
                tree.VInterval = vinterval;
            }

            Bitmap bmp = tree.DrawAsImage();
            pictureBox1.Image = bmp;
            pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
            pictureBox1.Refresh();
        }       
    }
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是使用WinForm创建一个简单的画板的步骤: 1. 创建一个WinForm窗体,并添加一个PictureBox控件作为画板。 2. 添加两个Button按钮,一个用于开始画画,另一个用于保存画板上的内容。 ```csharp // 创建一个Form窗体 public partial class Form1 : Form { // 用于记录鼠标当前位置的变量 private int currentXpos; private int currentYpos; // 用于判断是否开始移动鼠标的标志位 private bool beginMove = false; // 用于绘制图像的画笔和画板 private Pen myPen; private Graphics g; // 用于保存绘制的图像 private Image myImage; public Form1() { InitializeComponent(); // 初始化画笔和画板 myPen = new Pen(Color.Red, 2); myImage = new Bitmap(pictureBox1.Width, pictureBox1.Height); g = Graphics.FromImage(myImage); } // 鼠标按下时开始绘制 private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { beginMove = true; currentXpos = e.X; currentYpos = e.Y; } // 鼠标移动时绘制线条 private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { if (beginMove) { g.DrawLine(myPen, currentXpos, currentYpos, e.X, e.Y); pictureBox1.Image = myImage; currentXpos = e.X; currentYpos = e.Y; } } // 鼠标释放时停止绘制 private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { beginMove = false; } // 点击保存按钮保存绘制的图像 private void btnSave_Click(object sender, EventArgs e) { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "JPEG Image|*.jpg|Bitmap Image|*.bmp|PNG Image|*.png"; saveFileDialog.Title = "Save an Image File"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { myImage.Save(saveFileDialog.FileName); } } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值