程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++ Builder開發經驗幾則

C++ Builder開發經驗幾則

編輯:關於C++

Borland C++ Builder 是Inprise公司繼Delphi之後推出的又一激情之作,它使得C++的可視化編程真正成為了可能,這就為那些既不忍心放棄自己心愛的C++語言,又十分向往Windows平台下RAD編程的程序員們提供了一個近乎於完美的解決方案。其中堅版本Borland C++ Builder 3.0更是一優秀的全能型的開發工具。從開發功能上來說,其功能和現在如日中天的Microsoft的Visual C++相比不相上下,而從易用性方面來說,其易用性則要大大優於前者,正因為如此,所以Borland C++ Builder3.0在國內也逐漸得到了一些程序員的認同。但是Borland C++ Builder在國內的應用情況還遠不及它的同門師兄Delphi一樣普及,所以相對來說Borland C++ Builder3.0的參考資料也比較少。在這裡筆者把自己這一年來使用Borland C++ Builder 3.0所總結出來的經驗拿出幾條來與大家共飨,只希望能對你在編程時有一定的幫助,讓你少走一些彎路。

1.全局變量的定義

這個問題在標准的C/C++編程領域可以說根本不能算是一個問題,但是在Borland C++Builder3.0中卻有些不同。當一個程序包含一個定義在獨立頭文件中的全局變量時,程序編譯將會很順利地通過,但是在程序鏈接時則會出現找不到全局變量目標模塊的錯誤。這個問題曾令包括筆者在內的很多Borland C++ Builder 程序員感到困惑。直到前不久,我才找到了問題出現的原因和解決問題的方法。

在Borland C++ Builder 3.0中對全局變量的定義采用了定義函數一樣的方式,即全局變量不僅要有聲明部分,還要有實例定義部分。只有這樣定義過的全局變量在使用時才不會出錯。

以下舉例說明,在程序中要定義一個全局整型變量i,它的聲明部分寫在Struct.H頭文件中,如下所示:

#ifndef StructH

#define StructH

#include //此行必須加上

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

extern int i;//此處為全局變量i的聲明

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

#endif

而它的實例定義部分則應該寫在Struct.cpp文件中,具體如下:

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

#include “struct.h”

#pragma package(smart_init)//此行必須加上。

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

int i;//此處為全局變量i的實例定義

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

只有經過以上處理後,在程序中使用自定義全局變量時才不會出錯。

2.使同一個元件的Hint在StatusBar中與動態提示時有不同的顯示內容

這是我在閱讀VCL源碼時無意中發現的。雖然是一個小技巧,但是卻很是實用,以下具體舉例說明:

⑴:在Borland C++ Builder 3.0中新建一個項目,然後在窗口中加入一個Button元件和一個StatusBar元件,並在對象檢器中將Button元件的ShowHint屬性和StatusBar元件的SimplePanel屬性值都置為true。

⑵:將Button元件的Hint屬性置為“這是一個按鈕的提示信息|這是在提示行上顯示的信息”。

⑶:在窗口頭文件的窗口類中定義一個函數原型如下:

void __fastcall DisplayHint(TObject *Sender);

然後在CPP文件中編寫這個函數的代碼如下:

void __fastcall TForm1::DisplayHint(TObject *Sender)
{
StatusBar1->SimpleText=GetLongHint(Application->Hint);
//應用程序在顯示動態提示信息時,只會顯示“|"以前的部分,而想要顯示“|"以後的部分就只有通過調用GetLongHint函數來實現了。
}

⑷:最後再在窗口的構造函數中加入以下一行代碼:

Application->OnHint=DisplayHint;

⑸:保存並編譯項目後運行程序。

這時你會發現,當你把鼠標移到Button上時,Button上所顯示的動態提示信息和StatusBar上所顯示的提示信息是不同的。

下面附送一個為整個應用程序安裝動態提示的程序段。它摘自我正在開發的一個應用程序:

