프로그래밍 기술/소프트웨어 접근성, UI 자동화

9. 접근성 평가 도구 만들기 - 19. MainForm

언제나휴일 2017. 12. 12. 13:52
반응형

9.3.7 MainForm



 이제 마지막으로 MainForm을 작성합시다. MainForm을 작성한 후에 오류를 하나 하나 잡아가면서 필요한 부분은 다시 살펴보시길 바랍니다.

 

[그림 9.16] MainForm 배치1 - 프로젝트 탭

[그림 9.16] MainForm 배치1 - 프로젝트 탭

 

번호

컨트롤 형식

컨트롤 이름

특이 사항

1

TabControl

tc_main

tp_project, tp_acc_evaluate 탭 추가

2

Button

btn_new_project

 

3

ListBox

lbox_project

 

4

SplitContainer

sc_project

2,3 4의 왼쪽 Panel에 배치한 것임

5

MenuStrip

ms_main

메인 메뉴

6

FolderBrowserDialog

fbdlog

 

[ 9.7] MainForm 자식 컨트롤1

[그림 9.17] MainForm 배치2 - 접근성 평가 탭

[그림 9.17] MainForm 배치2 - 접근성 평가 탭

 

번호

컨트롤 형식

컨트롤 이름

특이 사항

7

Button

btn_view_image

 

8

TreeView

tv_hierarchy

 

9

ListView

lv_property

ch_name, ch_value 열 추가,

View 속성을 Details로 지정

10

ListBox

lbox_pattern

 

[ 9.8] MainForm 자식 컨트롤2

 

[그림 9.18] MainForm 메뉴

[그림 9.18] MainForm 메뉴

 

번호

컨트롤 형식

컨트롤 이름

특이 사항

12

ToolStripMenuItem

ms_file

 

13

ToolStripMenuItem

ms_file_new

 

14

ToolStripMenuItem

ms_file_save_Click

Enabled 속성을 False로 지정

15

ToolStripMenuItem

ms_file_end

Enabled 속성을 False로 지정

16

ToolStripMenuItem

ms_file_exit

 

17

ToolStripMenuItem

ms_view

 

18

ToolStripMenuItem

ms_view_highlight

Checked 속성을 True로 지정

CheckState 속성은 Checked

19

ToolStripMenuItem

ms_view_image

Enabled 속성을 False로 지정

20

ToolStripMenuItem

ms_view_invoke

Enabled 속성을 False로 지정

21

ToolStripMenuItem

ms_search

Enabled 속성을 False로 지정

22

ToolStripMenuItem

ms_search_first

Enabled 속성을 False로 지정

23

ToolStripMenuItem

ms_search_last

Enabled 속성을 False로 지정

24

ToolStripMenuItem

ms_search_after

Enabled 속성을 False로 지정

25

ToolStripMenuItem

ms_search_before

Enabled 속성을 False로 지정

26

ToolStripMenuItem

ms_search_parent

Enabled 속성을 False로 지정

[ 9.9] MainForm 자식 컨트롤3

 

 

 MainForm에서는 ImageForm InvokePatternForm을 생성한 개체를 참조하는 멤버를 두어 이미 생성했는데 다시 생성하는 것을 막습니다.

ImageForm image_form = null;

InvokePatternForm invokepattern_form = null;

 

 sc_project 컨트롤의 우측 편에 자식 요소로 표시한 컨트롤은 프로젝트 생성 과정에서 변하므로 이를 기억할 멤버 필드를 선언합니다.

UserControl sc_pro_panel2_child=null;

 

 프로그램 방식의 하이라이트인 EHHighlight 개체를 기억하는 멤버 필드를 선언합니다.

EHHighlight eh = null;

 

 평가에 관한 데이터를 관리하는 EvalManager 단일체 개체를 사용하기 편하게 속성을 정의합니다.

EvalManager EM

{

    get

    {

        return EvalManager.Manager;

    }

}

 

 MainForm Load 이벤트 핸들러를 추가합시다. 이벤트 핸들러에서는 프로그램 방식의 하이라이트 개체를 생성하고 평가 프로젝트 생성 이벤트 핸들러와 평가 프로젝트 변경 이벤트 핸들러를 추가합니다.

private void MainForm_Load(object sender, EventArgs e)

{

    eh = new EHHighlight();

    eh.Visible = true;

    EM.MakedProject += new MakeProjectEventHandler(EM_MakedProject);

    EM.ChangedProject += new MakeProjectEventHandler(EM_ChangedProject);

}

 

 평가 프로젝트가 생성되었을 때 수행하는 이벤트 핸들러에서는 평가 프로젝트를 프로젝트 리스트 박스에 추가하고 선택 아이템으로 지정합니다. 그리고 평가 대상 창이 이동했을 때 수행할 이벤트 핸들러를 추가합니다. 그리고 평가 정보를 제공하기 위한 작업을 수행하는 메서드와 평가에 관한 메뉴를 활성화하는 메서드를 호출합니다.

