kowala's home

kowala's home
這裡是我的學習筆記,陸續增加中。
http://kowala21.blogspot.com
顯示具有 BCB 標籤的文章。 顯示所有文章
顯示具有 BCB 標籤的文章。 顯示所有文章

2016-06-06

BCB6 - 2D實驗室 移動畫素

上一篇 2D實驗室,簡單介紹了畫素產生,我們使用了圖紙物件 TBitmap 來存放畫素。本篇接著介紹簡單地處理畫素移動,電腦螢幕的座標系統,是以左上為原點(0,0),向右x遞增,向下y遞增,如下圖左上角所示。


若我們想要圖形由右下朝左上移動,如上圖,水平x減少80個畫素,垂直y減少80個畫素,這樣就可以做到由右下朝左上移動。

好了,知道原理後該如何做?我希望在我們的實驗室中,按下move按鈕,圖形會朝左上移動,按下back按鈕,圖形會跑回來,如下圖。

那我們必須在move按鈕的按下事件中,寫右下朝左上移動,然後在back按鈕的按下事件中,寫左上朝右下移動。
觀察上圖,我們要移動綠色框所圈起來的畫素,那我們要知道綠色框的左上角點與圖紙的原點(左上角) 偏移多少畫素,綠色框的寬與高是多少畫素,然後每個畫素x-80,y-80,把它寫回圖紙物件 myLab (TBitmap物件),再把 myLab 指給Image1物件,這樣就會顯示移動的樣子了。

上述說明可以知道,為了移動這些像素,我們要知道好多參數,
綠色框偏移值
綠色框的寬與高
要移動多少畫素
...

    int ori_w;    //原圖寬
    int ori_h;    //原圖高
    int off_x;    //矩形對原點偏移x(左上點)
    int off_y;    //矩形對原點偏移y
    int box_w;    //框寬度限制
    int box_h;    //框高度限制
    int mov_x;    //tar x  矩形移動到(左上點)
    int mov_y;     //tar y

我不想直接在按鈕的事件中撰寫代碼,這會使程式看起來凌亂,我想要在事件中只寫參數,然後把參數傳遞給我們的LIB去處理,我們可以使用結構體來簡化參數的傳遞,也就是我只需傳遞結構體的指標就可以了。做法如下,

1.在 mylib.h中宣告結構體
struct coordinate{ //參數結構體宣告
    int ori_w;    //原圖寬
    int ori_h;    //原圖高
    int off_x;    //矩形對原點偏移x(左上點)
    int off_y;    //矩形對原點偏移y
    int box_w;    //框寬度限制
    int box_h;    //框高度限制
    int mov_x;    //tar x  矩形移動到(左上點)
    int mov_y;     //tar y
};

2.順便宣告結構體指標
coordinate *coor;

3.在mainfrm.cpp中,新增一個結構體變數
//new一個結構體參數
coor = new coordinate;

4.在按鈕的事件中給予座標值,呼叫函式moveTo(),把結構體指標 coor 及圖紙物件指標 myLab 傳進去,移動處理後,再把 myLab 指給Image1物件。

//move 按鈕的事件 右下朝左上
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    coor->ori_w=640;
    coor->ori_h=480;
    coor->off_x=240;    //矩形對原點偏移x(左上點)
    coor->off_y=180;    //矩形對原點偏移y
    coor->box_w=160;
    coor->box_h=120;
    coor->mov_x=160;    //tar x  = off_x-80
    coor->mov_y=100;     //tar y = off_y-80
    moveTo(myLab,coor);
    Image1->Picture->Bitmap=myLab;
}

//back 按鈕的事件 左上朝右下
void __fastcall TForm1::Button3Click(TObject *Sender)
{
    coor->ori_w=640;
    coor->ori_h=480;
    coor->off_x=160;    //矩形對原點偏移x(左上點)
    coor->off_y=100;    //矩形對原點偏移y
    coor->box_w=160;
    coor->box_h=120;
    coor->mov_x=240;    //tar x  = off_x+80
    coor->mov_y=180;     //tar y = off_y+80
    moveTo(myLab,coor);
    Image1->Picture->Bitmap=myLab;
}

