[소프트웨어 접근성] 초점 제어기 만들기 실습
이번에는 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;
}
* 사용하는 개발 도구의 버전에 맞게 변환하세요. 그리고 UI 자동화 관련 .NET 어셈블리를 참조 추가하셔야 합니다. *
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; } } } |
[소스] Form1.cs
이제 초점 제어기를 작성합시다. Windows Forms 응용 프로젝트를 생성하시고 Form1의 화면 배치합니다.
[그림] 초점 제어기 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 |
선택한 자동화 요소의 사각 영역 |
[표] 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; } } } |
[소스] 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; } } } |
[소스] 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(); } } } |
[소스] Form1.cs
너와 나의 연결고리 "공감"
'프로그래밍 기술 > 소프트웨어 접근성, UI 자동화' 카테고리의 다른 글
[소프트웨어 접근성] UI 자동화 이벤트와 이벤트 인자 형식 (0) | 2016.05.05 |
---|---|
[소프트웨어 접근성] UI 자동화 요소 탐색기 만들기 실습 - 메인 폼 구현 (0) | 2016.05.05 |
[소프트웨어 접근성] UI 자동화 요소 탐색기 만들기 실습 - 핵심 클래스 UISearcher 구현 (0) | 2016.05.05 |
[소프트웨어 접근성] UI 자동화 요소 탐색기 만들기 실습- 프로세스, 자동화 요소 래퍼 (0) | 2016.05.05 |
[소프트웨어 접근성] UI 자동화 요소 탐색기 만들기 실습 - 컨트롤 배치 (0) | 2016.05.05 |
[S/W 접근성] 윈도우 옵저버 실습 (0) | 2016.04.26 |
[S/W 접근성] ValuePattern, WindowPattern (0) | 2016.04.26 |
[S/W 접근성] TogglePattern, TransformPattern (0) | 2016.04.26 |
[S/W 접근성] TextPattern (0) | 2016.04.26 |
[S/W 접근성] 테이블 정보 탐색기 실습 (0) | 2016.04.19 |