void EM_MakedProject(object sender, MakeProjectEventArgs e)

{

    if (this.InvokeRequired)

    {

        this.Invoke(new MakeProjectEventHandler(EM_MakedProject), 

                           new object[] { sender, e });

    }

    else

    {

        lbox_project.Items.Add(e.AccEvalProject);

        lbox_project.SelectedItem = e.AccEvalProject;

        e.AccEvalProject.AEMoved += new AutomationPropertyChangedEventHandler(

                                                      AccEvalProject_AEMoved);

        EvaluationStart(e.AccEvalProject);

        SetEnableMenu(true);

   }

}

private void SetEnableMenu(bool flag)

{

    ms_file_save.Enabled = flag;

    ms_file_end.Enabled = flag;

    ms_view_image.Enabled = flag;

    ms_view_invoke.Enabled = flag;

    btn_view_image.Enabled = flag;

}

 

 평가 프로젝트를 시작하면서 제공하는 메서드는 평가 프로젝트가 시작, 변경, 종료할 때 수행합니다. 입력 인자로 받은 프로젝트가 null이면 종료를 의미합니다. 이 때는 평가 항목을 보여주는 리스트 박스에 선택한 프로젝트를 제거합니다. 만약 평가 프로젝트가 시작하거나 변경되었을 때는 평가 프로젝트 정보 컨트롤을 생성하여 MainForm에 배치하고 평가 대상의 구조를 보여주기 위해 tv_hierarchy 컨트롤의 Nodes 컬렉션에 평가 프로젝트의 루트 노드를 추가합니다.

private void EvaluationStart(AccEvalProject aeproject)

{

    if (aeproject == null)

    {

        lbox_project.Items.Remove(lbox_project.SelectedItem);

        return;

    }

    ProjectInfoControl pictrl = new ProjectInfoControl(aeproject);

    ChangeProjectPanel2Child(pictrl);

    EHProcess ehprocess = aeproject.EHProcess;

    tv_hierarchy.Nodes.Clear();

    tv_hierarchy.Nodes.Add(aeproject.Root);

    tv_hierarchy.ExpandAll();

}

 

 MainForm sc_project의 우측 패널에는 프로젝트 생성 과정에서 사용자 컨트롤이 바뀝니다. 메서드에서는 기존의 컨트롤은 해제하고 입력한 컨트롤을 배치합니다.

private void ChangeProjectPanel2Child(UserControl ctrl)

{

    if (sc_pro_panel2_child != null)

    {

        sc_pro_panel2_child.Dispose();

    }

    sc_pro_panel2_child = ctrl;

    if (ctrl != null)

    {

        ctrl.Parent = sc_project.Panel2;

        ctrl.Dock = DockStyle.Fill;

    }

}

 평가 대상 창이 이동했을 때 수행하는 이벤트 핸들러에서는 선택항목의 요소의 화면 영역을 얻어와 프로그램 방식의 하이라이트 개체의 영역을 조절합니다.

void AccEvalProject_AEMoved(object sender, AutomationPropertyChangedEventArgs e)

{

    if (this.InvokeRequired)

    {

        this.Invoke(new AutomationPropertyChangedEventHandler(

                       AccEvalProject_AEMoved), new object[] { sender, e });

        return;

    }

    TreeNode tn = tv_hierarchy.SelectedNode;

    if (tn != null)

    {

        EHAutoElem eae = tn.Tag as EHAutoElem;

        eh.Rect = eae.GetBoundaryRect();

    }

}

 

 평가 프로젝트를 변경하면 EvaluationStart 메서드를 호출하고 변경 프로젝트가 null이면 평가를 끝낸다는 것을 알려줍니다.

void EM_ChangedProject(object sender, MakeProjectEventArgs e)

{

    if (this.InvokeRequired)

    {

        this.Invoke(new MakeProjectEventHandler(EM_ChangedProject),

                       new object[] { sender, e });

    }

    else{

        EvaluationStart(e.AccEvalProject);

        if (e.AccEvalProject == null)

        {

            MessageBox.Show("평가를 끝냅니다.");

            EndProject();

        }

    }

}

 평가를 종료하는 메서드에서는 sc_project의 우측 패널의 자식 요소를 null로 변경하고 이미 열린 Form 개체를 닫습니다. 그리고 현재 평가 프로젝트가 있다면 이를 끝내고 평가 요소의 구조를 보여주는 자동화 요소 속성을 보여주는 리스트 뷰, 컨트롤 패턴을 보여주는 리스트 상자의 항목을 Clear 합니다.