在 mylib.h中,移動處理函式moveTo()代碼。
//move to
void moveTo(Graphics::TBitmap *scr,coordinate *co){
    Graphics::TBitmap *tmp;//開一塊 mem
    tmp = new Graphics::TBitmap();
    tmp->PixelFormat = pf24bit; //bmp
    tmp->Height = co->ori_h;//圖紙 h
    tmp->Width = co->ori_w;//圖紙 w
    int i,j;
    int len=co->ori_w*3;//line = (byte*) {B,G,R},{B,G,R}...
    //設定底色
    for(j=0;j<co->ori_h;j++){//initial value
        memset(tmp->ScanLine[j],clBlack,len);//clBlack=0=0x00,clWhite=255=0xff
    }
    //開始複製 moveto tmp
    for(i=0;i<co->box_w;i++){
        for(j=0;j<co->box_h;j++){
            tmp->Canvas->Pixels[i+co->mov_x][j+co->mov_y] =
            scr->Canvas->Pixels[i+co->off_x][j+co->off_y];
        }
    }
    //覆蓋回去 scr
    for(j=0;j<co->ori_h;j++){
        memcpy(scr->ScanLine[j],tmp->ScanLine[j],len);
    }
    delete tmp;
}

這樣就完成了

範例程式 IMGLab.rar

2016-04-05

BCB6 - 2D實驗室

本篇就是開一塊記憶體,隨便塗鴉,然後顯示出來,主要是做個環境來測試一些繪圖演算法,當然,你要當作秀圖機,開圖檔也可以的。

首先用 BCB 開一個 vcl 專案,詳細請參考前面文章
BCB6 視窗程式入門
http://kowala21.blogspot.tw/2013/01/bcb6.html

接著新增兩個按鈕,及一個 TImage 物件

把 TImage 物件屬性改成
Height 480
Width 640
這就是我們的工作區,但它現在是空的,我們還要新增TBitmap 物件,並指給它。
我們先新增個 mylib.h ,這樣會使程式看起來較簡潔。
 在專案右鍵,然後新增個 h檔,再改檔名為 mylib.h

把它引入, #include "mylib.h"
我們可以新增個圖紙物件 TBitmap,並指給TImage 物件,並為它設定屬性,指定底色。
看起來就像這樣。
這樣看起來很單調,為它加一些其他東西, 我希望能在 mylib.h 中完成,所以必須寫個函式,把 TBitmap 物件傳進去。

 然後我們可以在 mylib.h 中為所欲為,我為它加了框,畫了X,順便寫幾個字。

mylib.h

