当前位置:编程学习 > C#/ASP.NET >>

画图问题。(GDI+相关,类似画图板)

小弟再做一个类似画图板的工具,
现在有两个问题需要请教。

1.
画图板的画图区域可以缩小和拉伸,这个是怎么实现的啊。
(画图区域我用的Panel,建立了双缓冲区,怎么才能缩小和拉伸呢。)

2.
要在画图区域画一个矩形,然后在右侧弹出了一个入力框,要求输入行数,如果在框内输入4,矩形变成固定大小的4等分。这个我用表单可以实现,但是表单不能在画图区域拖动,我要实现等分后的矩形可以在画图区域任意拖动。

3.
类似与问题2,要在画图区域画一个椭圆,然后在右侧弹出了一个入力框,要求输入椭圆个数,如果在框内输入4,就会在椭圆列再生成等大的3个椭圆。
生成的椭圆可以在画图区域任意拖动,这个怎么实现呢?我现在只可以实现画一个椭圆。

求高手帮忙解答,给思路就行。
给的分数就是我所有的积分了。谢谢了。 --------------------编程问答-------------------- --------------------编程问答-------------------- 1 可以在每次绘制时按比例来绘制(不推荐使用GDI+的空间比例缩放)
2 可以仿图层渲染概念,用户看到的图像,是循环每一个图层一起绘制到屏幕上的,这样,鼠标操作时只操作其中一个图层,渲染部分只负责循环绘制。
3 同2 --------------------编程问答-------------------- 还有个问题:我用GDI画出的图形,别的程序覆盖在图形窗体上,移开后画的图就不见了,留一片空白 --------------------编程问答-------------------- dim B as new bitmap
using G as graphics=graphics.fromimage(b)
绘制。。。
end using

picturebox1.backgroundimage=B --------------------编程问答-------------------- 差不多,我现在遇到差不多的问题。 --------------------编程问答-------------------- 其实如果你想绘制出来的是对象(可拖动放大缩小),最好就绘制的时候就用对象,然后还可引入层的概念(panle一层一层叠,然后每层上绘制单一形状。),最后合并(把每一步绘制工作记录到一个列表,最后按层顺序绘制。)。 --------------------编程问答-------------------- 留下邮箱  我发给例子给你 --------------------编程问答--------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;

namespace 绘图程序
{
    public partial class Draw : Form
    {
        public Draw()
        {
            InitializeComponent();
        }
        private DrawTools dt;
        private string sType;//绘图样式
        private string sFileName;//打开的文件名
        private bool bReSize = false;//是否改变画布大小
        private Size DefaultPicSize;//储存原始画布大小,用来新建文件时使用


