Selected Category: BCB 程式開發筆記 (26)

View Mode: Post List Post Summary
假設你有一個 TreeView 叫做 tvArticle,有個 PopupMenu 叫做 PopupMenu1,你希望用右鍵可以點選 tvArticle 的節點,然後再顯示右鍵選單。
首先你要把 PopupMenu1 的 AutoPupop 屬性設為 false,然後在 tvArticle 的 OnMouseDown 事件加入以下程式碼。

void __fastcall TForm1::tvArticleMouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
TPoint p;
GetCursorPos(&p); // 取得游標在螢幕的真實座標
if (Button == mbRight && tvArticle->GetNodeAt(X, Y) != NULL)
{
tvArticle->GetNodeAt(X, Y)->Selected = true;
PopupMenu1->Popup(p.x, p.y); // 顯示右鍵選單
}
}

以上的程式碼會在你選中 TreeNode 時才會出現右鍵選單,若你希望不選中  TreeNode 也能出現選單的話,就改成以下這樣:

void __fastcall TForm1::tvArticleMouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
TPoint p;
GetCursorPos(&p); // 取得游標在螢幕的真實座標
if (Button == mbRight)
{
if (
tvArticle->GetNodeAt(X, Y) != NULL)
tvArticle->GetNodeAt(X, Y)->Selected = true;
PopupMenu1->Popup(p.x, p.y); // 顯示右鍵選單
}
}

Posted by Nelson at 痞客邦 PIXNET Comments(0) Trackback(0) Hits(950)

這一段程式碼是可以取得指定目錄及其子目錄下,所有副檔名為 .url 的檔案 (沒錯,這就是拿來掃瞄 IE 我的最愛),取得的所有檔名會存放在一個名叫 sList 的 StringList 裡頭。



void __fastcall TForm1::LoadFavorite(AnsiString Dir, TStringList *sList) // Dir 就是你要掃瞄的目錄, sList 拿來存放檔名