void EndProject()

{

    ChangeProjectPanel2Child(null);

    if (invokepattern_form != null)

    {

        invokepattern_form.Close();

    }

    if (image_form != null)

    {

       image_form.Close();

    }

    AccEvalProject aeproject = EM.CurrentProject;

    if (aeproject != null)

    {

        aeproject.End();

    }

    tv_hierarchy.Nodes.Clear();

    lv_property.Items.Clear();

    lbox_pattern.Items.Clear();

}

 

 btn_new_project 컨트롤의 클릭 이벤트 핸들러를 추가합니다. 핸들어에서는 프로젝트 생성 컨트롤을 생성하여 sc_project의 우측 패널의 자식 요소를 변경하는 메서드를 호출합니다.

private void btn_new_project_Click(object sender, EventArgs e)

{

    ProjectMakerControl pmctrl = new ProjectMakerControl();

    ChangeProjectPanel2Child(pmctrl);

}

 

 

 

 tv_herarchy 컨트롤의 AfterSelect 이벤트 핸들러를 추가합니다. 핸들어에서는 선택 항목의 UI 정보를 변경하는 메서드와 선택 항목의 부모 관계에 따라 메뉴 항목의 상태를 변경하는 메서드, 패턴을 변경하는 메서드를 호출하고 프로그램 방식의 하이라이트 사각 영역을 변경합니다.

private void tv_hierarchy_AfterSelect(object sender, TreeViewEventArgs e)

{

    if (tv_hierarchy.SelectedNode == null)

    {

        return;

   }

   TreeNode tn = tv_hierarchy.SelectedNode;

   EHAutoElem eae = tn.Tag as EHAutoElem;

   ChangeUIPropertyTreeView(eae);

   ChangeFamily(tn);

   ChangePattern(eae);

   eh.Rect = eae.GetBoundaryRect();

}

 

 자동화 요소의 UI 정보를 변경하는 메서드에서는 lv_property 컨트롤 항목을 지웁니다. 그리고 UI 속성 이름과 속성 값으로 ListViewItem 개체를 만들어 lv_property 컨트롤 항목으로 추가합니다.

private void ChangeUIPropertyTreeView(EHAutoElem eae)

{

    lv_property.Items.Clear();

    string[] vals = new string[2];

    for (ENUM_UIProperty i = 0; i < ENUM_UIProperty.MAX_UIPROPERTY; i++)

    {

        vals[0] = i.ToString();

        vals[1] = eae.GetAEPropertyByIndex((int)i);

        if (vals[1] == string.Empty)

        {

            vals[1] = string.Empty;

        }

        lv_property.Items.Add(new ListViewItem(vals));

   }

}

 선택한 요소에 따라 메뉴 항목중에 탐색 관련 항목의 Enable 상태를 변경하는 메서드를 작성합시다.

private void ChangeFamily(TreeNode tn)

{

    ms_search_parent.Enabled = (tn.Parent != null);

    ms_search_after.Enabled = (tn.NextNode != null);

    ms_search_before.Enabled = (tn.PrevNode != null);

    ms_search_first.Enabled = (tn.FirstNode != null);

    ms_search_last.Enabled = (tn.LastNode != null);

}

 

 자동화 요소의 패턴을 변경하는 메서드에서는 요소의 패턴을 보여주는 lbox_pattern 컨트롤의 항목을 지우고 입력 인자로 전달받은 요소가 어떠한 컨트롤 패턴인지 모두 확인하여 특정 컨트롤 패턴이면 lbox_pattern 컨트롤의 항목으로 추가합니다.

private void ChangePattern(EHAutoElem eae)

{

    object obj = null;

    lbox_pattern.Items.Clear();

    for (ENUM_CONTROL dt = 0; dt < ENUM_CONTROL.MAX_CONTROL; dt++)

    {

        obj = eae.GetPattern(dt);

        if (obj != null)

        {

           lbox_pattern.Items.Add(obj);

        }

    }

}

 

 lbox_project 컨트롤의 항목 선택 변경 이벤트 핸들러를 추가합니다. 이벤트 핸들러에서는 EvalManager 개체의 프로젝트를 변경 메서드를 호출합니다.

private void lbox_project_SelectedIndexChanged(object sender, EventArgs e)

{

    if (lbox_project.SelectedIndex == -1){    return;    }

    AccEvalProject aeproject = lbox_project.SelectedItem as AccEvalProject;

    EM.SetCurrentProject(aeproject.ToString());

}

 

 ms_view_highlight 메뉴 항목의 클릭 이벤트 핸들러를 추가하여 Checked 상태를 토글하고 이에 따라 EHHighlight 개체의 Visible 상태를 변경합니다.