        //pbimg"鼠标按下"事件处理方法
        private void pbImg_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (dt != null)
                {
                    dt.startDraw = true;//相当于所选工具被激活,可以开始绘图
                    dt.startPointF = new PointF(e.X, e.Y);
                }
            }
        }

        //pbimg"鼠标移动"事件处理方法
        private void pbImg_MouseMove(object sender, MouseEventArgs e)
        {
            Thread.Sleep(6);//减少cpu占用率
            mousePostion.Text = e.Location.ToString();
            if (dt.startDraw)
            {
                switch (sType)
                {
                    case "Dot": dt.DrawDot(e); break;
                    case "Eraser": dt.Eraser(e); break;
                    default: dt.Draw(e, sType); break;

                }
            }
        }

        //pbimg"鼠标松开"事件处理方法
        private void pbImg_MouseUp(object sender, MouseEventArgs e)
        {
            if (dt != null)
            {
                dt.EndDraw();
            }
        }

        //"窗体加载"事件处理方法
        private void Form1_Load(object sender, EventArgs e)
        {
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            this.UpdateStyles();
            Bitmap bmp = new Bitmap(pbImg.Width, pbImg.Height);
            Graphics g = Graphics.FromImage(bmp);
            g.FillRectangle(new SolidBrush(pbImg.BackColor), new Rectangle(0, 0, pbImg.Width, pbImg.Height));
            g.Dispose();
            dt = new DrawTools(this.pbImg.CreateGraphics(), colorHatch1.HatchColor, bmp);//实例化工具类
            DefaultPicSize = pbImg.Size;

        }

        //"打开文件"事件处理方法
        private void openPic_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();//实例化文件打开对话框
            ofd.Filter = "JPG|*.jpg|Bmp|*.bmp|所有文件|*.*";//设置对话框打开文件的括展名
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                Bitmap bmpformfile = new Bitmap(ofd.FileName);//获取打开的文件
                panel2.AutoScrollPosition = new Point(0,0);//将滚动条复位
                pbImg.Size = bmpformfile.Size;//调整绘图区大小为图片大小

                reSize.Location = new Point(bmpformfile.Width, bmpformfile.Height);//reSize为我用来实现手动调节画布大小用的
                //因为我们初始时的空白画布大小有限,"打开"操作可能引起画板大小改变,所以要将画板重新传入工具类
                dt.DrawTools_Graphics = pbImg.CreateGraphics();

                Bitmap bmp = new Bitmap(pbImg.Width, pbImg.Height);
                Graphics g = Graphics.FromImage(bmp);
                g.FillRectangle(new SolidBrush(pbImg.BackColor), new Rectangle(0, 0, pbImg.Width, pbImg.Height));//不使用这句话,那么这个bmp的背景就是透明的
                g.DrawImage(bmpformfile, 0, 0,bmpformfile.Width,bmpformfile.Height);//将图片画到画板上
                g.Dispose();//释放画板所占资源
                //不直接使用pbImg.Image = Image.FormFile(ofd.FileName)是因为这样会让图片一直处于打开状态,也就无法保存修改后的图片;详见http://www.wanxin.org/redirect.php?tid=3&goto=lastpost
                bmpformfile.Dispose();//释放图片所占资源
                g = pbImg.CreateGraphics();
                g.DrawImage(bmp, 0, 0);
                g.Dispose();
                dt.OrginalImg = bmp;
                bmp.Dispose();
                sFileName = ofd.FileName;//储存打开的图片文件的详细路径,用来稍后能覆盖这个文件
                ofd.Dispose();

            }
        }

        //"保存"事件处理方法
        private void savePic_Click(object sender, EventArgs e)
        {
            if (sFileName != null)
            {

                if (MessageBox.Show("是否要保存文件?", "系统提示", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    dt.OrginalImg.Save(sFileName);
                }
            }
            else
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.Filter = "JPG(*.jpg)|*.jpg|BMP(*.bmp)|*.bmp";
                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    dt.OrginalImg.Save(sfd.FileName);
                    sFileName = sfd.FileName;
                }
            }

        }

        //窗体移动最小化等造成的pbimg"重画"事件处理方法
        private void pbImg_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.DrawImage(dt.OrginalImg, 0, 0);
            //g.Dispose();切不可使用,这个Graphics是系统传入的变量,不是我们自己创建的,如果dispose就会出错

        }

        //"绘图工具选用"事件处理方法
        private void tool_Click(object sender, EventArgs e)
        {
            ToolStripButton tsb = sender as ToolStripButton;
            if (tsb != null)
            {
                sType = tsb.Name;
                currentDrawType.Text = tsb.Text;
                if (sType == "Eraser")
                {
                    pbImg.Cursor = new Cursor(Application.StartupPath + @"\img\pb.cur");
                }
                else
                {
                    pbImg.Cursor = Cursors.Cross;
                }
            }
        }

        //"清除图像"事件处理方法
        private void clearPic_Click(object sender, EventArgs e)
        {
            Bitmap newpic = new Bitmap(pbImg.Width, pbImg.Height);
            Graphics g = Graphics.FromImage(newpic);
            g.FillRectangle(new SolidBrush(Color.White), 0, 0, pbImg.Width, pbImg.Height);
            g.Dispose();
            g = pbImg.CreateGraphics();
            g.DrawImage(newpic, 0, 0);
            g.Dispose();
            dt.OrginalImg = newpic;
        }

        //"另存为"事件处理方法
        private void SaveAs_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "JPG(*.jpg)|*.jpg|BMP(*.bmp)|*.bmp";
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                dt.OrginalImg.Save(sfd.FileName);
                sFileName = sfd.FileName;
            }
        }

        //"退出"事件处理方法
        private void Quit_Click(object sender, EventArgs e)
        {
            dt.ClearVar();
            Application.Exit();
        }

        //"颜色改变"事件处理方法
        private void colorHatch1_ColorChanged(object sender, ColorHatch.ColorChangedEventArgs e)
        {
            dt.DrawColor = e.GetColor;
        }


        private void reSize_MouseDown(object sender, MouseEventArgs e)
        {
            bReSize = true;//当鼠标按下时,说明要开始调节大小
        }

        private void reSize_MouseMove(object sender, MouseEventArgs e)
        {
            if (bReSize)
            {
                reSize.Location = new Point(reSize.Location.X + e.X, reSize.Location.Y + e.Y);

            }
        }

        private void reSize_MouseUp(object sender, MouseEventArgs e)
        {
            bReSize = false;//大小改变结束
            //调节大小可能造成画板大小超过屏幕区域,所以事先要设置autoScroll为true.
            //但是滚动条的出现反而增加了我们的难度,因为滚动条上下移动并不会自动帮我们调整图片的坐标。
            //这是因为GDI绘图的坐标系不只一个,好像有三个,没有仔细了解,一个是屏幕坐标,一个是客户区坐标,还个是文档坐标。
            //滚动条的上下移动改变的是文档的坐标,但是客户区坐标不变,而location属性就属于客户区坐标,所以我们直接计算会出现错误
            //这时我们就需要知道文档坐标与客户区坐标的偏移量,这就是AutoScrollPostion可以提供的

            pbImg.Size = new Size(reSize.Location.X - (this.panel2.AutoScrollPosition.X), reSize.Location.Y - (this.panel2.AutoScrollPosition.Y));
            dt.DrawTools_Graphics = pbImg.CreateGraphics();//因为画板的大小被改变所以必须重新赋值

            //另外画布也被改变所以也要重新赋值
            Bitmap bmp = new Bitmap(pbImg.Width, pbImg.Height);
            Graphics g = Graphics.FromImage(bmp);
            g.FillRectangle(new SolidBrush(Color.White), 0, 0, pbImg.Width, pbImg.Height);
            g.DrawImage(dt.OrginalImg, 0, 0);
            g.Dispose();
            g = pbImg.CreateGraphics();
            g.DrawImage(bmp, 0, 0);
            g.Dispose();
            dt.OrginalImg = bmp;

            bmp.Dispose();
        }

        private void BuildNewPic_Click(object sender, EventArgs e)
        {

            pbImg.Size = DefaultPicSize;
            this.panel2.AutoScrollPosition = new Point(0, 0);
            Bitmap bmp = new Bitmap(DefaultPicSize.Width, DefaultPicSize.Height);
            Graphics g = Graphics.FromImage(bmp);
            g.FillRectangle(new SolidBrush(Color.White), 0, 0, DefaultPicSize.Width, DefaultPicSize.Height);
            g.Dispose();
            g = pbImg.CreateGraphics();
            g.DrawImage(bmp, 0, 0);
            g.Dispose();
            reSize.Location = new Point(DefaultPicSize.Width, DefaultPicSize.Height);
            dt.OrginalImg = bmp;
            sFileName = null;
        }

        private void AttributePic_Click(object sender, EventArgs e)
        {
            MessageBox.Show("图像高:" + pbImg.Height + " px ,图像宽:" + pbImg.Width+" px", "图像属性");
        }

    }
}
--------------------编程问答--------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace 绘图程序
{
    /// <summary>
    /// 绘图工具包括直线,矩形,铅笔,圆形,橡皮
    /// </summary>
    class DrawTools
    {
        public Graphics DrawTools_Graphics;//目标绘图板
        private Pen p;
        private Image orginalImg;//原始画布,用来保存已完成的绘图过程
        private Color drawColor = Color.Black;//绘图颜色
        private Graphics newgraphics;//中间画板
        private Image finishingImg;//中间画布,用来保存绘图过程中的痕迹

        /// <summary>
        /// 绘图颜色
        /// </summary>
        public Color DrawColor
        {
            get { return drawColor; }
            set
            {
                drawColor = value;
                p.Color = value;
            }
        }

        /// <summary>
        /// 原始画布
        /// </summary>
        public Image OrginalImg
        {
            get { return orginalImg; }
            set
            {
                finishingImg = (Image)value.Clone();
                orginalImg = (Image)value.Clone();
            }
        }


        /// <summary>
        /// 表示是否开始绘图
        /// </summary>
        public bool startDraw = false;

        /// <summary>
        /// 绘图起点
        /// </summary>
        public PointF startPointF;

        /// <summary>
        /// 初始化绘图工具
        /// </summary>
        /// <param name="g">绘图板</param>
        /// <param name="c">绘图颜色</param>
        /// <param name="img">初始画布</param>
        public DrawTools(Graphics g, Color c, Image img)
        {
            DrawTools_Graphics = g;
            drawColor = c;
            p = new Pen(c, 1);
            finishingImg = (Image)img.Clone();
            orginalImg = (Image)img.Clone();
        }

        /// <summary>
        /// 绘制直线,矩形,圆形
        /// </summary>
        /// <param name="e">鼠标参数</param>
        /// <param name="sType">绘图类型</param>
        public void Draw(MouseEventArgs e, string sType)
        {
            if (startDraw)
            {
                //为防止造成图片抖动,防止记录不必要的绘图过程中的痕迹,我们先在中间画板上将图片完成,然后在将绘制好的图片一次性画到目标画板上
                //步骤1实例化中间画板,画布为上一次绘制结束时的画布的副本(如果第一次绘制,那画布就是初始时的画布副本)
                //步骤2按照绘图样式在中间画板上进行绘制
                //步骤3将绘制结束的图片画到中间画布上
                //因为我们最终绘制结束时的图片应该是在鼠标松开时完成,所以鼠标移动中所绘制的图片都只画到中间画布上,但仍需要显示在目标画板上,否则鼠标移动过程中我们就看不到效果。
                //当鼠标松开时,才把最后的那个中间图片画到原始画布上

                Image img = (Image)orginalImg.Clone();//为防止直接改写原始画布,我们定义一个新的image去得到原始画布
                newgraphics = Graphics.FromImage(img);//实例化中间画板
                switch (sType)
                {
                    case "Line":
                        {//画直线
                            newgraphics.DrawLine(p, startPointF, new PointF(e.X, e.Y)); break;
                        }
                    case "Rect":
                        {//画矩形
                            float width = Math.Abs(e.X - startPointF.X);//确定矩形的宽
                            float heigth = Math.Abs(e.Y - startPointF.Y);//确定矩形的高
                            PointF rectStartPointF = startPointF;
                            if (e.X < startPointF.X)
                            {
                                rectStartPointF.X = e.X;
                            }
                            if (e.Y < startPointF.Y)
                            {
                                rectStartPointF.Y = e.Y;
                            }
                            newgraphics.DrawRectangle(p, rectStartPointF.X, rectStartPointF.Y, width, heigth);
                            break;
                        }
                    case "Circle":
                        {//画圆形
                            newgraphics.DrawEllipse(p, startPointF.X, startPointF.Y, e.X - startPointF.X, e.Y - startPointF.Y); break;
                        }
                    case "FillRect":
                        {//画实心矩形
                            float width = Math.Abs(e.X - startPointF.X);//确定矩形的宽
                            float heigth = Math.Abs(e.Y - startPointF.Y);//确定矩形的高
                            PointF rectStartPointF = startPointF;
                            if (e.X < startPointF.X)
                            {
                                rectStartPointF.X = e.X;
                            }
                            if (e.Y < startPointF.Y)
                            {
                                rectStartPointF.Y = e.Y;
                            }
                            newgraphics.FillRectangle(new SolidBrush(drawColor), rectStartPointF.X, rectStartPointF.Y, width, heigth);
                            break;
                        }
                    case "FillCircle":
                        {//画实心圆
                            newgraphics.FillEllipse(new SolidBrush(drawColor), startPointF.X, startPointF.Y, e.X - startPointF.X, e.Y - startPointF.Y); break;
                        }
                }
                newgraphics.Dispose();//绘图完毕释放中间画板所占资源
                newgraphics = Graphics.FromImage(finishingImg);//另建一个中间画板,画布为中间图片
                newgraphics.DrawImage(img, 0, 0);//将图片画到中间图片
                newgraphics.Dispose();
                DrawTools_Graphics.DrawImage(img, 0, 0);//将图片画到目标画板上
                img.Dispose();
            }

        }

        public void EndDraw()
        {
            startDraw = false;
            //为了让完成后的绘图过程保留下来,要将中间图片绘制到原始画布上
            newgraphics = Graphics.FromImage(orginalImg);
            newgraphics.DrawImage(finishingImg, 0, 0);
            newgraphics.Dispose();
        }

        /// <summary>
        /// 橡皮方法
        /// </summary>
        /// <param name="e">鼠标参数</param>
        public void Eraser(MouseEventArgs e)
        {
            if (startDraw)
            {
                newgraphics = Graphics.FromImage(finishingImg);
                newgraphics.FillRectangle(new SolidBrush(Color.White), e.X, e.Y, 20, 20);
                newgraphics.Dispose();
                DrawTools_Graphics.DrawImage(finishingImg, 0, 0);
            }
        }

        /// <summary>
        /// 铅笔方法
        /// </summary>
        /// <param name="e">鼠标参数</param>
        public void DrawDot(MouseEventArgs e)
        {
            if (startDraw)
            {
                newgraphics = Graphics.FromImage(finishingImg);
                PointF currentPointF = new PointF(e.X, e.Y);
                newgraphics.DrawLine(p, startPointF, currentPointF);
                startPointF = currentPointF;
                newgraphics.Dispose();
                DrawTools_Graphics.DrawImage(finishingImg, 0, 0);
            }
        }

        /// <summary>
        /// 清除变量,释放内存
        /// </summary>
        public void ClearVar()
        {
            DrawTools_Graphics.Dispose();
            finishingImg.Dispose();
            orginalImg.Dispose();
            p.Dispose();
        }

    }
}
补充:.NET技术 ,  C#
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,