程式設計物語 Programming Story

Archive for the ‘BCB經典範例’ Category

問題描述:

為了讓BCB使用其他C++編譯器產生的DLL檔案,首先使用靜態調度DLL的方式,方法為產生BCB需要的Lib檔案(使用implib MainAlgorithm.lib MainAlgorithm.dll 來產生)

包入*.lib後,在檔案開頭用
extern "C" __declspec(dllimport) int  SearchSolution(char* info);

宣告…

結果:當我們執行 迴圈:  while(SearchSolution(info)){….}  時候,且執行的東西夠大,立刻就會產生Overflow!!該怎麼解決呢?

這個問題,我解了很久,今天終於在一個大陸的網站找到解答,有趣的是,對方是問另一個完全不相干的問題,我就在想,該不會這有影響吧!一試下去!果然就靈!只能說C++Builder…我真搞不懂你啊XD…

答案….使用動態調度DLL大法!!!!

改宣告

HANDLE hdDll;

int ( *Dll_SearchSolution)(char* info);

hdDll=LoadLibrary("MainAlgorithm.dll");//使用WinAPI

Dll_SearchSolution =  (int( *)(char* info))GetProcAddress(hdDll,"SearchSolution");

接下來改使用Dll_SearchSolution 取代原先的函數!解決!

問題:

我用BCB設計了一個視窗,想讓使用者調整大小,但不希望樣式被破壞,因此想要限制使用者縮小視窗最小寬度或高度、我該怎麼設計?

笨的解法:

在FormResize事件當中限制能縮的大小,比方說:

if(Form1->Width<300) Form1->Width=300;

但這樣使用者縮視窗時後、會有震動的問題

聰明解法:

直接在初始化時後設定

Form1->Constraints->MinWidth=800;

就可以了!

昨天的方法,在輸入第一個字元為enter可能會導致出問題

另外要解的另個問題是,如果輸出超過兩行字、則會有行號判斷錯誤問題,幸好我們也找到解決方案

這邊設定字型為12,如果不是12,你在下面*19部分要調整一下

if(Key==13)
{
    suiMemo_Input->Lines->Delete(LineNum++);                  //消去最後一行
    suiMemo_Input->Lines->Append(">  "+Edit_Simulation->Text);//將訊息印出

    ToolButton1Click(Sender);
    suiMemo_Input->Lines->Append("> ");                       //並增加下一個>記號
    //if(Edit_Simulation->Top<19*10) Edit_Simulation->Top+=19;    //改變Edit位置,讓使用者以為換行
    if(suiMemo_Input->CaretPos.y<14) Edit_Simulation->Top = (suiMemo_Input->CaretPos.y-1) * 19 + 2;
    Edit_Simulation->Clear();                                 //當然,要清除掉原先內容
}
if ( Shift.Contains(ssCtrl))//最重要的部份!偵測是否有按下CTRL!
{
    if(Key==65)//A
    Edit_Simulation->SelectAll();//當ctrl+A發生時候,使用全選
    if(Key=='V')
    {       //很無聊的bug….當第一個字元為換行,則會沒有反應
            Memo1->PasteFromClipboard();
            if(Memo1->Text.Pos("\r\n")==1)  if(Memo1->Text.Pos("1."))
                Edit_Simulation->Text = (Memo1->Text.SubString(Memo1->Text.Pos("1"), Memo1->Text.Length()));
            Memo1->Clear();
    }
}

問題:

在C++Builder中,我想寫一個類似(模擬) DOS視窗的組件,有以下特性:

    每次我都只能在某一列輸入指令,指令最前面最好有個>提醒記號
    按下Enter時候,會顯示在命令列上面,並自動換下一行

答案:

事實上BCB沒有提供這樣的元件,這的確是一種遺憾。.Net也沒有,看來使用Dos命令列來輸入指令大概只能當老人的喜好,

既然沒有我們就自己寫吧!基本原理是使用Memo搭配Edit來模擬。事實上我們是在Edit上輸入命令,並輸出在Memo中

具體做法:

拉一個Memo,一個Edit,將memo的enabled設為false讓使用者無法focured,拉一個Edit,擺在適當位置。

按一下Memo的Lines,改變內容為:

Please input your data at below:
>
當然你也可以根據你的喜好改變這段文字,重點是Edit要剛好在>後面,使用者以為在Memo裡,實際輸入都在Edit中,只是每次按下Enter,會輸出訊息在Memo中…

接著輸入以下程式碼,這邊都很白話,你應該要看得懂每一行在做甚麼

int LineNum=1;
//—————————————————————————
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
LineNum = 1;
}
//—————————————————————————
void __fastcall TForm1::FormShow(TObject *Sender)
{
Edit_Simulation->SetFocus(); //讓游標聚焦在edit,好像命令列一樣
}
//—————————————————————————