code如下
void initSCR(Graphics::TBitmap *buf){
    int w,h,cx,cy,left, top, right, bottom;
    //先在中間畫個框 160*120 TRect(left, top, right, bottom)
    buf->Canvas->Pen->Color = clGreen;//綠色
    buf->Canvas->Brush->Style = bsClear;//框中間透明 Rectangle
    h=buf->Height;//480 工作區寬度
    w=buf->Width;//640 工作區高度
    cx=w/2;    cy=h/2;    //320*240 中心點
    left=cx-(160/2);//240
    top=cy-(120/2);//180
    right=cx+(160/2);//400
    bottom=cy+(120/2);//300
    buf->Canvas->Rectangle(TRect(left,top,right,bottom));//開始畫
    //中間畫 X,用描點的畫
    buf->Canvas->Pixels[cx-3][cy-3] = clWhite;
    buf->Canvas->Pixels[cx-2][cy-2] = clWhite;
    buf->Canvas->Pixels[cx-1][cy-1] = clWhite;
    buf->Canvas->Pixels[cx][cy] = clWhite;//center point (320,240)
    buf->Canvas->Pixels[cx+1][cy+1] = clWhite;
    buf->Canvas->Pixels[cx+2][cy+2] = clWhite;
    buf->Canvas->Pixels[cx+3][cy+3] = clWhite;

    buf->Canvas->Pixels[cx-3][cy+3] = clWhite;
    buf->Canvas->Pixels[cx-2][cy+2] = clWhite;
    buf->Canvas->Pixels[cx-1][cy+1] = clWhite;
    buf->Canvas->Pixels[cx][cy] = clWhite;
    buf->Canvas->Pixels[cx+1][cy-1] = clWhite;
    buf->Canvas->Pixels[cx+2][cy-2] = clWhite;
    buf->Canvas->Pixels[cx+3][cy-3] = clWhite;
    //再加個字
    buf->Canvas->Brush->Color = clGreen;//background color
    buf->Canvas->Font->Color = clWhite;//font color
    buf->Canvas->Font->Size=10;
    buf->Canvas->TextOutA(left+30,top+20,"再加個字");
    buf->Canvas->Brush->Color = clBlack;//background color
    buf->Canvas->Font->Color = clYellow;//font color
    buf->Canvas->TextOutA(left+50,top+80,"不要底色");
}
mainfrm.cpp
code 如下
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "mainfrm.h"
#include "mylib.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
Graphics::TBitmap *myLab;//宣告圖紙,當工作區
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    myLab = new Graphics::TBitmap();//開一塊圖紙,當工作區
    myLab->PixelFormat = pf24bit; //bmp
    myLab->Height = 480;//圖紙 h
    myLab->Width = 640;//圖紙 w
    //設定底色
    myLab->Canvas->Brush->Color = clBlack;//background = clBlack
    myLab->Canvas->FloodFill(0,0,clBlack,fsBorder);//fsSurface,fsBorder

    //把物件傳進去
    initSCR(myLab);

    //指給Image1物件
    Form1->Image1->Picture->Bitmap=myLab;

}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    this->Close();
}
//---------------------------------------------------------------------------

這樣就是一個簡單實驗室了

2016-03-07

BCB6 - 在 Windows8.1 安裝 mscomm32.ocx

很多時候,我們會需要與 RS232 通訊,這時我們就需要 com 通訊元件。
通訊元件有很多第三方元件及微軟的 mscomm32,
本例是在Wwindows8.1下取得 mscomm32 與手動安裝元件。

下載  mscomm32.ocx
http://originaldll.com/file/mscomm32.ocx/7698.html



上圖右下角按鈕,兩個都可以,按下後輸入隨機碼下載。


解壓縮可得到一個元件,只有一個。

mscomm32.ocx

接著是安裝 mscomm32 元件到 Windows8.1

1.複製 mscomm32.ocx
開檔案總管,複製 mscomm32.ocx 到 C:\Windows\SysWOW64


2.安裝 mscomm32.ocx
在視窗中,開啟目錄 C:\Windows\SysWOW64
找到 cmd.exe ,右鍵,以管理員身分執行,
一定要用管理員身分,否則權限不夠,會失敗。

執行下列命令
cd C:\Windows\SysWOW64

先移除註冊
regsvr32 /u MSCOMM32.OCX
再註冊
regsvr32 MSCOMM32.OCX
完成,試一下,OK

Dropbox 下載 mscomm32.ocx

2016-02-13

BCB6 EditorLineEnds.ttr issue

今天看到一個不錯的小程式範例 ColorFormat,可以查顏色代碼,很方便,哪裡知道,windows8.1很不給力,BCB一直出問題,最後,終於解決了,雖不滿意,尚可接受。

可愛的小程式  ColorFormat (click to see source code)
http://www.functionx.com/bcb/applications/colorformat.htm


上面附上已完成的 ColorFormat,調好顏色,按下按鈕,就會把顏色代碼複製到剪貼簿,然後按 Ctrl + v就可以叫出來貼上,也可以右邊 Numeric 數值輸入,0-255,真的很方便。

