Google
 

Friday, July 31, 2009

Kirim SMS dengan Delphi dan TOxygen

TOxygen

Fitur :

  1. Supports Nokia 3210, 3310, 3330, 3390, 3350, 3410, 3510, 5110, 5130, 5190, 5210, 6110, 6130, 6150, 6190, 6210, 6250, 6310, 6310i, 6510, 7110, 7190, 8210, 8290, 8250, 8310, 8390, 8850, 8855, 8890, 8910 phones.
  2. Bekerja dengan kabel data atau InfraRed
  3. Mendeteksi Model HP secara otomatis
  4. Bisa kirim SMS ke SMS Center apa aja
  5. Bisa kirim dan terima SMS teks atapun gambar
  6. Bisa kirim ringtone, logo ataupun flash message
  7. Bisa hapus pesan dan report nya otomatis
  8. Bisa mendapatkan parameter HP seperti IMEI, model, SMSCenter phone number, Hardware/Software revision dan tanggaknya, Battery dan Signal level.
  9. Componen di Borland Delphi 3,4,5,6,7 dan Borland C++ Builder 5.

Bayangkan, dengan kemampuan nya seperti itu, kita bisa buat aplikasi apa saja via SMS. Pooling, survey, undian dll. Bisa buat skripsi, tugas akhir, tugas de el el.

download componennnya disini

Custom MessageDlg


Artikel ini merupakan lanjutan dari Meng-Indonesia-kan MessageDlg yang pernah saya publikasikan beberapa bulan yang lalu (lebih tepatnya tahun yang lalu). Sebenarnya saya ingin mengangkat tema lain yang menurut saya lebih menarik, namun berhubung ada diskusi di forum Delphi Indonesia (Delphi-ID) mengenai membuat MessageDlg sesuai dengan keinginan secara dinamis, maka saya putuskan untuk menulisnya terlebih dahulu.

Ada anggapan bahwa artikel tersebut hanya menitik beratkan pada lokalisasi teks MessageDlg, sebenarnya lebih dari itu. Jika dicermati, saya memaparkan trik bagaimana mengubah judul dan tombol yang digunakan MessageDlg pada saat aplikasi berjalan (run-time). Kemudian trik tersebut saya kuatkan dengan demo agar lebih jelas dipahami. Oiya sekedar untuk diketahui trik tersebut berlaku global, untuk semua MessageDlg yang dipanggil oleh aplikasi yang menggunakan, tidak peduli berasal dari mana form atau unit pemanggilnya sampai aplikasi ditutup.

Ada anggapan bahwa trik tersebut bersifat sekali pakai saja, tidak dinamis. Nah inilah yang perlu saya luruskan. Tentu saja trik tersebut dapat dipanggil dan digunakan berkali – kali untuk menampilkan MessageDlg dengan judul dan teks tombol yang berbeda – beda pula.

Lalu bagaimanakah cara agar dapat menampilkan MessageDlg sesuai dengan konteks teks judul dan tombol yang kita inginkan?

Tentu saja cukup mudah!

Cukup panggil method ReplaceResourceString dengan parameter judul, tombol mana yang ingin diubah teks-nya.

Misalnya:

1.ReplaceResourceString(@SMsgDlgConfirm, 'Konfirmasi Penyimpanan');
2.ReplaceResourceString(@SMsgDlgYes, 'Simpan Perubahan');
3.ReplaceResourceString(@SMsgDlgNo, 'Jangan Simpan');

Ok, cukup, saya rasa Anda sudah mendapatkan inti-nya. Jika masih belum, coba simak kode sumber demo berikut, bagi yang belum paham, baca juga penjelasan yang saya tambahkan sebagai komentar:

