AutomationElement 클래스이 SetFocus 메서드는 해당 자동화 요소가 초점을 갖게 제어하는 메서드입니다.
public void SetFocus()
평가도구나 보조 기술에서 사용자가 원하는 자동화 요소에 초점을 이동하고자 할 때 사용할 수 있습니다.
다음 실습은 프로그램 방식으로 초점을 이동시키는 응용을 제작하는 실습입니다.
이번에는 SetFocus 메서드를 이용하여 원하는 자동화 요소로 초점을 옮기는 프로그램을 작성합시다.
초점 제어기를 만들기 전에 타겟 데모 응용 프로그램을 만들기로 합시다. 타겟 데모 응용 프로그램은 12개의 버튼이 있고 1개의 Label이 있습니다. 이 프로그램은 버튼에 초점이 오면 어느 버튼에 초점이 왔는지 Label에 표시하는 응용 프로그램입니다.
먼저 Windows Forms 응용 프로젝트를 생성하세요. 그리고 Form1에 버튼 12개와 Label 1개를 배치하세요. 그리고 Label의 이름 속성을 lb_focus로 설정합니다.
Fom1의 FormLoad 이벤트 핸들러를 추가하여 각 버튼에 초점이 왔을 때 lb_focus Label에 표시할 텍스트 속성을 변경하게 작성합시다.
private void Form1_Load(object sender, EventArgs e) { button1.GotFocus += new EventHandler(Button_GotFocus); button2.GotFocus += new EventHandler(Button_GotFocus); ...중략... button12.GotFocus += new EventHandler(Button_GotFocus); }
버튼에 초점이 왔을 때 이벤트 핸들러에서는 이벤트를 발생한 원인인 sender를 Button 형식으로 참조 연산한 후에 lb_focus의 Text 속성을 버튼의 속성을 대입합니다.
void Button_GotFocus(object sender, EventArgs e) { Button btn = sender as Button; lb_focus.Text = btn.Text; }
using System; using System.Windows.Forms; namespace DemoTarget { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { button1.GotFocus += new EventHandler(Button_GotFocus); button2.GotFocus += new EventHandler(Button_GotFocus); button3.GotFocus += new EventHandler(Button_GotFocus); button4.GotFocus += new EventHandler(Button_GotFocus); button5.GotFocus += new EventHandler(Button_GotFocus); button6.GotFocus += new EventHandler(Button_GotFocus); button7.GotFocus += new EventHandler(Button_GotFocus); button8.GotFocus += new EventHandler(Button_GotFocus); button9.GotFocus += new EventHandler(Button_GotFocus); button10.GotFocus += new EventHandler(Button_GotFocus); button11.GotFocus += new EventHandler(Button_GotFocus); button12.GotFocus += new EventHandler(Button_GotFocus); } void Button_GotFocus(object sender, EventArgs e) { Button btn = sender as Button; lb_focus.Text = btn.Text; } } }
[소스 3.4] Form1.cs
이제 초점 제어기를 작성합시다. Windows Forms 응용 프로젝트를 생성하시고 Form1의 화면 배치합니다.
번호 | 컨트롤 타입 | 컨트롤 명 | 설명 |
1 | Button | btn_refresh_pro | 프로세스 목록 새로고침 |
2 | ListBox | lbox_pro | 프로세스 목록을 보여주는 리스트 상자 |
3 | ListBox | lbox_ae | 선택한 프로세스의 자동화 요소 목록을 보여주는 상자 |
4 | Label | lb_name | 선택한 자동화 요소의 이름 |
5 | Label | lb_cname | 선택한 자동화 요소의 지역화 컨트롤 타입 |
6 | Label | lb_rect | 선택한 자동화 요소의 사각 영역 |
[표 3.5] Form1의 컨트롤
컨트롤 제어기의 동작 원리는 다음과 같습니다. 만약 프로세스 목록 새로고침 버튼을 누르면 프로세스 목록을 조사하여 메인 윈도우 핸들이 유효한 프로세스를 lbox_pro 목록에 추가합니다. 그리고 lbox_pro 목록의 선택 항목이 바뀔 때마다 선택한 프로세스의 메인 윈도우의 서브 트리에 있는 자동화 요소 중에 초점을 소유할 수 있는 버튼 컨트롤을 lbox_ae 목록에 추가합니다.
만약 lbox_ae 목록의 선택 항목이 바뀌면 선택한 자동화 요소의 정보를 각 Label에 표시하고 초점을 이동시킵니다.
이 프로그램에서는 효과적으로 프로세스와 자동화 요소를 ListBox에 추가하고 선택하였을 때 원하는 작업을 하기 위하여 WrapProcess와 WrapAE 클래스를 정의합시다.
먼저 WrapProcess 클래스를 추가합시다. class WrapProcess { Process 를 래핑할 것이며 이를 위해 자동 속성을 제공합시다. public Process Process{ get; private set; } ListBox 목록에 표시할 Title 속성을 제공합시다. public string Title { get { return Process.ProcessName+":"+ Process.MainWindowTitle; } } 프로세스의 메인 윈도우에 관한 자동화 요소를 제공합시다. public AutomationElement RootElement { get { 프로세스에 메인 윈도우가 유효하지 않으면 null을 반환합니다. if (Process.MainWindowHandle == IntPtr.Zero) { return null; } AutomationElement 클래스의 정적 메서드 FromHandler를 호출하여 메인 윈도우에 관한 자동화 요소를 반환합니다. return AutomationElement.FromHandle(Process.MainWindowHandle); } } 생성자에서는 프로세스 개체를 입력받아 Process 속성에 대입합니다. public WrapProcess(Process process) { Process = process; } ToString 메서드를 override 하여 ListBox에 타이틀을 표시할 수 있게 정의합니다. public override string ToString() { return Title; } }
using System; using System.Diagnostics; using System.Windows.Automation; namespace 초점제어기 { class WrapProcess { public Process Process{ get; private set; } public string Title { get { return Process.ProcessName+":"+ Process.MainWindowTitle; } } public AutomationElement RootElement { get { if (Process.MainWindowHandle == IntPtr.Zero) { return null; } return AutomationElement.FromHandle(Process.MainWindowHandle); } } public WrapProcess(Process process) { Process = process; } public override string ToString() { return Title; } } }
[소스 3.5] WrapProcess.cs
이번에는 AutomationElement를 래핑한 WrapAE 클래스를 정의합시다. class WrapAE { AutomationElement를 래핑할 것이며 이를 자동 속성으로 제공합시다. public AutomationElement AE{ get; private set; } 자동화 요소의 이름과 지역화 컨트롤 타입, 사각 영역을 속성으로 제공합시다. public string Name { get { 자동화 요소 이름은 AE. Current 속성의 Name 속성을 그대로 By Pass 합니다. return AE.Current.Name; } } public string ControlType { get { 컨트롤 타입은 지역화 컨트롤 타입을 By Pass할게요. return AE.Current.LocalizedControlType; } } public string Boundary { get { 사각 영역은 AE.Current의 BoundingRectangle 속성을 ToString 메서드를 사용하여 문자열 형태로 By Pass 합시다. return AE.Current.BoundingRectangle.ToString(); } } 생성자에서는 자동화 요소를 입력 인자로 받아 속성에 대입합니다. public WrapAE(AutomationElement ae) { AE = ae; } public override string ToString() { return Name; } }
using System.Windows.Automation; namespace 초점제어기 { class WrapAE { public AutomationElement AE{ get; private set; } public string Name { get { return AE.Current.Name; } } public string ControlType { get { return AE.Current.LocalizedControlType; } } public string Boundary { get { return AE.Current.BoundingRectangle.ToString(); } } public WrapAE(AutomationElement ae) { AE = ae; } public override string ToString() { return Name; } } }
[소스 3.6] WrapAE.cs
이제 Form1을 작업할 차례입니다. 먼저 프로세스 목록 새로고침 버튼 클릭 이벤트 핸들러를 추가하세요. private void btn_refresh_pro_Click(object sender, EventArgs e) { 먼저 프로세스 리스트 상자의 항목을 지웁니다. lbox_pro.Items.Clear(); 모든 프로세스 목록을 얻어옵니다. Process[] proes= Process.GetProcesses(); 얻어온 각 프로세스로 WrapProcess 개체를 생성하여 프로세스 리스트 상자에 추가합니다. 단 프로세스의 메인 윈도우 핸들이 유효하지 않는 것은 필터링 합니다. foreach (Process pro in proes) { if (pro.MainWindowHandle != IntPtr.Zero) { lbox_pro.Items.Add(new WrapProcess(pro)); } } } 프로세스 리스트 상자의 선택한 인덱스 변경 이벤트 핸들러를 추가합니다. private void lbox_pro_SelectedIndexChanged(object sender, EventArgs e) { 선택한 항목이 -1이면 선택 항목이 없는 것이므로 리턴합니다. if (lbox_pro.SelectedIndex == -1){ return; } 자동화 요소 항목을 지웁니다. lbox_ae.Items.Clear(); 프로세스 리스트 상자의 선택한 항목을 WrapProcess로 참조합니다. WrapProcess wp = lbox_pro.SelectedItem as WrapProcess; 선택한 프로세스의 최상위 루트 요소를 참조합니다. AutomationElement ae = wp.RootElement; 여기에서는 초점 제어기이므로 초점을 소유할 수 있는 자동화 요소만 탐색할 것입니다. 이를 위한 컨디션 개체를 생성합니다. Condition con_kf = new PropertyCondition( AutomationElement.IsKeyboardFocusableProperty,true); 버튼 컨트롤만 탐색하기 위한 컨트롤 개체도 생성합니다. Condition con_but = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button); 그리고 생성한 두 컨트롤 개체를 입력 인자로 AndCondition 개체를 생성합니다. Condition con = new AndCondition(con_kf,con_but); 루트 요소의 서브 트리에서 컨디션 개체를 전달하여 자동화 요소를 탐색합니다. AutomationElementCollection aec = ae.FindAll(TreeScope.Subtree, con); 탐색한 자동화 요소 개체를 WrapAE 개체로 래핑하여 리스트 상자 항목에 추가합니다. foreach (AutomationElement sae in aec) { lbox_ae.Items.Add(new WrapAE(sae)); } } 자동화 요소 리스트 상자의 선택 인덱스 변경 이벤트 핸들러를 추가합니다. private void lbox_ae_SelectedIndexChanged(object sender, EventArgs e) { 만약 선택 항목이 없으면 리턴합니다. if (lbox_ae.SelectedIndex == -1) { return; } 선택 항목을 WrapAE 형식으로 참조합니다. WrapAE wae = lbox_ae.SelectedItem as WrapAE; 선택한 요소의 속성으로 레이블의 Text 속성에 대입합니다. lb_name.Text = wae.Name; lb_cname.Text = wae.ControlType; lb_rect.Text = wae.Boundary; 선택한 자동화 요소의 SetFocus 메서드를 호출하여 초점을 제어합니다. wae.AE.SetFocus(); }
using System; using System.Windows.Forms; using System.Diagnostics; using System.Windows.Automation; namespace 초점제어기 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btn_refresh_pro_Click(object sender, EventArgs e) { lbox_pro.Items.Clear(); Process[] proes= Process.GetProcesses(); foreach (Process pro in proes) { if (pro.MainWindowHandle != IntPtr.Zero) { lbox_pro.Items.Add(new WrapProcess(pro)); } } } private void lbox_pro_SelectedIndexChanged(object sender, EventArgs e) { if (lbox_pro.SelectedIndex == -1) { return; } lbox_ae.Items.Clear(); WrapProcess wp = lbox_pro.SelectedItem as WrapProcess; AutomationElement ae = wp.RootElement; Condition con_kf = new PropertyCondition( AutomationElement.IsKeyboardFocusableProperty,true); Condition con_but = new PropertyCondition( AutomationElement.ControlTypeProperty, ControlType.Button); Condition con = new AndCondition(con_kf,con_but); AutomationElementCollection aec = ae.FindAll(TreeScope.Subtree, con); foreach (AutomationElement sae in aec) { lbox_ae.Items.Add(new WrapAE(sae)); } } private void lbox_ae_SelectedIndexChanged(object sender, EventArgs e) { if (lbox_ae.SelectedIndex == -1) { return; } WrapAE wae = lbox_ae.SelectedItem as WrapAE; lb_name.Text = wae.Name; lb_cname.Text = wae.ControlType; lb_rect.Text = wae.Boundary; wae.AE.SetFocus(); } } }
[소스 3.7] Form1.cs