窗體是程序的基礎。無論是主窗體,還是彈出窗體,他們往往都是需要首先定位的對象。窗體,作為一類特殊對象,他們都是根對象的直接子對象,針對這一特點,對他們定位就非常簡單了。通常,通過窗體標題,就能很好的找到所需的窗體。具體方法如下。
private double waitCheckInterval = ((Double) getOption(IOptionName.WAIT_FOR_EXISTENCE_DELAY_BETWEEN_RETRIES))
.doubleValue();
private double waitMaxTime = ((Double) getOption(IOptionName.MAXIMUM_WAIT_FOR_EXISTENCE))
.doubleValue();
private TestObject rootTO = null;

public boolean getRootWithCaption(String captionExpr)
{
double timeNow = System.currentTimeMillis() / 1000;
double endTime = timeNow + waitMaxTime;
rootTO = null;

while (rootTO == null && timeNow < endTime)
{
RootTestObject root = RootTestObject.getRootTestObject();
TestObject[] ftWinObjects = null;
RegularExpression exp = new RegularExpression(captionExpr, false);
ArrayList<Property> v = new ArrayList<Property>();
v.add(new Property(".captionText", exp));
v.add(new Property(".domain", "Java"));
v.add(new Property("showing", "true"));
ftWinObjects = root.find(atChild((Property[]) v.toArray(new Property[0])));

if (ftWinObjects != null)
{

if (ftWinObjects.length > 1)
{
throw new AmbiguousRecognitionException("Find more windows with capture: " + captionExpr);
}

if (ftWinObjects.length == 1)
{
rootTO = ftWinObjects[0];
return true;
}

} else
{
sleep(waitCheckInterval);
timeNow = System.currentTimeMillis() / 1000;
}
}
return false;
}

上面的方法首先取得對象查找的間隔時間、最大等待時間,并聲明了空的窗體對象。接下來進入方法,根據查找結果和最大等待時間來循環查找窗體。先獲得根測試對象,然后查找其直接子對象,查找條件為:窗體標題符合正則表達式captionExpr的定義,屬于Java域,并且當前為顯示狀態。最后處理查找結果,如果結果大于1個,則拋出異常;如果結果等于1,則返回true;如果結果為空,則等待并重新計算時間,并繼續循環查找;如果最后仍未空并退出循環,則返回false。
有的時候,窗口的出現并不是一定的,例如很多彈出窗口。這時候,對象查找并不需要循環等待,相應的方法應為:

public boolean getRootWithCaptionWithoutWait(String captionExpr)
{
rootTO = null;
sleep(waitCheckInterval);
RootTestObject root = RootTestObject.getRootTestObject();
TestObject[] ftWinObjects = null;
RegularExpression exp = new RegularExpression(captionExpr + "$", false);
ArrayList<Property> v = new ArrayList<Property>();
v.add(new Property(".captionText", exp));
v.add(new Property(".domain", "Java"));
v.add(new Property("showing", "true"));
ftWinObjects = root.find(atChild((Property[]) v.toArray(new Property[0])));

if (ftWinObjects != null)
{

if (ftWinObjects.length > 1)
{
throw new AmbiguousRecognitionException("Find more windows with capture: " + captionExpr);
}

if (ftWinObjects.length == 1)
{
rootTO = ftWinObjects[0];
return true;
}
}
return false;
}

這樣一來,就可以用統一的方法來進行窗體的查找。具體代碼如下:

protected boolean ExistWin(String winName, boolean wait)
{
release();
if (wait)
return og.getRootWithCaption(winName);
else
return og.getRootWithCaptionWithoutWait(winName);
}

public boolean isDialog(String caption, boolean wait)
{
return super.ExistWin(caption, wait);
}
前一個方法利用傳入的窗體標題正則表達式,和窗體查找邏輯,進行窗體查找。后一個方法對其進行調用,返回是否查找成功的結果。事實上,這兩個方法完全可以寫成一個,但是在設計框架時,應考慮到自動化操作的各個環節,應把每一個環節獨立開來,才能具有最大的靈活性。根據我的經驗,對對象的查找和查找后的操作應獨立成兩個不同類來完成,其中對對象的查找應為一個RFT的super class。其實也就是繼承了RationalTestScript類的抽象類,對對象的操作應為一個Script,這個Script的super class應為自己之前定義的對象查找類,而不是默認的RationalTestScript。這一部分后面還會講到。
當需要關閉可能出現的錯誤窗口時,可以這樣使用:

if (aDialog.isDialog(".*Error", false))
{
aDialog.close();
}
當需要操作一定出現的窗口時,可以這樣使用:

if (aDialog.isDialog("Warning", true))
{
aDialog.clickButton("Yes");
}
至此,所有針對窗體的處理邏輯就基本完整了。當然,可能有些被測程序可以同時打開多個實例,這就需要支持同時獲取并操作多個具有相同標題的窗體。這樣的問題大家可以一同探討如何處理。