C++ Builder初学问与答

时间:2022-06-01 21:32:53

一直以来都想写一点为BCB初学者快速入门的东西,前不久写了几篇《闲谈BCB》想把自己学习BCB中如何来解决难点的方法说给大家,没想到被骂得不成样子。本想不写了,但觉得这些东西留下来能做什么呢?还是用另一种方法来重新演译我的思维吧,最近有些忙,那几篇没有写完的文章,我也会尽快写完的,至于《深入QR》,我想我一定会用另一种手法来写,让你一看就会把QR这个娇女的所有衣服都脱光,不整理到这个地步,我是不敢轻易再拿出来,还请朋友见谅!

本文分为《基础入门》、《快速提高》与《成功编程者》三部分。

第一部分:基础入门

1.窗体

1)问:Windows的编程就是在窗体的基础上实现的, C++Builder是怎样处理窗体的呢?

 答:窗体的一部分功能通过窗体的属性来实现,窗体的属性非常多,这里只对其中比较重要的属性进行介绍。

1.   ActiveControl指定窗体上的某个组件为输入焦点。如下面的语句将窗体上的Label1组件成为输入焦点:ActiveControl=Label1。在同一时时刻,应用程序只能有一个输入焦点。

2.   BorderIcons用来设定标题栏上出现哪些系统图标。它是一个集合,可以设成以下几个类型:最大化按钮(biMaximize)、最小化按钮(biMinimize)、帮助按钮(biHelp)和系统菜单(biSystemMenu)。

3.   Icon属性用来指定当窗体最小化时显示的图标。

4.   KeyPreview属性为true时,表示击键事件发生时先传给窗体,然后再传给有输入焦点的组件上,相当于窗体截获了原本属于组件的事件。缺省值为false,表示击键事件只送到当前有输入焦点的组件上。

5.   Menu属性用来指定窗体的主菜单。

6.   Visible属性用来确定窗体是否可见。

此外还有一些运行时态属性,这些属性只有在程序运行的时候才能通过编程访问。这种属性主要有:

Active                   属性用来确定窗体是否获得输入焦点。

ActiveMDIChild   这个函数将返回当前活动的子窗体。

DropTarget           属性用来指定窗体是否是拖放操作的对象。

Parent                   属性用来设定包含窗体的窗口控件,通常是另一个窗体。如果窗体没有包含它的控件,那么它的Parent属性为nil。

2)问: Windows窗体有很多样式,比如对话框,弹出窗口。如果我要控制窗体的边界样式,应该怎么办?

答:属性BorderStyle可以指定窗体边界的外观和行为。它一共有六种可能的取值。

bsDialog         表示大小不可变的标准的对话框边界。

bsSingle          表示大小不可变的单线边界。

bsNone              表示大小不可变、没有边界。

bsSizeable      表示标准的可改变大小的窗体。

bsToolWindow 与bsSingle时类似,但是标题较小,用做工具框窗口。

bsSizeToolWin与bsSizeable时相似,但是标题较小,做工具框窗口。

要注意的是,对于MDI子窗体,bsDialog或bsNone将不起作用。

3)问:同样是获得焦点,ActiveControl与SetFocus()有什么不同?

答: ActiveControl是把焦点交给组件,它是一个属性。而SetFocus()是组件主动要焦点,是一个方法。书写格式也不一样。例如,我们想使同样的一个Button1获得焦点,可以下的两种写法:

ActiveControl=Button1或Button1=SetFocus()

二者作用是一样的,不过一般都习惯用第一种方式。

4)问:属性FormStyle有什么作用?

答:属性FormStyle可以确定窗体的类型,它一共有四种属性值。

fsNormal       表示窗体既不是MDI父窗口也不是MDI子窗口,只可能是单文档SDI窗口或者对话框。这个属性值是缺省值。

fsMDIChild   表示这个窗体是一个MDI子窗口。

fsMDIForm     表示这个窗体是一个MDI父窗口。

fsStayOnTop 表示窗体始终保持在窗体所属工程中其它窗体的上面,除非还有别的窗体的FormStyle属性也被设置成了fsStayOnTop。

要特别注意的是,在程序运行期间不要修改窗体的FormStyle属性。

5)问:属性Position有什么作用?

答:属性Position可以确定程序运行时出现在屏幕上的窗体的大小和位置,它有五种可能的取值。

1.poDesigned表示使用设计时指定的尺寸和位置属性时显示窗体。尺寸属性是指Height和Width,位置属性是指Left和Top。这个属性值是缺省值。

2.poDefault表示窗体在屏幕上显示的位置和大小由Windows决定。每次运行应用程序时,窗体都会稍微向下向右移动。

3.poDefaultPosOnly表示窗体以设计时的窗体尺寸显示窗体,但是在屏幕上显示的位置由Windows确定。每次运行应用程序时,窗体都会稍微向下向右移动。当无法再向下移动时,就又会从屏幕的左上角开始显示。

4.poDefaultSizeOnly表示窗体的位置由设计时指定的值确定,而尺寸由Windows确定。

  5.poScreenCenter表示使用设计时指定的尺寸和位置属性,在屏幕的*显示窗体。

6)问:如何最大化或最小化窗体?

答:属性WindowState与窗体的显示有关,它有三种可能的取值。

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=550&d=6xg2y3

wsNormal      窗体既不是最大化显示也不是最小化显示。这个值是缺省值。

wsMinimized 窗体最小化显示。

wsMaximized 窗体最大化显示。

7)问:属性ClientHeight和ClientWidth有什么作用?

答:这两个属性用来定义窗体用户区域的高和宽。所谓用户区域窗体的实际工作区域,就是除了窗体的标题栏、菜单条、工具条和状态条以及边框之外的窗体区域。所以对于新创建的窗体,它的用户区域比窗体的大小要稍微小一些,相对而言,窗体的大小是由属性Height和Width确定的。

8)问:如何动态创建一个窗体呢?

答:我们先创建一个主窗体MainForm,把她的Caption改为“主窗体”,把FormStyle属性改为fsMDIForm。再创建一个子窗体windows1,把Caption改为“子窗体”,把FormStyle属性改为fsMDIChild。

选择“Project|Options…”菜单项,将会弹出一个如图所示的对话框。   

在这里我们可以通过下拉框选择主窗体(Main form),在左侧的Auto-create forms里列出了所有的窗口,这里面的窗口通常是动态创建,你可以把需要动态创建的窗口(Available forms)通过中间的那四个按钮调到右侧,然后OK就可以了。

动态的创建的方法如下:

void _fastcall TForm1::Button1Click(TObject *Sender)

{

    Tform2 *Forms;

    try

    {

             Form2=new TForm2(Application);//动态创建Form2

             Form2->ShowModal();

            delete Form2;//把Form2释放

    }

    catch(Exception &exception)

    {

            delete Form2;

             Application->ShowException(&exception);

    }

}

要注意一般你可能不喜欢用上面的那种形式,而写成如下格式:

void _fastcall TForm1::Button1Click(TObject *Sender)

{

   Tform2 *Forms;

     Form2=new TForm2(Application);//动态创建Form2

     ……

}

你要记住,无论你的子窗体创建是否完成,你都必须运行delete来释放你刚才创建的子窗体,当然你也可以把释放的过程写在OnClose事件函数内,这个函数有一个参数为Action,它有四个取值:caNone为不关闭窗体,什么也不操作;caHide为不关闭窗体,但把它隐藏起来;caFree为关闭窗体,同时释放内存;caMinimize为最小化窗体,不关闭。所以我们也可以象下面这样来释放子窗体。

void _fastcall TForm2::FormClose(Tobject *Sender,TcloseAction &Action)

{

    Action=caFree;

}

9)问:为什么我们用Close()不能关闭我当前活动的子窗体?

答:关闭当前活动窗体,很多人会用如下的方法:

void _fastcall TForm1::Button2Click(Tobjcet *Sender)

{

    ActiveMDIChild->Close();//注意这是在主窗体(或者说在其它窗体)中来关闭当前活动的子窗体,这样做不好,一般的关闭应该象10)问中那样来做

}

此时窗体并没有关闭,而是最小化了,因此要在子窗体的OnClose事件中用如下代码来关闭。

void _fastcall TForm2::FormClose(Tobject *Sender,TCloseAction &Action)

{

     Action=caFree;

}

这段程序不用多说了,上面都说过了。

这里有一点要说明一下,就是在调用Close()时,会自动触发OnClose事件,而由上我们知道窗体没有关闭,而是最小化,说明在OnClose中Action的此时的值为caMinimize。所以我们要写上面的方法来关闭。

10)问:Show()与ShowModal()有什么不同?

答:我们的程序中不可能就只有一个Form,比如,有Form1和Form2两个窗口,我们在Form1中调用Form2应该先在Unit1.cpp的开头部分加入:

#include “Unit2.h”

在要调用的地方加入:

Form2->Show();//或是Form2->ShowModal();

两者的区别在于若使用了ShowModal()则必须关闭Form2,才能处理其它窗口的内容,而Show()则不用。当然你可以直接在Form2直接创建一个Button1来关闭她,程序内容如下:

void _fastcall TForm2::Button1Click(Tobject *Sender)

{

    Close();

}

在Close前,不需要加上Form2,因为这行程序就是在Form2上运行的,所以默认的父组件就是Form2

2.文本输入组件

11)问:如果要实现文本输入,在C++Builder中应该怎么办?

答:C++Builder常用文本输入组件来实现,常用的文本输入组件有Edit、MaskEdit 、Memo和RichEdit。他们的主要不同在于Edit和MaskEdit用于输入单行文本,而Memo和RichEdit可以输入多行文本。此外Label组件也可用来进行文本显示。

Edit和MaskEdit是一个窗口控件,它可以获得输入焦点。当用户需要输入单行文本时,就应该使用编辑框。它通常与标签组件一起使用。

12)问:编辑框(Edit)常用的属性有哪几个?

答:编辑框常用的几个属性如下:

Text属性是一个String类型的数据,它决定了在编辑框中出现的文本字符串。在编程中,我们经常要通过text属性获取编辑框中的文本字符串

MaxLength是一个Integer类型的数据,它指定编辑框所能容纳的最大字符数。缺省情况下为0,表示长度不限。

编辑框还可以用做口令输入。具体方法是,把PasswordChar属性设置为除#0之外的任何字符。这时,无论你在编辑框中输入什么字符,都只显示PasswordChar包含的字符。我们经常把PasswordChar设置为星号*,当用户输入口令时只显示星号。如输入#0表示编辑框正常显示。PasswordChar是一个字符类型的数据。

如果要限制用户对编辑框写的权利。可以使用属性ReadOnly,当ReadOnly的值为True时只读。

13)问:标签控件(Label)起什么作用?

答:标签的常用属性有Caption和FocusControl。

Caption属性是字符串类型,用来指定标签的标题,也就是标签的显示内容。

FocusControl属性是窗口控件类,用来指定一个与标签相连的窗口控件。从而允许这个控件使用快捷键来获得输入焦点。

标签是一个典型的非窗口控件,它不能获得输入焦点,所以经常被用来给一些没有Caption属性的组件做标签。标签还能同时给这些组件提供快捷键的功能,允许用户通过快捷键获得输入焦点。

14)问:那在Label中如何使用Caption与FocusControl呢?

答:下面举个例子说吧(这个例子在第19问中会用到):

首先在输入标题时需要指定一个快捷键,这可以用在一个字母前面加上一个连字符&来实现。单击caption属性输入栏,输入&N姓名,这里字母N就被指定为快捷键,要注意的是中文是不能被指定为快捷键的,只有26个英文字母才可以。

然后,把标签的FocusControl属性与编辑框Edit1相连,选择FocusControl属性,从属性值字段列举的窗体上所有的窗口控件中选取Edit1。这样当用户按下Alt+N时,输入焦点就会转移到编辑框Edit1。

15)问:我遇到一些程序,当在编辑中输入完文本后,按一下回车键,程序就开始执行了,C++Builder应该怎样实现?

答:当然可以。当我们按下回车键时,产生了OnKeyPress事件。所以如果要在程序中处理这种事件,这就要编写OnKeyPress事件处理程序。

还有三种事件是编辑框常用的事件:OnChange事件、OnEnter事件和OnExit事。每当编辑框中的文本发生改变时都会触发OnChange事件。当编辑框获得输入焦点时会触发OnEnter事件,而失去焦点时会产生OnExit事件。

16)问:简单说一下Memo组件的重要属性?

答: Memo与Edit的属性有很多相似的,下面只来说一下Memo组件的重要属性。

Lines属性是一个TStrings类的一个对象,它是由多个字符串组成的,每一个字符串就是Lines中的一个元素。Memo组件的每一行文本都是Lines中的一个字符串。

在设计阶段,如果要给Memo组件增加一些显示内容,可以在对象编辑器中选择属性Lines,单击Value列上的省略号按钮,这时会打开一个字符串编辑窗口。

在这个编辑器中输入文本。编辑器中显示的所有内容都会出现在Memo组件中。

Memo组件属性中:

Alignment 用来确定Memo组件中显示文本的对齐方式。

WordWrap 确定文本到达右边界时是否自动换行

WantReturn 确定用户是否可以在文本中插入回车符。

WantTabs 确定用户是否可以在文本中插入Tab字符。

属性ScrollBar是一个常见的属性,它确定着滚动组件滚动条的行为。ScrollBar有四种可能的取值:

SsNone 表示没有滚动条;

ssHorizonal 表示只有水平滚动条;

ssVertical 表示只有垂直条;

SsBoth 表示既有水平滚动条也有垂直滚动条。

当显示的内容比较多时,应该选择ssBoth,这样才能够使用户看到所有的内容。

17)问:要在程序运行期间修改Memo组件的显示内容,应该怎么办?

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=551&d=y2r7s3

答:这就需要使用TStrings类的某些属性和方法。例如要给Memo组件增加一句话“我来了”,那么可以使用方法Add来完成。

Lines->Add(“我来了”);

要寻找Memo中的某一行,可以使用Lines->Strings[n]的形式,不过要注意Lines的字符串是从0开始的,所以在与Memo中的实际行号对应时,行号需要减一。

18)问:如果我要实现文本的剪切、复制和粘贴,应该怎么办?

答:Memo组件提供了三个用来完成剪切、复制和粘贴的方法。CutToClipboard用来把Memo组件中被选中的文本剪切到剪切板。

CopyToClipboard用来把Memo组件中被选中的文本复制到剪切板。

PasteFromClipboard用来把剪切板的内容粘贴到Memo组件中光标所在的位置。

19)问:前面讲了几个控件,能把他们综合起来编制一个程序吗?

答:好的,就利用刚才已经放好的组件来编写一个用户姓名录入和显示的程序。

这个程序将实现当在编辑框中输入文本并按下Enter键后,文本就被增加到Memo组件中。因此需要给编辑框组件增加事件处理过程。

当用户按下Enter键时产生了OnKeyPress事件,所以应该编写这个事件的处理过程。

选中组件Edit1,

在对象观察器上选择Events标签页,

双击Edit1的事件OnKeyPress,C++Builder将自动生成这个事件处理程序的代码模板。在里面编写如下代码:

void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key)

{

    AnsiString Temp("用户姓名:");

    if((Key==0xD) && !Edit1->Text.IsEmpty())

        Memo1->Lines->Add(Temp+Edit1->Text);

}

或者写成如下的格式更好理解,它们是一样的。

void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key)

{

    AnsiString Temp="用户姓名:";

    if((Key==VK_RETURN) && Edit1->Text!="")

        Memo1->Lines->Add(Temp+Edit1->Text);

}

当用户输入文本并且按下回车键后,第三条语句将Temp和用户输入的字符串合并后加到Memo控件文本的末尾。现在,点击速度条上Run的按钮,运行这个程序,在编辑框中输入一个用户姓名,然后按回车键。用户的姓名就被自动加到了文本框的末尾。

用鼠标在Memo控件中点击一下,将焦点移动到它里面,然后按下Alt+N加速键,可以看出,标签控件将焦点移动到了编辑框中。

20)问:BCB中有一个和写字板差不多的组件RichEdit,学习她主要注意那几个属性的呢?

答:只要能够把设置缺省字符格式DefAttributes、设置选中字符格式SelAttributes与设置段落Paragraph三个属性掌握好就差不多了,因为她的其它属性与Memo差不多。

缺省字符格式DefAttributes、设置选中字符格式SelAttributes是TtextAttributes对象,它是用来控制字符格式的,它的Color、Height、Name、Size、Style、Pitch等性性和字体Tfont对象差不多,当然还有一些象CharSet、ConsistentAttributes、Protected等一些不太常用的属性。

设置段落Paragraph是TparaAttributes对象,用来设置段落的对齐Alignment、首行缩进FirstIndent、左缩进LeftIndent、右缩进RightIndent、编号方式Numbering、制表位Tab等属性。

段落的对齐Alignment的取值是taLeftJustify左对齐、taCenter居中和taRightJustify右对齐。

编号方式Numbering,用来设置编号方式,取nsNone表示没有编号,取nsBulet表示采用悬挂缩进方式编号。

制表位Tab用来设置某个制表位所在的位置。其声明为:_property int Tab[Byte Index]。第一个制表位为Tab[0],依次类推。

3. 按钮类组件

 

21)问:在进行Windows程序界面设计中,经常会用到按钮,在C++Builder中,按钮一定是通过按钮组件来实现的吗?

答:是的,并且C++Builder的按钮类组件十分丰富。BCB提供了两类按钮类组件:一类是执行类按钮,另一类是信息类按钮。所谓执行类按钮是指它们通常用来启动程序运行的,比如按钮、位图按钮、加速按钮。而信息类按钮一般用来获取信息,包括单选按钮和复选框。灵活地使用各种按钮,不仅可以使程序更加丰富多彩,而且可以提高程序的性能。

22)问:那么按钮组件有哪些常用的属性和方法呢?

答:对于按钮组件,Caption属性用来描述按钮的标题,也就是按钮上显示的文本,它与标签组件很相识,我们同样可以在这个属性中为按钮指定快捷键。

当Cancel属性值为True时,用户无论何时按下Esc键,都会产生OnClick事件,当窗体上有多个按钮时,Esc键触发TabOrder值最小的那个按钮的OnClick事件。它的缺省值为False

当Default属性值为true时,用户无论何时按下Enter键时,都会产生OnClick事件,与Cancel属性不同的是,如果输入焦点正好在一个按钮上,那么会产生这个按钮的OnClick事件。否则,产生TabOrder的值最小的那个按钮的OnClick事件。它的缺省值为True

Hint属性保存着按钮的提示内容,当用户把鼠标光标停留在按钮上时,就会显示提示信息。

ShowHint属性用来确定是否显示提示文本,缺省值为False。

按钮常用的事件就是OnClick事件,OnClick事件在鼠标单击按钮时产生,另外,通过快捷键、enter键和Esc键也可以产生OnClick事件,一般情况下,按钮都需要增加OnClick事件处理程序。

 

23)问:那么位图按钮又有什么特点呢?

答:位图按钮BitBtn除了可以像普通按钮那样显示文本外,还可以显示图形,除了具有一般按钮所具有的全部属性外,位图按钮还有一个特有的Kind属性。这个属性用来设定按钮为几种预定义图形按钮风格中的哪一种。这是几种预定义按钮风格。这些做好的按钮如下表:

 

 

Kind属性值

 

按钮外观

 

等价属性设置

 

bkCustom

 

 

 

缺省值

用来给用户制定

 

bkOK

 

 

 

Caption=”OK”

ModalResult=mrOK

Default=true

 

bkCancel

 

 

 

Caption=”Cancel”

ModalResult=mrCancel

Cancel=true

 

bkYes

 

 

 

Caption=”&Yes”

ModalResult=mrYes

Default=true

 

bkNo

 

 

 

Caption=”&No”

ModalResult=mrNo

Cancel=true

 

bkHelp

 

 

 

Caption=”&Help”

 

bkClose

 

 

 

Caption=”&Close”

 

bkAbort

 

 

 

Caption=”Abort”

ModalResult=mrAbort

 

bkRetry

 

 

 

Caption=”&Retry”

ModalResult=mrRetry

 

bkIgnore

 

 

 

<// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=552&d=314c54

span lang="EN-US">Caption=”&Ignore”

ModalResult=mrIgnore

 

bkAll

 

 

 

Caption=”&All”

ModalResult=mrAll

 

当把Kind的属性值设置为bkCustom时,还可以给位图按钮指定其他的图形,具体的方法是,在对象编辑器中选择Glyph属性,然后单击Value列中的省略号按钮,这时会出现一个图形编辑对话框,要求指定位图的位置。

单击Load按钮,在文件打开对话框中选择一个位图文件就可以了。要注意的是,如果选择的位图太大,位图按钮不会自动调整其尺寸,这时你只能看到一部分的图形。

 

24)问:位图按钮组件的NumGlyph属性有什么作用?

答:属性NumGlyph指出位图按钮使用的位图的数目,当你需要位图按钮使用多个位图分别表示按下,弹起等不同状态时,必须保证这些位图具有相同的尺寸,并且一个接着一个地水平排列着。

在C++Builder中,一个位图按钮最多可有四个位图,因此,NumGraph地取值范围只能是1到4,C++Builder将根据位图按钮地状态确定显示哪个位图。

一般来说,当按钮未选中时显示第一个位图。

当按钮不能选择时,显示第二个位图,

当按钮被单击时显示第三个位图,

当用户释放鼠标键时,又会重新显示第一个位图,

当没有希望的位图时,那么所有地状态都使用第一个位图。

 

25)问:快捷按钮有哪几个重要属性?

答:快捷按钮与位图按钮很相似,也可以显示图像,但也有一些不同之处:快捷按钮一般都比较小,缺省大小25*25,基本上都是只显示图像而不显示文字,最大差别是,快捷可以保持在按下的状态,而其它两类按钮不能。快捷按钮一般都是用来制作工具栏按钮,这时要和Panel配合使用。下面来看一下它的重要属性:

AllowAllUp:设置一个组的快捷按钮是否可以全部处于弹起的状态。缺省为false,这时可以用来模拟单选按钮,让同一个组的总有一个按钮处在按下状态。如果一个组中只有一个快捷按钮,把这个属性改为true,这时这个按钮就可以在按下和弹起两个状态之间切换,可以用来模拟一个复选按钮。

Down:表示按钮是否按下,若设为true,则处于按下的状态。

GroupIndex:用来把几个这个属性相同的快捷按钮编为一组,即相同取值的按钮为一组。缺省为0,表示这个按钮不编成组。

26)问:那么单选按钮又有什么特点呢?

答:单选按钮RadioButton是相互排斥的一种选择组件,在一组单选按钮中用户一次只能选取一个单选按钮。

虽然你可以只使用一个单选按钮,但是那样单选按钮也就失去了意义。单选按钮一般都是成组出现的。

单选按钮只有一个比较特殊的属性Checked,它表示按钮是否被选中。缺省情况下,Checked的属性是False,表示按钮未选中。

另外单选按钮也具备Caption属性,这就意味着它也可以通过快捷键来选中。

单选按钮在成组使用时有一些特点需要掌握。当你在同一容器(如:Form、Panel、GroupBox等)上直接放置单选按钮时,这些单选按钮自成一组,也就是说,无论在容器上放置2个或者几十个单选按钮,它们都是一组的,每次只能选中它们中的某一个。

27)问:如果我想在窗体上放置不止一组按钮,应该怎么办?

答:可以用两种方法。一种是使用组合框(GroupBox),另一种是使用单选按钮分组框(RadioGroup)。

组合框顾名思义就是用来把许多组件组合起来,使窗口变得整齐而有条理,每一组不同的按钮使用一个组合框。在设计时,首先把组合框放在窗体上,然后再把单选按钮放在分组框上。要记住的是,放置次序不能颠倒。一旦把单选按钮放在分组框中,那么这个单选按钮就属于这个组合框了,你无法把它从组合框中移走,如果删除组合框的话,分组框中所有的单选按钮也会被同时删除。

在实际应用中,我们经常使用单选按钮分组框而不是单选按钮。因为单选按钮分组框可以包含多个单选按钮,而它实际上只是一个组件。这比使用分组框和多个单选按钮更直观和简单。

28)问:单选按钮分组框又有哪些特殊的属性呢?

答: 单选按钮分组框有三个属性是比较特殊的:

属性Items是类TStrings的一个对象,这一点与Memo组件中的Lines属性很相似,但是它们的含义不同,Lines属性包含Memo组件中显示的每一行字符串,而Items属性虽然也包含许多字符串,但是每一个字符串代表单选按钮组中的一个单选按钮。

单击Items属性Value列中的省略号按钮,可以打开一个字符串编辑器,然后在这个编辑器中可以输入单选按钮的标题。每个单选按钮占用一行。

Columns属性决定着单选按钮分组框内分栏的数目,默认是1,最多可以有16栏,即16列。

ItemIndex属性为单选分组框中被选中项的序号。-1表示不指向任何一个项。

29)问:复选按钮(CheckBox)有什么作用?

答:复选按钮与单选按钮不同,你可以一次选择多个复选按钮。复选按钮有几个比较重要的属性。

Alignment属性控制复选框标题的位置。

 

taRightJustify

 

标题出现在复选框的右边

 

taLeftJustify

 

标题出现在复选框的左边

缺省值为taRightJustify。

AllowGrayed属性决定复选框是否可以处于灰色的状态,当属性值为True时,复选框有三种状态,选中、未选中、和灰色;当属性值为False时,复选框只有两种状态。缺省值为false。

Checked属性确定复选框是否被选中。缺省值为false。

要知道复选框是选中状态、未选中状态还是灰色状态。,可以在运行的时候,用程序读取运行时态变量State的值,缺省值为cbUnChecked。

虽然复选框之间并不互相排斥,也就是说,直接放置在窗体上的每一个复选按钮相互之间都不干扰,但是最好还是把复选框分组使用。这样做的好处是便于用户理解。

30)问: CheckBox、RadioButton如何完成动态改变其按钮的标题? RadioGroup能动态添加吧?读取上面三个组件标题又如何做呢?

答:CheckBox、RadioButton的属性里有一个Caption,它的属性值就是按钮的标题,所以应该说对这两个组件来说很容易做到的:

CheckBox1->Caption=”信息”;

Label1->Caption= CheckBox1->Caption;

RadioButton与CheckBox一样,这里就不多说了。

而RadioGroup里面有一个Items属性,这在《闲谈BCB》中说过这个问题,所以你要添加按钮,可以用下面的方法:

RadioGroup1->Items->Add(“我是新来的”);

读取可以利用ItemsIndex来完成:

Label1->Caption=RadioGroup1->Items->Strings[RadioGroup1->ItemIndex];

String是把选中的序号转换成你需要的文本,因为Items是Tstring对象,这类情况在你以后的学习中会经常看到的。

要注意在RadioGroup中也有一个Caption,这是用来给单选分组框设置标题的,这个标题与单选的文字无关。

4.列表类组件

31)问:当我需要使用多个选项的时候,使用单选按钮或复选框来进行选择不是很恰当,因为在窗体上放置大量的按钮既不利于布局的美观,又会消耗大量的系统资源,C++Builder有什么解决办法吗?

答:可以使用列表框(ListBox、CheckListBox)或组合框(ComboBox)这两类最常用的列表组件。

32)问:列表框有那些主要属性?

答:列表组件ListBox在缺省情况下,只能进行单项选择,当属性MultiSelected为True时,可以进行多项选择。这时你只要单击想要的选项,那么这些选项都会被选中。

Items属性:列表框中的所有选项都是通过这个属性来进行访问的。设置时只要点击Items右边的“…”就可以编辑了。

当属性ExtendedSelect也等于True时,有两种方法可以进行多项选择。一种是单击选项同时按下Ctrl键,这样可以选中两个选项之间的所有选项。它的缺省值为False。

Sorted属性确定列表框中显示的内容书否按照字母顺序排列。缺省值为False。

当不允许多项选择时,我们通过属性ItemIndex就可以返回被选中的选项。但是,如果打开了多项选择,那么属性ItemIndex只返回最后个被选中的选项序号(有些书上也说返回选中选项中具有输入焦点的选项序号,但我觉得这种说法有点不易让初学者理解)。

SelCount属性在MultiSelected属性为True时,指出了列表框中被选中项目的个数。当MultiSelected属性为False时,它的值为-1。

Selected属性指出了列表框中的某个项目是否被选中。

TcheckListBox是从TcustomListBox继承下来的的,TListBox也是直接从TcustomListBox继承下来的,因此这两个组件是兄弟关系,它们的属性和使用都非常相似。下面来看看它的不同之处:

AllowGrayed属性和多选按钮一样,当属性值为True时,则列表框中的选项有三种状态:选中、未选中和选中但变灰;当属性值为False时,列表框只有两种状态。缺省值为false。

Checked其声明为:_property bool Checked[int Index];这个属性用来返回或者设置列表框中的指定选项是否被选中。其中参数Index表示指定的选项的序号。

32)问:那么,组合框和列表框相比有什么相似之处和不一样的地方呢?

答:首先,从外观上来说,列表框占据了比较大的空间,而组合框只需要一行的空间就可以了。从另一方面来说,组合框还带有一个编辑框,用户可以直接在编辑框中输入文本,组合框在一般情况下只显示这个编辑框,当用户单击组合框右边的下拉箭头时,就会显示一个包含所有选项的下拉列表。

组合框和列表框最大的不同是组合框不能进行多项选择。

组合框与列表框有一定的相似之处,就是它们都能够包含许多的选项。但是组合框还是有不少独特的属性。

33)问:组合框有哪些常用属性及事件呢?

答:属性Style决定着组合框的样式,C++Builder为组合框定义了五种不同的样式。

CsDropDown:这时为一个标准的组合框,由一个编辑框和下拉列表组成。

CsDropDownList:与标准组合框相似,但不能在编辑框中输入文本。

CsSimple:没有下拉列表的组合框,只是一个编辑框,也就是说只能输入不能选择。

csOwnerDrawFixed和csOwnerDrawVariable这两种样式的组合框常用于需要图像作为项目时,当然你输入字符串也可以。前面一种样式组合框中各个项目的高度是固定的,而后面一种样式的高度可以变化,也就是说,各个项目的高度可以不一样,此外,在这两种样式中,编辑框是不可输入的。

Text属性用来设置或者返回组合框中显示出来的文本内容。

当编辑框中的内容发生变化时将触发OnChange事件。所以在组合框里我们用的就是它。

注意下面四段两组语句的区别与联系:

//………………第一组

void _fastcall TForm1::ComboBox1Change(TObject *Sender)

{

    if(ComboBox1->Text!=””)

        Edit1->Font->Size=StrToInt(ComboBox1->Text);

}

上面的代码还可以写成下面的样子,它们的作用是一样的:

void _fastcall TForm1::ComboBox1Change(TObject *Sender)

{

    if(!ComboBox1->Text.IsEmpty())

        Edit1->Font->Size= ComboBox1->Text.ToInt();

}

//………………第二组

void _fastcall TForm1::ComboBox2Change(TObject *Sender)

{

    Edit1->Font->Name= ComboBox2->Text;

}

也可以用下面的代码,它们在这里是等价的:

void _fastcall TForm1::ComboBox2Change(TObject *Sender)

{

    Edit1->Font->Name= ComboBox2->Items->String[ComboBox2->ItemIndex];

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=553&d=3le86z

}

我想通过对比,你会明白这些语句的区别与联系的,什么时候用什么样的语句,细细品味一下你就会明白了

34)问:前面您提到了面板组件,它是一种什么类型的组件?

答:它是一种容器组件,容器组件是可以包含其他组件的组件,最典型的容器组件就是窗体。其他比较常用的容器组件有面板(Panel)、组合框(GroupBox)。

面板组件可以容纳其他组件。任何放置在面板上的组件都会成为面板的子组件,当你删除面板组件时,放置在面板上的其他组件也同时被删除了,这是容器组件的共同特点。

面板组件没有什么特别的属性,只有BevelInner(面板内部斜面),BevelOuter(面板外部斜面),BevelWidth(斜面宽度,单位像素),BorderStyle(边界风格)和BorderWidth(边界宽度)几个属性有一些特点。这些属性的任意组合可以生成各种效果的边框。你可以设置这几个属性的值,可以得到不同的面板效果。

其中BevelInner(面板内部斜面),BevelOuter(面板外部斜面)的属性值是一样的:bvNone(缺省值)表示没有斜面;

bvLowered表示为沉降的斜面;

bvRaised表示为上升的斜面。

组合框(GroupBox)属性中你只要设置好Caption就可以了,它是标题的名称,表示此组合框类别、功能、选项等。GroupBox1为默认名称。

5.特殊的输入控制类组件

35)问:C++Builder有哪些输入控制类组件?

答:C++Builder输入控制类组件主要包括滚动条(ScrollBar)、轨迹条(TrackBar)、进程条(ProgressBar)以及加减组件UpDown,它们都可以实现边续范围内数值的选择。

36)问:滚动条主要用在什么地方,它又有哪些常用属性呢?

答:滚动条是常见的组件,它经常出现在列表框、Memo等组件中。这时,它是作为这些组件的一部分而存在的。其实滚动条还可以单独使用,单独使用时,滚动条一般用来控制连续的数值输入。象调节音量等,都可以使用滚动条输入。

滚动条有这样一些常用属性

1.         Position:这个属性用来设置或者返回当前流动条中滑块的位置。属性Max,Min,用来设置滚动条可以滚动的最大或最小位置。当Position等于Max时,滚动块位于滚动条的最右端;当Position等于Min时,滚动块位于滚动条的最左端。当Position等于Max和Min之间的某一个值时,滚动块位于滚动条中间的某个位置。

2.         属性Kind。属性Kind有两个可能的取值:sbHorizontal(缺省值)和sbVertical,分别表示水平滚动条和垂直滚动条。

3.         属性SmallChange决定当用户单击滚动条两端的箭头按钮时滚动块移动的距离。

4.         属性LargeChange确定当用户单击滚动块两边的空白或按下PgUp和PgDn键时,滚动块移动的距离。属性LargeChange和SmallChange的取值范围是1到32767。

37)问:滚动条能够响应哪些常用事件呢?

答:滚动条的常用事件是OnChange,只要属性Position的值发生改变都会产生这个事件。一般情况下,了解滚动条的这个属性就可以了。

但是有时候可能需要更详细地了解用户单击了滚动条的哪个位置,这时就需要响应OnScroll事件,其声明为:-_property TScrollEvent OnScroll;其中TscrollEvent的声明为:typedef void fastcall (closuer TScrollEvent)(System::Tobject Sender,TscrollCode ScrollCode,int &ScrollPos); OnScroll事件处理程序带有三个参数:

其中参数Sender指出了是哪个对象发送了这个消息,参数ScrollPos指出了滚动块的位置,参数ScrollCode返回滚动条的状态,这些状态是用这样一些参数值表示的,

scLineUp     表示用户单击了滚动条左端的箭头按钮(水平滚动条)或上端的箭头按钮(垂直滚动条)。

scLineDown   表示用户单击了滚动条右端的(水平滚动条)或下端的箭头按钮(垂直滚动条)。

scPageUp     表示用户单击了滚动块左边(水平滚动条)或上边(垂直滚动条)的区域。

scPageDown   表示用户单击了滚动块右边(水平滚动条)或下边(垂直滚动条)的区域。

scPosition   表示用户移动了滚动条但是已经释放了。

scTrack      表示用户正在移动滚动块。

scTop        表示用户把滚动块移动到了滚动条的左端(水平滚动条)或顶端(垂直滚动条)。

scBottom     表示用户把滚动块移动到了滚动条的右端(水平滚动条)或下端(垂直滚动条)。

scEndScroll  表示用户结束了移动滚动块的操作,释放了鼠标或者键盘按键。

38)问:事件OnChange和OnScorll都可以描述滚动条的滚动事件,他们有什么区别吗?

答:事件OnChange和OnScorll是有区别的。只要属性Position的值发生改变,那么无论这个值是用户操作滚动条引起的还是通过程序修改的,都会产生OnChange事件。而OnScorll事件只有在用户操作滚动条时才发生。当用户操作滚动条时,首先发生OnScorll事件,然后OnChange事件才会发生。

下面我们共同看一个程序来加深对滚动条的理解。

在窗体上放置一个水平滚动条ScrollBar1和一个垂直滚动条ScrollBar2,以及一个记录滚动条事件的Memo组件。当用户操作滚动条时,在Memo组件中就会显示发生的事件。

选择Memo组件,把它的ScrollBars属性设置为ssVertical。

选择水平滚动条组件,双击OnScroll的Value域,系统将生成事件处理模板,输入这样一段代码。

void __fastcall TForm1::ScrollBar1Scroll(TObject *Sender,

TScrollCode ScrollCode, int &ScrollPos)

{

AnsiString temp;

if(Sender==ScrollBar2)

temp="垂直滚动条的";

else

temp="水平滚动条的";

switch(ScrollCode)

{

case scLineUp:temp+="scLineUp";break;

case scLineDown:temp+="scLineDown";break;

case scPageUp:temp+="scPageUp";break;

case scPageDown:temp+="scPageDown";break;

case scPosition:temp+="scPosition";break;

case scTrack:temp+="scTrack";break;

case scTop:temp+="scTop";break;

case scBottom:temp+="scBottom";break;

case scEndScroll:temp+="scEndScroll";break;

default:

temp+="未知";break;

}

Memo1->Lines->Append(temp+"事件");

}

第一条语句声明一个AnsiString类型的变量,用来存放将要显示的字符串。

第二条语句判断发送事件的对象,如果是垂直滚动条,将temp初始化为 “垂直滚动条的”,否则初始化为 “水平滚动条的”。

第三条语句根据ScrollCode的值,显示相应的事件。

最后一条语句将要显示的字符串加到文本框的末尾。

在窗体中选择垂直滚动条组件,选择Events标签,单击OnScroll的Value域,从下拉列表框中选择ScrollBar1Scroll事件处理程序。这样,垂直滚动条和水平滚动条将共用一个事件处理程序。

选择水平滚动条组件,选择Events标签,双击OnChange域,然后输入:

Memo1->Lines->Append("水平滚动条的OnChange事件");

它将在文本框后面显示水平滚动条改变的信息。

类似的,给垂直滚动条的OnChange事件加上如下代码:

Memo1->Lines->Append("垂直滚动条的OnChange事件");

详细代码如下:

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::ScrollBar1Scroll(TObject *Sender,

TScrollCode ScrollCode, int &ScrollPos)

{

AnsiString temp;

if(Sender==ScrollBar2)

temp="垂直滚动条的";

else

temp="水平滚动条的";

switch(ScrollCode)

{

case scLineUp:temp+="scLineUp";break;

case scLineDown:temp+="scLineDown";break;

case scPageUp:temp+="scPageUp";break;

case scPageDown:temp+="scPageDown";break;

case scPosition:temp+="scPosition";break;

case scTrack:temp+="scTrack";break;

case scTop:temp+="scTop";break;

case scBottom:temp+="scBottom";break;

case scEndScroll:temp+="scEndScroll";break;

default: temp+="未知";break;

}

Memo1->Lines->Append(temp+"事件");

}

//---------------------------------------------------------------------------

void __fastcall TForm1::ScrollBar1Change(TObject *Sender)

{

Memo1->Lines->Append("水平滚动条的OnChange事件");

}

//---------------------------------------------------------------------------

void __fastcall TForm1::ScrollBar2Change(TObject *Sender)

{

Memo1->Lines->Append("垂直滚动条的OnChange事件");

}

//---------------------------------------------------------------------------

现在,编译并运行这个程序,点击滚动条,可以看出滚动条的事件产生情况。

 

哪个事件优先你能看出来吗?你一定会对OnScroll同一事件产生的两个属性值先后被OnChange分开而不解是吗?你好好看一下什么时候产生scEndScroll值J

其实我们如果要了解其他某个组件所产生的事件之间的顺序,也可以用同样的方法来实现。

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=554&d=ct243c

39)问:轨迹条(TrackBar)有那些主要属性呢?

答:轨迹条与滚动条有相似之处,它也有一个类似于滚动块的滑动块,可以用鼠标或者使用方向键移动。轨迹条的某些属性与滚动条完全相同,例如Max,Min和Position。但是它还有一些特殊的属性。

1.LineSize属性,用于指定当用户按下方向键时,轨迹条的滑动块移动的距离。

2.PageSize属性,用于指定当用户按下PgUp和PgDn时,轨迹条上的滑动块移动的距离。

3.Frequency属性,用于设置轨迹条刻度的单位。如果Max-Min等于100,而这个属性等于10,那么轨迹条就被分成了10等份。

4.Orientation属性,用来确定轨迹条的放置方向,它有两个值,tbHorizontal表示水平放置,tbVertical表示是垂直放置的。缺省情况下是水平放置的。

5.SelStart这个属性用来设置选择的起点。

6.SelEnd这个属性用来设置的选择终点。

7.TickMarks这个属性用来设置轨迹条标尺的位置。它有三个值,分别表示三种不同的滑动块位置:

tmBottomRight表示垂直放置时标尺显示在轨迹条的下面或者水平放置时显示在右边。

tmTopLeft表示垂直放置时标尺显示在轨迹条的上面或者水平放置时显示在左边。

tmBoth则表示轨迹条的两边都有标尺。

8.TickStyle这个属性用来确定轨迹条标尺的样式。它有三个值,分别表示三种不同的标尺样式:

tsAuto表示自动显示标尺的刻度。

tsManual表示需要使用SetTick过程才能设置在某个位置显示刻度。

tsNone表示标尺不显示刻度。

40)问:轨迹条有哪些常用的事件呢?

答:当用户用鼠标或者键盘操作轨迹条时,就会产生OnChange事件。不过要注意,在程序中改变属性Position的值不会产生OnChange事件,这一点与滚动条不同。

41)问:进程条(ProgressBar)如何用呢?

答:它的属性与上面的那些组件差不多,象Max、Min、Orientation、Position与上面的含义大同小异。其中Position是这个组件的关键,它用来设置或者返回进程条的填充小方块的当前位置,当进条结束的时候,这个位置应该是位置上限。

Smooth:布尔类型,缺省为false。这时的填充是按格进行的,如果设置为true,则填充是平滑进行的。

StepBy:其声明为:void _fastcall StepBy(int Detla);这个函数用来向前填充进程条,同时改变Position的属性值。它的增加量由参数Detla来指定。

StepIt:其声明为:void _fastcall StepIt(void);这个函数用来向前填充进程条,同时改变Position的属性值。其填充步长由Step属性来指定。

Step:这个属性用来设置当调用StepIt函数时,Position位置的增加量。缺省为10。

42)问:UpDown控件有什么用?

答:这个控件是一对上下箭头按钮,按下按钮时会自动增加或减少某个数值。它通常有一个附属组件,由UpDown控件的Associate属性指定。如果这个组件是一个编辑框,那么编辑框就会自动显示UpDown控件的属性Position的值。

UpDown控件也有一些滚动条和轨迹条所具备的属性,例如Max,Min,Position,Orientation,它们的意义也基本上相同,不过UpDown控件同样有一些特殊的属性。

AlignButton为udLeft时,表示将UpDown控件放置在附属组件的左边,为udRight时,则表示将UpDown控件放置在附属组件的右边。

Associate用来指定关联的附属组件。

ArrowKey属性,当属性为True时,按下上下方向键就像按下UpDown控件的上下箭头一样。缺省值为True。

Thousands属性, 当属性为True时,如果Position超过1000,那么就会自动给所显示的数值加上一个千分位。缺省值为True。

Wrap属性,当属性为True时,如果Position的值大于Max,那么就会自动回到Min属性指定的值。缺省值为False。

43)问:UpDown控件有哪些常用的事件呢?

答:UpDown控件有两个常用的事件:OnChanging和OnClick。当用户正在按下上下箭头时,将发生OnChanging事件;当用户按下上下箭头时,会发生OnClick事件。

我们共同来看一个例子:

在窗体上放置两个Edit控件,和两个UpDown控件,将两个UpDown控件的Orientation属性分别取值udHorizontal和udVertical。

将第二个UpDown控件的Max的取值为5000,Position值为100,将他们的Associate属性分别与两个编辑框关联。在对应事件中输入如下代码:

void _fastcall TForm1::UpDown1Changeing(TObject *Sender,bool &AllowChange)

{

Edit1->Text=UpDown1->Position;

}

// 注意参数AllowChange可以用来指定是否允许改变Position属性的值。

void _fastcall TForm1::UpDown2Click(TObject *Sender,TUBtnType Button)

{

Edit2->Text=UpDown2->Position;

}

//注意参数Button表示哪个按钮被按下:btNext为上箭头或者右箭头;btPrew为下箭头或者左箭头。

44)问:在UpDown右边有一个HotKey组件是做什么的?

答:热键HotKey用来在程序运行期间动态地指定某个组件或者菜单的快捷键。在它的属性中你只要记住HotKey属性就可以了,这个属性用来返回用户指定的快捷键。

代码如下:

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::X1Click(TObject *Sender)

{

Close();

}

//---------------------------------------------------------------------------

void __fastcall TForm1::HotKey1Change(TObject *Sender)

{

X1->ShortCut=HotKey1->HotKey;//X1为菜单名,注意有些书介绍用OnEnter事件,但我觉得不妥,不防你也试一下,用OnEnter你将得不到什么关联J

}

//---------------------------------------------------------------------------

为什么这里用了一个Button1?如果你的程序中没有另外一个组件可以获得焦点,你将感受不到快捷键的功能的,因为焦点会停在HotKey组件上,在这里就是想将焦点转移一下,然后用快捷键试一下效果

6.图形列表组件TreeView

45)问:有时侯,我希望实现类似资源管理器对文件夹管理的显示方式,和对文件的管理显示方式,在C++Builder中应该怎么办?

答:在C++Builder中可以直接使用图形列表组件来实现,它包括TreeView、ListView以及Outline组件。其中Outline组件实际上是基于Windows 3.1环境的组件,而且无论从功能还

是使用的角度来看,它都无法与TreeView相比,因此完全可以用TreeView组件代替Outline。所以我将主要介绍前面两种组件。这两个组件都在页Win32中。

 

 

46)问:TreeView组件是一个怎样的组件?

答:TreeView组件比较复杂,所以我们首先简单地介绍一下这个组件的基本使用情况,然后再深入讨论。

TreeView组件采用了树形结构,最典型的例子就是Windows 95的资源管理器,它用树形结构显示磁盘上的文件夹和文件。因此TreeView组件能够清晰地显示层次关系。

47)问:请给我演示一下怎样在设计状态编辑TreeView好吗?

答:首先在窗体上放置一个TreeView组件,然后在对象编辑器中单击属性Items中的省略号按钮,就会打开一个项目编辑器。

 

 

TreeView组件的项目编辑器是一个在设计时专门增加、删除节点和为节点赋予图标的工具。从屏幕上可以看到,项目编辑器由项目组框和项目属性组框组成。项目组框由一个项目列表框、

按钮New Item、按钮New SubItem、按钮Delete和按钮Load组成。当你刚打开项目编辑器时,项目列表框是空的,New SubItem和Delete按钮处于失效状态。

项目属性组框由编辑框Text、编辑框Image Index、编辑框Selected Index和编辑框State Index组成。

项目组框可以创建和删除节点、子节点。如果要载入一个已经存在的TreeView节点,可以单击按钮Load。要创建一个新项目,单击New Item,然后在文本编辑框中输入新节点的标题。

这时,New SubItem按钮由失效变为有效,允许你在节点下再嵌套子节点。如果项目列表框中显示了节点,那么Delete按钮也会变的有效。你只要在项目列表框中选中这个节点然后单击

Delete按钮,就可以删除这个节点了。

要注意的是:如果删除的节点还包括子节点,那么子节点也会被同时删除。

项目属性组框主要是为当前选中的节点(或子节点)设置属性的。其中编辑框Text可以修改节点的标题。如果要在不是当前被选中的节点的左边显示图像,那么应该在编辑框Image Index

中输入图像的索引号。要禁止显示图像可以把这个节点Image Index设置为缺省值-1。

如果要在被选中的节点的左边显示图像,应该在编辑框Selected Index中指定图像的索引号,索引号是从0开始的。要禁止显示图像可以把它设置为缺省值-1。

如果要在节点的左边多显示一个图像,可以在编辑框State Index中输入图像的索引号。这个索引号代表Tree View组件中的StateImages属性所表示的图像列表的索引。要禁止显示图像

可以把这个项目设置为缺省值-1。

注意:Image Index与 Selected Index 使用的是Images指定的ImageList;而State Index使用的是StateImages 指定的ImageList。

48)问:TreeView的属性太多了,我想问我一定要清楚哪些主要属性?

答: Items : 该属性包含TreeView组件中的所有节点,它是TtreeNodes的对象,在设计时,你可以使用项目编辑器来增加、删除和修改节点。在运行期间,可以通过Items属性访问每

一个节点,并且也能够增加、删除和修改节点。而每一个节点又都是一个TtreeNode对象。

AutoEWxpand:布尔类型。为true时,则当前被选择的节点将自动扩展,没有被选择节点将自动折叠。缺省为false,这时扩展和折叠要用户自己指定。

DragMode:其声明为:_property TdragMode DragMode;这个属性用来设置树状视图的拖放模式。缺省为dmManual,用户要拖放节点需要调用BeginDrag才能拖放。若设置为

dmAutomatic,则树状视图将支持自动拖放,用户可以把一个节点拖到另一个位置。

Images:用来设定TreeView中的不同节点的图标。

StateImages:用不同的的图像来表示节点的不同状态。

在TreeView组件中,每个节点除了可以有一个文字标题外,还可以附加图标,这样可以使用户界面更加直观。这两个属性就包含着节点所使用的图标。

这两个属性都是TImageList的对象,所以如果要在TreeView组件中给节点添加图标,就必须使用图标列表组件给这两个属性赋值。如果在窗体中放置了图标列表组件,那么单击属性Ima

ges中的下拉按钮,就可以选取这个组件了。

ShowButtons属性值为True时表示凡是有子节点的节点将自动具有扩展按钮(即+号按钮)和折叠按钮(即减号按钮),单击它们就可以扩展和折叠节点。属性值为False时,不显示这两

个按钮,缺省值为True。

ShowLines属性用来确定是否显示在节点和子节点之间的连线。缺省值为True。

ShowRoot属性用来确定与顶层节点连线是否显示。缺省值为True。

HideSelection属性用来确定当输入焦点从TreeView移动到其它控件上时,被选中的节点是否处于被选中状态。当属性值为True时,不再处于选中状态。缺省值为True。

Indent属性用来设置子节点与父节点之间缩进显示的距离。

ReadOnly用来确定用户是否可以直接修改节点的标题。当属性值为False时,表示可以修改。修改方法是,选中要修改的节点并单击进入编辑状态。缺省值为False。

SortType用来设置节点进行排序的方式。它有以下几种取值:

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=555&d=20o51m

stNone:不排序(缺省值);

stData:当节点所关联的对象发生改变时重新排序;

stText:当节点的标签发生变化时重新排序;

stBoth:当节点所关联的对象或者节点的标签发生改变时重新排序。

以上排序原则为在同一层的节点以标签的字母顺序排序。

此外,还有一些运行时态属性。

TopItem:这个属性用来设置一个节点,这个节点将显示在树状视图的最上面。

RowSelcet:缺省为false。若设置为true,则表示当前选择的节点所在的整行都将加亮显示。当ShowLines设置为true时,这个属性无效。

Selected:用来返回当前选择的节点。

49)问:属性Images和StateImages有什么区别呢?

答:每一个节点可以有两个附带的图标。一般情况下只需要显示一个图标,这时我们经常使用Images来指定图标,也就是说给属性Images赋予一个ImageList对象。如果某个节点要显示

两个图标,那么还需要给属性StateImages赋予一个ImageList对象。然后给节点的属性StateIndex指定图标的索引号。具体的方法是在项目编辑器中,修改编辑框State Index的值。

其实在显示一个图标时,也可以使用属性StateImages。但是使用Images属性有一个优点,就是它可以为处于不同状态的节点指定不同的图标。例如在Windows 95的资源管理器中,

被选中的节点显示一个打开的文件夹,而没有选中的节点显示一个关闭的文件夹。要实现这一点很简单,因为项目编辑器中的编辑框Image Index指定的图标在节点未选中时显示,而编辑

框Seleted Index指定的图像在节点选中时显示。

50)问:请在前面设计的TreeView组件的基础上,给TreeView组件中的节点增加图标。好吗?

答:好的,首先在窗体上放置两个ImageList组件,这两个组件将具有缺省的名字ImageList1和ImageList2。

其次、编辑ImageList组件:ImageList组件实际上是一个图标列表,它可以包含大量的图标,这些图标的大小由属性Width和Height确定,缺省值都是16。

ImageList刚建立时不包含任何图标,你需要把已创建好的图标引入到ImageList中。这个工作可以通过ImageList编辑器完成。

用鼠标右键单击ImageList组件,在快捷菜单中选择ImageList Editor或双击一下该组件,就会出现下面这个编辑器。

 

 

单击Add按钮,在弹出的Add Images对话框中选择要引入的图像文件,图标就会出现在Images框内。从图中可以看出,引入的图标被自动赋予索引号。

为了使用上的方便,每一个图标都有一个编号,这个编号就是这个图标的索引号。如果要引用某个图标,只需要使用它的索引号就可以了。

要注意的是:这个编辑器会自动把引入的图像分解成16×16的图标,之所以尺寸为16×16是因为ImageList的属性Width和Height被设置成了16。如果图标的尺寸不一样,那么可以修改

这两个属性,使其满足图标的要求。

然后、继续用项目编辑器给节点增加图标:我们已经在图标列表组件中加入了两个图标,其索引号分别为0和1,接着可以使用项目编辑器给节点增加图标。

再次打开项目编辑器,输入所有节点。

修改节点的ImageIndex, SelectedIndex属性,

要注意的是,编辑框Image Index中的索引号是0,编辑框Selected Index中的索引号是1。也就是说,在选中或未选中状态下,该节点显示的图标不同。

修改所有节点的图标索引号,使包含子节点的节点有两种不同的图标,而不含子节点的节点只有一种图标,也就是编辑框Image Index和Selected Index的索引号相同。

最后,修改TreeView1组件的Images属性,从下拉列表中选择ImageList1组件。

从屏幕上可以看到,图标已经出现在控件里面了。

51)问:那怎样给节点增加第二个图标呢?

答:要给节点增加第二个图标,首先必须再创建一个图标列表组件,然后把这个图标列表赋值给TreeView组件的属性StateImages。当然还要给这个图标列表引入图标。

完成这些工作后,我们就可以进入项目编辑器,选中要增加第二个图标的节点,修改编辑框State Index中的索引号即可。

52)问:TreeView有哪些重要的函数呢?

答:AlphaSort:其声明为:bool _fastcall AlphaSort(void);这个函数用来对所有的节点按标签的字母顺序排序。若排序成功,则返回true。

FullCollapse:其声明为void _fastcall FullCollapse(void);这个函数的作用是折叠所有的节点,直到最顶层为止。

FullExpand:其声明为 void _fastcall FullExpand(void);这个函数的作用是展开所有的节点,直到最底层为止。若ShowButtons属性为true,则所有的“+”都会变成“-”。

GetHitTestInfoAt:其声明为THitTests _fastcall GetHitTestInfoAt(int X,int Y);这个函数返回指定点与树状视图之间的位置关系。这个点的位置由参数X、Y确定。THitTests是个集

合,它可能包含下面的元素:

HtAbove:在树状视图的客户区上方;

HtBelow:在树状视图的客户区下方;

HtNowhere:在树状视图的客户区内但在最后一个节点下面;

HtOnItem:在某个节点的标签或者图标上;

HtOnButton:在某个节点的左边的图标上;

HtOnIcon:在某个节点的图标上;

HtOnIndent:在某个节点的缩进线上;

HtOnLabel:在某个节点的标签上;

htOnRight:在某个节点的右边;

htOnStateIcon:在某个节点的状态图标上;

htToLeft:在客户区的右边;

htToRight:在客户区的的左边。

GetNodeAt:其声明为TTreeNode*_fastcall GetNodeAt(int X,int Y);这个函数用来返回指定点所在的节点。参数X、Y为这个点的坐标。如果这个点没有节点,则返回NULL

53)问:能介绍一下TTreeNodes与TTreeNode?

答:在BCB中,树状视图的节点是通过TTreeNodes对象来管理的,通过这个对象可以对树状视图进行动态的增加、删除、插入、移动节点等操作。而每一个节点都是一个TTreeNode对象。

TTreeNode的主要属性和函数:

Count:这个属性用来返回某个节点所拥有的子节点的数目。它不包括其子节点。

Item:其声明为:_property TTreeNode* Item[int Index];这个属性用来访问该节点的某个子节点。其中参数Index为其子节点在所有子节点中的位置。

Index:这个属性用来返回该节点在其父节点的所有子节点中的位置。

Text:这个属性用来设置或者返回节点的标签。

Delete:这个函数用来删除该节点本身。

DeleteChildren:这个函数用来删除该节点的所有子节点。

EditText:这个函数用来对节点进行就地编辑。

IndexOf:其声明为:int _fastcall IndexOf(TTreeNode* Value);这个函数将返回该节点的某个子节点的序号。子节点由参数value指定。如果参数value指定的节点不是该节点的子节点,函数将返回-1。

TTreeNodes的主要属性和函数:

Count:这个属性用来返回树状视图中节点的数目。

Add:其声明为:TTreeNode *_fastcall Add(TTreeNode,const System::AnsiString S);这个函数将在树状视图中增加一个节点,新节点成为参数Node 指定的节点的父节点的最后一个子节点,参数S为新节点的标签。

AddChild:其声明为: TTreeNode *_fastcall AddChild(TTreeNode,const System::AnsiString S);增加的新节点为参数Node指定的节点的最后一个子节点。

AddChildFirst:其声明为: TTreeNode *_fastcall AddChildFirst(TTreeNode,const System::AnsiString S);这个函数与AddChild不同的是新增加的节点为Node节点的第一个子节点。

AddFirst :其声明为:TTreeNode *_fastcall AddFirst(TTreeNode,const System::AnsiString S);这个函数与Add 相似,不同的是新节点成为Node节点的父节点的第一个子节点。

Clear:这个函数将把整个树状视图都清空。

Delete:其声明:void _fastcall Delete(TTreeNode *Node);这个函数将删除参数Node 指定的节点。

Insert:其声明为:TTreeNode _fastcall Insert (TTreeNode* Node,const System::AnsiString S);这个函数用来在参数Node 指定的节点之后插入一个新的节点,新节点的标签由参数S指定。

7.图形列表组件ListView

54)问:TreeView组件能够实现资源管理器左边显示区的内容,可是它右边显示区能将列表用各种不同的方式显示,例如大图标方式、小图标方式、简单列表方式和详细列表方式。这在C++Builder应该怎样来实现?

答:这可以用ListView组件来实现,ListView组件从功能上讲与列表框相似,但是从组件的属性来看与TreeView相似。ListTiew组件所建立的列表可以用各种不同的方式显示,例如大图标方式、小图标方式、简单列表方式和详细列表方式。

ListView组件中的一部分属性与TreeView组件中的属性是相同的,例如Items,StateImages等。还有一些属性是ListView特有的。

LargeImages属性用来设置存放大图标的图标列表,当列表处于大图标显示方式时,列表使用这个图标列表中的图标显示。

SmallImages属性用来设置存放小图标的图标列表,当列表处于小图标显示方式时,列表使用这个图标列表中的图标显示。

MultiSelected属性可确定用户是否可以同时选择多个项目。缺省值为false。

属性ViewStyle确定了显示风格,可以取这样一些值。

vsIcon:列表以大图标方式显示,可以进行拖放操作。只显示第一层节点,放置方式由Arrangement决定。

vsSmallIcon:列表以小图标方式显示,可以进行拖放操作。只显示第一层节点,放置方式由Arrangement决定。

vsList:以简单列表的方式显示,不能进行拖放操作。节点是竖向放置的,只显示第一层节点,Arrangement不起作用。

vsReport:以详细列表的方式显示,显示的信息可以分成多列。最左边的列显示图标和文字,其余的列显示详细信息。节点是竖向放置的,每一层均已经展开,只有此时Columns的设置才起作用,Arrangement不起作用。

属性Columns 当属性ViewStyle被设置为vsReport时,列表中的每一项可以分成多列显示,这个属性用于设置列数和列的标题。

在设计时,按下Columns属性Value列中的省略号按钮可以打开一个ListView Columns编辑器,在这个编辑器中可以生成和编辑列及列的标题。

属性ColumnClick的值为True时,列表中的标题可以作为按钮使用, 这个属性最常见的应用是在Windows 95的资源管理器中,单击文件名或者其它几个列标题,列表中的文件就会按照文件名重新排序。

属性Items 包含列表中所有项目的集合。与TreeView组件中的Items属性类似,这个属性也有一个项目编辑器,你可以使用这个编辑器在设计时增加、删除项目,设置项目的图标索引以及标题等。它的使用方法与TreeView组件的Items编辑器基本相同。

IconOptions属性用来设置图标的显示方式。它还包含几个子属性:

(1)Arrangement属性:当该属性等于iaTop时,表示图标从左到右排列在ListView组件的顶部;等于iaLeft时,表示图标从上到下排列在组件的左边。

(2)AutoArrange属性:等于True时,表示增加、删除或移动图标时图标将自动重排。

(3)WrapText属性:等于True时,表示当项目的标题超过图标的宽度时标题将换行。

此外,还有运行时态属性

Selected属性用来返回列表中被选中的项目。

TopItem属性用来返回列表中当前可见的最顶端的项目。

55)问:请您编写一个程序来帮助我理解和记忆ListView控件好吗?

答:好的,选择File菜单的New Application菜单项,打开一个空的工程,在窗体上放置一个ListView控件,两个ImageList控件,一个ListBox控件。

 

选中ImageList1控件,将它的Height和Width属性设置为32。双击ImageList1控件,打开图像列表编辑框。点击Add按钮,选择一个大图标文件。点击打开按钮。然后点击OK按钮。同样方法给ImageList2控件加上小图标。选择TreeView控件,将它的LargeImages属性修改为ImageList1。

将它的SmallImages属性修改为ImageList2。在ListView控件上点击鼠标右键,选择Columns Editor选项(当然我们只要点击属性Columns右边的“…”就可以了)。弹出Columns编辑对话框。点击Add New工具按钮加入四个列表,选中它们,将它们的caption属性修改为名称、大小、类型、修改时间。

关闭列表编辑对话框。

在ListView控件上点击鼠标右键(同样我们只要点击 Itmes属性右边的“…”也一样),选择Items Editor选项。弹出Items编辑对话框(与TreeView的Items Editor差不多),输入树型结构文档。在这里,点击“New Item”按钮可以新建一个项,“NewSubItem”按钮用来设置这个项的子项。“Delete”用来删除某个项,包括它的子项。项司性编辑框中,Caption为这个项的标题,另外两个为项的图标。

编写列表框的OnClick事件代码如下:

void __fastcall TForm1::ListBox1Click(TObject *Sender)

{

switch(ListBox1->ItemIndex)

{

case 0: ListView1->ViewStyle=vsIcon;

break;

case 1: ListView1->ViewStyle=vsSmallIcon;

break;

case 2: ListView1->ViewStyle=vsList;

break;

case 3: ListView1->ViewStyle=vsReport;

break;

}

}

//---------------------------------------------------------------------------

把ListView中的ViewStyle属性改为vsReport,否则你将得不到上面的那种显示方式。

最后,编译并运行这个程序,选择不同的类型,我们可以看到TreeView控件的效果。

56)问:在TreeView、ListView中的图标管理能再说一下吗?

答:图形列表组件很难理解的,主要问题是不太容易掌握它使用图标的方式。图形列表组件使用一个名为ImageList的组件管理所有的图标,ImageList给每个图标提供一个索引号,这样在TreeView或ListView组件引用时就不必指出图标的名字而直接指定索引号就可以了。用ImageList集中管理图标,用户使用图标索引号的方式的确从某种角度减轻了编程人员的负担,但是也使得他们在编程时必须记住一大堆编号代表的各是哪一种图标,这就在一定程度上削弱了ImageList的优势,也许在C++Builder以后的版本中能有更好的方法。

57)问:如何动态的创建一个列表视图呢?

答:我们举例说明。我先建立如图的界面。

 

 

并编写如下的代码:

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=556&d=zl206o

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)

{

const char Names[6][3][10] =

{{"广东省","广州市","华南"},

{"上海市", "上海市","华东"},

{"北京市", "北京市","华北"},

{"辽宁省", "沈阳市","东北"},

{"湖北省", "武汉市","华中"},

{"云南省", "昆明市","西南"}};//准备各项的文字

TListColumn *NewColumn;//创建一个栏

TListItem *ListItem;//创建一个Items

ListView1->ViewStyle = vsReport;//定义显示方式

Button3->Enabled=false;

NewColumn = ListView1->Columns->Add();//增加栏

NewColumn->Caption = "省份";//添置栏的名称

NewColumn = ListView1->Columns->Add();

NewColumn->Caption = "省会";

NewColumn = ListView1->Columns->Add();

NewColumn->Caption = "方位";

for (int i = 0; i < 6; i++)

{

ListItem = ListView1->Items->Add();

ListItem->Caption = Names[i][0];//添置父节点

ListItem->SubItems->Add(Names[i][1]);//添置子节点

ListItem->SubItems->Add(Names[i][2]);

}

}/*此处有些朋友总感觉为什么还要创建TListColumn *NewColumn;

TListItem *ListItem;其实我们只要这样想就可以了,我们再手功创建时打开Columns、Items时等于又创建了一个项目,他们并不存在,我们却要用,所以只能用这种方法来动态创建了J*/

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

TListItem *temp;

temp=ListView1->Items->Add();

temp->Caption=Edit1->Text;

temp->SubItems->Add(Edit2->Text);

temp->SubItems->Add(Edit3->Text);

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)

{

ListView1->Items->Clear();

}

//---------------------------------------------------------------------------

void __fastcall TForm1::RadioButton1Click(TObject *Sender)

{

ListView1->ViewStyle = vsReport;

Button3->Enabled=false;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::RadioButton2Click(TObject *Sender)

{

ListView1->ViewStyle = vsIcon;

Button3->Enabled=true;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)

{

ListView1->AlphaSort(); //这个函数的作用是把列表视图中的项按照它们的标签字母顺序排列,成功返回true。

}

//---------------------------------------------------------------------------

58)问:我要想对TreeView、ListView里面的项进行操作如何来进行呢?

答:我们一般都是通过OnChange或OnChangeing事件来完成的,我们通过一个例子来看一下他们的应用及区别,我们在窗体中放上一个TreeView和一个Memo组件,并在TreeView的OnChange和OnChangeing分别写如下代码:

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::tvwChange(TObject *Sender, TTreeNode *Node)

