#
CCSprite的動作總結(jié)
1) CCAction如果是用具體類的actionWithFile(.....)或類似這樣的接口的,則系統(tǒng)默認(rèn)都是有自動維護(hù)引用計數(shù)的。即:這類對象創(chuàng)建出來后我們不需要釋放。 2) CCSprite::runAction()接口請一定要與CCSprite::stopAction()或CCSprite::stopAllActions()配合使用。 3) CCSprite在執(zhí)行CCMoveTo動作時,此時如果再對其設(shè)置幀動畫動作,則這兩個動作將是會共存執(zhí)行的。 ------ 以上3點很重要。
在介紹前,先介紹說幾點: 像opengl、directx是沒有自帶界面的,不過cocos可以為我們創(chuàng)建一個主界面,以用于顯示游戲場景等。該主界面由CCDirector類實例實現(xiàn)。 cocos2d中所有需要用到的類,基本上都繼承自CCObject類。它維護(hù)一個引用計數(shù)。所有從CCObject出來的類,都可以添加到自動釋放池中進(jìn)行自動維護(hù)。(與objective-c中的對象有點類似) 多數(shù)情況下,我們使用的對象,還是從CCNode出來的。CCNode是繼承自CCObject的一個類。
下面簡要介紹下各個主要類的功能 1) CCDirector 主要功能一:負(fù)責(zé)生成一個游戲主界面及游戲的初始化并。并在該界面上,渲染游戲場景。 主要功能二:負(fù)責(zé)控制各游戲場景間的相互切換。 主要功能三:負(fù)責(zé)初始化設(shè)置游戲的一些重要屬性。如:游戲渲染的幀率。游戲視窗的尺寸(即:960 X 640 還是 480 X 320等) 主要功能四:負(fù)責(zé)清空游戲中的緩存數(shù)據(jù)(個人認(rèn)為這個還是很重要的。因為到了手機上的游戲,硬內(nèi)存不多,及時清除是很有必要的) 注意:該對象是單實例的,不需要用戶維護(hù)。
2) CCScene 游戲中的場景類。當(dāng)程序啟動后,必須要為其設(shè)置一個場景,然后所有的對象在場景中場景。 主要功能:負(fù)責(zé)接收游戲中的任何對象。并將它們展現(xiàn)出來(如果可以展現(xiàn)的話,如:CCSprite等) 習(xí)慣上,用其維護(hù)多個的CCLayer
3) CCLayer 游戲中的層。習(xí)慣上,用其對資源展現(xiàn)進(jìn)行布局管理。
4) CCSprite 游戲中的精靈對象。游戲中,必不可少的。會用到許多的可視對象。這些,多數(shù)都是精靈對象。
5) CCTargetedTouchDelegate 觸摸響應(yīng)類。提供響應(yīng)觸摸響應(yīng)開始結(jié)束、觸摸移動以及取消觸摸幾個接口。多是需要在其派生類中進(jìn)行具體實現(xiàn)。如:一個精靈, 可支持觸摸功能,則它需要自行實現(xiàn)這些接口。
以上只是簡單介紹cocos2d中的幾個較為主要及常用的類。初學(xué),如有介紹不對的,請大家不吝指點。共同學(xué)習(xí),共同進(jìn)步。
編程時在C中需要用的類似Java的Split函數(shù)來解析一個長字符串,分割成子段使用,查函數(shù)庫發(fā)現(xiàn)有strtok可用,看了示例卻對它的用法有些疑惑為什么傳值是NULL,于是上網(wǎng)查資料,找到這篇包含strtok函數(shù)源碼的解釋,轉(zhuǎn)過來學(xué)習(xí),仔細(xì)研讀收獲良多。
查函數(shù)庫看到的strtok的解釋和示例:
strtok
Syntax: #include <cstring> char *strtok( char *str1, const char *str2 );
The strtok() function returns a pointer to the next "token" in str1, where str2 contains the delimiters that determine the token. strtok() returns NULL if no token is found. In order to convert a string to tokens, the first call to strtok() should have str1 point to the string to be tokenized. All calls after this should have str1 be NULL.
For example: char str[] = "now # is the time for all # good men to come to the # aid of their country"; char delims[] = "#"; char *result = NULL; result = strtok( str, delims ); while( result != NULL ) { printf( "result is /"%s/"/n", result ); result = strtok( NULL, delims ); }
The above code will display the following output: result is "now " result is " is the time for all " result is " good men to come to the " result is " aid of their country"
下面是查到的網(wǎng)絡(luò)文章對源碼的解釋:
原型:char * strtok(char * s,const char * ct)
用途:在s中找出以ct中的字符為分隔的字符串,即是源串中除去了含有分隔串中的所有字符后余下的一段段的字符串,每調(diào)用一次找到一串,找不到則返回空串。第一次調(diào)用必須傳給它有效的字符串,第二次傳NULL就可以了,每次調(diào)用返回找到的子串的時候都會把源串中該子串的尾部字符(原來是搜索串中的某一字符)修改成'/0'字符返回值為每次調(diào)用得到的字串。
下面看一下它的使用
char sbody[]= "Presetptz/r/nPreset1=hello/r/nPreset2=ttttt/r/nend/r/n";
///char *pbody= "Presetptz/r/nPreset1=hello/r/nPreset2=ttttt/r/nend/r/n";//errror char except[] = "12/r/n"; char *ptoken = NULL; ptoken = strtok(sbody,except); while(NULL!=ptoken) { printf("%s/n",ptoken); ptoken = strtok(NULL,except); }
輸出為: Presetptz Preset =hello Preset =ttttt end 下面我們看一下它的源碼:
char *___strtok;//關(guān)鍵這個全局指針變量
char * strtok(char * s,const char * ct) { char *sbegin, *send; sbegin = s ? s : ___strtok;//不等于NULL用原始字符串,否則用___strtok if (!sbegin) { return NULL;//結(jié)尾 } sbegin += strspn(sbegin,ct);// if (*sbegin == '/0') { ___strtok = NULL; return( NULL ); } send = strpbrk( sbegin, ct); if (send && *send != '/0') *send++ = '/0'; ___strtok = send; return (sbegin); }
其中: ssize_t strspn(const char* s,char*accept)// 返回accept中任一字符在s中第一次出現(xiàn)的位置
char * strpbrk(const char * cs,const char * ct)//返回指向ct中任一字符在cs中第一次出現(xiàn)的位置
這個函數(shù)不難分析,___strtok指針指向除去第一個有效字串后面的位置,到這里我們應(yīng)該清楚為什么第二次調(diào)用時只要傳NULL就可以了,當(dāng)然這里也暴露了它的缺點,就是說不能有兩個線程同時使用strtok否則就會出現(xiàn)錯誤。還有就是我在使用這個函數(shù)時碰到的問題,如上面的代碼如果我把sbody換成 pbody,則編譯沒有問題,運行時就會出錯,為什么?還是自己的基本功不扎實,pbody在是個靜態(tài)字符串,說白了,它是在編譯時就已經(jīng)賦值而且相當(dāng)于是一個const常量,不能被修改,而strtok是需要修改字符串的,所以產(chǎn)生問題不足為奇。
原文出處:http://www.cnblogs.com/finallyliuyu/archive/2010/10/11/1848130.html
一、C++中不能使用random()函數(shù)
==================================================================================
本文由青松原創(chuàng)并依GPL-V2及其后續(xù)版本發(fā)放,轉(zhuǎn)載請注明出處且應(yīng)包含本行聲明。
C++中常用rand()函數(shù)生成隨機數(shù),但嚴(yán)格意義上來講生成的只是偽隨機數(shù)(pseudo-random integral number)。生成隨機數(shù)時需要我們指定一個種子,如果在程序內(nèi)循環(huán),那么下一次生成隨機數(shù)時調(diào)用上一次的結(jié)果作為種子。但如果分兩次執(zhí)行程序,那么由于種子相同,生成的“隨機數(shù)”也是相同的。
在工程應(yīng)用時,我們一般將系統(tǒng)當(dāng)前時間(Unix時間)作為種子,這樣生成的隨機數(shù)更接近于實際意義上的隨機數(shù)。給一下例程如下:
#include <iostream> #include <ctime> #include <cstdlib> using namespace std;
int main() { double random(double,double); srand(unsigned(time(0))); for(int icnt = 0; icnt != 10; ++icnt) cout << "No." << icnt+1 << ": " << int(random(0,10))<< endl; return 0; }
double random(double start, double end) { return start+(end-start)*rand()/(RAND_MAX + 1.0); } /* 運行結(jié)果 * No.1: 3 * No.2: 9 * No.3: 0 * No.4: 9 * No.5: 5 * No.6: 6 * No.7: 9 * No.8: 2 * No.9: 9 * No.10: 6 */ 利用這種方法能不能得到完全意義上的隨機數(shù)呢?似乎9有點多哦?卻沒有1,4,7?!我們來做一個概率實驗,生成1000萬個隨機數(shù),看0-9這10個數(shù)出現(xiàn)的頻率是不是大致相同的。程序如下: #include <iostream> #include <ctime> #include <cstdlib> #include <iomanip> using namespace std;
int main() { double random(double,double); int a[10] = {0}; const int Gen_max = 10000000; srand(unsigned(time(0))); for(int icnt = 0; icnt != Gen_max; ++icnt) switch(int(random(0,10))) { case 0: a[0]++; break; case 1: a[1]++; break; case 2: a[2]++; break; case 3: a[3]++; break; case 4: a[4]++; break; case 5: a[5]++; break; case 6: a[6]++; break; case 7: a[7]++; break; case 8: a[8]++; break; case 9: a[9]++; break; default: cerr << "Error!" << endl; exit(-1); } for(int icnt = 0; icnt != 10; ++icnt) cout << icnt << ": " << setw(6) << setiosflags(ios::fixed) << setprecision(2) << double(a[icnt])/Gen_max*100 << "%" << endl; return 0; }
double random(double start, double end) { return start+(end-start)*rand()/(RAND_MAX + 1.0); } /* 運行結(jié)果 * 0: 10.01% * 1: 9.99% * 2: 9.99% * 3: 9.99% * 4: 9.98% * 5: 10.01% * 6: 10.02% * 7: 10.01% * 8: 10.01% * 9: 9.99% */ 可知用這種方法得到的隨機數(shù)是滿足統(tǒng)計規(guī)律的。
另:在Linux下利用GCC編譯程序,即使我執(zhí)行了1000000次運算,是否將random函數(shù)定義了inline函數(shù)似乎對程序沒有任何影響,有理由相信,GCC已經(jīng)為我們做了優(yōu)化。但是冥冥之中我又記得要做inline優(yōu)化得加O3才行...
不行,于是我們把循環(huán)次數(shù)改為10億次,用time命令查看執(zhí)行時間: chinsung@gentoo ~/workspace/test/Debug $ time ./test 0: 10.00% 1: 10.00% 2: 10.00% 3: 10.00% 4: 10.00% 5: 10.00% 6: 10.00% 7: 10.00% 8: 10.00% 9: 10.00%
real 2m7.768s user 2m4.405s sys 0m0.038s chinsung@gentoo ~/workspace/test/Debug $ time ./test 0: 10.00% 1: 10.00% 2: 10.00% 3: 10.00% 4: 10.00% 5: 10.00% 6: 10.00% 7: 10.00% 8: 10.00% 9: 10.00%
real 2m7.269s user 2m4.077s sys 0m0.025s
前一次為進(jìn)行inline優(yōu)化的情形,后一次為沒有作inline優(yōu)化的情形,兩次結(jié)果相差不大,甚至各項指標(biāo)后者還要好一些,不知是何緣由...
=================================================================================
random函數(shù)不是ANSI C標(biāo)準(zhǔn),不能在gcc,vc等編譯器下編譯通過。 可改用C++下的rand函數(shù)來實現(xiàn)。 1、C++標(biāo)準(zhǔn)函數(shù)庫提供一隨機數(shù)生成器rand,返回0-RAND_MAX之間均勻分布的偽隨機整數(shù)。 RAND_MAX必須至少為32767。rand()函數(shù)不接受參數(shù),默認(rèn)以1為種子(即起始值)。 隨機數(shù)生成器總是以相同的種子開始,所以形成的偽隨機數(shù)列也相同,失去了隨機意義。(但這樣便于程序調(diào)試) 2、C++中另一函數(shù)srand(),可以指定不同的數(shù)(無符號整數(shù)變元)為種子。但是如果種子相同,偽隨機數(shù)列也相同。一個辦法是讓用戶輸入種子,但是仍然不理想。 3、 比較理想的是用變化的數(shù),比如時間來作為隨機數(shù)生成器的種子。 time的值每時每刻都不同。所以種子不同,所以,產(chǎn)生的隨機數(shù)也不同。 // C++隨機函數(shù)(VC program) #include <stdio.h> #include <iostream> #include <time.h> using namespace std; #define MAX 100 int main(int argc, char* argv[]) { srand( (unsigned)time( NULL ) );//srand()函數(shù)產(chǎn)生一個以當(dāng)前時間開始的隨機種子.應(yīng)該放在for等循環(huán)語句前面 不然要很長時間等待 for (int i=0;i<10;i++) cout<<rand()%MAX<<endl;//MAX為最大值,其隨機域為0~MAX-1 return 0; } 二、rand()的用法 rand()不需要參數(shù),它會返回一個從0到最大隨機數(shù)的任意整數(shù),最大隨機數(shù)的大小通常是固定的一個大整數(shù)。 這樣,如果你要產(chǎn)生0~10的10個整數(shù),可以表達(dá)為: int N = rand() % 11; 這樣,N的值就是一個0~10的隨機數(shù),如果要產(chǎn)生1~10,則是這樣: int N = 1 + rand() % 10; 總結(jié)來說,可以表示為: a + rand() % n 其中的a是起始值,n是整數(shù)的范圍。 a + rand() % (b-a+1) 就表示 a~b之間的一個隨機數(shù)若要0~1的小數(shù),則可以先取得0~10的整數(shù),然后均除以10即可得到隨機到十分位的10個隨機小數(shù),若要得到隨機到百分位的隨機小數(shù),則需要先得到0~100的10個整數(shù),然后均除以100,其它情況依此類推。 通常rand()產(chǎn)生的隨機數(shù)在每次運行的時候都是與上一次相同的,這是有意這樣設(shè)計的,是為了便于程序的調(diào)試。若要產(chǎn)生每次不同的隨機數(shù),可以使用srand( seed )函數(shù)進(jìn)行隨機化,隨著seed的不同,就能夠產(chǎn)生不同的隨機數(shù)。 如大家所說,還可以包含time.h頭文件,然后使用srand(time(0))來使用當(dāng)前時間使隨機數(shù)發(fā)生器隨機化,這樣就可以保證每兩次運行時可以得到不同的隨機數(shù)序列(只要兩次運行的間隔超過1秒)。
原諒轉(zhuǎn)載自:http://lukas06.blog.sohu.com/94010246.html
C++編譯器在生成DLL時,會對導(dǎo)出函數(shù)進(jìn)行名字改編,并且不同的編譯器使用的改編規(guī)則不一樣,因此改編的名字后的名字是不一樣的。因此,如果利用不同的分別生成DLL文件和訪問DLL文件的客戶端,那么后者在訪問該DLL文件的時候就會出現(xiàn)問題。例如:使用C++編寫了一個DLL,而使用C語言編寫的客戶端進(jìn)行訪問就會出現(xiàn)問題。由于C++編譯器已經(jīng)對該導(dǎo)出函數(shù)名字進(jìn)行了改編,所以用C語言編寫的客戶端就找不到DLL的導(dǎo)出函數(shù)。這就是DLL導(dǎo)出函數(shù)的名字改編問題。
如果希望動態(tài)鏈接庫文件在編譯時,導(dǎo)出函數(shù)的名稱不要發(fā)生改變,那么在定義導(dǎo)出函數(shù)時,需要加上限定符:extern "C"。注意:雙引號中的“C”一定要大寫。
例如:Dll1.h頭文件 #ifdef DLL1_API #else #define DLL1_API extern "C" _declspec(dllimport) #endif
DLL1_API int add(int a,int b); DLL1_API int subtract(int a,int b);
Dll1.cpp源文件 #define DLL1_API extern "C" _declspec(dllexport) #include "Dll1.h"
int add(int a,int b) { return a+b; } int subtract(int a,int b) { return a-b; } 這樣利用dumpbin工具可以查看Dll2.dll的導(dǎo)出函數(shù),>dumpbin -exports Dll2.dll,可以發(fā)現(xiàn)名字沒有被改編。
利用限定符extern "C"可以解決C++和C語言之間相互調(diào)用時函數(shù)命名的問題。但是這種方法有一個缺陷:就是不能用于導(dǎo)出一個類的成員函數(shù),而只能用于導(dǎo)出全局函數(shù)這種情況。
但是還有一個問題是,如果使用了標(biāo)準(zhǔn)調(diào)用約定,也就是pascal調(diào)用約定,WINAPI調(diào)用約定:_stdcall,此時即使使用了extern "C",仍然會出現(xiàn)導(dǎo)出函數(shù)名字被改編的問題。例如:使用C語言編寫一個DLL文件,而客戶端使用Delphi進(jìn)行編寫,那么在編寫導(dǎo)出函數(shù)時,應(yīng)該指定其使用標(biāo)準(zhǔn)的函數(shù)調(diào)用約定。此時,就會出現(xiàn)問題,即C語言編寫的DLL文件的導(dǎo)出函數(shù)發(fā)生了名字改編。在這種情況下,可以使用一個稱為模塊定義文件(DEF)的方式解決名字改編問題。 例如:Dll2.def LIBRARY
EXPORTS add subtract 如果想使用與源文件中定義的不一樣的函數(shù)名,可以按照以下語法:entryname=internalname 其中,entryname是要導(dǎo)出的符號名,而internalname是DLL中將要導(dǎo)出的函數(shù)名。
示例:
LIBRARY "VerifyLocalResType"
EXPORTS
VerifyDDSSize VerifyDDSType VerifyTGASize VerifyTGAType
無意中看到的一篇,挺不錯的。呵呵。收藏下。
c++字符大小寫轉(zhuǎn)換
原為某著名軟件公司試題,大意如下:請實現(xiàn)以下兩個函數(shù):char toupper(char c); char tolower(char c); 分別用于將傳入的字母轉(zhuǎn)為大寫和小寫。兩個函數(shù)傳入的參數(shù)取值范圍都是[a-zA-Z],并且為ASCII編碼,實現(xiàn)時不用檢查參數(shù)合法性。兩個函數(shù)的實現(xiàn)不能使用任何形式的分支、跳轉(zhuǎn)等類型的語句或指令(特別說明:C/C++的條件操作符?:也是分支指令的一種形式,故而不能使用)。請盡可能多的寫出你知道的辦法。
分析解決:此題比較特別,限制嚴(yán)格,根據(jù)題目要求,排除if else、for、while、do while、switch case、?:外,能使用的語句就只有 =、+=、-=、&、|、^、++、--這些了,想要實現(xiàn)大小寫轉(zhuǎn)換,只能從這些語句中進(jìn)行選擇思考,由于字符集為ASCII編碼,且范圍明確為[a-zA-Z],我們知道,a-z對應(yīng)ASCII值為97-122,A-Z對應(yīng)ASCII為65-90,觀察這些數(shù)字,可以發(fā)現(xiàn)97-122都大于96 ,65-90都大于64且小于96,進(jìn)一步從二進(jìn)制上考慮,則發(fā)現(xiàn)所有小寫字母對應(yīng)的二進(jìn)制形式為011XXXXX,大寫字母對應(yīng)的二進(jìn)制形式為010XXXXX,一到這里,哈哈,答案就出來了,通過位運算&和|就可實現(xiàn)了。代碼描述如下
1char toupper(char c) 2{ 3 return c & 0x5F; 4} 5 6char tolower(char c) 7{ 8 //c | 0x60也行,但不太好,因為0x60會改變結(jié)果的第7位值,根據(jù)題目意思,改變第6位值為1,而其它位保持不變就夠了。 9 return c | 0x20; 10} 至于其它方法,我就沒多想了,還希望各位大俠多多分享一下哈。
#include <time.h> //* 方法一 time_t tt = time(NULL);//這句返回的只是一個時間cuo tm* t= localtime(&tt); printf("%d-%02d-%02d %02d:%02d:%02d\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); //* 方法二 SYSTEMTIME st = {0}; GetLocalTime(&st); printf("%d-%02d-%02d %02d:%02d:%02d\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
下面幾個,是網(wǎng)上找的:轉(zhuǎn)載地址: http://apps.hi.baidu.com/share/detail/17815869
個人覺得第二種還是比較實用的,而且也是最常用的~
不過當(dāng)計算算法耗時的時候,不要忘記second,不能只要用Milliseconds來減,不然后出現(xiàn)負(fù)值,若是算法耗時太長就得用minutes啦。再不然,就hours……
//方案— 優(yōu)點:僅使用C標(biāo)準(zhǔn)庫;缺點:只能精確到秒級 #include <time.h> #include <stdio.h> int main( void ) { time_t t = time(0); char tmp[64]; strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A 本年第%j天 %z",localtime(&t) ); puts( tmp ); return 0; } size_t strftime(char *strDest, size_t maxsize, const char *format, const struct tm *timeptr); 根據(jù)格式字符串生成字符串。 struct tm *localtime(const time_t *timer); 取得當(dāng)?shù)貢r間,localtime獲取的結(jié)果由結(jié)構(gòu)tm返回 返回的字符串可以依下列的格式而定: %a 星期幾的縮寫。Eg:Tue %A 星期幾的全名。 Eg: Tuesday %b 月份名稱的縮寫。 %B 月份名稱的全名。 %c 本地端日期時間較佳表示字符串。 %d 用數(shù)字表示本月的第幾天 (范圍為 00 至 31)。日期 %H 用 24 小時制數(shù)字表示小時數(shù) (范圍為 00 至 23)。 %I 用 12 小時制數(shù)字表示小時數(shù) (范圍為 01 至 12)。 %j 以數(shù)字表示當(dāng)年度的第幾天 (范圍為 001 至 366)。 %m 月份的數(shù)字 (范圍由 1 至 12)。 %M 分鐘。 %p 以 ''AM'' 或 ''PM'' 表示本地端時間。 %S 秒數(shù)。 %U 數(shù)字表示為本年度的第幾周,第一個星期由第一個周日開始。 %W 數(shù)字表示為本年度的第幾周,第一個星期由第一個周一開始。 %w 用數(shù)字表示本周的第幾天 ( 0 為周日)。 %x 不含時間的日期表示法。 %X 不含日期的時間表示法。 Eg: 15:26:30 %y 二位數(shù)字表示年份 (范圍由 00 至 99)。 %Y 完整的年份數(shù)字表示,即四位數(shù)。 Eg:2008 %Z(%z) 時區(qū)或名稱縮寫。Eg:中國標(biāo)準(zhǔn)時間 %% % 字符。
//方案二 優(yōu)點:能精確到毫秒級;缺點:使用了windows API #include <windows.h> #include <stdio.h> int main( void ) { SYSTEMTIME sys; GetLocalTime( &sys ); printf( "%4d/%02d/%02d %02d:%02d:%02d.%03d 星期%1d\n",sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute, sys.wSecond,sys.wMilliseconds,sys.wDayOfWeek); return 0; } //方案三,優(yōu)點:利用系統(tǒng)函數(shù),還能修改系統(tǒng)時間 //此文件必須是c++文件 #include<stdlib.h> #include<iostream> using namespace std; void main() { system("time"); } //方案四,將當(dāng)前時間折算為秒級,再通過相應(yīng)的時間換算即可 //此文件必須是c++文件 #include<iostream> #include<ctime> using namespace std; int main() { time_t now_time; now_time = time(NULL); cout<<now_time; return 0; } 注意:GetLocalTime()與GetSystemTime()是有區(qū)別的
http://www.4ucode.com/Study/Topic/1996448VS2008中創(chuàng)建DLL工程 文件->新建->項目->visual c++->win32->win32控制臺應(yīng)用程序(win32項目也可以) 填寫項目名稱MyDLL->確定->下一步->DLL(附加選項 對空項目打鉤)->完成。 到這里DLL工程就創(chuàng)建完畢了,下面新建兩個文件testDLL.cpp和testDLL.h。 C++ .h 文件 #define DLL_EXPORT __declspec(dllexport)
extern "C" DLL_EXPORT int MyMinus(int a,int b);
.cpp 文件 // testDLL.cpp : 定義 DLL 應(yīng)用程序的導(dǎo)出函數(shù)。
//
#include "stdafx.h"
#include "testDLL.h"
int MyMinus(int a,int b)
{
return (a-b);
}
delphi調(diào)用代碼 unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
edt1: TEdit;
edt2: TEdit;
lbl1: TLabel;
lbl2: TLabel;
lbl3: TLabel;
btn1: TButton;
lbl4: TLabel;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
const
TestDll = 'testDLL.dll';
function MyMinus(a:Integer;b:Integer):Integer;cdecl;external TestDll;
implementation
{$R *.dfm}
procedure TForm1.btn1Click(Sender: TObject);
begin
lbl4.Caption := IntToStr(MyMinus(StrToInt(edt1.Text),StrToInt(edt2.Text)));
end;
end.
原諒轉(zhuǎn)載自: http://tech.ddvip.com/2008-11/122662837992492.htmlVisual C++中提供的MFC類CtreeCtrl(樹型控件)用來顯示具有一定層次結(jié)構(gòu)的數(shù)據(jù)項時方便、直觀,所以它已經(jīng)被廣泛地應(yīng)用在各種軟件中,如資源管理器中的磁盤目錄就用的是樹型控件,我們在編程中也會經(jīng)常用到這個控件,但是這個控件也有缺陷,那就是它并不直接支持拖動節(jié)點等高級特性,這使得程序員在編程時使用它受到了很大限制,同時又給軟件用戶帶來了一些不便。為此,本實例通過從 CTreeCtrl 中派生了一個類 CXTreeCtrl ,實現(xiàn)樹型控件中節(jié)點的拖動。這個類具有如下的功能:⑴ 基本項目條拖動的實現(xiàn);⑵ 處理項目條的無意拖動;⑶ 能處理項目條拖動過程中的滾動問題;⑷ 拖動過程中節(jié)點會智能展開。程序編譯運行后的效果如圖所示:
570)?'570px':'auto';
}" src="http://img.ddvip.com/2008_11_14/1226628379_ddvip_9835.png">
圖一:樹型控件節(jié)點拖動示例
一、實現(xiàn)方法
我們針對上述自定義類的實現(xiàn)功能,介紹實現(xiàn)思路和方法。
(1)基本項目條拖動的實現(xiàn)
當(dāng)我們要拖動樹型控件的一個項目條時,樹型控件會給它的父窗口發(fā)送一個TVN_BEGINDRAG通知消息,所以可以在此消息的響應(yīng)函數(shù)中,調(diào)用 CTreeCtrl ::CreateDragImage ()函數(shù)創(chuàng)建表示當(dāng)前項目條正處在拖動操作中的圖象,該函數(shù)創(chuàng)建的圖象由項目條的圖象和標(biāo)簽文本組成。創(chuàng)建了拖動圖象后,調(diào)用CImageList::BeginDrag()函數(shù)指定拖動圖象的熱點位置,然后調(diào)用CImageList::DragEnter()函數(shù)顯示拖動圖象。接下來處理 WM_MOUSEMOVE 消息用于更新拖動圖象,我們想讓移動中的圖象經(jīng)過某些項目時高亮度顯示,這可以調(diào)用 CTreeCtrl ::SelectDropTarget() 來實現(xiàn)。在調(diào)用 SelectDropTarget()函數(shù)之前,需要先調(diào)用CImageList::DragShowNolock ( false )函數(shù)來隱藏圖象列表,然后再調(diào)用CImageList::DragShowNolock ( true ) 函數(shù)來恢復(fù)圖象列表的顯示,這樣就不會在拖動過程中留下難看的軌跡。最后我們處理 WM_LBUTTONUP 消息用于完成拖動操作,在該消息響應(yīng)函數(shù)中,我們需要完成結(jié)束拖動圖象的顯示、刪除拖動圖象、釋放鼠標(biāo)、節(jié)點的拷貝/刪除等操作。在節(jié)點的拷貝/刪除操作中,如果是父節(jié)點拖到子節(jié)點上,我們可以先將父節(jié)點拷到根結(jié)點下的臨時節(jié)點中,再從臨時結(jié)點處拷到子節(jié)點,然后將根結(jié)點下的臨時節(jié)點刪除,這樣做的目的是防止產(chǎn)生異常。
(2)處理項目條的無意拖動
牐犎綣在鼠標(biāo)按下時不小心移動了鼠標(biāo),這時系統(tǒng)就認(rèn)為產(chǎn)生了一個移動操作,這就產(chǎn)生了誤操作。解決這個問題的方法是設(shè)置時間延遲,也就是說當(dāng)用戶按下鼠標(biāo)后必須在原位置停留一段時間,才能激活拖動操作。
(3)處理拖動過程中的滾動問題
當(dāng)我們拖動樹型控件的項目條時,如果目的節(jié)點不可見,則需要拖動滾動條或收攏其它一些節(jié)點以使得目的節(jié)點顯示出來,無疑,這會給我們帶來很大的不便。為此就要給樹型控件添加自動滾動支持。首先設(shè)置一個定時器,在 WM_TIMER 消息中檢測鼠標(biāo)的位置,如果靠近樹型控件的下邊緣,則使得控件向下滾動。靠近上邊緣則向上滾動。滾動速度根據(jù)鼠標(biāo)的位置確定。
(4)拖動過程中節(jié)點的智能展開
為了實現(xiàn)在拖動過程中鼠標(biāo)停留在某個節(jié)點上一段時間后,該節(jié)點會自動展開的功能。設(shè)置一個定時器,當(dāng)鼠標(biāo)在拖動過程中停止在某個節(jié)點上時,定時器被啟動,再設(shè)置一變量保存當(dāng)前的鼠標(biāo)位置。
二、編程步驟
1、 新建一對話框工程DragTree,編輯資源,在對話框中加入一樹型控件IDC_TREE ,屬性設(shè)置為:Has Buttons、Has Lines、Lines at root、Edit Labels、Border;
2、 使用Class Wizard給該控件添加一個成員變量 m_wndTree ,在代碼部分將該控件的類型修改為CXTreeCtrl。
3、 在對話框的OnInitDialog()函數(shù)中添加代碼,初始化樹型控件的項目條;
4、 制作一個圖像資源(ID為IDB_TREEIMAGE),其中包含兩個小圖標(biāo),用來作為樹型控件項目條的顯示圖標(biāo);
5、 添加代碼,編譯運行程序。
三、程序代碼
// XTreeCtrl.h : header file #if !defined(AFX_XTREECTRL_H__3EF12526_EF66_4FD9_A572_59476441D79A__INCLUDED_) #define AFX_XTREECTRL_H__3EF12526_EF66_4FD9_A572_59476441D79A__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CXTreeCtrl : public CTreeCtrl { // Construction public: CXTreeCtrl(); // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CXTreeCtrl) //}}AFX_VIRTUAL // Implementation public: virtual ~CXTreeCtrl(); // Generated message map functions protected: UINT m_TimerTicks; //處理滾動的定時器所經(jīng)過的時間 UINT m_nScrollTimerID; //處理滾動的定時器 CPoint m_HoverPoint; //鼠標(biāo)位置 UINT m_nHoverTimerID; //鼠標(biāo)敏感定時器 DWORD m_dwDragStart; //按下鼠標(biāo)左鍵那一刻的時間 BOOL m_bDragging; //標(biāo)識是否正在拖動過程中 CImageList* m_pDragImage; //拖動時顯示的圖象列表 HTREEITEM m_hItemDragS; //被拖動的標(biāo)簽 HTREEITEM m_hItemDragD; //接受拖動的標(biāo)簽 //{{AFX_MSG(CXTreeCtrl) afx_msg void OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnTimer(UINT nIDEvent); //}}AFX_MSG DECLARE_MESSAGE_MAP() private: HTREEITEM CopyBranch(HTREEITEM htiBranch,HTREEITEM htiNewParent,HTREEITEM htiAfter); HTREEITEM CopyItem(HTREEITEM hItem,HTREEITEM htiNewParent,HTREEITEM htiAfter); }; #endif //////////////////////////////////////////////////////////// CXTreeCtrl #include "stdafx.h" #include "DragTree.h" #include "XTreeCtrl.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define DRAG_DELAY 60 CXTreeCtrl::CXTreeCtrl() { m_bDragging = false; } CXTreeCtrl::~CXTreeCtrl() {} BEGIN_MESSAGE_MAP(CXTreeCtrl, CTreeCtrl) //{{AFX_MSG_MAP(CXTreeCtrl) ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_WM_LBUTTONDOWN() ON_WM_TIMER() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CXTreeCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; *pResult = 0; //如果是無意拖曳,則放棄操作 if( (GetTickCount() - m_dwDragStart) < DRAG_DELAY ) return; m_hItemDragS = pNMTreeView->itemNew.hItem; m_hItemDragD = NULL; //得到用于拖動時顯示的圖象列表 m_pDragImage = CreateDragImage( m_hItemDragS ); if( !m_pDragImage ) return; m_bDragging = true; m_pDragImage->BeginDrag ( 0,CPoint(8,8) ); CPoint pt = pNMTreeView->ptDrag; ClientToScreen( &pt ); m_pDragImage->DragEnter ( this,pt ); //"this"將拖曳動作限制在該窗口 SetCapture(); m_nScrollTimerID = SetTimer( 2,40,NULL ); } void CXTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) { HTREEITEM hItem; UINT flags; //檢測鼠標(biāo)敏感定時器是否存在,如果存在則刪除,刪除后再定時 if( m_nHoverTimerID ) { KillTimer( m_nHoverTimerID ); m_nHoverTimerID = 0; } m_nHoverTimerID = SetTimer( 1,800,NULL ); //定時為 0.8 秒則自動展開 m_HoverPoint = point; if( m_bDragging ) { CPoint pt = point; CImageList::DragMove( pt ); //鼠標(biāo)經(jīng)過時高亮顯示 CImageList::DragShowNolock( false ); //避免鼠標(biāo)經(jīng)過時留下難看的痕跡 if( (hItem = HitTest(point,&flags)) != NULL ) { SelectDropTarget( hItem ); m_hItemDragD = hItem; } CImageList::DragShowNolock( true ); //當(dāng)條目被拖曳到左邊緣時,將條目放在根下 CRect rect; GetClientRect( &rect ); if( point.x < rect.left + 20 ) m_hItemDragD = NULL; } CTreeCtrl::OnMouseMove(nFlags, point); } void CXTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) { CTreeCtrl::OnLButtonUp(nFlags, point); if( m_bDragging ) { m_bDragging = FALSE; CImageList::DragLeave( this ); CImageList::EndDrag(); ReleaseCapture(); delete m_pDragImage; SelectDropTarget( NULL ); if( m_hItemDragS == m_hItemDragD ) { KillTimer( m_nScrollTimerID ); return; } Expand( m_hItemDragD,TVE_EXPAND ); HTREEITEM htiParent = m_hItemDragD; while( (htiParent = GetParentItem(htiParent)) != NULL ) { if( htiParent == m_hItemDragS ) { HTREEITEM htiNewTemp = CopyBranch( m_hItemDragS,NULL,TVI_LAST ); HTREEITEM htiNew = CopyBranch( htiNewTemp,m_hItemDragD,TVI_LAST ); DeleteItem( htiNewTemp ); SelectItem( htiNew ); KillTimer( m_nScrollTimerID ); return; } } HTREEITEM htiNew = CopyBranch( m_hItemDragS,m_hItemDragD,TVI_LAST ); DeleteItem( m_hItemDragS ); SelectItem( htiNew ); KillTimer( m_nScrollTimerID ); } } HTREEITEM CXTreeCtrl::CopyItem(HTREEITEM hItem, HTREEITEM htiNewParent, HTREEITEM htiAfter) //拷貝條目 { TV_INSERTSTRUCT tvstruct; HTREEITEM hNewItem; CString sText; //得到源條目的信息 tvstruct.item.hItem = hItem; tvstruct.item.mask=TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; GetItem( &tvstruct.item ); sText = GetItemText( hItem ); tvstruct.item.cchTextMax = sText.GetLength (); tvstruct.item.pszText = sText.LockBuffer (); //將條目插入到合適的位置 tvstruct.hParent = htiNewParent; tvstruct.hInsertAfter = htiAfter; tvstruct.item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT; hNewItem = InsertItem( &tvstruct ); sText.ReleaseBuffer (); //限制拷貝條目數(shù)據(jù)和條目狀態(tài) SetItemData( hNewItem,GetItemData(hItem) ); SetItemState( hNewItem,GetItemState(hItem,TVIS_STATEIMAGEMASK),TVIS_STATEIMAGEMASK); return hNewItem; } HTREEITEM CXTreeCtrl::CopyBranch(HTREEITEM htiBranch, HTREEITEM htiNewParent, HTREEITEM htiAfter) //拷貝分支 { HTREEITEM hChild; HTREEITEM hNewItem = CopyItem( htiBranch,htiNewParent,htiAfter ); hChild = GetChildItem( htiBranch ); while( hChild != NULL ) { CopyBranch( hChild,hNewItem,htiAfter ); hChild = GetNextSiblingItem( hChild ); } return hNewItem; } void CXTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) //處理無意拖曳 { m_dwDragStart = GetTickCount(); CTreeCtrl::OnLButtonDown(nFlags, point); } void CXTreeCtrl::OnTimer(UINT nIDEvent) { //鼠標(biāo)敏感節(jié)點 if( nIDEvent == m_nHoverTimerID ) { KillTimer( m_nHoverTimerID ); m_nHoverTimerID = 0; HTREEITEM trItem = 0; UINT uFlag = 0; trItem = HitTest( m_HoverPoint,&uFlag ); if( trItem && m_bDragging ) { SelectItem( trItem ); Expand( trItem,TVE_EXPAND ); } } //處理拖曳過程中的滾動問題 else if( nIDEvent == m_nScrollTimerID ) { m_TimerTicks++; CPoint pt; GetCursorPos( &pt ); CRect rect; GetClientRect( &rect ); ClientToScreen( &rect ); HTREEITEM hItem = GetFirstVisibleItem(); if( pt.y < rect.top +10 ) { //向上滾動 int slowscroll = 6 - (rect.top + 10 - pt.y )/20; if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)) ) { CImageList::DragShowNolock ( false ); SendMessage( WM_VSCROLL,SB_LINEUP ); SelectDropTarget( hItem ); m_hItemDragD = hItem; CImageList::DragShowNolock ( true ); } } else if( pt.y > rect.bottom - 10 ) { //向下滾動 int slowscroll = 6 - (pt.y - rect.bottom + 10)/20; if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)) ) { CImageList::DragShowNolock ( false ); SendMessage( WM_VSCROLL,SB_LINEDOWN ); int nCount = GetVisibleCount(); for( int i=0 ; i<nCount-1 ; i++ ) hItem = GetNextVisibleItem( hItem ); if( hItem ) SelectDropTarget( hItem ); m_hItemDragD = hItem; CImageList::DragShowNolock ( true ); } } } else CTreeCtrl::OnTimer(nIDEvent); } //////////////////////////////////////////////////////////// BOOL CDragTreeDlg::OnInitDialog() { CDialog::OnInitDialog(); …………………….//此處代碼省略 // TODO: Add extra initialization here m_image.Create ( IDB_TREEIMAGE,16,1,RGB(255,255,255) ); m_wndTree.SetImageList ( &m_image,TVSIL_NORMAL ); HTREEITEM hti1 = m_wndTree.InsertItem ( _T("唐詩"),0,1 ); HTREEITEM hti2 = m_wndTree.InsertItem ( _T("宋詞"),0,1 ); HTREEITEM hti3 = m_wndTree.InsertItem ( _T("元曲"),0,1 ); HTREEITEM hti4 = m_wndTree.InsertItem ( _T("李白"),0,1,hti1 ); m_wndTree.InsertItem ( _T("靜夜思(床前明月光)"),0,1,hti4 ); m_wndTree.InsertItem ( _T("將進(jìn)酒(君不見黃河之水天上來)"),0,1,hti4 ); m_wndTree.InsertItem ( _T("望廬山瀑布(日照香爐生紫煙)"),0,1,hti4 ); m_wndTree.InsertItem ( _T("蜀道難(噫吁戲,危乎高哉)"),0,1,hti4 ); HTREEITEM hti5 = m_wndTree.InsertItem ( _T("杜甫"),0,1,hti1 ); m_wndTree.InsertItem ( _T("蜀相(丞相祠堂何處尋)"),0,1,hti5 ); m_wndTree.InsertItem ( _T("春望(國破山河在)"),0,1,hti5 ); m_wndTree.InsertItem ( _T("茅屋為秋風(fēng)所破歌(八月秋高風(fēng)怒號)"),0,1,hti5 ); HTREEITEM hti6 = m_wndTree.InsertItem ( _T("白居易"),0,1,hti1 ); m_wndTree.InsertItem ( _T("長恨歌(漢皇重色思傾國)"),0,1,hti6 ); m_wndTree.InsertItem ( _T("琵琶行並序(潯陽江頭夜送客)"),0,1,hti6 ); m_wndTree.InsertItem ( _T("李清照"),0,1,hti2 ); m_wndTree.InsertItem ( _T("柳永"),0,1,hti2 ); return TRUE; // return TRUE unless you set the focus to a control }
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenuW(MF_BYCOMMAND | MF_STRING, ID_RIGHT_CLEAR, _T("剪切(&X)"));
menu.AppendMenuW(MF_BYCOMMAND | MF_STRING, ID_RIGHT_COPY, _T("復(fù)制(&C)"));
menu.AppendMenuW(MF_BYCOMMAND | MF_STRING, ID_RIGHT_PASTE, _T("粘貼(&P)"));
menu.AppendMenuW(MF_SEPARATOR);
menu.AppendMenuW(MF_BYCOMMAND | MF_STRING, ID_RIGHT_CLEAR, _T("清除\tCtrl + C"));
ClientToScreen(&point);
menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTALIGN, point.x, point.y, this);
CView::OnRButtonDown(nFlags, point);
}
|