My Question
好了,推完這支程式之後,來說說我遭遇到甚麼困難,搞了一整天。
我先安裝 BCB 在 Win8.1,完成之後,開個專案,關掉 BCB,要再開啟時,悲劇了,一直錯誤,無法開啟,跳出如下對話。



重新開機又可執行一次 BCB,經過 Google 查詢,發現很多人都有這問題,指向微軟更新包的錯誤,而且到現在還沒改善。

BCB執行時會建立一個檔 EditorLineEnds.ttr,在 windows temp 目錄中,奇怪的是,它會被 System 開啟,然後就不放手,以至於 BCB 要再次執行時,無法再建立該檔,就一直產生錯誤,刪也刪不掉,因為 INUSE。


這很可惡,總不能執行一次就重開機一次吧,後來繼續找解決方案,發現大家的解法就是改檔名,但仍然刪不掉,不過卻可以執行 BCB 而不用重開機了。

國外有人是寫成批次檔來改檔名,也有寫成執行檔供人下載,但我試過,改檔名部分有一些日期會產生非法字元" / "會失敗,所以繼續研究一下,在批次檔中如何改檔名可以不重複,還是要取日期+時間,到分鐘就好,改寫如下,它主要就是把那個作怪的檔

C:\Users\myCon\AppData\Local\Temp\EditorLineEnds.ttr

改檔名

EditorLineEnds2016-2-13.4.33.ttr

然後做一個目錄,全部集中丟裏頭,這樣 BCB 就可以重複執行了,就是執行前,先執行這個批次檔,處理掉這個作怪的檔,然後再執行 BCB。

批次檔 bcb.bat 請自行存成 bcb.bat,並用最高權限執行
SET /A yy=%date:~0,4%
SET /A mm=%date:~5,2%
SET /A dd=%date:~8,2%
SET dt=%yy%-%mm%-%dd%
@echo %date% = %dt%

SET /A Hou=%time:~0,2%
SET /A Min=%time:~3,2%
SET /A Sec=%time:~6,2%
SET /A Ms=%time:~9,2%*10
SET tt=%Hou%.%Min%
@echo 時間 %time% = %tt%

SET dttt=%dt%.%tt%
@echo 日期+時間 %dttt%

C:
cd %Temp%

if exist "EditorLineEnds.ttr" (
   ren EditorLineEnds.ttr EditorLineEnds%dttt%.ttr
) else (  
   goto runbcb  
)
if exist "dzEditorLineEndsFix" (
   MOVE "EditorLineEnds%dttt%.ttr" "dzEditorLineEndsFix"
) else (
   md "dzEditorLineEndsFix"
   MOVE "EditorLineEnds%dttt%.ttr" "dzEditorLineEndsFix"
)
:runbcb
mshta "javascript:alert('SUCCESS MOVE EditorLineEnds.ttr that you can run BCB fine.');close()"


這是在 Win8.1環境下測試,其他板沒測過。

說明:

SET /A yy=%date:~0,4%
SET /A mm=%date:~5,2%
SET /A dd=%date:~8,2%
SET dt=%yy%-%mm%-%dd%
@echo %date% = %dt%

這是取系統日期,然後改成合法字元組合
/A 表示數值,這樣可以解決空白問題

date = 2016/02/13 週六

經過重新組合後,會變成

2016-2-13

接著是時間

SET /A Hou=%time:~0,2%
SET /A Min=%time:~3,2%
SET /A Sec=%time:~6,2%
SET /A Ms=%time:~9,2%*10
SET tt=%Hou%.%Min%
@echo 時間 %time% = %tt%

time =   5:40:29.85

經過重新組合後,會變成

5.40

再把這兩個合起來

SET dttt=%dt%.%tt%

2016-2-13.5.40

然後改檔名

EditorLineEnds.ttr

EditorLineEnds2016-2-13.5.40.ttr

接著檢查存放目錄是否存在?不存在就做一個
然後搬移進去,這樣就完成了。

