NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET Core 매크로 프로그램 만들기. (멀티 다클라 매크로 2부)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 이전 시간에 멀티 스크립트로 다클라 매크로를 만들기 위한 준비를 했었습니다. 스크립트는 하나의 플레이어입니다. 그리고, 스크립트안에 여러개의 핸들이 있는 경우 핸들 수만큼 플레이어를 만들어서 동시에 실행할 수 있도록 합니다. 다시 말해서 스크립트는 하나의 플레이어를 가지고, 멀티 핸들인 경우 플레이어는 여러개의 플레이어를 가지는 구조입니다.

     

    하나의 스크립트가 멀티 플레이어를 가지는 경우는 문제가 되지 않지만, 여러개의 스크립트를 제어하려면 각각의 스크립트를 관리할 수 있는 매니저가 필요합니다. 이전 시간에 스크립트를 관리할 수 있는 매니저를 만들었습니다. 매니저는 여러개의 스크립트를 실행할 때 생성되는 플레이어들을 관리하고, 각각 실행과 중지할 수 있습니다. 오늘은 여러개의 스크립트를 만들어서 전체 실행하는 방법에 대해서 알아보도록 하겠습니다.

     

    스크립트의 실행 버튼은 자기 자신에게만 해당됩니다. 따라서, 클라이언트에 열려 있는 모든 스크립트를 실행할 수 있는 전체 실행 버튼이 필요합니다. 이왕 만드는김에 실행, 중지, 일시 중지와 전체 실행, 전체 중지, 전체 일시 중지 버튼도 같이 만들었습니다.

    WOIvOMB.jpeg

     

     

    메뉴를 추가하는 방법은 아래와 같이 코딩 해줍니다. 코드 내용중에 크게 어려운 부분은 없을겁니다. 3개짜리 버튼 그룹을 2개 만들고, 구분자도 하나 추가했습니다.

                var scriptGroup = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroup();
                scriptGroup.TextLine1 = "Script";
                var groupTriple1 = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupTriple();
                
                var playGroupButton = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupButton();
                playGroupButton.TextLine1 = "Play";
                playGroupButton.Click += PlayGroupButton_Click;
    
                var stopGroupButton = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupButton();
                stopGroupButton.TextLine1 = "Stop";
                stopGroupButton.Click += StopGroupButton_Click;
    
                var pauseGroupButton = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupButton();
                pauseGroupButton.TextLine1 = "Pause";
                pauseGroupButton.Click += PauseGroupButton_Click;
    
                groupTriple1.Items.AddRange(new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupItem[] {
                    playGroupButton,
                    stopGroupButton,
                    pauseGroupButton
                });
    
                var groupTriple2 = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupTriple();
    
                var playAllGroupButton = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupButton();
                playAllGroupButton.TextLine1 = "All Play";
                playAllGroupButton.Click += PlayAllGroupButton_Click;
    
                var stopAllGroupButton = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupButton();
                stopAllGroupButton.TextLine1 = "All Stop";
                stopAllGroupButton.Click += StopAllGroupButton_Click;
    
                var pauseAllGroupButton = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupButton();
                pauseAllGroupButton.TextLine1 = "All Pause";
                pauseAllGroupButton.Click += PauseAllGroupButton_Click;
    
                groupTriple2.Items.AddRange(new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupItem[] {
                    playAllGroupButton,
                    stopAllGroupButton,
                    pauseAllGroupButton
                });
    
                var seperator = new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupSeparator();
    
                scriptGroup.Items.AddRange(new ComponentFactory.Krypton.Ribbon.KryptonRibbonGroupContainer[] {
                    groupTriple1,
                    seperator,
                    groupTriple2
                });
    
                editor.Ribbon.RibbonTabs[2].Groups.Add(scriptGroup);

     

    아직, 다국어와 아이콘 이미지는 적용하지 않은 상태입니다. 디테일은 나중에~ 리그레이션 테스트하면서 추가해야 할거 같습니다. 지금은 기본 기능을 먼저 구현하는게 급하니까요. 추가한 6개의 버튼에 각각 이벤트 핸들러를 추가 해줍니다. 이벤트는 아래와 같이 구현해주면 됩니다.

            private void PlayGroupButton_Click(object? sender, EventArgs e)
            {
                _client.CurrentScript.Play();
            }

     

    _client 맴버 변수는 에디터, 플레이어 또는 디자이너와 같은 매인 프로그램을 말합니다. 여기에서는 에디터가 될테고요. IClient 인터페이스를 구현하고 있습니다.

    namespace Ai.Interface
    {
        public interface IClient
        {
            System.Resources.ResourceManager ResxMessage { get; }
    
            System.Resources.ResourceManager ResxCaption { get; }
    
            System.Resources.ResourceManager ResxImage { get; }
    
            IOutput Output { get; }
    
            object Option { get; set; }
    
            Ai.Interface.IScriptView? CurrentScript { get; }
        }
    }

     

    인터페이스에 보면 CurrentScript 속성이 있습니다. 이 속성은 현재 선택된 스크립트를 반환합니다. 따라서, 위의 실행 버튼 이벤트 핸들러에서 클라이언트의 활성 스크립트를 가져와서 실행하도록 했습니다. 스크립트 인터페이스를 구현하는 페이지 뷰는 실행, 중지, 일시 중지 메소드를 직접 만들어야 합니다. 이 부분은 앞서 설명했으므로 넘어가도록 하겠습니다.

     

    전체 실행을 구현하는 부분은 아래와 같습니다. 클라이언트는 에디터가 될수도 있고, 플레이어가 될수도 있습니다. 시각화 된 스크립트 뷰는 에디터에서만 사용하기 때문에 클라이언트를 에디터로 캐스팅해야 합니다. 그리고, 페이지들을 관리하는 DockingManager에서 스크립트 페이지들을 모두 가져옵니다.

            private void PlayAllGroupButton_Click(object? sender, EventArgs e)
            {
                var dockHelper = new DockHelper(_client);
                var views = dockHelper.GetViews<Ai.Interface.IScriptView>(((Ai.Interface.IEditor)_client).DockingManager);
    
                foreach (var view in views)
                    view?.Play();
            }

     

    dockHelper 인스턴스의 GetViews는 제네릭 메소드입니다. 가져올 뷰의 타입을 선택하면 매치되는 페이지들을 모두 가져오도록 코딩되어 있습니다.

            internal IEnumerable<T?> GetViews<T>(KryptonDockingManager manager)
            {
                return manager.Pages.Select(s => s.Controls.OfType<T>().FirstOrDefault()).Where(w => w != null);
            }

     

    Ai.Interface.IScriptView 인터페이스를 구현하는 모든 페이지를 가져온 후 반복기를 통해 실행 메소드를 호출해줍니다.

                foreach (var view in views)
                    view?.Play();

     

    여기까지가 핸들을 이용한 멀티 다클라가 아닌 멀티 스크립트로 구현하는 다클라 매크로입니다. 참고로, 각각의 스크립트에서 멀티 핸들을 설정하더라도 문제 없이 동작합니다. 각각의 플레이어들은 매니저에서 격리된채로 관리되고, 다 사용한 플레이어는 메모리에서 자동으로 해제됩니다. 이제 테스트를 해볼까요? 앞서 멀티 핸들을 이용한 다클라 매크로에서 사용했던 예제 스크립트입니다.

    3NmxOAD.jpeg

     

     

    새로운 스크립트를 하나 더 만들고, 첫번째 스크립트를 모두 선택해서 복사하고, 두번째 스크립트에 붙여넣기 해줍니다. 그리고, 아래 그림과 같이 프로그램 인덱스를 1로 설정하세요. 스크립트 1번은 첫번째 메모장에 텍스트를 입력하고, 스크립트 2번은 두번째 메모장에 텍스트를 입력합니다.  메모장의 제목이 동일하기 때문에 각자 하나씩 핸들이 설정될 수 있도록 프로그램 인덱스를 다르게 설정해야 합니다.

    PM3St7U.jpeg

     

     

    두번째 스크립트를 실행 해보세요. 아래쪽에 위치한 메모장에 텍스트가 써집니다. 그리고, 전체 실행 버튼을 클릭하면 스크립트가 모두 실행되서 메모장에 모두 텍스트를 씁니다. 간단한 내용이지만, 직접 클라이언트를 구성하고 데이터를 스크립트와 오른쪽 속성창에 보내는 자잘한 작업들도 남아 있습니다. 아직 디테일에 신경쓸 수준의 퀄리티는 아니기 때문에 핵심 기능 위주로 빠르게 만들어 나가야겠습니다.

     

     

    가끔 완벽을 추구하다가 너무 많은 시간을 보내는 분들이 많습니다. 개발자도 그렇고요. 개발 퍼포먼스를 높이려면 빠르게 핵심 기능을 구현하고, 정말 의도한대로 동작하는지 테스트 및 검증하는게 중요합니다. 자잘한 기능에 너무 매몰되서 일을하다보면 너무 많은 시간이 흐르고, 금방 지치게 됩니다. 빠르게 포기하는 사람들의 특징은 크게 2가지입니다. 자기 자신을 믿지 못해서 한두번 해보다가 포기하는 사람과 너무 디테일에 집착한 나머지 완성하기도 전에 포기하는 사람입니다.

     

    공부도 그렇고, 프로그램 또는 자동화 스크립트를 만드는것도 동일합니다. 작은 기능들을 빠르게 만들어서 테스트해보고 적용하면서 성취감을 느껴야 합니다. 그래야 다음 단계로 넘어갈 수 있습니다. 어떤 기능을 만드는데 있어서 이런저런 생각이 많아지면 계속해서 살을 붙이게 됩니다. 이렇게하면 테스트도 하기전에 코드가 꼬이고 망치는 경우들이 있습니다. 이런것들을 방지하기 위해서 형상 관리 프로그램을 사용하는것도 좋은 방법입니다. 뭔가를 가장 빠르게 만드는 방법은 작은 단위의 기능을 빠르게 만들고 검증하는겁니다. 물론, 설계나 디자인의 실수로 리펙토링이 필요할수도 있습니다^^

     

    사실 가장 중요한건 꾸준함인거 같아요. 저도 계속 글을 써나가는건 일을 만들기 위함이 아니라 기억의 한계 때문에 이력(History)을 남기기 위함이 큽니다. 어떨때는 제가 짠 코드를 보고도 왜 이렇게 했지라는 의문이 들때가 있거든요. 어떤 의도로 코딩했는지를 파악하기가 쉽지 않습니다. 그래서 이력을 남기는 습관을 가지고 있는거 같아요. 또 한가지는 글을 쓰면서 차근 차근 테스트하다보면 안보였던 문제들도 보이고요. 디테일도 살아나는 장점들이 있습니다. 글쓰는 습관은 좋은거 같아요^^

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.