001.{-----------------------------------------------------------------------------
002.The contents of this file are subject to the Mozilla Public License
003.Version 1.1 (the "License"); you may not use this file except in compliance
004.with the License. You may obtain a copy of the License at
006.
007.Software distributed under the License is distributed on an "AS IS" basis,
008.WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
009.the specific language governing rights and limitations under the License.
010.
011.The Original Code is: CustomMessageDlgDemoUnit.pas, released on 2008-08-05
012.
013.The Initial Developer of the Original Code is Bayu Prasetio
014.Portions created by Bayu Prasetio are Copyright (C) 2007, 2008 Bayu Prasetio.
015.All Rights Reserved.
016.-----------------------------------------------------------------------------}
017.
018.{-----------------------------------------------------------------------------
019. Perhatian :
020. Apa yang tertera pada kode sumber ini sebaiknya dipahami terlebih dahulu,
021. jangan asal 'copy-paste' dan melakukan protes jika tidak sesuai dengan
022. keinginan.
023.
024. Yang perlu saya tekankan adalah, bahwa materi yang terdapat dalam kode
025. sumber ini sekedar demo, 'proof-of-concept' untuk mendukung eksplorasi
026. lanjutan dari 'Meng-Indonesia-kan MessageDlg' sampai ke batas yang Anda
027. tentukan sendiri berdasarkan imajinasi dan kreativitas Anda. Ingat, demo
028. ini belum optimal dan terbaik. Dan tentu saja harapan saya adalah Anda
029. dapat mengeksplorasi dan mengembangkan jauh lebih baik dari yang ada di
030. demo ini.
031.
032. Kelemahan mendasar adalah:
033. - Ukuran tombol hanya berubah pada saat 'ReplaceResourceString' pertama,
034. pemanggilan berikutnya tidak mengubah ukuran tombol
035.-----------------------------------------------------------------------------}
036.
037.unit CustomMessageDlgDemoUnit;
038.
039.interface
040.
041.uses
042. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
043. Dialogs, StdCtrls, ComCtrls;
044.
045.type
046. TfrmCustomMessageDlg = class(TForm)
047. btnStandard: TButton;
048. btnIndonesian: TButton;
049. btnContextSave: TButton;
050. mmoLegend: TMemo;
051. stbMain: TStatusBar;
052. btnContextPrint: TButton;
053. procedure btnStandardClick(Sender: TObject);
054. procedure btnIndonesianClick(Sender: TObject);
055. procedure btnContextSaveClick(Sender: TObject);
056. procedure btnContextPrintClick(Sender: TObject);
057. private
058. { Private declarations }
059. procedure ReplaceResourceString(RStringRec: PResStringRec; AString: PChar);
060. procedure SetCustomMessageStandard;
061. procedure SetCustomMessageIndonesian;
062. procedure SetCustomMessageContextSave;
063. procedure SetCustomMessageContextPrint;
064. public
065. { Public declarations }
066. end;
067.
068.var
069. frmCustomMessageDlg: TfrmCustomMessageDlg;
070.
071.implementation
072.
073.{$R *.dfm}
074.
075.uses
076. Consts;
077.
078.const
079. // konstanta default untuk MessageDlg
080. _SMsgDlgWarning = 'Warning';
081. _SMsgDlgError = 'Error';
082. _SMsgDlgInformation = 'Information';
083. _SMsgDlgConfirm = 'Confirm';
084. _SMsgDlgYes = '&Yes';
085. _SMsgDlgNo = '&No';
086. _SMsgDlgOK = 'OK';
087. _SMsgDlgCancel = 'Cancel';
088. _SMsgDlgHelp = '&Help';
089. _SMsgDlgHelpNone = 'No help available';
090. _SMsgDlgHelpHelp = 'Help';
091. _SMsgDlgAbort = '&Abort';
092. _SMsgDlgRetry = '&Retry';
093. _SMsgDlgIgnore = '&Ignore';
094. _SMsgDlgAll = '&All';
095. _SMsgDlgNoToAll = 'N&o to All';
096. _SMsgDlgYesToAll = 'Yes to &All';
097.
098. // konstanta MessageDlg untuk Bahasa Indonesia
099. _SMsgDlgWarningIndonesian = 'Peringatan';
100. _SMsgDlgErrorIndonesian = 'Kesalahan';
101. _SMsgDlgInformationIndonesian = 'Informasi';
102. _SMsgDlgConfirmIndonesian = 'Konfirmasi';
103. _SMsgDlgYesIndonesian = '&Ya';
104. _SMsgDlgNoIndonesian = '&Tidak';
105. _SMsgDlgOKIndonesian = 'OK';
106. _SMsgDlgCancelIndonesian = 'Batal';
107. _SMsgDlgHelpIndonesian = '&Panduan';
108. _SMsgDlgHelpNoneIndonesian = 'Panduan tidak tersedia';
109. _SMsgDlgHelpHelpIndonesian = 'Panduan';
110. _SMsgDlgAbortIndonesian = '&Batal';
111. _SMsgDlgRetryIndonesian = '&Ulang';
112. _SMsgDlgIgnoreIndonesian = 'A&cuh';
113. _SMsgDlgAllIndonesian = '&Semua';
114. _SMsgDlgNoToAllIndonesian = 'T&idak untuk Semua';
115. _SMsgDlgYesToAllIndonesian = 'Ya untuk S&emua';
116.
117. // konstanta MessageDlg untuk konteks Pencetakan
118. // yang digunakan adalah konfirmasi, mbOK, mbYes dan mbNo
119. _SMsgDlgWarningContextPrint = 'Peringatan';
120. _SMsgDlgErrorContextPrint = 'Kesalahan';
121. _SMsgDlgInformationContextPrint = 'Informasi';
122. _SMsgDlgConfirmContextPrint = 'Konfirmasi Tujuan Pencetakan';
123. _SMsgDlgYesContextPrint = '&Printer';
124. _SMsgDlgNoContextPrint = 'Dokumen PD&F Lebar Yak';
125. _SMsgDlgOKContextPrint = '&Layar';
126. _SMsgDlgCancelContextPrint = 'Batal';
127. _SMsgDlgHelpContextPrint = '&Panduan';
128. _SMsgDlgHelpNoneContextPrint = 'Panduan tidak tersedia';
129. _SMsgDlgHelpHelpContextPrint = 'Panduan';
130. _SMsgDlgAbortContextPrint = '&Batal';
131. _SMsgDlgRetryContextPrint = '&Ulang';
132. _SMsgDlgIgnoreContextPrint = 'A&cuh';
133. _SMsgDlgAllContextPrint = '&Semua';
134. _SMsgDlgNoToAllContextPrint = 'T&idak untuk Semua';
135. _SMsgDlgYesToAllContextPrint = 'Ya untuk S&emua';
136.
137. // konstanta MessageDlg untuk konteks Penyimpanan
138. // yang digunakan adalah konfirmasi, mbYes dan mbNo
139. _SMsgDlgWarningContextSave = 'Peringatan';
140. _SMsgDlgErrorContextSave = 'Kesalahan';
141. _SMsgDlgInformationContextSave = 'Informasi';
142. _SMsgDlgConfirmContextSave = 'Konfirmasi Penyimpanan';
143. _SMsgDlgYesContextSave = '&Simpan';
144. _SMsgDlgNoContextSave = '&Lanjut Saja';
145. _SMsgDlgOKContextSave = 'OK';
146. _SMsgDlgCancelContextSave = 'Batal';
147. _SMsgDlgHelpContextSave = '&Panduan';
148. _SMsgDlgHelpNoneContextSave = 'Panduan tidak tersedia';
149. _SMsgDlgHelpHelpContextSave = 'Panduan';
150. _SMsgDlgAbortContextSave = '&Batal';
151. _SMsgDlgRetryContextSave = '&Ulang';
152. _SMsgDlgIgnoreContextSave = 'A&cuh';
153. _SMsgDlgAllContextSave = '&Semua';
154. _SMsgDlgNoToAllContextSave = 'T&idak untuk Semua';
155. _SMsgDlgYesToAllContextSave = 'Ya untuk S&emua';
156.
157.procedure TfrmCustomMessageDlg.btnContextPrintClick(Sender: TObject);
158.begin
159. SetCustomMessageContextPrint;
160.end;
161.
162.procedure TfrmCustomMessageDlg.btnContextSaveClick(Sender: TObject);
163.begin
164. SetCustomMessageContextSave;
165.end;
166.
167.procedure TfrmCustomMessageDlg.btnIndonesianClick(Sender: TObject);
168.begin
169. SetCustomMessageIndonesian;
170.end;
171.
172.procedure TfrmCustomMessageDlg.btnStandardClick(Sender: TObject);
173.begin
174. SetCustomMessageStandard;
175.end;
176.
177.{-- taken from bpCodeReplacement.pas by Bayu Prasetio}
178.procedure TfrmCustomMessageDlg.ReplaceResourceString(RStringRec: PResStringRec;
179. AString: PChar);
180.var
181. OldProtect: Cardinal;
182.begin
183. if RStringRec = nil then Exit;
184. if VirtualProtectEx(GetCurrentProcess, RStringRec, SizeOf(RStringRec^), PAGE_EXECUTE_READWRITE, OldProtect) then
185. begin
186. RStringRec^.Identifier := Integer(AString);
187. VirtualProtectEx(GetCurrentProcess, RStringRec, SizeOf(RStringRec^), OldProtect, @OldProtect);
188. end;
189.end;
190.
191.procedure TfrmCustomMessageDlg.SetCustomMessageContextPrint;
192.begin
193. // sebagai contoh, ubah resource string untuk MessageDlg berdasarkan konteks kejadian
194. // dalam hal ini adalah proses pencetakan
195. // mbOK disetarakan tayang ke layar (preview)
196. // mbYes disetarakan cetak ke printer
197. // mbNo disetarakan cetak ke dokumen PDF
198. ReplaceResourceString(@SMsgDlgConfirm, _SMsgDlgConfirmContextPrint);
199. ReplaceResourceString(@SMsgDlgYes, _SMsgDlgYesContextPrint);
200. ReplaceResourceString(@SMsgDlgNo, _SMsgDlgNoContextPrint);
201. ReplaceResourceString(@SMsgDlgOK, _SMsgDlgOKContextPrint);
202.
203. // gunakan ModalResult dari MessageDlg untuk menentukan tindakan selanjutnya
204. // hati - hati, Anda tidak dapat menggunakan ShowMessage sekehendak hati
205. // karena ShowMessage sebenarnya MessageDlg dengan parameter MessageType mtInformation
206. // dan Buttons [mbOK]. Pahamkan mengapa tombol 'OK' berubah menjadi 'Layar' ?
207. case MessageDlg('Tentukan tujuan pencetakan dokumen ?', mtConfirmation, [mbOK, mbYes, mbNo], 0) of
208. mrOK : ShowMessage('Dokumen ditayangkan ke layar');
209. mrYes : ShowMessage('Dokumen dicetak ke printer');
210. mrNo : ShowMessage('Dokumen disimpan dalam format .PDF');
211. end;
212.end;
213.
214.procedure TfrmCustomMessageDlg.SetCustomMessageContextSave;
215.begin
216. // sebagai contoh, ubah resource string untuk MessageDlg berdasarkan konteks kejadian
217. // dalam hal ini adalah proses simpan
218. ReplaceResourceString(@SMsgDlgConfirm, _SMsgDlgConfirmContextSave);
219. ReplaceResourceString(@SMsgDlgYes, _SMsgDlgYesContextSave);
220. ReplaceResourceString(@SMsgDlgNo, _SMsgDlgNoContextSave);
221. ReplaceResourceString(@SMsgDlgCancel, _SMsgDlgCancelContextSave);
222.
223. MessageDlg('Anda Yakin akan menyimpan dokumen ini ?', mtConfirmation, mbYesNoCancel, 0);
224.end;
225.
226.procedure TfrmCustomMessageDlg.SetCustomMessageIndonesian;
227.begin
228. // ubah semua resource string untuk MessageDlg ke bahasa Indonesia
229. ReplaceResourceString(@SMsgDlgWarning, _SMsgDlgWarningIndonesian);
230. ReplaceResourceString(@SMsgDlgError, _SMsgDlgErrorIndonesian);
231. ReplaceResourceString(@SMsgDlgInformation, _SMsgDlgInformationIndonesian);
232. ReplaceResourceString(@SMsgDlgConfirm, _SMsgDlgConfirmIndonesian);
233. ReplaceResourceString(@SMsgDlgYes, _SMsgDlgYesIndonesian);
234. ReplaceResourceString(@SMsgDlgNo, _SMsgDlgNoIndonesian);
235. ReplaceResourceString(@SMsgDlgOK, _SMsgDlgOKIndonesian);
236. ReplaceResourceString(@SMsgDlgCancel, _SMsgDlgCancelIndonesian);
237. ReplaceResourceString(@SMsgDlgHelp, _SMsgDlgHelpIndonesian);
238. ReplaceResourceString(@SMsgDlgHelpNone, _SMsgDlgHelpNoneIndonesian);
239. ReplaceResourceString(@SMsgDlgHelpHelp, _SMsgDlgHelpHelpIndonesian);
240. ReplaceResourceString(@SMsgDlgAbort, _SMsgDlgAbortIndonesian);
241. ReplaceResourceString(@SMsgDlgRetry, _SMsgDlgRetryIndonesian);
242. ReplaceResourceString(@SMsgDlgIgnore, _SMsgDlgIgnoreIndonesian);
243. ReplaceResourceString(@SMsgDlgAll, _SMsgDlgAllIndonesian);
244. ReplaceResourceString(@SMsgDlgNoToAll, _SMsgDlgNoToAllIndonesian);
245. ReplaceResourceString(@SMsgDlgYesToAll, _SMsgDlgYesToAllIndonesian);
246.
247. MessageDlg('Anda Yakin akan menyimpan dokumen ini ?', mtConfirmation, mbYesNoCancel, 0);
248.end;
249.
250.procedure TfrmCustomMessageDlg.SetCustomMessageStandard;
251.begin
252. // ubah semua resource string untuk MessageDlg ke default
253. ReplaceResourceString(@SMsgDlgWarning, _SMsgDlgWarning);
254. ReplaceResourceString(@SMsgDlgError, _SMsgDlgError);
255. ReplaceResourceString(@SMsgDlgInformation, _SMsgDlgInformation);
256. ReplaceResourceString(@SMsgDlgConfirm, _SMsgDlgConfirm);
257. ReplaceResourceString(@SMsgDlgYes, _SMsgDlgYes);
258. ReplaceResourceString(@SMsgDlgNo, _SMsgDlgNo);
259. ReplaceResourceString(@SMsgDlgOK, _SMsgDlgOK);
260. ReplaceResourceString(@SMsgDlgCancel, _SMsgDlgCancel);
261. ReplaceResourceString(@SMsgDlgHelp, _SMsgDlgHelp);
262. ReplaceResourceString(@SMsgDlgHelpNone, _SMsgDlgHelpNone);
263. ReplaceResourceString(@SMsgDlgHelpHelp, _SMsgDlgHelpHelp);
264. ReplaceResourceString(@SMsgDlgAbort, _SMsgDlgAbort);
265. ReplaceResourceString(@SMsgDlgRetry, _SMsgDlgRetry);
266. ReplaceResourceString(@SMsgDlgIgnore, _SMsgDlgIgnore);
267. ReplaceResourceString(@SMsgDlgAll, _SMsgDlgAll);
268. ReplaceResourceString(@SMsgDlgNoToAll, _SMsgDlgNoToAll);
269. ReplaceResourceString(@SMsgDlgYesToAll, _SMsgDlgYesToAll);
270.
271. MessageDlg('Anda Yakin akan menyimpan dokumen ini ?', mtConfirmation, mbYesNoCancel, 0);
272.end;
273.
274.end.

