1.4?Tab?控件?
1.4.1?Tab?控件設(shè)計(jì)方法?
Tab?控件類似分隔標(biāo)簽或一組文件夾上的標(biāo)簽,使用Tab?控件可以在應(yīng)用程序窗口或?qū)υ捒蛑械耐粎^(qū)域定義多個(gè)頁(yè)面。該控件包含了一個(gè)或多個(gè)panel?面板集合。在設(shè)計(jì)時(shí)和運(yùn)行時(shí),可以設(shè)置其屬性來(lái)控制Tab?控件的外觀,如可設(shè)置標(biāo)簽以多行形式顯示,將標(biāo)簽放在Tab?控件的上下左右各種位置,并可在標(biāo)簽上顯示圖標(biāo)。
LabWindows/CVI?中的Tab?控件最初是由Panel?面板轉(zhuǎn)換而來(lái),控件中的每個(gè)頁(yè)面都有自己的句柄(類似于面板句柄),可以認(rèn)為Tab?控件是一個(gè)容器,里面包含了面板的集合,因此,Tab?控件內(nèi)也可重復(fù)內(nèi)嵌Tab?控件。正是由于Tab?控件具有這些特點(diǎn)與屬性,在使用某些函數(shù)時(shí),如SetCtrlVal?、GetCtrlVal?等時(shí),參數(shù)中的面板句柄設(shè)置應(yīng)區(qū)分是一般面板句柄還是Tab?頁(yè)面句柄。
在LabWindows/CVI?中,Tab?控件是最為特殊的一個(gè)控件,這主要是因?yàn)橐肓巳萜髦械娜萜鞲拍睿üP者定義)。與其他語(yǔ)言最大的區(qū)別是,在LabWindows/CVI?中,一個(gè)面板即為一個(gè)容器,所有的控件必須放置在這個(gè)容器內(nèi),不允許在這個(gè)面板上存在其他的容器,如果換個(gè)角度,把容器看作句柄,也就是說(shuō),一個(gè)面板只有一個(gè)句柄,控件沒(méi)有句柄,只有ID(ActiveX?控件除外),即使是Radio?Group?這類控件,嚴(yán)格上來(lái)說(shuō)也是由Tree?控件衍生而來(lái),不具有控件句柄。這樣設(shè)計(jì)的好處是,LabWindows/CVI?的消息傳遞是扁平化的,只在一個(gè)容器中進(jìn)行消息循環(huán),事件響應(yīng)及時(shí);缺點(diǎn)也顯而易見(jiàn),不能設(shè)計(jì)出像Visual?Basic?或Delphi?中非常完美的控件組或頁(yè)框(如Frame),但這也是LabWindows/CVI?設(shè)計(jì)的一大優(yōu)點(diǎn),簡(jiǎn)化設(shè)計(jì)思路,使程序設(shè)計(jì)者更加專注于邏輯系統(tǒng)設(shè)計(jì)而非語(yǔ)言本身。舉例說(shuō)明,如果在Visual?Basic?或Delphi?中建有一個(gè)工程,F(xiàn)orm?(窗體)里面有一個(gè)Tab?控件,Tab?控件內(nèi)嵌套一個(gè)Numeric?控件,可以對(duì)其進(jìn)行屬性操作,即獲得或設(shè)置屬性值;同理,在LabWindows/CVI?集成開(kāi)發(fā)環(huán)境中也建有一個(gè)工程,Panel(面板)里面有一個(gè)Tab?控件,控件內(nèi)嵌套一個(gè)Numeric?控件,則引用方法如下:
(1)Visual Basic 語(yǔ)句 ??? ?
賦值??
Form.Tab.Numeric.value = 1 ??? ?
取值??
x = Form.Tab.Numeric.value ??? ?
(2)Delphi 語(yǔ)句??
賦值??
Form.Tab.Numeric.value := 1 ?? ?
取值??
x := Form.Tab.Numeric.value ?? ?
(3)LabWindows/CVI 函數(shù) ? ?
賦值(函數(shù)語(yǔ)句取自本例程)
panelHandle = LoadPanel (0, "Tab 控件.uir", PANEL); GetPanelHandleFromTabPage (panelHandle, PANEL_TAB, 0, &TabPanelHandle); SetCtrlVal (TabPanelHandle, TABPANEL_NUMERICTHERM, temp); 取值(函數(shù)語(yǔ)句取自本例程)
panelHandle = LoadPanel (0, "Tab 控件.uir", PANEL); GetPanelHandleFromTabPage (panelHandle, PANEL_TAB, 0, &TabPanelHandle); GetCtrlVal (TabPanelHandle, TABPANEL_NUMERICKNOB, &temp); ???
有意思的是,Visual?Basic?和Delphi?對(duì)控件屬性的引用中用了3?個(gè)“.”,這3?個(gè)“.”對(duì)應(yīng)于LabWindows/CVI?的3?個(gè)函數(shù)語(yǔ)句,三種語(yǔ)言之間,屬性獲得或設(shè)置都是從容器到實(shí)例的逐次遞進(jìn)引用,邏輯上是相同的,只是表現(xiàn)方式不同,其邏輯關(guān)系如圖1-9?所示。
(a)?Visual?Basic?或Delphi?(b)LabWindows/CVI
圖1-9?屬性獲得或設(shè)置邏輯關(guān)系
與Visual Basic 和Delphi 的差別也可以很清晰地發(fā)現(xiàn),LabWindows/CVI 的編碼量巨大,函數(shù)量眾多,而且大量的編碼是用在屬性設(shè)置上的,為了克服編碼量大、函數(shù)多程序員不容易記,書寫容易出現(xiàn)錯(cuò)誤的缺點(diǎn),LabWindows/CVI 引入函數(shù)面板(Function Panel),即我們常用的.fp 文件,使得對(duì)于屬性的編程只需要用函數(shù)面板輸入幾個(gè)參數(shù)就可以實(shí)現(xiàn)大部分功能,簡(jiǎn)單、易操作。
在編輯狀態(tài),雙擊面板中的Tab 控件,彈出Edit Tab 對(duì)話框,如圖1-10 所示。在Control Apperarance 框中,Tabs Fit Mode 用來(lái)設(shè)置單行、多行顯示等,默認(rèn)為單行顯示,Tab Location 用來(lái)設(shè)置Tab 標(biāo)簽的位置,默認(rèn)放置在控件的左上角。在Tab 框中,可以設(shè)置每一個(gè)頁(yè)面的標(biāo)簽、常量名等,可以進(jìn)行添加、剪切、復(fù)制、粘貼,頁(yè)面的前后移動(dòng),對(duì)頁(yè)面標(biāo)簽添加圖標(biāo)以及設(shè)置每個(gè)頁(yè)面控件的焦點(diǎn)轉(zhuǎn)移次序Tab Order 等操作。
圖1-10 Edit Tab 對(duì)話框
1.4.2 Tab 控件程序設(shè)計(jì)
(1)面板設(shè)計(jì)
編寫一個(gè)Tab 控件屬性設(shè)置程序,能夠響應(yīng)頁(yè)面(標(biāo)簽頁(yè))內(nèi)的事件、設(shè)置標(biāo)簽、計(jì)算Tab 頁(yè)面數(shù)目,改變標(biāo)簽的顯示風(fēng)格,并且在標(biāo)簽上可以設(shè)置顯示圖標(biāo)。在頁(yè)面中,有兩個(gè)Command Button 控件,擁有相同的常量值和回調(diào)函數(shù)名,在調(diào)用時(shí),需要通過(guò)標(biāo)題字符來(lái)區(qū)分所要響應(yīng)的事件。面板設(shè)計(jì)如圖1-11 所示,面板中主要控件屬性設(shè)置如表1-11 所示。
圖1-11 Tab 控件面板
表1-11 控件屬性設(shè)置表
?。?)程序源代碼
//頭文件聲明
#include 《formatio.h》
#include 《cvirte.h》
#include 《userint.h》
#include “Tab 控件.h”
//Tab 頁(yè)面句柄聲明
static int TabPanelHandle;
//Tab 頁(yè)面索引聲明
static int index = 0;
static int panelHandle; //主函數(shù)
int main (int argc, char *argv[])
{
if (InitCVIRTE (0, argv, 0) == 0)
return –1; /* out of memory */ if ((panelHandle = LoadPanel (0, “Tab 控件.uir”, PANEL)) 《 0)
return –1;
DisplayPanel (panelHandle);
RunUserInterface ();
DiscardPanel (panelHandle);
return 0;
} //面板回調(diào)函數(shù)
?int CVICALLBACK PanelCB (int panel, int event, void *callbackData,
int eventData1, int eventData2)
{
switch (event)
{
case EVENT_CLOSE:
QuitUserInterface (0);
break;
}
return 0;
}
//事件響應(yīng)頁(yè)面
int CVICALLBACK valset (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
int temp;
switch (event)
{
case EVENT_COMMIT:
// 獲得Tab 頁(yè)面句柄
GetPanelHandleFromTabPage (panelHandle, PANEL_TAB, 0, &TabPanelHandle);
// 獲得Tab 頁(yè)面中控件值
GetCtrlVal (TabPanelHandle, TABPANEL_NUMERICKNOB, &temp);
// 設(shè)置Tab 頁(yè)面中控件值
SetCtrlVal (TabPanelHandle, TABPANEL_NUMERICTHERM, temp);
break;
}
return 0;
}
//頁(yè)面中的Command Button 按鈕
int CVICALLBACK OkCallback (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
int area;
char s[20];
char label[20];
int count;
switch (event)
{
case EVENT_COMMIT:
// 獲得控件屬性
GetCtrlAttribute (panel, control, ATTR_LABEL_TEXT, label);
// 獲得當(dāng)前激活頁(yè)面索引
GetActiveTabPage (panelHandle, PANEL_TAB, &index);
// 通過(guò)索引獲得當(dāng)前頁(yè)面句柄
GetPanelHandleFromTabPage (panelHandle, PANEL_TAB, index, &TabPanelHandle);
? // 如果當(dāng)前頁(yè)面中的按鈕為“設(shè)置”時(shí),執(zhí)行以下操作
if (CompareStrings (label, 0, “ 設(shè)置”, 0, 1) == 0)
{
// 獲得頁(yè)面中指定值
GetCtrlVal (TabPanelHandle, TABPANEL_2_STRING, s);
// 設(shè)置當(dāng)前頁(yè)面中標(biāo)簽為指定值
SetTabPageAttribute (panelHandle, PANEL_TAB, index, ATTR_LABEL_TEXT, s);
}
// 如果當(dāng)前頁(yè)面中的按鈕為“獲取”時(shí),執(zhí)行以下操作
if (CompareStrings (label, 0, “ 獲取”, 0, 1) == 0)
{
// 獲得Tab 控件中頁(yè)面數(shù)目
GetNumTabPages (panelHandle, PANEL_TAB, &count);
// 顯示頁(yè)面數(shù)目
SetCtrlVal (TabPanelHandle, TABPANEL_3_NUMERIC, count);
}
break;
}
return 0;
}
//顯示風(fēng)格回調(diào)函數(shù)
int CVICALLBACK style (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
int kind;
switch (event)
{
case EVENT_COMMIT:
// 獲得控件值
GetCtrlVal (panel, control, &kind);
// 設(shè)置Tabp 控件風(fēng)格
SetCtrlAttribute (panelHandle, PANEL_TAB, ATTR_TABS_LOCATION, kind);
break;
}
return 0;
}
3:程序注釋
?、?GetPanelHandleFromTabPage 函數(shù)獲得Tab 頁(yè)面句柄。函數(shù)原型為:
int GetPanelHandleFromTabPage (int Panel_Handle, int Control_ID, int Index, int
*Tab_Panel_Handle);
Panel_Handle:Tab 控件所在面板句柄。
Control_ID:Tab 控件ID。
Index:Tab 頁(yè)面(標(biāo)簽頁(yè))索引,第一個(gè)頁(yè)面為0,依次遞增。注意,此值需要用戶設(shè)定而非系統(tǒng)返回值。
*Tab_Panel_Handle :返回Tab 頁(yè)面索引指定的頁(yè)面句柄。
② GetActiveTabPage 函數(shù)獲得當(dāng)前激活的Tab 頁(yè)面索引。函數(shù)原型為:int GetActiveTabPage (int Panel_Handle, int Control_ID, int *Active_Index);
*Active_Index :當(dāng)前激活頁(yè)面索引值,從0 開(kāi)始計(jì),–1 表示沒(méi)有活動(dòng)頁(yè)面。
?、?CompareStrings 函數(shù)
字符串比較函數(shù)。將字符串1 中從某一位置開(kāi)始所組成的子串與字符串2 中從某一位置開(kāi)始所組成的子串進(jìn)行比較。函數(shù)原型為:
int CompareStrings (char String_1[], int String_1_Index, char String_2[], int String_2_Index, int
Case_Sensitive);
String_1[] :字符串1。
String_1_Index :子串1 起始位置。
String_2[] :字符串2。
String_2_Index :子串2 起始位置。
Case_Sensitive:是否區(qū)分大小寫。
返回值:0 表示兩子串相等,–1 表示子串1 小于子串2,1 表示子串1 大于子串2。
?、?valset 回調(diào)函數(shù)
在valset 回調(diào)函數(shù)中編寫了GetCtrlVal (TabPanelHandle, TABPANEL_NUMERICKNOB, &temp) 語(yǔ)句,值得注意的是,GetCtrlVal 函數(shù)Panel Handle 參數(shù)并非在程序前面聲明的panelHandle, 而是采用了GetPanelHandleFromTabPage 函數(shù)的返回Tab 頁(yè)面句柄TabPanelHandle,也可以利用控件回調(diào)函數(shù)傳回的函數(shù)句柄panel 。Control ID 參數(shù)可以寫成TABPANEL_NUMERICKNOB ,也可以利用控件回調(diào)函數(shù)傳回的控件常量control 參數(shù)。此外,為了使數(shù)值設(shè)置與數(shù)值顯示看起來(lái)同步,可以將event 事件中的EVENT_COMMIT 改寫為EVENT_VAL_CHANGED ,修改后的回調(diào)函數(shù)如下:
int CVICALLBACK valset (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
int temp;
switch (event)
{
case EVENT_VAL_CHANGED:
// 獲得Tab 頁(yè)面句柄
GetPanelHandleFromTabPage (panelHandle, PANEL_TAB, 0, &TabPanelHandle);
// 獲得Tab 頁(yè)面中控件值
GetCtrlVal (panel, control, &temp);
// 設(shè)置Tab 頁(yè)面中控件值
SetCtrlVal (panel, TABPANEL_NUMERICTHERM, temp);
break;
}
return 0;
}
?、?具有相同常量名和回調(diào)函數(shù)的Command Button 按鈕事件響應(yīng)方式設(shè)計(jì)在面板設(shè)計(jì)中,Command Button 按鈕在標(biāo)簽設(shè)置和Tab 數(shù)目頁(yè)面出現(xiàn)了兩次,分別為“設(shè)置”和“獲取”按鈕,其回調(diào)函數(shù)名稱和常量名完全一致,只是標(biāo)題不同,這是由于Tab 控件本身就是多面板的集合,類似于一個(gè)容器控件,Tab 頁(yè)面以子面板的方式出現(xiàn),造成了可以重命名不同控件的問(wèn)題,雖然不利于控件事件的區(qū)分,但卻能減少回調(diào)函數(shù)的數(shù)量,利于代碼的優(yōu)化。面板和控件在程序頭文件中定義如下:
#define PANEL 1
#define PANEL_TAB 2
#define TABPANEL_NUMERICTHERM 2
#define TABPANEL_NUMERICKNOB 3
#define TABPANEL_2_STRING 2
#define TABPANEL_2_OKBUTTON 3
#define TABPANEL_3_NUMERIC 2
#define TABPANEL_3_OKBUTTON 3
#define TABPANEL_4_RING 2
從以上代碼可以看出,雖然兩個(gè)控件在界面設(shè)計(jì)階段具有相同的常量名,在由于所在的Tab 頁(yè)面不同,系統(tǒng)生成的常量名并不相同,分別為TABPANEL_2_OKBUTTON 和TABPANEL_3_OKBUTTON ,但常量值是相同的且均為3,在相同回調(diào)函數(shù)下,只能通過(guò)控件的不同標(biāo)題來(lái)區(qū)分所響應(yīng)的事件。
(4)運(yùn)行效果圖
點(diǎn)擊工具欄中的Debug Project 按鈕,程序開(kāi)始運(yùn)行,其效果如圖1-12 所示。
圖1-12 運(yùn)行效果圖
評(píng)論
查看更多