david's daily developer note

C# 다수의 버튼 컨트롤을 동적으로 생성 및 버튼 이동시키는 이벤트 추가하기 본문

[Develop] Language/C#

C# 다수의 버튼 컨트롤을 동적으로 생성 및 버튼 이동시키는 이벤트 추가하기

mouse-david 2010. 12. 29. 11:44
728x90

일반적으로, 윈도우 응용 프로그램을 개발할 때, 자주쓰는 텍스트 박스나, 버튼 컨트롤을 폼에 배치하려면, 단순하게, 도구상자에서 컨트롤을 선택하고, 윈도우 폼에 클릭만 하면 되었다. 이 과정에서 VS는 자동으로 컨트롤의 인스턴스를 생성해주고, 기본 속성값으로 초기화도 해준다. 또한 컨트롤에 이벤트를 추가하는 것은, 단순히 이벤트 탭에서 추가하고자 하는 이벤트를 선택만하면 됨으로 매우 단순하고 직관적이다.


이와같이 편리할 툴을 이용해서, 윈도우 응용 프로그램을 개발을 쉽게 할 수 있다. 하지만, 어떤 경우에서는 고정된 UI가 아닌 사용자의 선택에 따라 변화하는 다양한 경우의 UI를 개발할 필요가 존재한다. 예를 들어, 그래픽툴, UI제작툴, 프로토타입 제작툴 등, 당연하지만, IDE에서 제공하는 UI 컨포넌트들은 직접 소스를 작성하여서도 작업할 수 있다.
매우 방대한 컨트롤과 각각에 대응되는 이벤트들이 존재하지만, 동일한 패턴이 존재하기 때문에, 쉽게 감을 잡을 수 있다.

다음의 예제를 보자. 


이 예제는 "버튼 생성" 이란 버튼을 누르고, 탭 컨트롤 영역(tabPage)을 선택하면 동적으로 버튼이 생성되고, 생성된 버튼을 잡고 이동시킬 수 있는 예제이다. 먼저 버튼 컨트롤을 탭(Tab) 컨트롤에 추가하는 방법을 알아보자.

private void makeButton(string name , string text , int x , int y)
{
    Button newButton = new System.Windows.Forms.Button();
    tabPage1.Controls.Add(newButton);
    newButton.Name = name;
    newButton.Text = text;
    //newButton.Click += new System.EventHandler(this.testButtonClick);
    newButton.MouseMove += new System.Windows.Forms.MouseEventHandler(this.testButtonMove);
    newButton.MouseDown += new System.Windows.Forms.MouseEventHandler(this.testButtonDown);
    newButton.MouseUp += new System.Windows.Forms.MouseEventHandler(this.testButtonUp);
    newButton.Location = new System.Drawing.Point(x ,y );
}

버튼 생성이란 버튼이 클릭되면 위의 함수를 호출한다. 클릭했을 때의 마우스 좌표와 버튼 속성에 입력된 이름과 텍스트를 인자로 받았다. 함수의 동작은 다음과 같다.

1. 새로운 버튼을 생성하고, 탭 콘트롤에 추가하였다. 
2. 추가한 버튼의 이름과 텍스트를 변경하고, 3가지 이벤트를 추가하였다.
3. 마우스로 선택한 좌표에 추가한 버튼을 위치시킨다.

위 좌측 그림과 같이 버튼 컨트롤의 동적 생성이 완료되었다. 이제 버튼을 이동시키기기 위해서 추가한 3가지 이벤트 함수(testButtonMove, testButtonDown, testButtonUp)를 동작 순서대로 작성해보겠다.

1. 마우스 다운(MouseDown)

먼저 마우스로 버튼을 이동 시키기 위해서 가장 먼저 발생하는 이벤트는 마우스 다운이다. 즉 버튼 컨트롤 위해서 마우스 다운벤트가 발생하였다면, 이동을 위한 준비를 해야한다. 아래 함수가 이에 해당한다.