void __fastcall TForm1::DisplayHint(TObject *Sender)
{
// 先對已經存在窗口的Tag屬性賦值,然後再通過判斷當前窗口的方法來進行動態提示。
//如果將建的窗口也需要動態提示的話,那麼可先給窗口的Tag屬性賦值,然後再將判斷這個Tag屬性的代碼加入到下面的switch語句中。
switch(Screen->ActiveForm->Tag)
{
case 1 :DFSStatusBar1->Panels->Items[1]->Text=GetLongHint(Application->Hint);break;
case 5 :Form5->StatusBar1->SimpleText=GetLongHint(Application->Hint);break;
case 8 :Form8->StatusBar1->SimpleText=GetLongHint(Application->Hint);break;
case 11:Form11->StatusBar1->SimpleText=GetLongHint(Application->Hint);break;
}
}

3.如何使DateToStr函數轉換後的結果為長格式的日期字符串

這是我在實際開發過程中遇到的一個問題。當我把TDateTimePicker元件的Date屬性通過DateToStr函數轉換後賦給一個Edit元件的Text屬性時,Text得到的日期字符串數據只是以yy-mm-dd格式表示的短格式日期字符串數據。千年蟲!眼看就要到二千年了,這怎麼能行。本來我想用判斷字符串的辦法來解決這個問題,但是後來經過深入思考後發現該方法有很多的弊端。所以只有用一種通用的方法來解決問題了。在這種情況下,我查找了很多的資料,但是很不幸的是,我所查找的資料中沒有一個提到解決這個問題的方法。無奈之下我打開了Borland C++ Builder 3.0的幫助文件,查看了所有關於日期的幫助信息。此招果然有效,在幫助文件中我找到了一組用於日期顯示的外部變量,其中有兩個AnsiString型變量,它們分別是ShortDateFormat和LongDateFormat。從它們的名稱就可以看出,它們是用來存儲短日期格式和長日期格式的。當時靈機一動,想通過修改這兩個變量值的方法來解決問題,於是當即寫了一段代碼並運行之,才發現我的想法是可行的。具體代碼段如下:

void __fastcall TForm7::WriteLongDate(void)
{
AnsiString temp=ShortDateFormat;
ShortDateFormat=LongDateFormat;
Edit1->Text=DateToStr(DateTimePicker1->Date);
ShortDateFormat=temp;
}

該程序段先保存短日期格式變量,然後將長日期格式變量賦給短日期格式變量,這樣做後就使得當前的短日期格式和長日期格式的表示方式相同了。接下來使用日期轉字符串函數DataToStr來將日期數據轉換為AnsiString型數據,轉換後的AnsiString就已經變成了長格式的日期數據。最後將先前保存的短日期格式變量恢復一下即可。就這樣,問題被很好地解決了。同理,如果將長格式日期字符串轉換為短格式日期數據,也可以使用上述方法,只不過要將上面賦值的順序反過來即可。

4.程序在編譯鏈接時提示找不到某某文件應該怎麼辦?

這是一個實際編程工作中經常遇到的問題。造成這個問題的原因很多,很難一一介紹,所以我在這裡只向大家介紹幾個造成這個問題的典型原因,以及其解決方法。希望能對你在解決這個問題時起到拋磚引玉的作用。

⑴:編譯器找不到存在的文件。

這個問題經常出現在編譯添加新元件的應用程序時。其原因在於項目文件的搜索路徑中並沒有這個新元件所在路徑的信息。這個問題解決起來比較簡單,只需打開Project/Options菜單,在彈出的“選擇”窗口中選擇“Directories/Conditionals"標簽頁,然後將新元件的路徑信息添加到包含路徑(Include Path)和庫文件路徑(Library Path)中即可。

⑵:編譯器要找不存在的文件情況之一