不過,還是刪不掉,不曉得要怎麼把 inuse 解除,如果你知道的話,請留言告訴我怎麼做,謝謝!

2013-05-26

BCB6 字串處理

BCB 本身提供一種字串形態 UnicodeString 很好用,也很容易轉型到其它型態,如 string, char... 等等,但本篇是要介紹古老的 std::string 用法,主要是用在函式間傳遞,理由是。。。我用習慣了 = =

以下分為兩個部分,第一是如何把字串傳址進去函式,然後函式幫您處理好,也不用還您,您就可以直接使用。
第二部分則是再進階,假如一個字串不夠用,那我就傳回一個字串陣列,這樣就夠酷吧,也許您可以再修改一下,就可以傳回自定義的結構資料。

先來看看結果,我只截取 API 上的 Memo 畫面,雖然有點醜,但不影響閱讀及程式的正確性。


第一部分、如何把字串傳址進去函式


第二部分、傳回一個字串陣列


最後,我還是把程式碼放在下面,方便複製使用。當然,Memo1 就是 BCB6 提供的文字集物件,這我就不說明了。

呼叫部分
//------------------------------------
    //測試字串傳址
    string str1;
    strTest1(str1);//傳址
    Memo1->Lines->Add(str1.c_str());

    //測試傳回字串陣列
    string *str2;//字串陣列
    str2=strTest2();//測試傳回字串陣列
    Memo1->Lines->Add(str2[0].c_str());
    Memo1->Lines->Add(str2[1].c_str());
    Memo1->Lines->Add(str2[2].c_str());
//-------------------------------------

函式部分
//--------------------------------------------------------------------
//測試字串傳址
void strTest1(string &str){
    str="測試字串傳址...";
}
//測試傳回字串陣列
typedef string * strArr;//給陣列傳回用,直接宣告編譯不會過
strArr strTest2(){
    string ss="測試傳回字串陣列...";
    string *str = new string[3];
    str[0]= "0:" ; str[0]+= ss;
    str[1]= "1:" ; str[1]+= "typedef string * strArr;";
    str[2]= "2:" ; str[2]+= "給陣列傳回用,直接宣告編譯不會過.";
    return str;
}
//--------------------------------------------------------------------

結果當然是秀出下面這樣

測試字串傳址...
0:測試傳回字串陣列...
1:typedef string * strArr;
2:給陣列傳回用,直接宣告編譯不會過.

2013-01-19

BCB6 視窗程式入門

BCB6 全名是 CodeGear™ C++Builder® 2009,網路上都稱 BCB6,所以這裡也稱它為BCB6 好了。

它是目前最簡單入手的視窗版 C++ IDE,這裡就簡單的開個視窗程式來示範使用它,並且定位為可發行的範例,所謂可發行就是使用者拿到就可以使用的意思,不用再找 LIB, DLL...都把它包起來成一個檔,並且換上我們自己的 icon,下面僅僅簡單示範一個按鈕物件使用,主要是介紹從專案到完成編譯。

 這裡假設您已經擁有BCB6並且安裝完成,讓我們開始。

開啟一個專案
File->New->VCL ...

修改 Title

禁止最大化最小化按鈕

專案改名子

 加入自己的 icon,須先準備好於資料夾中

另存新檔,把 untitle 改為 mainfrm

專案選項設定,把 Lib,Dll 等包成一個執行檔,
這樣才不會在執行期,跳出缺少 xx Dll 的錯誤。

設定執行檔的圖示,須事先準備好。

 把專按存在某個地方,我是在桌面開個資料夾來放。
先 RUN 一次,再關掉專案,它會問你要不要存檔,按 Yes,
然後指向我們準備好的目錄,按存檔,這樣就完成了。

 再重新開啟專案,點兩下 findMatch.cbproj 檔,BCB6 就會幫你開啟。
現在來加個物件,加個按鈕,用來離開視窗。

 run 看看,會不會動。

剛剛忘記指定開啟位置,就指定在桌面中央。

這樣就完成了,不難吧。