private void testButtonDown(object sender, MouseEventArgs e)
{
    if (!buttonMoveFlag)
    {
        buttonMoveFlag = true;
        string buttonText = ((Button)sender).Text;
        Control[] test = tabPage1.Controls.Find("테스트1", true);
        cotrolItems = test.ToList();

        foreach (Control tempTest in cotrolItems)
        {
            if (tempTest.Text.Equals(buttonText))
            {
                selectButtonIndex = cotrolItems.IndexOf(tempTest);
                gapX = e.Location.X ;
                gapY = e.Location.Y ;
            }
        }
    }
}

testButtonDown의 동작은 다음과 같다.
  1. boolean 타입 buttonMoveFlag가 True일때, 동작한다. 버튼 이동과정에 약간의 연산이 들어가는데, 버튼이 없거나, 버튼을 선택하지 않았을 때, 발생하는 마우스 다운 이벤트에서 해당 연산을 처리하지 않기 위해서이다.
  2. 버튼 컨트롤이 이동가능할 때, tabPage1에 포함된 모든 버튼 컨트롤을 가져온다. 
  3. 모든 버튼 컨트롤에서 방금 선택한 버튼을 텍스트값을 이용해 찾는다.(모든 버튼 컨트롤을 저장하고 있는 List의 인덱스를 기억)
  4. 현재 마우스 다운이 일어난 좌표를 기억한다. 해당 좌표는 버튼 콘트롤 범위안에서 마우스가 다운된 좌표이다. 
    버튼 컨트롤의 위치를 지정하는 것은 좌측 상단의 모서리 값의 지정을 의미하는데, 버튼 이동이 끝나고 버튼을 위치시킬때, 마우스 업한 위치가 버튼의 좌측 상단 모서리가 되는 부자연스러운 현상을 제거하기 위해서 필요하다. 다음 그림이 버튼 이동 문제를 설명한다.

따라서, 마우스 다운시의 좌표가 버튼내에서의 마우스 좌표이고, 마우스 업할때, 버튼이 취하는 좌표는 tabPage내에서의 좌표임으로, 마우스 업 할때, 지금 저장한 gapX, Y값을 빼주면, 아래 그림과 같이 부드러운버튼 이동이 가능하다.



2. 마우스 이동(Mouse Move)

이제, 버튼을 선택한 상태로 마우스를 이동하였을 때, 이벤트를 작성한다.

private void testButtonMove(object sender, MouseEventArgs e)
{
    if (buttonMoveFlag)
    {
        cotrolItems[selectButtonIndex].Location = new System.Drawing.Point(
            (cotrolItems[selectButtonIndex].Location.X + e.X) - gapX,
            (cotrolItems[selectButtonIndex].Location.Y + e.Y) - gapY);
                tabPage1.Update();
    }
}
1번 과정으로 선택된 버튼의 인덱스를 알고 있다. 따라서 모든 버튼 컨트롤을 담고 있는 cotrolItems에서 선택된 특정 인덱스의 버튼에 대해서, 이동 이벤트를 적용할 것이다. 순서는 다음과 같다.
첫째, 선택된 버튼의 위치에 현재 마우스 위치를 더한다.(즉, 위치 변경을 위해서 마우스가 이동한 값을 더한다. )
둘째, 1번 과정에서 설명한 대로, 결과값에 gap을 뺀고, 버튼의 위치를 갱신한다.

3. 마우스 업(Mouse Up)

최종적으로 버튼 이동이 종료되면 마우스 업이벤트가 발생할 것이다.
private void testButtonUp(object sender, MouseEventArgs e)
{
    if (buttonMoveFlag)
    {
        buttonMoveFlag = false;
            cotrolItems[selectButtonIndex].Location = new System.Drawing.Point(
            (cotrolItems[selectButtonIndex].Location.X + e.X) - gapX,
            (cotrolItems[selectButtonIndex].Location.Y + e.Y) -gapY);
    }
}

buttonMoveFlag값을 false로 바꾸고 버튼 이동을 중지한다. 
버튼 위치를 변경하는 것은 마우스 이동 이벤트의 처리 과정과 동일하다. 


작업 결과는 아래와 같다.

 

 
끝~ ㅎㅎㅎ
728x90