{

��� WIN32_FIND_DATA filedata;� // Structure for file data

��� HANDLE filehandle;�������� // Handle for searching

��� AnsiString szFileName, szDir;

��� szDir = IncludeTrailingPathDelimiter(Dir);� // 確保最後有反斜線����



��� filehandle = FindFirstFile((szDir + "*.*").c_str(), &filedata);� // 因為我們要包含子目錄,所以要用 *.*,不然直接用 *.url 就行了

��� if (filehandle != INVALID_HANDLE_VALUE)

��� {

������� do

������� {

����������� /* 不處理隱藏檔及 . 跟 .. */

����������� if ((filedata.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0 ||

��������������� strcmp(filedata.cFileName, ".") == 0 ||

��������������� strcmp(filedata.cFileName, "..") == 0)

��������������� continue;

����������� /* 若是資料夾 */

����������� if ((filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)

����������� {

��������������� szFileName = szDir + AnsiString(filedata.cFileName);�// 資料夾完整路徑

��������������� Application->ProcessMessages();

��������������� LoadFavorite(szFileName); // 遞迴找下一層目錄

����������� }

����������� else if (ExtractFileExt(filedata.cFileName).LowerCase() == ".url")�// 若找到的檔案的副檔名是 .url

����������� {

��������������� szFileName = szDir + AnsiString(filedata.cFileName);

��������������� sList->Add(szFileName);� // 將完整路徑加到 sList 裡頭

��������������� Application->ProcessMessages();

����������� }

������� } while (FindNextFile(filehandle, &filedata));

������� FindClose(filehandle);

��� }

}


Posted by Nelson at 痞客邦 PIXNET Comments(0) Trackback(0) Hits(1435)

我們可以透過 ComponentCount 來掃瞄 Form 底下的所有元件,進而控制這些元件,例如底下這個 sample code 可以把 Form 底下的 Edit 元件一口氣改掉。

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

{

� � if (Components[i]->ClassNameIs("TEdit"))

� � � � ((TEdit *)Components[i])->Text = "我被改了";

}



那若是要改某個元件底下的子元件呢? 例如要改 GroupBox 裡頭的所有 Label 要怎辦呢? 這時就要用到 ControlCount 了。

for (int i = 0; i < GroupBox1->ControlCount; ++i)

{

� � if (GroupBox1->Controls[i]->ClassNameIs("TLabel"))

� � � � ((TLabel *)GroupBox1->Controls[i])->Caption = "我被改了";

}


這樣就可以了~


再補上一招,若是要修改名稱有固定規則的元件又要怎麼做呢? 例如要修改 Edit1~Edit10 的文字內容。這時我們可以叫出 FindComponent() 來幫忙

for (int i = 1; i <= 10; ++i)
{
� � ((TEdit *)FindComponent("Edit" + IntToStr(i)))->Text = "我被改了";
}

類似地,也可以用 FindChildControl() 找到子元件

for (int i = 0; i < 10; ++i)
{
��� ((TEdit *)GroupBox1->FindChildControl("Edit" + IntToStr(i)))->Text = "我被改了";
}


戲法人人會變,巧妙各有不同。透過以上三個例子,應該可以滿足大部分需要大量修改元件屬性的需求了。至於怎麼應用,就看個人的心思啦 :)






Posted by Nelson at 痞客邦 PIXNET Comments(3) Trackback(0) Hits(1237)

void __fastcall TForm1::ListBox1MouseUp(TObject *Sender,
����� TMouseButton Button, TShiftState Shift, int X, int Y)
{
��� if (Button == mbRight)
��� {
������� ListBox1->ItemIndex = ListBox1->ItemAtPos(Point(X,Y), true);
��� }
}


Posted by Nelson at 痞客邦 PIXNET Comments(0) Trackback(0) Hits(693)

void __fastcall TformMain::CheckInstance(void)
{
��� Application->Title = Caption;
��� HANDLE PrevInstHandle;
��� Mutex = OpenMutex(SYNCHRONIZE, false, Application->Title.c_str());

�� �/* 檢查是否有重複執行 */
��� if (Mutex != NULL)
��� {
�� ��� �/*
�� ��� � *�� �若有重複,把之前的程式帶到前景,
�� ��� � *�� �再關閉本身
�� ��� � */
������� String AppTitle = Application->Title;
������� Application->ShowMainForm = false;
������� SetWindowText(Application->Handle, NULL);
������� PrevInstHandle = FindWindow("TApplication", AppTitle.c_str());
������� if (IsIconic(PrevInstHandle))
����������� ShowWindow(PrevInstHandle, SW_RESTORE);
������� else
������� {
����������� BringWindowToTop(PrevInstHandle);
����������� SetForegroundWindow(PrevInstHandle);
������� }
������� Application->Terminate();
��� }
��� else
������� Mutex = CreateMutex(NULL, false, Application->Title.c_str());
}
//---------------------------------------------------------------------------
void __fastcall TformMain::FormClose(TObject *Sender, TCloseAction &Action)
{
��� ReleaseMutex(Mutex);��� // 記得在結束程式前,要釋放為了避免重複執行而產生的 Mutex
}


Posted by Nelson at 痞客邦 PIXNET Comments(0) Trackback(0) Hits(1033)

有時候你可能會需要讓使用者在 Memo 貼上文字之後自動換行。要達到這樣的效果有幾種方法辦得到。第一種是在 OnMouseUp event 裡頭偵測使用者是否按下了 Ctrl+V。不過這方法並不是很好,所以在這裡我要介紹第二種方法。第二種方法是直接偵測送到 MemoWM_PASTE 訊息。



// 在 Unit1.h

private:��� // User declarations

��� TWndMethod OldMemoProc;

��� void __fastcall NewMemoProc(TMessage &Message);





// 在 Unit1.cpp

void __fastcall TForm1::NewMemoProc(TMessage &Message)

{

��� OldMemoProc(Message);

��� if (Message.Msg == WM_PASTE)��� // 若是貼上

������� Memo1->Lines->Add(""); � � �// 就自動換行

}

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

void __fastcall TForm1::FormCreate(TObject *Sender)

{

��� OldMemoProc = Memo1->WindowProc;

��� Memo1->WindowProc = NewMemoProc;

}




Posted by Nelson at 痞客邦 PIXNET Comments(0) Trackback(0) Hits(1204)

【作者】geniustom

【內文】http://delphi.ktop.com.tw/topic.asp?topic_id=59601



一般人看到【取亂數不重複】..很直接的想法就是一直取,每次取完之後再跟之前的比較..

其實這樣的效率極差!取N個不重複的亂數需要做N階乘次比對..

有學過資料結構的應該都知道.在複雜度裡面..N階乘算是【極差】

取亂數可以使用洗牌法..

意思就是說..

1..假設剛買來的牌..有52張..分別照順序排好...

2..你只需要把52張牌全部攤開..隨便選2張交換...

3..交換52次之後..可以做出很平均的亂數處理..

所以..如果要產生A~B不重複的亂數.演算法如下..

var

Nums: array of integer;

i,j,k,temp: integer;

begin

randomize; 灑下亂數種子

setlength(Nums,B-A) //產生B-A張牌

for i := 0 to (B-A)-1 do

Nums[i] := i; //產生一副新牌..都是照順序排好的

for i := 0 to (B-A)-1 do

begin

j := random(B-A+1); //隨便選兩張牌(索引) 取出0~(B-A)的亂數

k := random(B-A+1);

temp := Nums[j]; //交換兩張隨便取的牌

Nums[j] := Nums[k];

Nums[k] := temp;

end;

for i := 0 to (B-A)-1 do

Nums[j]:=Nums[j]+A; //最後..把這邊的排全部變成A~B的值

end;



假如您要取5個..

那只要選Nums[0]~Nums[4]..就是一組很漂亮的亂數..

效率極佳..只需要O(n)次...

而一般人想到那種差勁的演算法..差不多到100..程式就要死當了


Posted by Nelson at 痞客邦 PIXNET Comments(0) Trackback(0) Hits(1940)

int MessageBox(const char* Text, const char* Caption, int Flags);

Text : 您要顯示的訊息

Caption : MessageBox 的標題

Flags : 設定要顯示哪些東西



以下是 Flags 的設定值

0 (MB_OK) : OK按鈕

1 (MB_OKCANCEL) : OK, Cancel按鈕

2 (MB_ABORTRETRYIGNORE) : Abort, Retry, Ignore按鈕

3 (MB_YESNOCANCEL) : Yes, No, Cancel按鈕

4 (MB_YESNO) : Yes, No按鈕

5 (MB_RETRYCANCEL) : Retry, Cancel按鈕

16 : 圖示

32 : 圖示

48 : 圖示

64 : 圖示

0 :�� 將第一按鈕設為預設

256 : 將第二按鈕設為預設

512 : 將第三按鈕設為預設


將數字加起來就可以得到你要的樣式了。





以下是它的回傳值,代表按了什麼按鈕,您可根據回傳值做些相應的動作。

1 (IDOK)

2 (IDCANCEL)

3 (IDABORT)

4 (IDRETRY)

5 (IDIGNORE)

6 (IDYES)

7 (IDNO)



//這是多行訊息。


String s = "這是測試1\n";

s += "這是測試2";

Application->MessageBox(s.c_str(), "Test", 32+3);� //最後的Flag可用數字組合.


Posted by Nelson at 痞客邦 PIXNET Comments(1) Trackback(0) Hits(2714)

1 2 3 4