>백엔드 개발 >C#.Net 튜토리얼 >C# GDI+ 간단한 그리기 (4)

C# GDI+ 간단한 그리기 (4)

高洛峰
高洛峰원래의
2016-12-17 09:49:461400검색

이전 글에서 GDI+를 사용하여 그리는 방법을 소개했고, 스크린샷 예시를 만들어봤습니다. 이번 글에서는
개인적으로, 윈도우 그리기와 비슷한 도구를 만드는 방법을 소개하겠습니다. 강력한 그리기 도구를 만들려면 단순히 GDI를 마스터하는 것만으로는 충분하지 않습니다. 현재로서는 상대적으로 간단한 그리기 도구만 만들 수 있습니다. 어떤 결함이라도 토론하는 것을 환영합니다!

먼저 최종 효과를 살펴보겠습니다.

c# GDI+简单绘图

주요 기능: 직선 그리기, 직사각형, 지우개, 원, 색상 전환, 사진 열기, 그림을 저장하고 그림을 지우고 소프트웨어가 처음 시작되면 캔버스 크기를 수동으로 조정합니다. 캔버스에 직접 그릴 수도 있고 메뉴의 "열기"를 통해 그림을 가져올 수도 있습니다. 우리는 그림에 그릴 수 있습니다.
플랫폼 : VS2005 WINFORM

코드가 너무 많아서 여기서는 제작 단계만 간략하게 소개하고 프로젝트 다운로드를 제공하겠습니다.
1. 전체 인터페이스를 배치합니다.
2. 그리기 도구 기능 구현
3. 색상 픽업 기능 구현 여기서는 지난번에 작성한 사용자 정의 컨트롤을 직접 사용합니다.
4. 메뉴 기능 구현
5. 캔버스 크기 수동 조정 기능 구현
6. 테스트

그리기 도구 기능 구현
코드 결합 정도가 작아지고 조금 사용됩니다. 디자인 패턴을 몇 가지 배웠지만, 잘 못해서 코드가 여전히 좀 지저분해요, 헤헤! 그리기 도구에 대한 이러한 모든 기능 블록은 DrawTools 클래스에 작성됩니다. 그런 다음 기본 양식에서는 너무 많은 특정 그리기 코드를 사용하지 않고 이 클래스를 호출하여 그리기를 완료하면 됩니다. 이 그리기 도구 클래스에서 제공하는 주요 도구는 연필, 지우개, 직선, 직사각형, 원, 실선 직사각형 및 실선 원입니다. 이러한 함수 블록에 대한 코드는 이전 기사를 주의 깊게 읽으면 이해할 수 있을 것입니다.
여기서 주의할 점은 다음과 같습니다.
1. 드로잉 과정의 불필요한 흔적이 기록되는 것을 방지하는 방법은 무엇입니까?
이 문제는 세 번째 기사에서 언급되었습니다. 해당 기사를 먼저 읽어보세요. 코드의 가독성을 높이기 위해 두 개의 이미지 변수를 설정했는데,finingImg는 그리기 과정의 흔적을 저장하는 데 사용되고 orginalImg는 완료된 그리기 과정과 초기 배경 이미지를 저장하는 데 사용됩니다.
2. 이 클래스는 메인폼과 어떻게 소통하나요?
물론, 이러한 펑션블록을 메인폼에 직접 작성한다면 이런 문제는 없을 것입니다. 그러나 코드가 매우 혼란스러워 보일 것입니다. 도구 코드에만 문제가 있으면 전체 프로젝트를 변경해야 합니다. 여기서는 메인 폼이 속성에 값을 할당하여 아트보드, 캔버스, 색상에 대한 정보를 도구 클래스에 전달할 수 있도록 메서드와 속성을 정의한 후, 해당 도구 메서드를 호출하여 이러한 도구를 사용할 수 있도록 합니다.
3. 주요 속성
이러한 도구가 제대로 작동하려면 대상 아트보드(즉, 그림 상자), 그리기 색상, 원본 캔버스 등의 항목이 사용자에게 전달되어야 합니다.

메뉴 기능 구현

c# GDI+简单绘图

여기서 파일 동작에 대한 약간의 이해가 필요하며 관련 정보를 확인할 수 있습니다.
가장 큰 어려움은 "열기" 메뉴 항목의 구현입니다
수정 후 열린 사진을 다시 저장하려면 파일을 연 후 닫아야 합니다. 그렇지 않으면 파일이 열려 있기 때문에 덮어쓰지 않습니다. . 원본 문서. 이로 인해 컴파일 중에 "GDI 일반 오류"가 팝업됩니다. 따라서 인터넷상의 다른 친구들이 하는 방법에 따르면 먼저 열린 이미지를 GDI+를 통해 다른 캔버스에 그린 다음 즉시 열려 있는 이미지와 이미지를 그리는 데 사용된 작업판을 닫습니다.

 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)是因为这样会让图片一直处于打开状态,也就无法保存修改后的图片
                bmpformfile.Dispose();//释放图片所占资源
                g = pbImg.CreateGraphics();
                g.DrawImage(bmp, 0, 0);
                g.Dispose();
                dt.OrginalImg = bmp;
                bmp.Dispose();
                sFileName = ofd.FileName;//储存打开的图片文件的详细路径,用来稍后能覆盖这个文件
                ofd.Dispose();

            }
        }

이미지를 지우는 것은 실제로 캔버스 전체를 흰색으로 채우는 것입니다
다른 것들은 상대적으로 간단하므로 여기서는 자세히 설명하지 않겠습니다.

캔버스 크기 수동 조정 실현
인터넷에서 일부 사람들은 API를 사용하라고 하지만 개인적으로는 다른 컨트롤을 사용하는 것이 더 쉽다고 생각합니다. 적어도 우리는 그것을 이해할 수 있습니다.
아이디어: 그림 상자1(크기 5*5)을 배치하고 메인 작업판 오른쪽 하단에 고정한 다음 마우스가 들어갈 때 커서를 화살표 모양으로 변경하고 마우스를 눌렀을 때 이벤트를 설정하고 이동하고 picturebox1이 마우스 움직임을 따르도록 합니다. 마우스를 놓으면 메인 드로잉보드의 오른쪽 하단의 좌표를 picturebox1의 좌표로 조정합니다.
코드를 살펴보겠습니다.
reSize는 우리가 도움을 주기 위해 사용하는 picturebox 컨트롤입니다.

private bool bReSize = false;//是否改变画布大小
        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();
        }

효과는 아래와 같습니다(흰색 오른쪽 하단 모서리를 주의 깊게 살펴보세요). 지역):

c# GDI+简单绘图

이때 작은 사각형을 드래그하여 이미지 크기를 조절할 수 있습니다.
 
이로써 주요 문제는 거의 해결되었지만 여전히 부족한 점이 있습니다. 여러분의 귀중한 의견을 환영합니다.


더 많은 c# GDI+ Simple Drawing(4) 관련 글은 PHP 중국어 홈페이지를 주목해주세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.