IT/C#

[C#] 마우스 휠 이벤트에 따른 확대, 축소 (+ 마우스 위치 확대)(+21.02.22 재수정)

Ella.J 2018. 11. 22. 18:29
728x90
반응형

프로그램 개발 도중 추가 요청 사항이 있어 개발을 진행하였다.

다음 2가지 개발 사항에 대해서 포스팅하고자 한다.

 

1. Mouse Wheel 이벤트에 따른 Zoom IN / OUT 기능

2. Mouse Click, Move 이벤트로 Zoom 사진 시점 이동

 

 

원본 이미지

         

확대 이미지

(좌측 원본 이미지, 우측 확대 이미지)

 

 

1. Mouse Wheel 이벤트에 따른 Zoom IN / OUT 기능

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private Point LastPoint;
private Bitmap img;
 
private double ratio = 1.0F;
private Point imgPoint;
private Rectangle imgRect;
private Point clickPoint;
 
public Form1()
{
    InitializeComponent();
 
    pictureBox1.MouseWheel += new MouseEventHandler(pictureBox1_MouseWheel);
 
    img = new Bitmap(@"E:\01.bmp");
    imgPoint = new Point(pictureBox1.Width / 2, pictureBox1.Height / 2);
    imgRect = new Rectangle(00, pictureBox1.Width, pictureBox1.Height);
    ratio = 1.0;
    clickPoint = imgPoint;
 
    pictureBox1.Invalidate();
}
cs

 

MouseWheel 이벤트는 MouseEventHandler를 직접 선언해줘야 한다.

마우스 포인트를 저장할 Point 변수 imgPoint clickPoint 를 선언하고, 확대, 축소 이미지를 Handling 할 Rectangle 변수 imgRect 를 선언해준다.

확대, 축소 비율을 Handling 할 ratio 변수도 선언해 준다.

 


2021.2.22 추가 수정

- 마우스 포인터 위치에서 확대 축소 기능


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private void pictureBox1_MouseWheel(object sender, MouseEventArgs e)
{
    int lines = e.Delta * SystemInformation.MouseWheelScrollLines / 120;
    PictureBox pb = (PictureBox)sender;
 
    if (lines > 0)
    {
       ratio *= 1.1F;
        if (ratio > 100.0) ratio = 100.0f;
 
        imgRect.Width = (int)Math.Round(pictureBox1.Width * ratio);
        imgRect.Height = (int)Math.Round(pictureBox1.Height * ratio);
        imgRect.X = -(int)Math.Round(1.1F * (imgPoint.X - imgRect.X) - imgPoint.X);
        imgRect.Y = -(int)Math.Round(1.1F * (imgPoint.Y - imgRect.Y) - imgPoint.Y);
    }
    else if (lines < 0)
    {
       ratio *= 0.9F;
        if (ratio < 1) ratio = 1;
 
        imgRect.Width = (int)Math.Round(pictureBox1.Width * ratio);
        imgRect.Height = (int)Math.Round(pictureBox1.Height * ratio);
        imgRect.X = -(int)Math.Round(0.9F * (imgPoint.X - imgRect.X) - imgPoint.X);
        imgRect.Y = -(int)Math.Round(0.9F * (imgPoint.Y - imgRect.Y) - imgPoint.Y);
    }
 
    if (imgRect.X > 0) imgRect.X = 0;
    if (imgRect.Y > 0) imgRect.Y = 0;
    if (imgRect.X + imgRect.Width < pictureBox1.Width) imgRect.X = pictureBox1.Width - imgRect.Width;
    if (imgRect.Y + imgRect.Height < pictureBox1.Height) imgRect.Y = pictureBox1.Height - imgRect.Height;
    pictureBox1.Invalidate();
}
cs

 

먼저, 마우스 휠 이벤트를 등록해주고, pictureBox1 위에서 마우스 휠 스크롤 할 때의 값을 lines 으로 받아온다.

 

또한, 마우스 위치에서 확대를 가능하게 하기 위해 아래 MouseMove 이벤트에서

마우스 왼쪽 클릭이 아닐 때 마우스 위치를 가져오기 위해서 else 아래에 한 줄을 추가해준다.

imgPoint = new Point(e.X, e.Y);

 

스크롤을 증가시키면 lines 값은 + 값이 되고,

스크롤을 감소시키면 lines 값은 - 값이 된다.

 

스크롤이 증가될 때, 즉, lines > 0 이면 ratio *= 1.1F 를 해준다.

1.1F 값은 사진이 110% 의 비율로 확대 된다는 의미이며 임의로 정한 값이다.

150% 의 비율로 확대되게 하려면 1.5F 를 곱해주면 된다.

 

반면, 스크롤이 감소될 때, 즉, lines < 0 이면 ratio *= 0.9F 를 해준다.

이는 90%의 비율로 사진이 축소된다는 의미이다.

마찬가지로 50% 비율로 축소되게 하려면 0.5F 를 곱해주면 된다.

 

<!-- 21.02.22 수정 내용

스크롤에 따라 imgRect의 Width와 Height 값에 ratio 확대 비율을 곱해주는 것은 기존과 동일하나,,

마우스 위치에서 확대를 하기위해 imgRect의 X, Y 값을 구해주는 공식을 변경해서 적용했다. -->

 

만약, Zoom IN 후 Zoom OUT 시에 ratio 가 1보다 작아지면 원래 이미지 크기와 같기 때문에 더 이상 Zoom OUT을 해주지 않도록 하였다.

원래 이미지 사이즈보다 작게도 Zoom OUT을 하려면 생략해주어도 무방하다.

Ratio 값을 스크롤 움직임에 따라 변경해주고, imgRect 값에 적용시켜주면 이미지가 Zoom IN / OUT 이 가능해진다.

 

맨 아래 코드는 imgRect.X, Y의 min, max 값을 지정해 주는 것이다.

이미지가 pictureBox를 벗어나는 경우가 생기기 때문에,

그러한 경우를 방지하기 위해서 pictureBox1.Invalidate(); 위에

다음과 같이 네줄을 추가해 준다.

 

if (imgRect.X > 0) imgRect.X = 0;

if (imgRect.Y > 0) imgRect.Y = 0;

if (imgRect.X + imgRect.Width < pictureBox1.Width) imgRect.X = pictureBox1.Width - imgRect.Width;

if (imgRect.Y + imgRect.Height < pictureBox1.Height) imgRect.Y = pictureBox1.Height - imgRect.Height;

 

2019.09.23 추가 수정

- 친절한 분이 댓글로 질문하신 덕분에 아래 내용을 추가하게 되었습니다. 감사합니다 : )