private void ms_view_highlight_Click(object sender, EventArgs e)

{

    ms_view_highlight.Checked ^= true;

    eh.Visible = ms_view_highlight.Checked;

}

 

 ms_view_image 클릭 이벤트 핸들러를 추가하여 ImageForm 개체 생성과 FormClosed 이벤트 핸들러를 추가합니다. ImageForm이 닫히면 image_form 멤버를 null로 지정합니다.

private void ms_view_image_Click(object sender, EventArgs e)

{

    if (image_form == null)

    {

        image_form = new ImageForm();

        image_form.FormClosed += new FormClosedEventHandler(

                                               image_form_FormClosed);

        image_form.Show();

    }

}

void image_form_FormClosed(object sender, FormClosedEventArgs e)

{

    image_form = null;

}

 

 

  ms_view_invoke 메뉴 항목을 클릭 이벤트 핸들러도 추가합니다. 이벤트 핸들러에서는 평가 프로젝트의 루트 노드의 자동화 요소를 얻어와서 InvokePatternForm 개체를 생성합니다. 마찬가지로 FormClosed 이벤트 핸들러를 추가합니다.

private void ms_view_invoke_Click(object sender, EventArgs e)

{

    if (invokepattern_form == null)

    {

        TreeNode root = EM.CurrentProject.Root;

        EHAutoElem eae = root.Tag as EHAutoElem;

        invokepattern_form = new InvokePatternForm(eae);

        invokepattern_form.FormClosed += new FormClosedEventHandler(

                       ip_form_FormClosed);

        invokepattern_form.Show();

    }

}

void ip_form_FormClosed(object sender, FormClosedEventArgs e)

{

    invokepattern_form = null;

}

 

 ms_file_new 메뉴 항목의 클릭 이벤트 핸들러는 btn_new_project 컨트롤의 클릭 이벤트 핸들러인 btn_new_project _Click로 지정합니다.

 

 ms_file_save 메뉴 항목의 클릭 이벤트 핸들러를 추가합시다. 핸들러에서는 폴더 브라우저 다이얼로그를 보여주고 선택한 폴더에 평가 프로젝트의 결과를 저장하는 메서드를 호출합니다.

private void ms_file_save_Click(object sender, EventArgs e)

{

    if (fbdlog.ShowDialog() == DialogResult.OK)

    {

        AccEvalProject aeproject = EM.CurrentProject;

        aeproject.Save(fbdlog.SelectedPath);

    }

}

 

 

 ms_file_end 메뉴 항목의 클릭 이벤트 핸들러를 추가하여 EndProject를 호출합니다. 그리고 ms_file_exit 메뉴 항목의 클릭 이벤트 핸들러도 추가하여 폼을 닫습니다. 그리고 탐색에 관한 메뉴 항목들도 클릭 이벤트 핸들러를 추가하세요.

private void ms_file_end_Click(object sender, EventArgs e)

{

    EndProject();

}

private void ms_file_exit_Click(object sender, EventArgs e)

{

    Close();

}

private void ms_search_first_Click(object sender, EventArgs e)

{

    TreeNode tr = tv_hierarchy.SelectedNode;

    tv_hierarchy.SelectedNode = tr.FirstNode;

}

private void ms_search_last_Click(object sender, EventArgs e)

{

    TreeNode tr = tv_hierarchy.SelectedNode;

    tv_hierarchy.SelectedNode = tr.LastNode;

}

private void ms_search_after_Click(object sender, EventArgs e)

{

    TreeNode tr = tv_hierarchy.SelectedNode;

    tv_hierarchy.SelectedNode = tr.NextNode;

}

private void ms_search_before_Click(object sender, EventArgs e)

{

    TreeNode tr = tv_hierarchy.SelectedNode;

    tv_hierarchy.SelectedNode = tr.PrevNode;

}

private void ms_search_parent_Click(object sender, EventArgs e)

{

    TreeNode tr = tv_hierarchy.SelectedNode;

    tv_hierarchy.SelectedNode = tr.Parent;

}

 상용 버전의 평가 도구가 되려면 평가 도중에 창의 변화에 관한 정보 수집과 전달도 제공해야 하고 평가자의 평가 점수나 코멘트등을 기술할 수 있게 해 주는 세부 기능들을 제공해야 할 것입니다.

 

 이 책에서는 S/W 접근성이 무엇인지 소개하고 UI 자동화 기술을 프로그램에 적용하는 방법을 전달하는 것이 목적이라 상용 버전 수준보다 품질이 떨어지는 것을 이해하리라 믿습니다. 이 보다 책의 기술 방식이나 구성이 미흡한 부분은 다음에 기회가 생기면 수정하도록 하겠습니다.


반응형