Dan sebagai catatan, ada kelemahan yang perlu diketahui perihal trik, yaitu ukuran tombol hanya berubah pada saat ‘ReplaceResourceString’ pertama, pemanggilan berikutnya tidak mengubah ukuran tombol.

Ok, seperti yang telah saya tulis komentar di kode sumber, “harapan saya adalah Anda dapat mengeksplorasi dan mengembangkan jauh lebih baik dari yang ada di demo ini”. Saya sengaja membuat demo ini belum optimal, jadi silahkan gunakan logika, kreativitas dan imajinasi Anda.

Semoga bermanfaat.

Thursday, July 30, 2009

Hindari FieldByName pada Penggunaan Intensif

Hindari FieldByName pada Penggunaan Intensif

Bagi Delphiers yang sering berinteraksi dengan database, tentu tidak asing dengan penggunaan FieldByName. Pada operasi akses field yang bersifat intensif, misalnya konversi data, penyalinan data dari satu database atau tabel ke database atau tabel lainnya, penggunaan FieldByName harus dihindari.

Untuk mencapai suatu field dengan menggunakan FieldByName, terlebih dahulu harus dilakukan pencarian alamat referensi field yang dimaksud dengan melakukan iterasi setiap field pada daftar field (FieldList) dari awal hingga akhir untuk mencocokkan namanya (FieldName). Proses iterasi akan berhenti ketika ditemukan nama field pada daftar field. Proses kemudian mengembalikan alamat referensi field yang dimaksud.

Sekilas, proses yang terjadi pada FieldByName ditunjukkan pada potongan kode berikut:

1.function TFields.FieldByName(const FieldName: WideString): TField;
2.begin
3. Result := FindField(FieldName);
4. if Result = nil then DatabaseErrorFmt(SFieldNotFound, [FieldName], DataSet);
5.end;

Jika ditelusuri, fungsi FindField adalah sebagai berikut:

01.function TFields.FindField(const FieldName: WideString): TField;
02.var
03. I: Integer;
04.begin
05. for I := 0 to FList.Count - 1 do
06. begin
07. Result := FList.Items[I];
08. if WideCompareText(Result.FFieldName, FieldName) = 0 then Exit;
09. end;
10. Result := nil;
11.end;

Oke, untuk lebih mantapnya, perlu kita buat sebuah rutin untuk mengukur bagaimana penggunaan FieldByName pada operasi yang intensif mengakses field. Perlu diingat bahwa kode yang dijadikan sebagai contoh dibuat sesederhana mungkin, hanya mengakses 2 field saja dan tidak ada operasi lain yang menyertainya seperti perhitungan, seleksi kondisi dan sebagainya. Pada keadaan sesungguhnya, bentuk operasi bisa jauh lebih kompleks dan bervariasi.

Berikut gambaran singkat mengenai data yang akan dijadikan bahan pengukuran
- Sistem Core2Duo 1.66GHz, 667MHz FSB, 2MB L2 Cache, 1GB RAM, dengan free ram > 256MB (ada program yg berjalan: Delphi2007, FF, EMS SQL Manager, Notepad++)
- Windows XP Professional SP3
- MySQL 5.1.21, akses lokal, konfigurasi standar
- Tabel dengan jenis InnoDB, jumlah record sekitar 29000-an
- Pengukuran menggunakan QueryPerformaceCounter & QueryPerformanceFrequency
- Sangat dimungkinkan terjadi proses caching pembacaan hasil proses sebelumnya. Untuk itu lakukan proses perhitungan dengan jeda waktu yang lama dan berkali - kali untuk meyakinkan nilainya.