void __fastcall TForm1::Edit_SimulationKeyDown(TObject *Sender, WORD &Key,
TShiftState Shift)
{
if(Key==13)
{
suiMemo_Input->Lines->Delete(LineNum++);                //消去最後一行
suiMemo_Input->Lines->Append(">"+Edit_Simulation->Text);//將訊息印出
suiMemo_Input->Lines->Append(">");                      //並增加下一個>記號
if(Edit_Simulation->Top<100) Edit_Simulation->Top+=21;  //改變Edit位置,讓使用者以為換行
Edit_Simulation->Clear();                               //當然,要清除掉原先內容
}
}
//—————————————————————————

void __fastcall TForm1::Edit_SimulationKeyPress(TObject *Sender, char &Key)
{
if(Key==13 || Key==1)      Key=0;    //消除令人困擾的訊息聲音
}
//—————————————————————————

問題:

使用BCB,我拉了一個memo元件,並設計好ctrl+A就會全選的動作,結果只要我在memo元件上按下ctrl+任何按鍵,系統喇叭都會發出噁心的咚咚聲、警告聲,很像古早系統的BEEP,我該怎麼把她消除掉?

解答:

需要攔截系統事件、改系統廣播??太麻煩了,通通不用!

開啟KeyPress事件,加入一行Code就能解決!

void __fastcall TForm1::Memo1KeyPress(TObject *Sender, char &Key)
{
if(Key<10) Key=0;
}
//—————————————————————————

問題:

在BCB中,我拉了一個Speedbutton、並且放了圖案在上面,我要怎麼樣設計成按一下按鈕、就會陷下去,在按一下會彈回來呢?改變down屬性好像沒用!

解答:

使用 Speedbutton->down沒錯,但要記得把GroupIndex設為一個>0的值

狀況分析

1. 在關閉BCB界面時會出現如下訊息:
An exception (C0000005) occurred during DllEntryPoint or DllMain in module:
c:\program files\borland\cbuilder6\Bin\idefilters60.bpl

2. 按ok後,就出現 "C++ Builder Development Environment發生問題,必須關閉,謹此致歉…"的資訊
     這時有 "除錯"/"關閉" 兩個選項

3. 承2,如果選 "關閉",會出現 "Runtime error 216 at 40009009" 的 Error 提示,按下ok就又回到 2.

4. 承2,如果選 "除錯",再關掉除錯的BCB program,才能完全關掉

解決問題的方法:
下載C++Builder 6 Update Pack 4並更新完成

不過官方下載的網址似乎已經消失 ,因此我這邊提供自己下載點的備份檔案
http://www.box.net/shared/lx4hjx63qn
(2011.04.28重新上傳)
這個 UPDATE 主要修正,安裝 UPDATE 1 和 UPDATE 2 後會產生的一些錯誤,例如:關閉程式會出現存取錯誤的訊息:

An exception(C0000005)occurred during DllEntryPoint or DllMain in module:
c:\program files\borland\cbuilder6\Bin\idefilters60.bpl

Runtime error 216 at 40009009

另外這個修正檔也更新了一些 DEPHI 7 和 BCB6 共用的一些 DLL 檔,所以若要安裝 DELHI 請在安裝完後再更新一次程式。

問題:如何用C程式語言擷取全螢幕,並輸出成BMP檔案?
   請別回答按下Print Scr XD!

解答:
void CaptureFullWindow(void)
{
    HDC  hScrDC,
hMemDC;      
    int  width, height;

    //the pointer will
save all pixel point's color value
    BYTE  *lpBitmapBits = NULL;
   
//creates a device context for the screen device
    hScrDC =
CreateDC(_T("DISPLAY"), NULL, NULL, NULL);

    //get the screen
point size
    width = GetDeviceCaps(hScrDC, HORZRES);
    height =
GetDeviceCaps(hScrDC, VERTRES);

    //creates a memory device
context (DC) compatible with the screen device(hScrDC)
    hMemDC =
CreateCompatibleDC(hScrDC);

     //initialise the struct
BITMAPINFO for the bimap infomation,
     //in order to use the
function CreateDIBSection
     // on wince os, each pixel stored by
24 bits(biBitCount=24)
     //and no compressing(biCompression=0)

   
BITMAPINFO RGB24BitsBITMAPINFO;
   
ZeroMemory(&RGB24BitsBITMAPINFO, sizeof(BITMAPINFO));
   
RGB24BitsBITMAPINFO.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   
RGB24BitsBITMAPINFO.bmiHeader.biWidth = width;
   
RGB24BitsBITMAPINFO.bmiHeader.biHeight = height;
   
RGB24BitsBITMAPINFO.bmiHeader.biPlanes = 1;
   
RGB24BitsBITMAPINFO.bmiHeader.biBitCount = 24;
    //use the function
CreateDIBSection and SelectObject
    //in order to get the bimap
pointer : lpBitmapBits
    HBITMAP hBitmap = CreateDIBSection(hMemDC,
(BITMAPINFO*)&RGB24BitsBITMAPINFO,
       DIB_RGB_COLORS, (void
**)&lpBitmapBits, NULL, 0);
    HGDIOBJ hOldBitmap =
SelectObject(hMemDC, hBitmap);

    // copy the screen dc to the
memory dc
    BitBlt(hMemDC, 0, 0, width, height, hScrDC, 0, 0,
SRCCOPY);
     //if you only want to get the every pixel color value,
   
 //you can begin here and the following part of this function will be
unuseful;
     //the following part is in order to write file;

   
 //bimap file header in order to write bmp file
   
 BITMAPFILEHEADER bmBITMAPFILEHEADER;
   
 ZeroMemory(&bmBITMAPFILEHEADER, sizeof(BITMAPFILEHEADER));
   
 bmBITMAPFILEHEADER.bfType = 0x4d42;  //bmp
   
 bmBITMAPFILEHEADER.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER);
     bmBITMAPFILEHEADER.bfSize =