也許你在編程中有過這樣的遭遇,當你編譯並鏈接一個新的程序時,編譯程序竟然會告訴你,需要你已經卸載了的元件參加編譯。不知道你當時的感覺怎麼樣,反正,當我還不知道這個問題解決辦法的時候,它總給我一種死去的元件陰魂不散的感覺。其實造成這個問題的原因是由於新元件在安裝時要將其庫文件的信息添加到缺省項目文件中的“編譯鏈接所需庫文件”部分,而元件在卸載時又不能自動將其刪除。這就使得以後所有新建的項目在編譯鏈接時都需要使用這些庫文件。為了解決這個問題,我們就只有對缺省項目文件進行編輯了。進入Borland C++ Builder 3.0的BIN目錄下,你可以找到一個叫做DEFAULT.BPR的項目文件,這個文件就是缺省項目文件,即所有新建項目文件的父本。打開這個文件後,找到SPARELIBS段,將“死去元件”的“陰魂”Kill掉,即可永絕後患了。

⑶:編譯器要找不存在的文件情況之二

這種情況的出現還是與新元件的安裝有關。當你在安裝一些有源碼的Delphi元件時,有可能遇到這樣的情況:編譯器告訴你找不到某某文件,使得挺好的一個元件就是無法使用。其實這個問題的出現多半是由於元件源碼中的一些判斷Delphi版本的預編譯信息所造成的。由於Delphi的不同版本之間都有著一定的差異,所以很多Delphi元件為了增強自己的可移植性都在元件的源碼中加入了判斷Delphi版本的預編譯信息。然而Borland C++ Builder 3.0的Delphi編譯器對這些Delphi版本的信息支持並不是很好,這就造成了Borland C++ Builder 3.0在編譯這些元件時通常是“胡子眉毛一把抓”,自然會出錯(值得注意的是,在編譯Delphi元件時的很多其它編譯錯誤也是由於這個原因所造成的)。這時我們就只有使用手工刪除這些不需要的預編譯信息(一般為{$IFDEF中的內容)的方法來解決這個問題了。

⑷:編譯器要找不存在的文件情況之三

有一次一個從BC++轉到Borland C++ Builder 3.0的朋友給我打電話問我,說他一時間動了懷舊的情緒,使用Borland C++ Builder 3.0編譯了一個OWL程序。但是在編譯時編譯器卻提示找不到OWL所需要的類庫文件,問我這是為什麼。當即我便回答了他,告訴他Borland C++ Builder 3.0的默認安裝將不安裝對OWL和MFC的支持庫(這在Borland C++ Builder 3.0安裝程序的安裝類型界面中已經寫得很明白了,只不過是英文的,他沒有注意看罷了。)。如果需要這些東西的話,就只有在安裝時選擇定制安裝或完全安裝來安裝對其的支持了。如果你也遇到了以上的問題,那麼請你照我上面所說的話去做吧。

5 動態調用窗體Form

在缺省情況下,由File/NewForm生成添加入項目文件中的窗體都具有"AutoCreate"(自動創建)的特性。即只要程序運行,該窗體就存在於內存中了,不管當前它是否被調用。具有這種特性的窗體一般適用於窗體屬性比較固定、經常被調用的情況。其優點是速度快,缺點是占用內存。在實際程序設計中,會遇見大量類似對話框功能的窗體,它們用於顯示狀態或輸入信息,僅須在程序中調用一下,完成其功能就行了,無需常駐內存。這時可以通過選擇Project/Options/Forms,將"Auto--Createforms"欄中相應的窗體,如Form1,用">"鍵移動到"Availableforms"欄中,並在程序需調用該窗體處,加入下列語句:

TForm1 *myform=newTForm1(this);
myform->ShowModal();
deletemyform;

6 用Enter鍵控制焦點切換的方法

在Windows環境下,要使一個控件取得焦點,可在該控件上用鼠標單擊一下,或按Tab鍵將焦點移至該控件上。這種控制焦點切換的方法有時不符合用戶的習慣。就圖一而言,用戶就希望用Enter鍵,控制焦點由Edit1切換到Edit2。要實現這樣的功能需借助WinAPI函數SendMessage來完成。方法是:先設Form1的KeyPreview屬性為true,然後在Form1的OnKeyPress事件中加入如下的代碼。這樣,用戶就可以通過按Enter,鍵控制焦點按定義好的Taborder順序來移動了!

void__fastcallTForm1::
FormKeyPress(TObject*Sender,char&Key)
{
if(Key==VK_RETURN)
{
SendMessage(this->Handle,WM_NEXTDLGCTL,0,0);
Key=0;
}
}

7 為TStringGrid的文字加上顏色

TStringGrid是C++Builder提供給用戶的一種字符網格控件。美中不足的是,它沒有提供分別修改各單元字體顏色、大小的方法。其實要為TStringGrid實現這樣功能,只需在程序中稍加處理就行了。方法是自定義一個二維數組cellbuf,它的下標與網格單元列行一一對應,用於存放各網格單元的顏色、文字等信息。

structCellStru
{
AnsiStringmsg; //文字信息
TColorcolor; //文字顏色
};
CellStrucellbuf[MAXCOL][MAXROW];

----初始化cellbuf後,再在字符網格控件StringGrid1的OnDrawCell響應事件中,加入如下的代碼即可。

void__fastcallTForm1::StringGrid1DrawCell
(TObject*Sender,intCol,
intRow,TRect&Rect,TGridDrawStateState)
{
StringGrid1->Canvas->Font->
Color=cellbuf[Col][Row].color;
StringGrid1->Canvas->TextOut(Rect.Left+3,
Rect.Top+3,cellbuf[Col][Row].msg);
}

8 軟件封面的實現

----現代軟件設計的流行做法是,在程序運行完成初始化之前,先調用一幅畫面做為封面,通常是1/4屏幕大小,顯示一下軟件的名稱、作者、版本等信息。要用C++Builder實現這樣的功能,方法很簡單:①自定義一窗體類TSplashForm,將其設置成"透明窗口",即BorderIcons下的所有選項均置成false,BorderStyle=bsNone,FormStyle=fsStayOnTop,Position=poScreenCenter;②在TSplashForm窗體上放置一TPanel(相當於圖形的鏡框);③在TPanel上放置一TImage控件,調入所需要的圖形;④對WinMain函數稍加修改,加入如下所示代碼即可。需要指出的是,這段代碼通過函數FindWindow,搜索內存中是否有窗口標題為"Demo"應用程序存在,若存在,則退出程序的運行。該功能可防止程序的再次運行。在某些場合這樣設計是必須的。

WINAPIWinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
try
{
if(FindWindow(NULL,"Demo")!=0)
{
Application->MessageBox
("程序已經運行!","警告",MB_ICONSTOP);
return0;
}
TSplashForm*splash=newTSplashForm(Application);
splash->Show();
splash->Update();
Application->Initialize();
Application->CreateForm(__classid(TForm1),&Form1);
splash->Close();
deletesplash;
Application->Run();
}
catch(Exception&exception)
{
Application->ShowException(&exception);
}
return0;
}

9 如何永久清除DBF中的已被刪除的記錄

----用table->Delete()刪除的DBF記錄,並沒有真正從DBF數據庫中被刪除,而僅僅是做上了一個刪除標記。如何實現類似dBase中的Pack命令的功能呢?請看下面的代碼。

table->Close();
for(;;)
try
{
table->Exclusive=true;
table->Open();
break;
}
catch(...)
{
}
if(DbiPackTable(table->DBHandle,table->Handle,NULL,szDBASE,true)!=DBIERR_NONE)
Application->MessageBox("不能刪除記錄","錯誤",MB_ICONSTOP);

最後再說一種最糟的情況。由於你的某種誤操作,造成了某些編譯器在編譯時所需要文件被誤刪除。這時你唯一的解決方法就只有從Borland C++ Builder 3.0的光盤上將你所需要的文件直接拷貝過來。如果你的Borland C++ Builder 3.0只是一個安裝版的話,那麼你也就只好准備一杯清茶或一杯咖啡,在重新安裝Borland C++ Builder 3.0時慢慢品味了.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved