Translate

ebook【Delphi跨平台資料庫程式設計火速上手】電子書出版 (CHT)

Delphi 跨平台資料庫程式設計火速上手,是本關於整合 Delphi 的跨平台技術打造 2-Tier 架構的跨平台 APP 的入門技術書。 全書沒有需要理解的技術知識,只講套路。 力求短時間把製作 APP 的工法熟悉,未來要開發其它的應用程式也能舉一反三。 底下...

2009/08/31

[轉貼]Vector用法

出處:Vector用法
內容:
Vector用于存储对象数组

常用方法

1.push_back 在数组的最后添加一个数据

2.pop_back 去掉数组的最后一个数据

3.at 得到编号位置的数据

4.begin 得到数组头的指针

5.end 得到数组的最后一个单元+1的指针

6.front 得到数组头的引用

7.back 得到数组的最后一个单元的引用

8.max_size 得到vector最大可以是多大

9.capacity 当前vector分配的大小

10.size 当前使用数据的大小

11.resize 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值

12.reserve 改变当前vecotr所分配空间的大小

13.erase 删除指针指向的数据项

14.clear 清空当前的vector

15.rbegin 将vector反转后的开始指针返回(其实就是原来的end-1)

16.rend 将vector反转构的结束指针返回(其实就是原来的begin-1)

17.empty 判断vector是否为空

18.swap 与另一个vector交换数据

2009/08/26

將不特定檔案存入取出資料庫內

來源:請問如何將不特定檔案存入取出資料庫內
事實上方法極為簡單, 範例如下
(1)載入檔案存入note欄位內(note是一blob)

TFileStream *fs;
TStream *s;

if( OpenDialog1->Execute() )
{
s=Table1->CreateBlobStream( Table1->FieldByName("Note"), bmWrite );
s->Seek( 0, 0 );
fs=new TFileStream( OpenDialog1->FileName, fmOpenRead );
s->CopyFrom( fs, fs->Size );
fs->Free();
s->Free();
}

(2)自note內取出資料存成檔案
TFileStream *fs;
TStream *s;

if( SaveDialog1->Execute() )
{
s=Table1->CreateBlobStream( Table1->FieldByName("Note"), bmRead );
s->Position=0;
fs=new TFileStream( SaveDialog1->FileName, fmCreate );
fs->Seek(0, 0);
fs->CopyFrom( s, s->Size );
fs->Free();
s->Free();

夠簡單吧! 不過就是用 FileStream & Stream 在那兒轉來轉去而已
但它沒有原始檔名資料,建議你另加一欄位存放原始檔名
如果你不想存檔可以將Stream傳至您的其他元件直接觀看,例如pdf, bmp, jpg
tiff, word, excel..........等其他方式處理,反正BLOB是完完整整的將檔案存起來也不管你的資料格式是啥隨便你玩,只是請注意一下容量大小,若你是經由端
伺服器那麼最好有經過特別處理或不純放太大檔案

TClientDataSet的詳細介紹

出處:CSDN
=============================================================
在三層結構中,TClientDataSet的地位是不可估量的,她的使用正確與否,是十分關鍵的,
本文從以下幾個方面闡述她的使用,希望對你有所幫助.
1.動態索引
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
if (not column.Field is Tblobfield) then//Tblobfield不能索引,二進制
ClientDataSet1.IndexFieldNames:=column.Field.FieldName;
end;
2.多層結構中主從表的實現
設主表ClientDataSet1.packetrecord為-1,所有記錄
設從表ClientDataSet1.packetrecord為0,當前記錄
3.Taggregates使用
(1)在字段編輯中add new field類型為aggregates
後設置expression(表達試)
設置active:=true即可
使用dbedit的field為前者即可
(2)使用Aggergates屬性add設計表達式
調用
  showmessage(floattostr(ClientDataSet1.Aggregates.Count));
  showmessage(ClientDataSet1.Aggregates.Items[0].Value);
 
4.在單層數據庫中不要BDE
使用ClientDataSet代替table,使用ClientDataSet的loadfilename裝入cds
代替table的tablename的db或者dbf
原來的程序改造方法:
加一個ClientDataSet,使用右鍵assign locate data
後savetofile,再loadfromfile,後刪除table
將原連table的datasource設為ClientDataSet
唯一注意的是:要將midas.dll拷到system或者當前目錄
5.三層結構的公文包的實現方法
同時設定1:filename(*.cds)2.remote server
6.可以對data賦值(從另一個數據集取值)
ClientDataSet2.Data:=ClientDataSet1.Data;
ClientDataSet2.Open;
或者
ClientDataSet2.CloneCursor(ClientDataSet1,true);
ClientDataSet2.Open;
7.附加數據取得
客戶程序嚮應用服務器請求數據。如果TClientDataSet 的
FetchOnDemand 屬性設為True,
客戶程序會根據需要自動檢索附加的數據包如BLOB字段的值或嵌套表的內容。
否則,
客戶程序需要顯式地調用GetNextPacket 才能獲得這些附加的數據包。
ClientDataSet的packetrecords設置一次取得的記錄個數
8.ClientDataSet與服務器端query連接方法
(1)sql內容為空
ClientDataSet1.Close;
ClientDataSet1.CommandText:=edit1.Text;//即sql內容
ClientDataSet1.Open;
對於沒有應用服務器設置filter 如:country like 'A%'
filtered=true可實現sql功能
(2)有參數
如服務端query的sql為
select * from animals
where name like :dd
則:客戶端ClientDataSet
var
pm:Tparam;
begin
ClientDataSet1.Close;
ClientDataSet1.ProviderName:='DataSetProvider1';
pm:=Tparam.Create(nil);
pm.Name:='dd';
pm.DataType:=ftString;
ClientDataSet1.Params.Clear;
ClientDataSet1.Params.AddParam(pm);
ClientDataSet1.Params.ParamByName('dd').AsString:=edit1.Text ;
ClientDataSet1.Open;
pm.Free;
end;

9.數據的更新管理
(1)savepoint 保存目前為止數據狀態,可以恢復到這個狀態
var
pp:integer;
begin
pp:=ClientDataSet1.SavePoint;
ClientDataSet1.Edit;
ClientDataSet1.FieldByName('姓名').asstring:='古話';
ClientDataSet1.Post;
table1.Refresh;
end;
恢復點
ClientDataSet1.SavePoint:=pp;
(2)cancel,RevertRecord
取消對當前記錄的修改,只適合沒有post的,如果post,調用
RevertRecord
(3)cancelupdate
取消對數據庫所有的修改
(4)UndoLastChange(boolean),changecount
取消上一次的修改,可以實現連續撤消
參數為true:光標到恢復處
false:光標在當前位置不動
changecount返回修改記錄的次數,一個記錄修改多次,返回只一次
但UndoLastChange只撤消一次

10.可寫的recno
對於Ttable和Tquery的recno是只讀的,而TClientDataSet的recno可讀可寫
ClientDataSet1.recno:=5;是設第五個記錄為當前記錄
11.數據保存
對於table使用post可更新數據
而ClientDataSet1的post只更新內存數據,要更新服務器數據要使用
ApplyUpdates(MaxErrors: Integer),他有一個參數,是允許發出錯誤的
次數,-1表示無數次,使用simpleobjectbroker時常設為0,實現自動容錯和負載平衡

AnsiString類別介紹

以下也是轉載而來的內容,來源是:
AnsiString

全文如下:
AnsiString
其實是一個類(class),不過,它並不歸屬於VCL的框架,不是派生於TObject. 該類封裝了C,C++裏字串的大多操作,並有所發展。方便了C++程式師在程式中使用字串。下面挑典型和重要的說。

一、String就是AnsiString.typedef AnsiString String;
二;在VCL,幾乎所有字串都是AnsiString。若是屬性,則有要求, += 的重載對屬性不保證一定起作用。

Form1->Caption = "窗口標題"; //OK
Form1->Caption += " - 世界你好"; //Err
Form1->Caption = Form1->Caption + " - 世界你好"; //OK

同樣的事情發生 >>(移出) 或 << (移入) 重載上。如字元:
this->Font->Style >> fsBold; //不行的
三、如果要用空串,最好不用 "";
而是:AnsiString emptyStr = *NullStr;
四、現在你不用(顯式地)?字串管理記憶體了:
AnsiString name = "Mike";
ShowMessage(name); //顯示Mike
name = "張三";
ShowMessage(name); //顯示張三
AnsiString name2 = name;
name = 李四";
ShowMessage(name);
ShowMessage(name2);
AnsiString twoName = name + name2;
ShowMessage(twoName);

上面其實說明了,AnsiString 重載了 = 和 + 操作符,讓我們可以直接通過簡單的=或+操作,來賦值,改變一個字串。
如果不用Ansistring這樣或類似的而在C,C++,同樣的操作將是類似於(並不一定和上面完全一致的過程):
char* name = "Make";
ShowMessage(name);
name = new char[strlen("張三") + 1];
stcpy(name, "張三");
ShowMessage(name);
char* name2 = new char [strlen(name1)+1);
strcpy(name2,name);
delete[] name;
name = new char[strlem("李四")+1];
strcpy(name,"李四");
ShowMessage(name);
ShowMessage(name2);
char* twoName = new char [strlen(name) + strlen(name2) + 1)];
strcpy(twoName,name);
strcat(twoName,name2);
ShowMessage(twoName);
delete[] twoName;
delete[] name2;
delete[] name;

肯定可以看出後者在記憶體管理(初始分配,擴容,連接,釋放)上的一堆瑣事。當然,可以考慮用純C的 malloc,realloc, free ,及 sprintf連減少一些操作,但在C++世界裏,這樣的記憶體管理會和使用new,new[] , delete,delete[]的代碼在交接上?生問題。並不是C++程式師的首選。

可能還會說,我就是原意累點,可是直接寫記憶體管理,會帶來高效率啊。。這是不知量力。由於字串管理在一個程式中的使用率太高了,事實上不管是VC的CString, 還是STL的string,或者是C#的string,及我們這裏的AnsiString,統統採用記憶體池,及“realloc on modify(在修改時才生分配記憶體)”等技術,可謂既提高了連續記憶體使用率,又提高了運行速度,這類高級功能,不是一般你我有精力甚至能力去實現。
四、小心,AnsiString 帶有Pascal風格。
AnsiString這個類也重載 [] 操作符 ,用於得到字串中指定的字元,可是,雖然AnsiString純是用C++寫成,但它是?了實現Object Pascal內置類型string,所以必須和Object Pascal保持相容,所以,它的下標也是從1開始:
AnsiString pascal = "Pascal";
char c = pascal[1]; // c 是 'P'
五、可以得到C風格的字串。
Windows在編程介面上還是非面向物件,(等.Net完全取代後,就是了) 它的API還得用到很多的C風格的字串(上面我們舉例的那個);再者,C++既然說完全相容C,那我們難免有時還會喜歡用用C的函數庫。
AnsiString s = "123456";
int len = strlen(s.c_str());
沒錯, c_str() 這個成員函數返回的是一個 const char* 常量字串指標。因?是const的,所以用在類似strlen()這樣僅要求是const char* 的函數還算方便,如果你想安全一點,或者人家函數指定就不能是const ,那你只好複製走:
AnsiString s = "123456";
char* tmp = new char[7];
strcpy(tmp, s.c_str()); //複製
然後對tmp愛幹嘛幹嘛去。
六、它有好多字串操作成員函數,並一般都有對應的同名全局函數。
比如取長度:
AnsiString s = "Hello!";
int len = s.Length(); //求長度
但你也可以這樣:
int len = Length(s);
或例如求子串:
string subString = s.SubString(2,3);
ShowMessage(subString) // "ell"
同樣用個全局的SubString(s,2,3);
注意了,索引從1開始。