pictureBox1_MouseWheel 이벤트 마지막 줄에서 pictureBox1.Invalidate(); 라는 구문이 있다.

이는 해단 컨트롤 영역을 무효화해서 Paint 이벤트가 일어날 때 처리하도록 한다.

따라서, pictureBox1_Paint 이벤트를 사용해서 처리해줘야 이미지가 갱신이 된다.

아래에 이벤트 함수를 추가하였다.

위의 MouseWheel 이벤트에서 적용해준 imgRect 값을 이용하여 이미지를 업데이트 해주면 마우스 휠을 움직일 때 마다 이미지가 확대 축소가 가능해 진다.

 

<!-- 21.02.22 수정 내용

참고로, 이미지 사이즈가 작으면 InterpolationMode를 HighQuiltyBicubic으로 해주어도 속도에 차이가 별로 없지만,이미지 사이즈가 크면 실행 속도가 굉장히 느려진다. 따라서, 속도가 느릴경우 InterpolationMode를 Default 혹은 Low 값으로 변경해주면 그나마 속도가 빨라진다.-->

 

1
2
3
4
5
6
7
8
9
10
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    if (pictureBox1.Image != null)
    {
        e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
 
        e.Graphics.DrawImage(pictureBox1.Image, imgRect);
        pictureBox1.Focus();
    }
}
cs

 

 

 

2. Mouse Click, Move 이벤트로 Zoom 사진 시점 이동

 

1
2
3
4
5
6
7
8
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        clickPoint = new Point(e.X, e.Y);
    }
    pictureBox1.Invalidate();
}
cs

 

확대된 상태의 이미지를 클릭한 상태의 이벤트로 클릭한 시점의 마우스 포인트 지점을 clickPoint 에 저장한다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        imgRect.X = imgRect.X + (int)Math.Round((double)(e.X - clickPoint.X) / 5);
        if (imgRect.X >= 0) imgRect.X = 0;
        if (Math.Abs(imgRect.X) >= Math.Abs(imgRect.Width - pictureBox1.Width)) imgRect.X = -(imgRect.Width - pictureBox1.Width);
        imgRect.Y = imgRect.Y + (int)Math.Round((double)(e.Y - clickPoint.Y) / 5);
        if (imgRect.Y >= 0) imgRect.Y = 0;
        if (Math.Abs(imgRect.Y) >= Math.Abs(imgRect.Height - pictureBox1.Height)) imgRect.Y = -(imgRect.Height - pictureBox1.Height);
    }
    else
    {
        LastPoint = e.Location;
    }
 
    pictureBox1.Invalidate();
}
cs

 

이미지 마우스 클릭 상태로 마우스를 움직이게 되면 시점이 마우스 포인트 움직임에 따라 이동하게 해주는 이벤트이다.

마우스 클릭 시 기억해둔 포인트 지점(clickPoint.X, clickPoint.Y)에서 움직일 때의 마우스 포지션(e.X, e.Y)에 따라 이미지 시점(imgRect.X, imgRect.Y) 값을 변화 시켜 준다.

imgRect.X = imgRect.X + (int)Math.Round((double)(e.X - clickPoint.X) / 5);

Math.Round 식 마지막에 나눠주는 값을 5 보다 키워주면 이동값이 작아지기 때문에 마우스 이동 시 화면 이동이 더 느려지고,

5보다 줄여주면 이동값이 커져 마우스 이동 시 화면 이동이 더 빨라지게 된다.

 

 

프로그램 생성 후 실행 동영상

 

 

 

728x90
반응형