{

if(Node->Text=="辽宁")

Memo1->Lines->Add("I'm change!") ;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::tvwChangeing(TObject *Sender, TTreeNode *Node,

bool &AllowChange)

{

AllowChange=false;

if(Node->Text=="辽宁")

Memo1->Lines->Add("I'm changeing!") ;

}

//---------------------------------------------------------------------------

运行效果如下:

 

 

只有OnChangeing起了作用,为什么呢?再看下面代码:

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::tvwChange(TObject *Sender, TTreeNode *Node)

{

if(Node->Text=="辽宁")

Memo1->Lines->Add("I'm change!") ;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::tvwChangeing(TObject *Sender, TTreeNode *Node,

bool &AllowChange)

{

//AllowChange=false;这与把此句写成AllowChange=true是一样的

if(Node->Text=="辽宁")

Memo1->Lines->Add("I'm changeing!") ;

}

两个事件都起作用了,并且OnChangeing先于Onchange发生,所以原因很显然:这一切都是OnChangeing的参数AllowChange造成的,所以要注意对这个参数的使用。

在ListView中只要把上面的Node->Text改成Item->Caption就可以了

7.     图形类组件

59)问:Windows是一个图形系统,C++Builder是怎样处理图形的呢?

答:C++Builder通过提供图形组件来处理图形,其中比较常用的有图像组件(Image)、几何图形组件(Shape)和画板组件(PaintBox)。前两个组件位于Additional页中,画板组件位于System页中。

在BCB中,Form、Image、BitMap、PaintBox等都具有绘图能力,这些组件中都有Canvas属性。

60)问:图像控件有哪些特殊的属性?

答:图像组件可以显示各种以文件形式存储在磁盘上的图形。它有这样一些特殊的属性。

AutoSize属性,当属性值为True时,图像组件会自动调节尺寸以便适应图像组件的大小。缺省值为True。

Stretch属性,当该属性为True时,图像的尺寸自动调整并填满整个图像组件的范围。但ICO文件无法产生这种效果。缺省值为False。

Transparent属性,确定是否允许图像中指定的颜色透明,从而使组件下面的物体显示出来。缺省值为False。

Center属性,当该属性为True时,图像居中显示;否则,从左上角开始显示。

属性Picture,你可以在设计阶段利用这个属性指定所要显示的图片,也可以在运行期间再显示。前面一种情况下,你可以单击Picture属性的Value列中的省略号按钮,这时会出现一个图片编辑对话框,单击对话框中的Load按钮就可以选择载入要显示的图片了。

61)问:如果是在程序运行期间载入图片,应该怎么办?

答:如果是在程序运行期间载入图片,那么可以使用TPicture类的方法LoadFromFile,这个方法可以载入存储在磁盘上的图像文件。例如要载入D盘根目录下的picture.bmp,可以这样调用:

Image1->Picture->LoadFromFile("d://picture.bmp");

这个控件可处理的图片文件的类型有:.BMP文件、.ICO文件、.EMF和.WMF等多种图像文件。如果你试图载入一种无法识别的文件类型,将会产生异常错误。

62)问:能说一下AutoSize与Stretch的区别吗?

答:好的,在窗体上放置两个图像组件,将左边的图像组件的AutoSize属性为True,所以载入任何图片后,组件的尺寸与图片的尺寸完全相同。而且如果你增大或减小图像组件的尺寸,图片的显示仍然不变。将右边的图像组件的AutoSize属性设置为False,将它的Stretch属性设置为True。当你增大或减小图像组件的尺寸,图片将按比例增大或缩小,也就是说图片始终充满整个组件。

63)问:TShape控件有什么重要属性?

答:这个组件可以显示一些常见的几何图形,例如矩形、圆、椭圆等。几何图形组件有几个比较重要的属性:Brush,Pen 和Shape。

Brush属性,用来设置几何图形内部的填充特性,包括填充的图案(Style)和颜色(Color)等。

Pen属性,用来设置几何图形的外框特性,包括画笔的颜色(Color)、线型(Style)和线宽(Width)及Mode关系等。

属性Shape,用来指出所显示的几何图形类型。这个属性可以有六种不同的值,分别表示六种不同的几何图形;

(1)stEllipse表示椭圆。

(2)stRectangle表示矩形。

(3)stRoundRect表示圆角矩形。

(4)stRoundSquare表示圆角正方形。

(5)stSquare表示正方形。

(6)stCircle表示圆。

在设计阶段,你可以使用鼠标改变图形的尺寸。在运行期间,可以通过Height和Width属性改变图形的尺寸。

64)问:属性Brush前面有一个加号,它是什么意思?

答:它表示这个属性是可以展开的,也就是说,它还包含一些子属性。单击加号,可以发现它的子属性是:Color和Style。

Color属性包含一系列C++Builder预定义的颜色,你可以从中为显示的几何图形选择一种填充颜色。

Style属性确定了几何图形的填充样式,它可以分别取这样8种值:bsBDiagonal, bsClear, bsCross, bsDiagCross, bsDiagonal, bsHorizontal, bsSolid和bsVertical。

属性Pen也象属性Brush一样有子属性。它的子属性是Color, Mode, Style和Width。其中最常用的就是Style和Width,它们分别表示线型和线宽。子属性Style可以取这样一些值来画边框:

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=557&d=t14my7

psSolid 表示实线。

psDash 表示破折号。

psDot 表示圆点。

psDashDot 表示破折号和圆点。

psDashDotDot 表示破折号、圆点、圆点。

psClear 表示没有线。

psInsideFrame 表示内框实线。

65)问:这个画板组件有什么作用?

答:画板组件主要为用户提供一块作图区域,用户可以使用绘图语句在这个作图区域上画出各种不同的图形。

要注意的是,由于画板组件没有边界,所以通常应该把它放在一个有边界的容器类组件上。

画板组件主要使用Canvas属性来进行绘图工作。Canvas(画布)是类TCanvas的对象,类TCanvas包含绘图中使用的各种方法和属性。下面我们首先介绍Canvas对象的各种属性。

画笔(Pen) Canvas对象中有一个画笔成员,它确定绘制几何图形时使用的画笔类型。刚才我们介绍了画笔的线型和线宽。

画笔的Color属性是绘图时使用的前景色。

画笔的属性Mode用来确定画笔与屏幕上原有点的混合方式。可结合当前的颜色、屏幕的颜色或它们的反转值,对线段的颜色重新定义。但不改变Color属性。

它可以取这样一些值:

pmBlack:表示用黑色绘图;

pmWhite:表示用白色绘图;

pmNot:画笔绘制的点的颜色与原有的颜色相反;

pmCopy:画笔用Color属性中定义的颜色绘图。

PmNotCopy:画笔用Color属性中定义的颜色的反转色绘图;

PmMergePenNot:画笔用Color属性中定义的颜色与屏幕颜色的反转色结合后绘图;

PmMaskNotPen:画笔用屏幕颜色与Color属性中定义的颜色结合后绘图;

PmMergeNotPen:画笔用屏幕颜色与Color属性中定义的颜色的反转值结合后绘图。

Brush属性,刷子属性在前面已经详细介绍过,它可以确定图形的填充模式和填充颜色。

属性ClipRect,用来确定绘图区域的范围。任何超出这个范围的图形不会显示。

66)问:在Canvas对象上,我们可以用怎样的方法来完成作图工作?

答:Canvas对象有一些基本做图方法:

1.首先是MoveTo方法,MoveTo将笔的当前位置设置到点(x,y)处,笔的当前位置将保存到PenPos属性中,要注意的是,改变笔的当前位置用MoveTo方法,而不要修改PenPos属性。函数形式为MoveTo(x,y)。

2.LineTo方法,用来完成从当前位置画一条直线至点(x,y),并把笔的位置移动到这一点。函数形式为LineTo(x,y)。

在画线时一般首先使用方法MoveTo移动线的起始点,然后再使用方法LineTo画直线。

3.方法Rectangle用来在画布上用当前画刷绘制矩形,其中x1,y1是矩形的左上角坐标,x2,y2是矩形的右下角坐标。因为正方形实际上就是一种特殊的矩形,所以你可以使用这个方法画出正方形。函数形式为Rectangle(x1,y1,x2,y2)。

4.方法Ellipset用来在画布上给定的矩形边界上画一个椭圆,其中x1,y1是边界矩形的左上角坐标,x2,y2是边界矩形的右下角坐标。所谓边界矩形就是圆或椭圆的外接矩形。函数形式为Ellipse(x1,y1,x2,y2)。

5.方法RoundRect用来绘制圆角矩形:其中x1,y1,x2,y2分别是圆角矩形虚拟的左上角和右下角。x3,y3是圆角的长短半径。函数形式为RoundRect(x1,y1,x2,y2)。

6.方法Polygon可以画出多边形。函数形式为Polygon(Tpoint p,int Point_Size)。

参数P是类Tpoint的一个数组,每一个Tpoint对象包含一个点的X和Y坐标。Points_Size用来指示数组的大小。这个是实心多边形,Polyline是画多边形的,二者用法基本相同。

67)问:在显示区域输出文本信息,我们是不是还象DOS下用printf函数来实现?

答:printf是一个控制台函数,不能在窗口程序中使用,一般我们TextOut输出文本,其声明:void _fastcall TextOut(int X,int Y,const AnsiString Text);其中x,y是输出字符串起始点的坐标,text是要输出的文本。当然你要用Lable也是可以的

9.多页组件

68)问:我觉得C++Builder的组件模板的管理方式很好,在这个模板中通过单击页就可以在各个页之间进行切换,在C++Builder中我应该怎样来实现呢?

答:我们可以用多页组件来实现,它的好处就是可以在有限的空间中尽量多地存放信息,而且便于把信息分类。就拿组件模板来说吧,在那么小的屏幕中放置了上百个组件,而且并不显得凌乱,这都是多页组件的功劳。

如果窗体上要放置大量的组件,而且这些组件又是分组使用的,那么可以考虑使用多页组件。这样做可以使窗体更加简洁明了。多页组件既有多页的特性,又是一个容器组件,它就像窗体一样可以包含其他的组件。

C++Builder提供了几种功能相似的多页组件,它们是:Win32页中的TabControl,PageControl组件,Win31页中的TabSet和TabbedNoteBook组件。从它们所在的页的不同就可以知道,前两个组件是应用在32位系统中的组件,无论从性能还是风格上来看,这两个组件都更适合在Windows 95以上的板本中使用。后面两种组件是为喜爱Windows 3.1风格的用户保留的,其实我们完全可以只使用前两种组件。

69)问:TabControl组件和PageControl组件他们看起来简直是一模一样?

答:初看起来这两种组件的确差不多,我们可以通过下面的操作可以说明这一点。

(1)在窗体上放置这两个组件,通过修改Height和Width属性把它们的尺寸设置成相同的。

(2)在对象编辑器中,单击TabControl的属性Tabs中的省略号按钮,这时会弹出一个字符串编辑器。在这个编辑器中分三行输入第一页,第二页和第三页。然后点击OK按钮。

(3)在窗体中选取PageControl组件,用鼠标右键单击该组件,在弹出的快捷菜单中选择NewPage命令,PageControl组件将生成一个缺省名为“TabSheetN”的页,其中N是从1开始的整数。第一次运行New Page命令生成的页名为TabSheet1,第二次生成的名为TabSheet2,以此类推。我们使用这个命令生成三个页。

与TabControl组件不同的是,你可以直接单击页来切换页面。单击页在切换页面的同时也选中了整个PageControl组件。如果要选择某个页,可以先单击页切换到该页,然后再单击页面就可以了。

(4)在对象编辑器中,选择TabSheet1,TabSheet2和TabSheet3的Caption属性,把它分别修改为第一页,第二页和第三页。

这样看起来他们就完全一样。

 

70)问:但要是一样,为什么有两个不同的组件呢,用一个不就行了,好象他们并不真的完全一样?

答:你说的对,千万不要被他们的外表假象所蒙蔽,实际上它们并不一样。TabControl是一种“假”多页组件,而PageControl才是“真”多页组件。

我们知道多页组件把所要显示的信息放在不同的页中,实际上每个页都是一个窗体,并可以通过页来进行页的切换。TabControl组件虽然有多个页,但是实际上只有一个页的模板,也就是说,每次用户单击页时,这个页都要根据页模板更新一次,以便对用户的选择作出响应。

很显然,如果需要在每个页上显示不同的组件,那么TabControl肯定无法胜任这种工作。因为你每次换页时,必须用代码更新页模板,这在C++Builder中实在不是一个好办法。如果每个页所显示的组件相同只是内容有变化,那么使用TabControl会更加合适,因为它消耗的系统资源比较少。

而PageControl则是每页对应一个页模板。所以,它适宜于每页都不同的情况。

71)问:TabControl组件有哪些常用的属性?

答:HotTrack属性用来确定当鼠标指向页时,页上的标签是否自动被加亮显示。缺省值为False。

MultiLine属性用来确定当页一行显示不下时是否显示到下一行。缺省值False表示在一行无法显示完时,在行的右边自动出现一个双向箭头,可以用来移动页。

TabHeight属性用来设置页的高度。缺省值0表示页的高度将自动适应页上文本的高度。

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=565&d=7e4mg0

TabWidth属性用来设置页的宽度。缺省值0表示页的宽度将自动适应页上文本的宽度。

TabPosition属性为tpTop时,表示将页放在TabControl组件的上面,为tpBottom时则表示放在下面。

TabControl组件上的每一个页都有自己的索引,最左边的页的索引为0,紧接着的页的索引为1,以此类推。TabIndex属性返回当前被按下的页。