用C++實作Strtok (類似 Java StringTokenizer)

來源:strtok:Split string into tokens

在網路上在查Strtok的做法,無意間找到C++的處理模式
有網友熱心的公佈出他的程式碼(類似 Java StringTokenizer)
內容寫的真的很棒,所以就轉來這邊收藏。
如果要套用AnsiString,則可以使用AnsiString的c_str()函式,也同樣適用哦!
以下是它的源始碼內容:
//---------------------------------------------------------------------------
#include <iostream>
#include <string>
#include <vector>
#pragma hdrstop

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

#pragma argsused
using namespace std;

class StringTokenizer : public std::vector<string>{

public:
 StringTokenizer(const string& s, const string& delim = " ,") {
   string::size_type lastPos = s.find_first_not_of(delim, 0);
   string::size_type pos = s.find_first_of(delim, lastPos);

   while( string::npos != pos || string::npos != lastPos ) {
     push_back(s.substr(lastPos, pos - lastPos));
     lastPos = s.find_first_not_of(delim, pos);
     pos = s.find_first_of(delim, lastPos);
   }
 }
};
int main(int argc, char* argv[])
{
 StringTokenizer stk("1, 2, 3");

 for( StringTokenizer::size_type i = 0; i < stk.size(); i++ ) {
   cout << stk[i] << endl;
 }

 system("pause");
 return 0;
}
//---------------------------------------------------------------------------

2009/08/21

羅技新滑鼠m555b試用心情(?)

最近用了一下m555b的感覺,很棒!
滾輪零磨擦!滾一下就滾個沒完沒了,需要手動煞車
常常也因為這樣而讓食指磨掉一層皮 (誤)

好用的電池更換開關,按一下蓋子就和本體分離了!很方便!

1000dpi的解析度,滑起來很柔很滑順(?)

預設的中鍵是在滾輪後面的按鈕,按滾輪是沒反應的唷!

而滾輪的左右鍵預設也是沒作用的,需要另外安裝driver才行,下次再來試試看吧!

20090821更新:
裝了m555b的驅動程式後,設定介面就跑出來了,滾輪的左右鍵也可以正常使用了
中鍵的應用程式切換鍵(有點像ALT + TAB功能的方式)所帶出來的介面很炫!跟VISTA的切換視窗功能很像,但沒這麼耗資源。

另外,零磨擦滾輪其實可以變成傳統棘輪滾輪(會出現咔啦咔啦聲音的那種)
只要壓一下滾輪,就可以做傳統和零磨擦模式的切換哦!

真是好棒的滑鼠呀!

2009/08/19

[轉載]加快你ADD Items的速度!virtual list、vector for TListview教學

寫這篇文章的人真的是佛心來的耶!超厲害的啦!
希望我有一天也能夠寫出這樣的作品 ^___^
轉載自:300分求解决listview大量数据添加慢的方法



主  题: 讨论ListView里显示十万级以上记录时,象SQL Server里的返回所有行的方式显示记录,怎么实现?

作  者: cmsoft (韦小宝是我的老乡)

等  级:

信 誉 值: 100

所属论坛: C++ Builder 基础类

问题点数: 99

回复次数: 38

发表时间: 2002-12-31 9:57:02

回复人: bigwhiteshark(大白鲨) ( )

信誉:被封杀

哈哈正中本人下怀

如何用TListView来处理大量数据

采用常规方法处理ListView,在数据量大时无论是还是用了BeginUpdata和EndUpdata()

还是处理WM_EraseBkgnd信息都不会得到理想的效果,那答案是什么呢?嗯,

采用所谓Virtual ListView技术。说起来很神秘,其实点通了很简单。

通常ListView中的所有数据都是由ListView自己来管理的,它负责这些数据空间的分配和释放,

当你把ListView->OwnerData设为true时,ListView就把数据的管理权交给了你,而它只负责显示。

这时你需要自己来为数据分配和释放空间,至于你怎样来管理这些数据完全有你自己来定,

ListView完全不关心,当ListView需要显示某条数据时,它就调用OnData事件,

你只要在这个事件的处理函数里指定ListView即将显示的Item的内容就可以了。

这就是所谓的Virtual ListView技术。

由于ListView对数据管理的功能强大,随之而来的却是效率低下,

如果你采用更高效的数据管理方式就会极大的改变效率。

而且Virtual ListView只在数据需要显示时才调用OnData事件载入数据,所以速度很快。
  下面的例子中,假设ListView中需要显示4列数据,所有的数据被保存在vector里。

/*Unit1.h*/
//---------------------------------------------------------------------------
#ifndef Unit1H

#define Unit1H

//---------------------------------------------------------------------------
#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <ComCtrls.hpp>

#include <vector.h>

using namespace std;

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

struct ListViewData //用於存儲一條資料的結構體

{

AnsiString Caption;

AnsiString SubItems1;

AnsiString SubItems2;

AnsiString SubItems3;

};

class TForm1 : public TForm

{

__published: // IDE-managed Components

TListView *ListView1;

void __fastcall ListView1Data(TObject *Sender, TListItem *Item);

private: // User declarations

vector<ListViewData*> m_lvDataVector; //用於存儲所以資料的向量

public: // User declarations

__fastcall TForm1(TComponent* Owner);

__fastcall ~TForm1();

};

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

extern PACKAGE TForm1 *Form1;

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

#endif

/*unit1.cpp*/

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

#include <vcl.h>

#pragma hdrstop
#include "Unit1.h"

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

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

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

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

ListView1->OwnerData = true;

const int iListViewCount = 5000;

ListView1->Items->Count = iListViewCount; //必須指定,以使ListView知道其虛擬資料量

//保存資料

for(int i = 0; i < iListViewCount; ++i) {

ListViewData *plvData = new ListViewData;

plvData->Caption = "Caption" + AnsiString(i);

plvData->SubItems1 = "SubItems1" + AnsiString(i);

plvData->SubItems2 = "SubItems2" + AnsiString(i);

plvData->SubItems3 = "SubItems3" + AnsiString(i);

m_lvDataVector.push_back(plvData); //向vector中添加一項

}

}

__fastcall TForm1::~TForm1()

{

int iCount = ListView1->Items->Count;

for(int i = 0; i < iCount; ++i) {

ListViewData *plvData = m_lvDataVector[i];

delete plvData; //釋放資料佔用的資源

}

m_lvDataVector.clear(); //清空vector中所有條目

}

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

//ListView在要顯示某條資料時會調用這個函數

void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item)

{

if(Item->Index > m_lvDataVector.size())

return;

ListViewData *plvData = m_lvDataVector[Item->Index];

//指定要顯示的條目的資料

Item->Caption = plvData->Caption;

Item->SubItems->Add(plvData->SubItems1);

Item->SubItems->Add(plvData->SubItems2);

Item->SubItems->Add(plvData->SubItems3);

}

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


速度很快,5000条数据只要1秒左右.

在使用Virtual ListView方式时,如果要对数据排序,只需对你保存的内部数据(这里时vector对象)排序,然后ListView->Refresh()即可。这时你在ListView中看到的数据就是排好序的数据了。

2009/08/09

你今天上線了沒?

這兩天颱風天出門,發現了很有趣的景象,連結電線杆的電線上面滿滿都是麻雀。

嘰嘰喳喳吵個不停,彷彿是在聊天………

「你今天上線了沒?」

不知道有沒有人懂我的笑話,哈!