Metode 1

Metode 1 menggunakan FieldByName seperti pada potongan kode berikut:

01.procedure TForm2.btnMethod1Click(Sender: TObject);
02.var
03. A, B : Double;
04. FFreq : Int64;
05. FStartCounter : Int64;
06. FStopCounter : Int64;
07. I : Integer;
08.begin
09. MyConnection1.Connected := True;
10. MyQuery1.Active := True;
11.
12. A := 0;
13. B := 0;
14. QueryPerformanceFrequency(FFreq);
15. QueryPerformanceCounter(FStartCounter);
16. for I := 0 to 1000 do
17. begin
18. MyQuery1.First;
19. while not MyQuery1.Eof do
20. begin
21. A := MyQuery1.FieldByName('jumlah').AsFloat;
22. B := MyQuery1.FieldByName('jumlahnetto').AsFloat;
23. MyQuery1.Next;
24. end;
25. end;
26. QueryPerformanceCounter(FStopCounter);
27.
28. Label1.Caption := FloatToStr((FStopCounter - FStartCounter) / FFreq);
29.
30. MyQuery1.Active := False;
31. MyConnection1.Connected := False;
32.end;

Hasil dari eksekusi rutin tersebut adalah 117,7975 detik.

Hasil Pengukuran Metode 1