Tabs属性用来设置页的个数及其标题,在设计时是使用一个字符串编辑器来实现的。

72)问:TabControl控件有哪些比较重要的事件呢?

答:TabControl有两个比较重要的事件OnChange和OnChanging。每当页被选中后就会发生OnChange事件,这时可以根据属性TabIndex判断哪个页被选中,然后再采取响应的动作。

OnChanging事件正好发生在页被选中之前,也就是正好在一个页切换到另一个页之前。这个事件使得我们可以在页切换之前采取某些行动,例如在某些条件没有设置之前不准离开这一页。

其实这两个事件以前我们已经详细的研究过,这里就不再举例说明了。

73)问:PageControl组件好像比TabControl组件功能更强大,它是怎样使用的?

答:与TabControl相比,PageControl组件的功能确实更加强大,但是却并不复杂。PageControl中的每一个页都是一个TTabSheet组件,这个组件实际上是一个容器,你可以在上面放置各种控件。每个TTabSheet组件都有自己的属性。

实际上这里有两层关系。最顶层的是PageControl组件,它负责管理多个TTabSheet组件,而每个TTabSheet组件也管理着放在它上面的组件。

74)问:PageControl组件有哪些比较重要的属性呢?

答:ActivePage这个属性显示当前被选中的页,它也可以用来切换页。

MultiLine属性用来确定当页一行显示不下时是否显示到下一行。缺省值False表示在一行无法显示完时,在行的右边自动出现一个双向箭头,可以用来移动页。缺省值为False。

TabHeight属性用来设置页的高度。缺省值0表示页的高度将自动适应页上文本的高度。

TabWidth属性用来设置页的宽度。缺省值0表示页的宽度将自动适应页上文本的宽度。

TabPosition这个属性的值为tpTop时,页将放在TabControl组件的上面,而为tpBottom时将显示在下面。

此外,还有运行时态属性:

Pages这个只读属性是PageControl组件上所有的页组成的数组。

PageCount这个属性返回PageControl组件上的页数。

75)问: PageControl的每一页都是一个TTabSheet组件,那TTabSheet有些什么属性呢?

答:TabVisible 这个属性用来屏蔽某一页的显示。也说是说,它的值为False的时候PageControl组件将不显示这个页了,但是这个页还存在,你还可以把这个属性设置为True来恢复它的显示。在程序运行期间不能删除页,只能屏蔽页的显示。

PageIndex是页的索引号,

此外,还有运行时态属性。

PageControl属性返回该页所在的PageControl组件。

TabIndex属性返回该页在所有可见页中的索引号。

因为在程序运行时是不能删除页的,所以PageIndex索引号是固定不变的。但是页可以被屏蔽,当没有页被屏蔽时,TabIndex与PageIndex完全相同;当有页被屏蔽时,TabIndex就与PageIndex就不同了。TabIndex是这一页在所有可见页中的索引号,也就是说,第一个可见页的TabIndex是0,第二个可见页的TabIndex是1,以此类推。

76)问:能设计一个例子让我更好的理解一下它们吗?

答:好的 ,首先在TabControl组件的页面上放置一个编辑框组件。

然后在PageControl组件的Tab1页中放置一个编辑框组件。

接着将PageControl组件切换到Tab2页,放置一个文本编辑框组件。

最后,编译并运行这个程序。

点击tabControl组件的tab1到tab3标签,可以看出,编辑框出现在组件的每一页中。

点击PageControl组件的tab1到tab3标签,可以看出,每一页组件都不相同。

10.菜单组件

77)问:菜单是Windows常用的用户界面。对于一个能够实际应用的程序,菜单是必不可少的组成部分。C++Builder中是怎样实现菜单的?

答:C++Builder为我们提供了两种菜单组件:一种是主菜单组件MainMenu;另一种是弹出菜单PopMenu组件。

主菜单组件的作用是在窗体上生成菜单条。菜单组件刚放到窗体上时,菜单是不可见的,当双击它打开菜单编辑器并且增加了菜单项后,菜单条才出现在窗体的顶部。设计时的菜单条与运行时的菜单条完全一样。

下面我们介绍利用菜单编辑器进行菜单设计的过程。

首先要打开菜单编辑器

从组件模板上的Standard选项卡中选择MainMenu组件,放置到窗体上。然后,用鼠标右键单击菜单组件,然后在弹出菜单中选择Menu Designer。当然,你也可以双击菜单组件打开菜单编辑器。

被加亮显示的小方框就是一个空白菜单项。

接着要添加菜单项

选中这个菜单项,这时对象编辑器中将出现这个菜单项的属性。

我们在菜单项的Caption属性中输入“文件(&File)”,其中“&F”可以生成一个快捷键,这样用户就可以通过键盘操作了,并且F下面出现了下划线(注意:由于是系统原因,”&”一定要在英文状态下输入)。当我们输入完标题并按下回车键时,C++Buildr会自动给这个菜单项赋一个名字,这里的名字是N1。如果你不满意这个名字可以修改Name属性。

添加完菜单项后会自动出现一个空白的子菜单项等待你输入。

现在菜单编辑器中的输入焦点移到了这个空白子菜单项上,同时对象编辑器将对应显示这个子菜单项的属性。你可以在Caption属性中输入子菜单项的标题“打开(&Open)”,然后按下回车键。菜单编辑器会打开一个新的子菜单项,并把输入焦点移动到这个子菜单项上。这样,就可以给菜单项增加一系列的子菜单了。

同样方法添加退出菜单。

 

要开始编辑下一个菜单项,可以用鼠标单击菜单项“文件”的右边的虚线框,它表示一个空白的菜单项。

78)问:当菜单项中的子菜单项属于不同类别时,有必要用分隔条把子菜单项进行分组,菜单组件是怎样实现这个功能的?

答:我们在退出和保存两个菜单项中间加入选择分隔条,在退出菜单项上点击鼠标右键,从弹出菜单中选择Insert,这时,一个空白的菜单项就插入了,将它的Caption属性设置为“–”这个减号符就可以了。

79)问:那么,我们又怎样给菜单项设置热键呢?

答:每个菜单项都有一个属性ShortCut,利用这个属性就可以给这个菜单项设置热键了。现在我们给打开文件菜单项添加热键。单击这个菜单项,选择属性ShortCut,出现一个下拉菜单,其中包括一系列的热键的组合。选择Ctrl+O,这个热键中就被赋给了退出菜单项。

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=566&d=nafj74

80)问:快捷键与热键这两个概念我已经弄糊涂了,您能给我解释一下吗?

答:好的,快捷键与热键相同的方面是,它们都是通过键盘来访问。

一个菜单项可以同时拥有快捷键和热键。所谓快捷键通常只是一个字母,而热键通常是一个组合键。另外它们的激活方式不一样,例如一个子菜单项有一个快捷键O和一个热键Ctrl+O,那么使用热键就可以直接激活这个子菜单项,而使用快捷键你必须首先选中该子菜单项上一层的菜单项,然后按下快捷键才可以激活这个子菜单项。

81)问:您讲解的菜单到现在还只有菜单项和子菜单两级,如果我希望子菜单还有自己的子菜单,应该怎么办?

答:这种嵌套的菜单项实际上就是级联菜单。这里,我们给颜色菜单项添加子菜单项,选择颜色菜单,单击鼠标右键,在弹出的快捷菜单中选择Create Submenu命令,这时在子菜单项中将出现一个指向右的箭头,同时还产生了一个级联菜单。

当然,你也可以用Ctrl+方向键右键。

82)问:很多菜单项的旁边有复选标记,请问菜单编辑器是否提供了这个功能呢?

答:复选标记就是在菜单项的标题的前面出现的勾号。复选标记经常用于一些状态设置的菜单项,当处于该状态时就会出现复选标记,否则复选标记消失。

现在,我们给回绕菜单项设置复选标记,在对象编辑器中把它的属性Checked改为True,这样这个菜单项就会显示复选标记。要取消复选标记可以把Checked属性再次设置为False。

83)问:我有时要设计一组互相排斥的菜单项,也就是单选菜单项,应该怎么办呢?

答:要使一组菜单项成为单选菜单项,必须满足几个条件。

首先,这一组菜单必须在同一个下拉菜单中。

其次,它们的RadioItem属性必须都设置成了True。

最后,它们的GroupIndex属性必须相同。

这一组中唯一被选中的菜单项的前面将会显示一个圆点标记。

84)问:我怎样使菜单项失效呢?

答:只要把菜单项的Enabled属性设置为False,就可以使菜单项失效,这时菜单项是灰色的。在设计时和运行时你可以任意设置菜单项的Enabled属性。

85)问:菜单项有些什么常用的事件呢?

答:菜单项只有一种事件OnClick,在实际编辑中这个事件是一定要响应的。

86)问:我们一般在主菜单之外还会提供一个快捷菜单,就像C++Builder一样,在窗体中单击右键随时都可以打开一个弹出菜单。C++Builder是怎样实现弹出菜单的?

答:弹出菜单有时候又称为快捷菜单。弹出菜单与主菜单的区别是:主菜单是固定的,而弹出菜单是活动的;主菜单有多组菜单项,而弹出菜单只有一组。弹出菜单的设计方法与主菜单基本相同,也是使用菜单编辑器来完成的。

11.工具条组件

87)问:工具条是Windows编程经常要用的, C++Builder能不能实现这个功能呢?

答:当然可以,工具条是由许多具有图形的按钮组成的,这些按钮被分隔符分隔成许多组,每个组都能够完成特定的工作。工具条上的按钮具有与位图按钮相似的特性——可以拥有多个位图,当按钮处于不同状态时,例如按下、失效等,将显示不同的位图。以前C++Builder制作工具条的方法是通过把加速按钮放在面板组件Panel上实现的。现在,我们不必使用这两种组件的组合,只要使用ToolBar就可以创建工具条了。工具条是比较难掌握的,它之所以不容易掌握是因为它包含的TToolButton组件有三个属性:Grouped,AllowAllUp和Down,它们的组合可以产生各种不同效果的按钮组。这三个属性我们一定要好好理解。

88)问:那请给我介绍一下Toolbar这个组件的使用方法好吗?

答:好的,我们先从ToolBar的属性入手,通过对一些重要属性的分析来了解它。ToolBar包含一些前面没有见过的属性:

ButtonHeight 属性指出了工具条中按钮的高度。

ButtonWidth 属性用来设定工具条中按钮的宽度。

Flat 属性为true时,使工具条透明,同时使工具条上按钮之间的边界消失。俗称平面工具条,它的缺省值为False。

Indent 用来在工具条的左边创建一个边沿区。

ShowCaptins 确定是否允许在工具条的按钮上显示标题。缺省值为False。

Wrapable 设定是否允许工具条上的按钮换行。缺省值为True。

List 属性,当这个属性为True时,工具条上按钮的图标在左,标题在右。为False时,按钮的图标在上,标题在下。缺省值为False。

Images 用来设定正常情况下,按钮上显示的图标列表。

HotImages 用来设定当鼠标移动到按钮上显示的图标列表。

DisabledImages 用来设定按钮失效时显示的图标列表。

工具条上所有按钮显示的图标就包含在这三个图标列表中。

在前面介绍的ListView组件中,属性LargeImages和SmallImages分别表示在两种不同的状态下显示的图标列表。ToolBar的这三种属性也有类似的特点,它们分别表示在正常状态、鼠标指向工具条以及按钮失效时显示的图标列表。

此外,还有几个运行时态属性:

ButtonCount属性,指出了工具条中按钮的个数。

Buttons存放着工具条中按钮的列表。

RowCount指示着工具条的行数。

89)问:C++Builder为什么要采用图标列表的方式来管理工具条上的图标呢?

答:因为这样可以集中统一地管理大量的图标,从而大大地减轻了程序员的负担。

答:要为应用程序建立工具条,可以按照下面的步骤:

(1)从选项卡Win32中选择工具条组件,放置在窗体上。

注意,刚放置在窗体上的工具条组件一定是在窗体的顶部,因为这时工具条的Align属性被设置为alTop。

(2)在窗体上增加两个ImageList组件,并为这些组件引入图标。

(3)将一个ImageList组件赋予工具条的属性Images,另一个赋予工具条的属性DisabledImages。

(4)用鼠标右键单击工具条,在弹出菜单中选择New Button。

这时将在工具条上出现一个按钮,这个按钮无标题。这是因为工具条的ShowCaption属性被设置成了False。实际上这个按钮有一个缺省的标题ToolButton1。

这个新创建的按钮与我们前面介绍的按钮都不一样,它是一个TTtoolButton组件。

(5)选中工具条上的按钮,把按钮的ImageIndex属性改为所需要图标的索引号。这个图标实际上是存放在ImageList组件中的。

(6)重复第四步和第五步,在工具条上创建更多的按钮。这样一个工具条就建立了。

90)问:工具条上的按钮好像与普通按钮不一样,请问它有些什么特点呢?

答:工具条上的按钮是一个TToolButton组件。它包括一些与工具条有关的特性,可以简化工具条上按钮的配置,并增加一些显示特性。TToolButton有这样一些重要属性。

AllowAllUp属性允许一个组中的按钮同时全部处于未选中状态。缺省值是False。

Down属性指定按钮是否被选中。在设计期间把该属性设置为True,可以使按钮初始化为选中状态,缺省值为False。

DropDownMenu属性把一个弹出菜单与按钮相连。

ImageIndex属性指定出现在按钮上的图标的索引号。

Indeterminate属性确定按钮是否处于一种既不是选中也不是未选中的中间状态。缺省值为False。

Wrap属性强迫这个按钮是这一行的最后一个按钮,下一个按钮从下一行开始。缺省值为False。

Style属性用来确定按钮的样式,它可以有五种不同的取值,这五种取值分别表示五种不同样式的按钮。

tbsButton表示按钮正常显示与一般的加速按钮一样。

tbsCheck表示单击这种类型的按钮时可以切换Down属性。一旦你选中了该按钮,那么按钮将保持选中状态直到再次单击。

tbsDropDown表示按钮显示成一个向下的箭头。

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=567&d=cnyxvg

tbsSeparator表示按钮显示成工具条上的一个空格。

tbsDivider表示按钮显示成工具条上的一个垂直线段。

Grouped属性确定是否允许连续的多个tbsCheck类型的按钮组成一组。缺省值是False。如果连续的多个按钮,每个按钮的Grouped属性都设置为True,同时Style属性都设置为tbsCheck,那么这些组件一次只能选取一个。选中其中一个按钮将使其他按钮变成未选中状态。

91)问:如何用加速按钮创建工具条?

答:工具条的另一种创建方法是使用面板组件+加速按钮SpeedButton的方法。加速按钮在前面曾经提到过,它与位图按钮很相似,也使用属性Caption和Glyph放置文本和图标,不过加速按钮还有一些属性是比较特殊的。

下面我们先介绍加速按钮的属性:

GroupIndex:通过GroupIndex属性可以使加速按钮像单选按钮那样使用。也就是说,把多个单选按钮的GroupIndex属性赋予相同的值以便组成一组,这样这个组中的按钮一次只能有一个按钮可以被按下,当你按下一个按钮时,其他按钮就会弹起。需要注意的是GroupIndex必须大于0。如果GroupIndex属性等于0,那么表示该按钮是一个普通的加速按钮。

Down:属性值可以控制按钮是否处于按下状态,当该属性值为True时,按钮处于按下状态。你可以在设计时把属性Down设置为True,这样当程序运行时,按钮一开始就处于按下状态。

AllowAllUp:这个属性用来指定一个组中的所有加速按钮是否可以同时处于未被按下的状态。当该属性为True时,单击该组中被按下的按钮,这个按钮会弹起。当该属性为False时,单击该组中被按下的按钮,这个按钮不会弹起。

如果你比较一下加速按钮和TToolButton组件就会发现,它们都有上面介绍的这三种属性,只不过TToolButton组件中使用属性Grouped来完成类似于GroupIndex的功能。

92)问:用加速按钮设计工具条与用Toolbar组件相比有什么不同?

答:用加速按钮设计工具条时必须首先在窗体上放置面板组件,而且应该把它的Align属性设置为alTop(因为工具条一般都放在窗口的顶部)。然后在面板组件上放置加速按钮。

一般要利用按钮的Caption和Glyph属性为加速按钮设置文本和图标。如果这些按钮只是像普通按钮那样操作的话,那么这样设置就可以了。但是如果这些按钮要像单选按钮那样使用,那么还必须对GroupIndex属性进行设置。

93)问:那如何用加速按钮来设计工具条呢?

答:我们要用到Additional页的可控组件ControlBar、Speedbutton与Win32页面中的ToolBar。下面来看一下他的实现:

①双击ControlBar,把她放到窗体中;

②双击ToolBar,并将其放到ControlBar上;

③在ToolBar上添加SpeedButton;

④选中一个SpeedButton,在Object Inspector中找到Glyph属性,来选择图片。

*SpeedButton的Flat属性改为true,则按钮为透明的

*AutoSize改为true,则容器大小随容件变化

12.状态条组件

94)问:在Windows编程中,状态条可以显示程序当前的一些状态信息,是一个很有用的部件,它也被广泛应用在许多程序中,请问,C++Builder是怎样编写状态条的?

答:状态条StatusBar实际上是由一组状态面板组成的,通常显示在应用程序窗口的底部,它的功能主要是显示一些提示信息和状态信息。例如,C++Builder的代码编辑器底部就显示了一个状态条,而且显示了多个状态面板。

状态条可以只显示一个状态面板,也可以显示多个状态面板。当显示多个状态面板时,状态条被分割为几个部分,每个部分都有自己的Text属性,通过这个属性就可以在状态条显示信息了。

如果要在状态条上显示多个状态面板,就需要把状态条的SimplePanel属性设置为False,否则只能显示一个状态面板。

如果状态条只需要显示一个状态面板,那么只要简单地在窗体上放置状态条就可以了。这时窗体上的文本保存在属性SimpleText中。如果要显示多个状态面板,那么就需要使用面板编辑器创建多个状态面板。单击属性Panels的Value列中的省略号按钮(或者双击菜单条),就可以打开状态面板编辑器。

单击编辑器上的按钮Add可以增加状态条上的状态面板。单击面板编辑器中新创建的状态面板,在对象编辑器中就会列出该状态面板的属性。

95)问:可以看出状态条上的状态面板有五个属性,他们分别有什么作用呢?

答:Alignment属性用来确定面板中所显示文本的对齐方式。它的可能值为:taLeftJustify表示左对齐、taRightJustify表示右对齐和taCenter表示居中对齐。缺省值为taLeftJustify。

Bevel用来确定面板的样式。共有三种方式,None表示面板处于平整的状态;Lowered表示面板下沉;Raised表示突起。

Style属性用来确定在面板中显示的内容是Text文本还是OwnerDraw自绘制图形方式。如果要在面板中作图,那么就需要编写OnDrawPanel事件处理过程。

Text属性用来保存面板中显示的字符串。

Width用来设定面板的长宽。

13.对话框组件

96)问:怎样编写文件打开、保存等对话框?

答:C++Builder为我们提供了许多常用的对话框组件,这些对话框组件都放在组件模板的Dialogs选项卡中,例如Font,Color,Open和Print对话框。其中OpenDialog对话框组件最具有代表性,只要掌握了它的用法,那么你也就会使用其他的对话框组件了。

97)问:对话框组件的特性有哪些特性呢?

答:对话框组件是一种不可见组件。当你把它放在窗体上时,它是一个大小不变的图形按钮,当程序运行时,对话框组件不会立刻显示,而必须使用每个对话框都有的Execute方法,使对话框显示出来。

C++Builder提供的对话框大多数是有模式对话框。这种对话框要求首先必须响应该对话框,然后才能继续进行工作。所谓响应对话框就是你必须单击OK或者Cancel按钮,使对话框返回一个值。当用户单击对话框上的按钮OK时,返回True,单击Cancel按钮返回False。用户可以根据返回值的不同进行不同的处理。

非模式的对话框使你在响应对话框之前可以完成其他的工作,不必非要首先响应对话框。这类对话框有:FindDialog,ReplaceDialog等。

98)问:能更细点的说明对话框组件的用法吗?

答:我们就编制一个文本阅读器来说明如何使用文件打开对话框。

打开一个新的窗体,我们放上一个按钮组件和一个Memo组件,将Memo的ScrollBars属性设置为ssBoth,使得Memo能够显示垂直和水平的滚动条。

选中Lines属性,删除里面的文本。

在窗体上放置OpenDialog组件。

选中OpenDialog组件,可以看出,OpenDialog有这样一些主要的特性

FilrerIndex属性用来指定每次打开对话框所用的缺省过滤器。

DefaultExt属性是一个扩展名,当用户在文件编辑框中输入的文件名没有带扩展名时,对话框会用它作为文件缺省的扩展名。

InitialDir属性用来设置对话框打开时显示的目录。

FileName属性用来返回最近一次选中的文件的完整路径名。

Filter属性,这个属性用来设计在对话框的文件列表中将列出哪些类型的文件。

OpenDialog对话框提供了一个专门的编辑器来编辑属性filter,单击属性Filter的value列中的省略好按钮就可以打开这个编辑器。

左边用来输入过滤器的名称,右边用来输入文件扩展名。

现在,我们输入文本文件和C++文件的过滤器。这样,在每次打开对话框时候,在文件类型下拉列表中将显示过滤器的名称。

双击文打开按钮,输入这样一段代码:

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

if(OpenDialog1->Execute())//首先执行打开文件对话框函数,这时,打开文件对话框才显示出来。

//如果执行成功,这个函数返回true,否则返回false

{

Memo1->Lines->Clear();//把Memo中的内容清掉

Caption=OpenDialog1->FileName; //获得用户选择的文件的路径名,并将它设置成窗体的标题。

//注意,因为是在Form1窗口(容器)中进行的操作,所以Caption前省了Form1,当然你可以加上

Memo1->Lines->LoadFromFile(OpenDialog1->FileName);// 调用文本装入函数从文件中装入文本,并显示在编辑框中

}

}

//---------------------------------------------------------------------------

99)问:其它对话框的各有什么重要属性?

答:保存对话框SaveDialog与打开对话框非常相似,至于OpenPictureDialog、SavePictureDialog就不用多说了。其它象字体对话框FontDialog的Font属性;颜色对话框ColorDialog的Color属性;查找对话框FindDialog的FindText。这里就不用多说了,看一下就明白了。

// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=568&d=wq2d7s

100)问:对话框组难道就只能用上面说的那些组件吗?要是有,能介绍一下吗?

答:在C++ Builder集成开发环境的可视化组件中库中,给应用程序开发员提供了一系列的标准的对话框函数。我们可以直接调用这些函数来显示一些标准的对话框。

这类函数还真不少,但我们只要掌握以下五个就足够了J

extern PACKAGE int _fastcall MessageDlg(const AnsiString Msg,TmsgDlgType DlgType,TmsgDlgButtons Buttons,int HelpCtx):用来在计算机屏幕*显示对话框。

其中,参数Msg是指定要对话框中显示的字符串。

参数DlgType是TMsgDlgType类的变量,它用来指定对话框的显示特征。TmsgDlgType是一个集合,它可以取以下的值:

mtWarning:对话框中包含黄色的惊叹符号;

mtError:对话框中包含红色的惊叹符号;

mtInformation:对话框中包含蓝色的“I”符号;

mtConfirmation:对话框中包含绿色的问号;

mtCustom:对话框中不包含位图符号,标题名称为应用程序名称。

参数Buttons是用来指定对话框中包含的按钮的类型,它是一个集合,可以是以下若干个元素的组合:

mbYes:对话框含有“Yes”按钮;

mbNo :对话框含有“No”按钮;

mbOK:对话框含有“OK”按钮;

mbCancel :对话框含有“Cancel”按钮;

mbAbort :对话框含有“Abort”按钮;

mbRetry :对话框含有“Retry”按钮;

mbIgnore :对话框含有“Ignore”按钮;

mbAll :对话框含有“All”按钮;

mbNoToAll :对话框含有“NoToAll”按钮;

mbYesToAll :对话框含有“YesToAll”按钮;

mbHelp :对话框含有“Help”按钮.

C++ Builder还专门定义了三个常用的按钮组合:

mbYesNoCancel:包含了mbYes、mbNo和mbCancel元素;

mbOKCancel:包含了mbOK和mbCancel元素;

mbAbortRetryIgnore:包含了mbAbort、mbRetry和mbIgnore元素。

参数HelpCtx用来指定当用户选择帮助时,帮助系统中的上下文编号。这个函数根据用户选择的按钮,将返回相应的值,它有以下返回值:mrNone、mrAbort、mrOK、mrRetry、mrNo、mrCancel、mrIgnore、mrAll。

extern PACKAGE void _fastcall ShowMessage(const AnsiString Msg):这个函数用来显示一个对话框,这个对话框中包含一个“OK”按钮。其中对话框中显示的内容由参数Msg来确定。

extern PACKAGE AnsiString _fastcall InputBox(const AnsiString Acaption, const AnsiString Aprompt, const AnsiString Adefault):这个函数用来在计算机屏幕上显示一个对话框,这个对话框有一个文本编辑框,可以用来接收用户输入的字符串信息。

Acaption:用来指定对话框的标题;

Aprompt:用来指定对话框中显示的内容;

Adefault:用来指定对话框打开时在编辑框中显示的内容。

extern PACKAGE bool _fastcall LoginDialog(const AnsiString Acaption, AnsiString &AuserName, AnsiString &AuserName):这个函数用来显示一个标准的登录对话框,用来连接一个数据库服务器,其参数分别为对话框中数据库的名字、用户输入的用户名和密码。

extern PACKAGE bool _fastcall SelectDirectory(const AnsiString Caption,const WideString Root,AnsiString &Directory)或extern PACKAGE bool _fastcall SelectDirectory(AnsiString &Directory,TselectDirOpts Options,int HelpCtx):这个函数用来显示一个让用户输入目录名称的对话框。其中:

第一种语法的参数Caption用来指定对话框的标题;Root用来指定从哪个根目录开始浏览;参数Dircetory用来确定用户选择的目录。这个语法不能改变当前的目录。

第二种语法的参数Options是一个集合,它可以由以下几个元素组合而成:

sdAllowCreate:允许用户输入一个不存在的目录名字,但并不创建这个新目录;

sdPerformCreate:它必须和sdAllowCreate配合使用,当用户输入一个不存在的目录名时,对话框将创建这个目录;

sdPrompt:它必须和sdAllowCreate配合使用,当用户输入一个不存在的目录名时,将出现消息对话框,询问用户是否创建这个新目录。若用户选择是,在包含sdPerformCreate元素时将创建这个新目录,若没有包含sdPerformCreate元素,将不创建目录。

《基础入门》100问与答到这就结束了,由于原文是在WORD下写的,帖到这里时有时会出现一些错误,由此给编辑带来很多不必要的劳动,所以要感谢编辑的辛苦工作!J

注:本文所有例程均在XP系统、BCB6下编译通过。

(全文未完)