bmBITMAPFILEHEADER.bfOffBits + ((width*height)*3); ///3=(24 / 8)

   
 DWORD dwNumBytes;

    HANDLE hFile = CreateFile( L"\\Storage
Card\\capture.bmp",
                      GENERIC_WRITE,
       
     (DWORD) 0, NULL, CREATE_ALWAYS,
          FILE_ATTRIBUTE_NORMAL,
NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return ;

   
WriteFile(hFile, &bmBITMAPFILEHEADER, sizeof(BITMAPFILEHEADER),
&dwNumBytes, NULL); // Write the file header
    WriteFile(hFile,
&(RGB24BitsBITMAPINFO.bmiHeader), sizeof(BITMAPINFOHEADER),
&dwNumBytes, NULL); // Write the DIB header
    WriteFile(hFile,
lpBitmapBits, 3*width*height, &dwNumBytes, NULL); //Write DIB bits
   
FlushFileBuffers(hFile);

    CloseHandle(hFile);

   
 //delete
     DeleteObject(hMemDC);
     DeleteObject(hScrDC);
   
 DeleteObject(hBitmap);
     DeleteObject(hOldBitmap);
}

問題:我有一個pcm檔案(純資料檔),我要如何使用BCB/VC++的WindowsAPI函式撥放這個PCM格式的資料

解答:
        char Example_Wave[]=
        {
                0x52,0x49,0x46,0x46,//RIFF標誌
                0x44,0x93,0x6F,0x00,//文件長度,這邊是 7312196 byte
                0x57,0x41,0x56,0x45,//Wave標誌
                0x66,0x6D,0x74,0x20,//fmt標誌
                0x10,0x00,0x00,0x00,//non
                0x03,0x00,          //格式類別
                0x02,0x00,          //channel 數量
                0x80,0xBB,0x00,0x00,//取樣頻率,這邊是bb80h = 48000
                0x00,0xDC,0x05,0x00,//波形音頻數據傳送速率,其值為通道數×每秒數據位數×每樣
                                    //本的數據位數/8。播放軟件利用此值可以估計緩衝區的大小。
                0x08,0x00,          //數據塊的調整數(按字節算的),其值為通道數×每樣本的數據位值/8。
                                    //播放軟件需要一次處理多個該值大小的字節數據,以便將其值用於緩衝區的調整。
                0x20,0x00,          //每樣本的數據位數,表示每個聲道中各個樣本的數據位數。這邊是32 bytes
                                    //如果有多個聲道,對每個聲道而言,樣本大小都一樣。
                0x64,0x61,0x74,0x61,//數據標記符”data”
                0x20,0x93,0x6F,0x00 //語音數據的長度 7312160 byte
        };
        struct WaveForm
        {
                char szRiffID[4];  // 'R','I','F','F'
                int dwRiffSize;
                char szRiffFormat[4]; // 'W','A','V','E'
                char  szFmtID[4]; // 'f','m','t',' '
                int dwFmtSize;
                short wFormatTag;
                short wChannels;
                int dwSamplesPerSec;
                int dwAvgBytesPerSec;
                short wBlockAlign;
                short wBitsPerSample;
                char szDataID[4]; // 'd','a','t','a'
                int dwDataSize;
        }*Wave;
        Wave = (struct WaveForm*) Example_Wave;

        TMemoryStream *pcm = new TMemoryStream;
        pcm->LoadFromFile(OpenDialog1->FileName);
        Wave->dwDataSize = pcm->Size;
        Wave->dwRiffSize = pcm->Size+36;

        TMemoryStream *wav2 = new TMemoryStream;
        wav2->Write(Wave,sizeof(struct WaveForm));
        wav2->Write(pcm->Memory,pcm->Size);
        PlaySound((char *)wav2->Memory, 0, SND_SYNC | SND_MEMORY);
        delete pcm;
        delete wav2;

問題:
BCB中,我想在ListView元件上新增一列資料,並設定他被選取,我該怎麼做呢?
設定temp->Selected都沒反應啊!!

解答:
        TListItem *temp = ListView1->Items->Add();
        temp->Caption = ”Test”;
        temp->Selected = true;
        temp->Focused = true;
        ListView1->SetFocus(); 即可

 但要注意囉!如果你是把ListView1放到另外一個元件上,比方說PageControl,
 則會出現BUG訊息,目前推估是bcb元件問題
 解決方式:令此元件被focued,範例:(以PageControl為例)
        suiPageControl1->ActivePageIndex = 1;
        suiPageControl1->ActivePageIndex = 0;
 (這邊ListView是放在suiPageControl1的第一個分頁)