Hasil Pengukuran Metode 1

Cukup lama bukan ? Lalu adakah teknik untuk mempersingkat operasi tersebut ? Tentu saja ada !

Metode 2

Teknik ini mungkin sudah banyak diketahui, namun mungkin jarang digunakan. Alih - alih menggunakan nama field untuk mencari field yang dikehendaki, teknik ini langsung mengakses alamat referensi dari field yang dikehendaki dengan memanfaatkan nomor indeks field tersebut dalam daftar field. Tentu saja untuk melakukannya harus diketahui terlebih dahulu nomor indeks yang tepat. Field pertama diakses melalui nomor indeks 0, field kedua diakses melalui nomor indeks 1, demikian seterusnya.

Salah satu sebab teknik ini jarang dilakukan adalah karena konsistensi nomor urut field. Jika misalnya terdapat perubahan susunan tabel atau perintah query, maka nomor urut field dimungkinkan tidak sesuai lagi. Dengan demikian harus dilakukan perubahan nomor urut pada kode sumber.

Disisi lain, teknik ini sangat sesuai apabila diterapkan pada aplikasi konversi / migrasi database / tabel dimana jumlah dan nama field sangat variatif. Disini, nama field tidak dapat dijadikan sebagai acuan. Yang perlu dilakukan hanyalah memberikan nomor indeks dari awal hingga akhir dan lakukan proses iterasi per record, dari field awal sampai akhir.

Berdasarkan kode metode 1, maka dilakukan perubahan seperti pada kode berikut:

01.procedure TForm2.btnMethod2Click(Sender: TObject);
02.var
03. A, B : Double;
04. FFreq : Int64;
05. FStartCounter : Int64;
06. FStopCounter : Int64;
07. I : Integer;
08.begin
09. MyConnection1.Connected := True;
10. MyQuery1.Active := True;
11.
12. A := 0;
13. B := 0;
14. QueryPerformanceFrequency(FFreq);
15. QueryPerformanceCounter(FStartCounter);
16. for I := 0 to 1000 do
17. begin
18. MyQuery1.First;
19. while not MyQuery1.Eof do
20. begin
21. A := MyQuery1.Fields[12].AsFloat;
22. B := MyQuery1.Fields[13].AsFloat;
23. MyQuery1.Next;
24. end;
25. end;
26. QueryPerformanceCounter(FStopCounter);
27.
28. Label2.Caption := FloatToStr((FStopCounter - FStartCounter) / FFreq);
29.
30. MyQuery1.Active := False;
31. MyConnection1.Connected := False;
32.end;

Hasil dari eksekusi rutin tersebut adalah 27,1231 detik. Sangat manjur bukan ?

Hasil Pengukuran Metode 2

Hasil Pengukuran Metode 2

Masih belum puas dengan hasil tersebut ? Simak teknik berikutnya.

Metode 3

Teknik ini lebih jarang lagi digunakan. Alih - alih melakukan penunjukan field yang dimaksud dengan memberikan nomor indeks yang sesuai pada setiap iterasi record dimana proses penunjukan field membutuhkan proses untuk mengakses kelas TField, teknik ini langsung mengakses kelas TField tersebut berada. Caranya adalah dengan terlebih dahulu mendapatkan alamat dimana kelas TField tersebut berada. Alamat tersebut kemudian di simpan pada variabel lokal yang akan digunakan untuk mengakses field tersebut secara langsung.

Berikut kode untuk metode 3:

01.procedure TForm2.btnMethod3Click(Sender: TObject);
02.var
03. A, B : Double;
04. FFreq : Int64;
05. FStartCounter : Int64;
06. FStopCounter : Int64;
07. I : Integer;
08. AField : TField;
09. AField2 : TField;
10.begin
11. MyConnection1.Connected := True;
12. MyQuery1.Active := True;
13.
14. A := 0;
15. B := 0;
16. QueryPerformanceFrequency(FFreq);
17. QueryPerformanceCounter(FStartCounter);
18. AField := MyQuery1.FieldByName('jumlah');
19. AField2 := MyQuery1.FieldByName('jumlahnetto');
20. for I := 0 to 1000 do
21. begin
22. MyQuery1.First;
23. while not MyQuery1.Eof do
24. begin
25. A := AField.AsFloat;
26. B := AField2.AsFloat;
27. MyQuery1.Next;
28. end;
29. end;
30. QueryPerformanceCounter(FStopCounter);
31.
32. Label3.Caption := FloatToStr((FStopCounter - FStartCounter) / FFreq);
33.
34. MyQuery1.Active := False;
35. MyConnection1.Connected := False;
36.end;

Hasil dari eksekusi rutin tersebut adalah 26,9201 detik.

Hasil Pengukuran Metode 3

Hasil Pengukuran Metode 3

Tentu saja masih ada celah perbaikan walaupun pengaruhnya mungkin tidak signifikan, tergantung dari kode Anda, yaitu dengan mengganti kode FieldByName menjadi Fields[x] dimana x adalah nomor indeks field yang dikehendaki.

Contoh kode diatas sangat intensif menggunakan variabel bertipe TField untuk menampung alamat referensi dari field yang dikehendaki. Lalu bagaimana apabila jumlah field yang diakses sangat banyak atau bahkan sangat bervariasi ? Bukankah sangat tidak efisien apabila mendeklarasikan semua variabel yang diperlukan ? Lalu adakah teknik untuk mensiasatinya ? Simak metode selanjutnya.

Metode 4

Salah satu teknik yang dapat digunakan adalah dengan menggunakan array dinamis. Namun untuk menyederhanakan pembahasan, pada contoh ini hanya akan mengunakan array statis.

01.procedure TForm2.btnMehtod4Click(Sender: TObject);
02.var
03. A, B : Double;
04. FFreq : Int64;
05. FStartCounter : Int64;
06. FStopCounter : Int64;
07. I : Integer;
08. AField : array [1..2] of TField;
09.begin
10. MyConnection1.Connected := True;
11. MyQuery1.Active := True;
12.
13. A := 0;
14. B := 0;
15. QueryPerformanceFrequency(FFreq);
16. QueryPerformanceCounter(FStartCounter);
17. AField[1] := MyQuery1.FieldByName('jumlah');
18. AField[2] := MyQuery1.FieldByName('jumlahnetto');
19. for I := 0 to 1000 do
20. begin
21. MyQuery1.First;
22. while not MyQuery1.Eof do
23. begin
24. A := AField[1].AsFloat;
25. B := AField[2].AsFloat;
26. MyQuery1.Next;
27. end;
28. end;
29. QueryPerformanceCounter(FStopCounter);
30.
31. Label4.Caption := FloatToStr((FStopCounter - FStartCounter) / FFreq);
32.
33. MyQuery1.Active := False;
34. MyConnection1.Connected := False;
35.end;

Sama seperti sebelumnya, tentu saja masih ada celah perbaikan walaupun pengaruhnya mungkin tidak signifikan, tergantung dari kode Anda, yaitu dengan mengganti kode FieldByName menjadi Fields[x] dimana x adalah nomor indeks field yang dikehendaki.

Hasil dari eksekusi rutin tersebut adalah 26,8862 detik.

Hasil Pengkuran Metode 4

Hasil Pengkuran Metode 4

Sebagai latihan, silahkan mencoba dengan jumlah field yang lebih banyak dan bandingkan hasilnya. Adakah terjadi peningkatan kecepatan ? Silahkan cari tahu sendiri sebabnya.

Semoga bermanfaat.