Delphi memo
2008年4月30日〜
Suns & Moon Laboratory
あちこち勘違いな所もあったるすので、ごめんなさい。と、逃げをうっておく。
型
基本
| Integer | 符号付き32bit |
| Cardinal | 符号付き32bit |
符号付き
| ShortInt | 符号付き8bit |
| SmallInt | 符号付き16bit |
| LongInt | 符号付き32bit |
| Int64 | 符号付き32bit |
符号無し
| Byte | 符号無し8bit |
| Word | 符号無し16bit |
| LongWord | 符号無し32bit |
| UInt64 | 符号無し32bit |
要注意 Win64のExtendedは、Win32よりも精度が悪い
| Win32 | Win64 |
| Double | 8byte | 8byte |
| Extended | 10byte | 8byte |
Generics
Generics.Collections
TObjectXXXは、リスト(スタック,キュー)から削除した時に、オブジェクトを自動的に開放する。
TArray
TEnumerable
| TDicitionary | キー-値ペア |
| TList | インデックスによってアクセス出来る順序付きリスト |
| TQueue | FIFO |
| TStack | FILO |
TObjectDictionary
TObjectList
TObjectQueue
TObjectStack
uses Generics.Collections;
var
xlist:TList<integer>;
begin
xlist:=TList<integer>.Craete;
try
xlist.Add(1);
xlist.Add(2);
xlist.Add(3);
for i=0 to xlist.Count-1 do
begin
memo(StrToInt(xlist[i]))
end;
finally
xlist.Free;
end;
仮想メソッドと動的メソッド
| 仮想メソッド | 動的メソッド |
| virtual | dynamic |
| 実効速度最適化 | コードサイズ最適化 |
オーバーライドと隠蔽
オーバーライドした場合は、継承されたメソッドが呼び出される
隠蔽した場合は、宣言したクラスのメソッドが呼び出される。
program OverrideRedeclared;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
const
CRLF = #13#10;
type
T1 = class(TObject)
procedure Act; virtual;
end;
T2 = class(T1)
procedure Act; // Act is redeclared, but not overridden
end;
T3 = class(T1)
procedure Act; override; // Act is redeclared, overridden
end;
procedure std_out(str: string);
begin
write(str + CRLF);
end;
var
SomeObject1: T1;
SomeObject2: T2;
procedure T1.Act;
begin
std_out('T1.Act');
end;
procedure T2.Act;
begin
std_out('T2.Act');
end;
procedure T3.Act;
begin
std_out('T3.Act');
end;
begin
try
{ TODO -oUser -cConsole メイン : ここにコードを記述してください }
SomeObject1 := T2.Create;
try
SomeObject1.Act; // calls T1.Act
finally
SomeObject1.Free;
end;
SomeObject2 := T2.Create;
try
SomeObject2.Act; // calls T2.Act
finally
SomeObject2.Free;
end;
SomeObject1 := T3.Create;
try
SomeObject1.Act; // calls T3.Act
finally
SomeObject1.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
抽象メソッド
実装が無いメソッド
procedure DoSomething; virtual; abstract;
クラスフィールド
C言語の静的データメンバみたいなもの...
オブジェクト参照なしでアクセスできるクラス内のデータフィールド
クラスフィールドに保存されるデータは、クラスの全てのインスタンスで共有
クラスまたはクラスのインスタンス変数からアクセス
type TMyClass = class(TObject)
public
class var//静的クラスフィールドのブロック開始
Top:Integer;
Bottom:Integer;
var//ブロック終了
end;
GDI+
GDI+DelphiXE2
こんな感じで拡大・縮小表示可能。便利。
implementation
uses GDIPAPI, GDIPOBJ;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
grp: TGPGraphics;
img: TGPImage;
rct: TGPRect;
ratio: double;
begin
if OpenPictureDialog1.Execute then
begin
grp := TGPGraphics.Create(Image1.Canvas.Handle);
img := TGPImage.Create(OpenPictureDialog1.FileName);
try
ratio := img.GetWidth / img.GetHeight;
rct := MakeRect(0, 0, Trunc(Image1.Height * ratio), Image1.Height);
grp.DrawImage(img, rct);
finally
grp.Free;
img.Free;
end;
end;
end;
GDI+Delphi2009
Delphi2009で使うには、下記からダウンロードする。
ID: 26950, Easy to use Delphi 2009 GDI+ 1.1 Library (version 1.2)
デバッグ出力
表示→デバッグ→イベントログ
OutputDebugString(PWideChar(index+' '+IntToStr(ofs)+' = '+Result));
keyword dbgout
配列
配列、動的配列 わかりやすい
動的配列の実体はポインタなんだけど、逆参照演算子(^)使っちゃいけいないそうだ。(ObjectPascal言語ガイド)

動的配列
SetLength関数で要素数を設定
High関数で要素数-1を取得。要素数が0の時は、-1を返す。
Length関数で要素数を取得
colors:array of TColor;
SetLength(colors,5);
for i=0 to High(colors) do
colors[i]
多次元動的配列
const
SIZEW = 4;
SIZEH = 10;
procedure TForm1.Button1Click(Sender: TObject);
var
arr1: array [0 .. SIZEW - 1] of array [0 .. SIZEH - 1] of integer;
arr2: array of array of integer;
i, j, k: integer;
str: string;
begin
SetLength(arr2, SIZEW);
for i := 0 to SIZEW - 1 do
begin
SetLength(arr2[i], SIZEH);
end;
k := 0;
for i := 0 to SIZEW - 1 do
begin
for j := 0 to SIZEH - 1 do
begin
arr1[i, j] := k;
arr2[i, j] := k;
inc(k);
end;
end;
for i := 0 to SIZEW - 1 do
begin
str := '';
for j := 0 to SIZEH - 1 do
begin
str := str + ' ' + IntToStr(arr2[i, j]);
end;
memo(str);
end;
動的メモリ
GetMemory→FreeMemory
GetMem→FreeMem
var
ptr:pointer;
begin
try
ptr:=GetMemory(600*1024*1024); //600MBytes!!
finally
FreeMemory(ptr);
end;
GetMemとの差は、Delphi2010のヘルプ(System.GetMemory)によると、
メモ: GetMemory は、GetMem の C++ 互換バージョンです。
AllocMemとGetMem
AllocMemは、割り当てて0初期化する。GetMemは0初期化しない。
フィル
メモリの初期化
FillChar(m_Buffer^,total_size,$FF);
動的配列の場合
ちょっとわかりにくいが、こうみたい。
FillChar(Buffer[0],total_size,$FF);
コピー
最後にNULを付加するので、MaxLen+1のDestが必要
SysUtils.StrLCopy(Dest,Source,MaxLen)
コピー。名前は移動だけど。
procedure Move(const Source; var Dest; Count: Integer);
memcpyと方向逆なのと、var渡しのが要注意。ここらへんが判りづらい。
move例1
procedure TForm1.Button1Click(Sender: TObject);
var
Buffer: array of Byte;
src_ptr,dst_ptr:PByte;
i: integer;
begin
SetLength(Buffer, 256);
for i := 0 to Length(Buffer) - 1 do
Buffer[i] := i;
memo('before');
for i := 0 to 10 - 1 do
begin
memo(IntToStr(i) + '=' + IntToStr(Buffer[i]));
end;
src_ptr:=PByte(Buffer);
dst_ptr:=PByte(Buffer);
inc(src_ptr,4);
Move(src_ptr^, dst_ptr^, 3);
memo('after');
for i := 0 to 10 - 1 do
begin
memo(IntToStr(i) + '=' + IntToStr(Buffer[i]));
end;
Move(Buffer[7], Buffer[0], 3);
memo('after2');
for i := 0 to 10 - 1 do
begin
memo(IntToStr(i) + '=' + IntToStr(Buffer[i]));
end;
end;
出力
before
0=0
1=1
2=2
3=3
4=4
5=5
6=6
7=7
8=8
9=9
after
0=4
1=5
2=6
3=3
4=4
5=5
6=6
7=7
8=8
9=9
after2
0=7
1=8
2=9
3=3
4=4
5=5
6=6
7=7
8=8
9=9
move例2
procedure TForm1.Button2Click(Sender: TObject);
var
buf1: array of Byte;
buf2: array of Byte;
i: integer;
begin
SetLength(buf1, 8);
SetLength(buf2, 8);
for i := 0 to High(buf1) do
buf1[i] := i;
for i := 0 to High(buf2) do
buf2[i] := 0;
memo('--- before ---');
for i := 0 to High(buf1) do
memo('buf1[' + IntToStr(i) + ']=' + IntToStr(buf1[i]));
for i := 0 to High(buf2) do
memo('buf2[' + IntToStr(i) + ']=' + IntToStr(buf2[i]));
Move(PByte(buf1)^, PByte(buf2)^, Length(buf1));
memo('--- after ---');
for i := 0 to High(buf1) do
memo('buf1[' + IntToStr(i) + ']=' + IntToStr(buf1[i]));
for i := 0 to High(buf2) do
memo('buf2[' + IntToStr(i) + ']=' + IntToStr(buf2[i]));
end;
出力
--- before ---
buf1[0]=0
buf1[1]=1
buf1[2]=2
buf1[3]=3
buf1[4]=4
buf1[5]=5
buf1[6]=6
buf1[7]=7
buf2[0]=0
buf2[1]=0
buf2[2]=0
buf2[3]=0
buf2[4]=0
buf2[5]=0
buf2[6]=0
buf2[7]=0
--- after ---
buf1[0]=0
buf1[1]=1
buf1[2]=2
buf1[3]=3
buf1[4]=4
buf1[5]=5
buf1[6]=6
buf1[7]=7
buf2[0]=0
buf2[1]=1
buf2[2]=2
buf2[3]=3
buf2[4]=4
buf2[5]=5
buf2[6]=6
buf2[7]=7
スタックサイズ
配列が大きくてスタックオーバーフローする場合は、スタックを大きくする。という手も有る。
メモリ割り当てサイズ(Delphi) - RAD Studio XE2
{$M minstacksize,maxstacksize} {$MINSTACKSIZE number} {$MAXSTACKSIZE number}
{$M 16384,1048576}
文字列・バイト配列
文字(配列)操作
FillChar
Move
文字列からバイト列に変換 Delphi2010
静的配列・動的配列・動的メモリへ変換。StrLCopyを使う。※MaxLen+1のバッファサイズ必要。
AnsiStringにしているのは、アプリケーションの都合です。
procedure TForm1.Button1Click(Sender: TObject);
var
static_arr: array [0 .. 12] of Byte;
dyn_arr: array of Byte;
buffer: PByte;
str: string;
procedure dump(ptr: PByte; len: integer);
var
i: integer;
tmp: string;
begin
tmp := '';
for i := 0 to len - 1 do
begin
tmp := tmp + IntToHex(ptr^, 2) + ' ';
inc(ptr);
end;
Memo1.Lines.Add(tmp)
end;
begin
// -----------------------------------------
Memo1.Lines.Add('文字列をバイト列に変換(静的配列)');
Memo1.Lines.Add('Length(static_arr)=' + IntToStr(Length(static_arr)));
str := '01234567';
Memo1.Lines.Add(str);
FillChar(static_arr, sizeof(static_arr), 1);
dump(@static_arr, sizeof(static_arr));
StrLCopy(PAnsiChar(@static_arr), PAnsiChar(AnsiString(str)), Length(static_arr) - 1); // ok
dump(@static_arr, sizeof(static_arr));
// -----------------------------------------
Memo1.Lines.Add('文字列をバイト列に変換(動的配列)');
str := '76543210';
Memo1.Lines.Add(str);
SetLength(dyn_arr, 16);
Memo1.Lines.Add('Length(dyn_arr)=' + IntToStr(Length(dyn_arr)));
FillChar(dyn_arr[0], Length(dyn_arr), 2);
dump(PByte(dyn_arr), Length(dyn_arr));
StrLCopy(PAnsiChar(dyn_arr), PAnsiChar(AnsiString(str)), Length(dyn_arr) - 1);
dump(PByte(dyn_arr), Length(dyn_arr));
// -----------------------------------------
Memo1.Lines.Add('文字列をバイト列に変換(動的メモリ)');
buffer := GetMemory(20);
try
str := '01234567';
Memo1.Lines.Add(str);
FillChar(buffer^, 20, 3);
dump(PByte(buffer), 20);
StrLCopy(PAnsiChar(buffer), PAnsiChar(AnsiString(str)), 22 - 1);
dump(PByte(buffer), 20);
finally
FreeMemory(buffer);
end;
end;
実行結果
Memo1
文字列をバイト列に変換(静的配列)
Length(static_arr)=13
01234567
01 01 01 01 01 01 01 01 01 01 01 01 01
30 31 32 33 34 35 36 37 00 01 01 01 01
文字列をバイト列に変換(動的配列)
76543210
Length(dyn_arr)=16
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
37 36 35 34 33 32 31 30 00 02 02 02 02 02 02 02
文字列をバイト列に変換(動的メモリ)
01234567
03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
30 31 32 33 34 35 36 37 00 03 03 03 03 03 03 03 03 03 03 03
バイト配列からStringに変換 Delphi2010
例1
var
byte_buf:array[0..15]of Byte;
begin
byte_buf[bytebuf_wr]:=0;//ヌル終端
str:=String(PAnsiChar(@byte_buf));
例2
var
static_arr:array [0..8] of Byte;
begin
StrLCopy(@static_arr,AnsiString('1234'),Length(static_arr)-1);
Memo1.Lines.Add(String(PAnsiChar(@static_arr)));
Memo1.Lines.Add(String(PAnsiChar(@static_arr[1])));
end;
実行結果
1234
234
Pointerからstringに変換 Delphi2010
var
buf:Pointer;
ptr:PByte;
begin
buf:=AllocMem(16);//AllocMemは領域を0クリアする
try
ptr:=PByte(buf);
ptr^:=$30;
inc(ptr);
ptr^:=$31;
Memo1.Lines.Add(string(PAnsiChar(buf)));
finally
FreeMem(buf);
end;
文字列を数値に変換する
TryStrToIntDef を使うと例外を出さずに数値変換出来る。
文字列処理とUnicode(Delphi2009以降)
Delphi2009以降は、VCLがUnicode化されたため、既存ソースの移行は、いろいろとあります。
Delphi 2009 特集 ★必読。わかりやすいのでお勧め。
Delphi2007以前
String = AnsiString
Char = AnsiChar
Delphi2009以降
String = UnicodeString
Char = WideChar
Delphi2010でこんなコードを書いてみる
procedure TForm1.btnAnsiCharClick(Sender: TObject);
var
arr:array [0..2] of AnsiChar;
str:String;
begin
arr[0]:=AnsiChar($82);
arr[1]:=AnsiChar($A0);
arr[2]:=AnsiChar(0);
str:=arr;
Memo1.Lines.Add('AnsiChar配列に「あ」$82$A0を入れた場合');
Memo1.Lines.Add(str);
end;
procedure TForm1.btnCharClick(Sender: TObject);
var
arr:array [0..2] of Char;
str:String;
begin
arr[0]:=Char($82);
arr[1]:=Char($A0);
arr[2]:=Char(0);
str:=arr;
Memo1.Lines.Add('Char配列に「あ」$82$A0を入れた場合');
Memo1.Lines.Add(str);
end;
結果はこう
AnsiChar配列に「あ」$82$A0を入れた場合
あ
Char配列に「あ」$82$A0を入れた場合
□
□の部分は、見た目がそうなるという事で、□のコードに変換されたわけでは無いです。
文字列処理
Ansi付き関数は、日本語使える
Ansi無しは日本語つかうと駄目な時有る
比較
uses SysUtils
function SameStr(S1: string; S2: string): Boolean;//大文字小文字区別する
function SameText(S1: string; S2: string): Boolean;//大文字小文字区別しない
CompareStr,CompareTextも同様だが、戻り値がIntegerになる。
検索
uses System
function Pos(const Substr: string; const S: string): Integer;
SubstrがSに有る場合は、その位置を1〜nで返す。※1からというのが罠
無い場合は、0を返す。
切り出し
uses System
function Copy(S:string;Index:Integer;Count:Integer):string;
Indexは1からというのが罠
置換
uses StrUtils
ReplaceStr(const AText:string;const AFromText:string;const AToText:string):string; 大文字小文字区別
ReplaceText(const AText:string;const AFromText:string;const AToText:string):string; 大文字小文字区別しない
StringReplace AnsiString用
初期化 initialization
var
uid:integer;
implementation
:
:
initialization
uid:=0;
end.
ラベルとgoto
procedure test;
label
exit_success;
begin
goto exit_success;
:
:
exit_success:
:
end;
プロパティで配列
function Getvalues(index: integer): string;
procedure Setvalues(index: integer; const Value: string);
property values[index:integer]:string read Getvalues write Setvalues;
プロパティで関数
type
TSampleEvent = procedure (const Value: string) of object;
type
TTestEventProperty = class(TObject)
private
FOnSample: TSampleEvent;
public
property OnSampleEvent: TSampleEvent read FOnSample write FOnSample;
end;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure testfunc(const Value: string);
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.testfunc(const Value: string);
begin
ShowMessage(Value);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
sample:TTestEventProperty;
begin
sample:=TTestEventProperty.Create;
try
sample.OnSampleEvent:=testfunc;
sample.OnSampleEvent('syokun!');
finally
sample.Free;
end;
end;
例外
uses SysUtils;
raise Exception.Create('Error!!');
浮動小数点(double,float)を文字列に変換
その1
uses SysUtils;
FloatToStrF(Tick/1000,ffFixed,15,3);
その2
uses SysUtils;
FormatFloat('00',12);
その3
f:=0.000012345678;
memo(FloatToStrF(f,ffExponent,4,1));
memo(FloatToStrF(f,ffExponent,4,2));
memo(FloatToStrF(f,ffExponent,3,2));
//出力
1.235E-5
1.235E-05
1.23E-05
日付時刻
EncodeDateTime 年月日から日付時刻を生成
uses SysUtils;
dt := EncodeDateTime(2012,8,29);
DateTimeToStr 日付時刻を文字列に変換
ソース
uses SysUtils;
Memo1.Lines.Add(DateTimeToStr(Now));
結果
2009/01/29 20:28:12
DateTimeToString 日付時刻を文字列に変換
ソース
uses SysUtils;
var
str:string;
fname:string;
begin
DateTimeToString(str,'yymmdd_hhnnss',Now);
fname:=ExtractFilePath(Application.ExeName)+str+'.csv';
Memo1.Lines.Add(fname);
end;
結果
070127_112913
070127_112914
TDateTimeから曜日を取得
Delphi2010
uses DateUtils;
DayOfTheWeek(dt)
で、戻り値は
DayMonday
とかで比較。
TDateTime演算
Delphi2010
一日増やすのは単純に1足せばよい。
日付間の日数は、下記関数で求める。
uses DateUtils;
DaysBetween(ANow:TDateTime,ATHen:TDateTime):integer;
| DaySpan | 端数有り |
| DaysBetween | 端数無し |
| HoursBetween | |
| MinuteBetween | |
| SecondsBetween | |
| WeeksBetween | |
| YearsBetween | |
ファイルの日付取得
function get_file_date(fname: string): integer;
var
FileHnd: integer;
begin
{ ファイルのハンドルを取得 }
FileHnd := FileOpen(fname, fmOpenRead);
try
{ ファイルのタイムスタンプを取得 }
Result := FileGetDate(FileHnd);
{ タイムスタンプを日付型に変換 }
finally
FileClose(FileHnd);
end;
end;
列挙型
CでいうところのEnum
type
TGohan = (ghAsaGohan,ghHiruGohan,ghBanGohan);
この場合、Ord(ghAsaGohan)は0、Ord(ghHiruGohan)は1を返す。
名前衝突の回避
例えばghAsaGohanの名前衝突が起きた場合。
Gohan:=MyUnit.ghAsaGohan;
参照 単純型 → 列挙型
集合
type
TGohan = set of (ghAsaGohan,ghHiruGohan,ghBanGohan);
if ghAsaGohan in gohan then
nattou.mazemaze;
空集合は[]で表す。
構造体,Record
type
PNS_HEAD = ^NOTE_TO_SH;
NOTE_TO_SH = record
lMitei2Size:Longint;
lVerUpStartAddress:Longword;
cYobi:array[0..31] of char;
end;
TFileStream,ファイルサイズ,共有モード
read GetMemして読み込み
var
fs: TFileStream;
ptr: PByte;
begin
GetMem(ptr, BUFFER_SIZE);
try
fs := TFileStream.Create(filename, fmOpenRead);
try
fs.Read(ptr^, BUFFER_SIZE);
finally
fs.Free
end;
finally
FreeMem(ptr);
end;
end;
read 配列に読み込み
var
fs:TFileStream;
size:integer;
chunk_size:integer;
read_size:integer;
fname:string;
arr:TLongwordArray;
i:integer;
begin
fname:='sample.bin';
fs:=TFileStream.Create(fname,fmOpenRead or fmShareDenyWrite);
try
size:=fs.Size;
chunk_size:=4096;
read_size:=chunk_size;
while size>0 do
begin
if read_size>size then
read_size:=size;
fs.Read(arr,read_size);
for i := 0 to (read_size div 4) - 1 do
begin
//arr[i]
end;
size:=size-read_size;
end;
finally
fs.Free;
end;
end;
write
var
fs:TFileStream;
begin
acc_size:=READ_MEMORY_SIZE;
remain:=readsize;
fs:=TFileStream.Create(fname,fmCreate);
try
while remain>0 do
begin
fs.Write(PChar(m_Buffer + SizeOf(SH4USBIF_HEADER)+SizeOf(SH_TO_NOTE))^,acc_size);
end;
finally
fs.Free
end;
end;
注意点
procedure TForm1.btnRefClick(Sender: TObject);
var
fs:TFileStream;
fname:string;
begin
if OpenDialog1.Execute then
begin
fname:=OpenDialog1.FileName;
edFname.Text:=fname;
fs:=TFileStream.Create(fname,fmOpenRead or fmShareDenyNone);
try
edSize.Text:=IntToStr(fs.Size);
finally
fs.Free;
end;
end;
end;
TImage上でマウスドラッグ
procedure TfrmMain.ImageViewMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
memo('mouse down');
MouseCapture:=True;
end;
procedure TfrmMain.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
memo('main mouse move');
end;
procedure TfrmMain.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
memo('main mouse up');
MouseCapture:=False;
end;
TChart(TeeChart)
TChartのヘルプ
なんか、どう探してもインストールされていない様な気がします(RAD Studio 2007)。
しかたないので、CODE GEARからTeeChartをダウンロード、インストールして、その中に有るヘルプを見ています。
TChartの情報
TeeChart Pro version 8 VCL / CLX
ニュートンQ&A(TeeChart Pro 7J VCL)
PointerのStyle

↓こんな雰囲気
TLineSeries.Pointer.Style:=TSeriesPointerStyle(cmbPointerStyle.ItemIndex);
TLineSeries.Pointer.Visible:=chkPointerVisible.Checked;
↓実際はこう。VisibleをTrueにしないと見えない。
Series1.Pointer.Style:=psCircle;
Series1.Pointer.Visible:=True;
終了コード
System.ExitCodeで戻り値を返す事が可能。
戻り値はバッチファイルならば、ERRORLEVELで判定可能。
別のexe実行
ShellExecute
ShellExecute(Application.Handle,'open',PChar(cmd),PChar(option),nil,SW_NORMAL);
ShellExecuteEX
バッチファイルから終了コードを返したい場合は、「exit 1」とかで指定可能です。
function TForm1.shell_exec(cmd:string;option:string):DWORD;
var
sei:SHELLEXECUTEINFO;
begin
ZeroMemory(@sei, sizeof(SHELLEXECUTEINFO));
//構造体のサイズ
sei.cbSize := sizeof(SHELLEXECUTEINFO);
//起動側のウインドウハンドル
sei.Wnd := Handle;
//起動後の表示状態
sei.nShow := SW_SHOWNORMAL;
//このパラメータが重要で、セットしないとSHELLEXECUTEINFO構造体のhProcessメンバがセットされない。
sei.fMask := SEE_MASK_NOCLOSEPROCESS;
//起動プログラム
sei.lpFile := PChar(cmd);
sei.lpParameters := PChar(option);
//プロセス起動
if not ShellExecuteEx(@sei) then//shell32.lib必須
exit;
//エラー?
if sei.hInstApp <= 32 then
exit;
//終了を待つ
WaitForSingleObject( sei.hProcess, INFINITE ) ;
//戻り値を取得
GetExitCodeProcess(sei.hProcess, Result);
end;
CreateProcess
パイプ使った入出力のサンプルは↓から
http://www.autch.net/page/tips/delphi_anonymous_pipe.html
エクスプローラからドラッグドロップ
type
TForm1 = class(TForm)
private
{ Private 宣言 }
procedure WMDropFiles(var Msg: TWMDropFiles); Message WM_DropFiles;
end;
implementation
uses ShellApi;
{$R *.dfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
DragAcceptFiles(Handle,True);
end;
procedure TForm1.WMDropFiles(var Msg: TWMDropFiles);
var
num_files:integer;
i:integer;
FileName: Array[0..MAX_PATH] of Char;
begin
num_files := DragQueryFile(Msg.Drop, $FFFFFFFF, nil, 0);
for i := 0 to num_files - 1 do
begin
DragQueryFile(Msg.Drop, i, FileName, SizeOf(FileName));
Memo1.Lines.Add(String(FileName));
end;
DragFinish(Msg.Drop);
end;
参考
http://kwi.cocolog-nifty.com/blog/2005/12/delphi_drag__dr_e30d.html
http://www.geocities.co.jp/Milano/8000/delphi/dragdrop.html
コンポーネントを動的に生成
一般的な例ではないのですが、こんな感じで。
procedure TForm1.btnComm1CreateClick(Sender: TObject);
begin
comm1:=TComm.Create(self);
comm1.BaudRate:=9600;
comm1.ByteSize:=cbs8;
comm1.ParityBits:=cpbNone;
comm1.StopBits:=csb1;
comm1.FlowControls:=[];
comm1.Port:=1;
comm1.OnCommReceive:=Comm1CommReceive;
comm1.Open;
end;
procedure TForm1.Comm1CommReceive(Sender: TObject; Size: Word);
begin
end;
タスクバーに表示しない
メインフォームをタスクバーで非表示にする方法。
ヘルプを見ると、Runメソッドの呼び出し前にとなっています。
とりあえずFormCreateとかで良いかと。
Application.ShowMainForm:=False;
環境変数
GetEnvironmentVariable('OS')
ファイルとフォルダの有無確認
ファイルの有無確認はFileExists
ディレクトリの有無確認はDirectoryExists
if not DirectoryExists('xyz') then
MkDir('xyz');
タイトルバーの無いフォームの移動(WM_NCHITTEST)
引用元失念。
procedure WMNCHITTEST(var Msg: TWMNCHITTEST); message WM_NCHITTEST;
procedure WMNCLButtonDBLCLK(var msg :TWMNCHitMessage); message WM_NCLBUTTONDBLCLK;
procedure TFormHusen.WMNCHITTEST(var Msg: TWMNCHITTEST);
var
Pt:TPoint;
begin
//マウス座標を取得
GetCursorPos(Pt);
//フォーム上の座標に変換
Pt := ScreenToClient(Pt);
if GetAsyncKeyState(VK_LBUTTON) < 0 then
//ウィンドウズにタイトル バーで発生することを示すHTCAPTIONを返す
Msg.Result := HTCAPTION
else
Msg.Result := HTCLIENT;
end;
//WMNCHITTESTで小細工しているので、ダブルクリックをFormのイベントで検出出来ない
procedure TFormHusen.WMNCLButtonDBLCLK(var msg: TWMNCHitMessage);
begin
end;
TListView
選択されたアイテムを取得する方法。
TCustomListView.GetNextItem メソッド
TListを継承して独自のリストを作成。ついでにソートもしてみる。
TListはメモリの確保をしないので、メモリの確保と解放をするように実装。
TObjectListを参考に実装してみました。
とりあえず作ってみた物の、悩み中。
実装
unit IkCustomList;
interface
uses Classes;
type
TIkDoubleList = class(TList)
Protected
procedure Notify(Ptr: Pointer; Action: TListNotification); override;
function GetItem(Index: Integer): Double;
procedure SetItem(Index: Integer; const Value: Double);
public
procedure Clear; override;
function Add(Value: Double): Integer;
property Items[Index: Integer]: Double read GetItem write SetItem; default;
end;
function CompareDouble(item1,item2:Pointer):Integer;
implementation
//Sort用比較関数
function CompareDouble(item1, item2: Pointer): Integer;
begin
if PDouble(item1)^ < PDouble(item2)^ then
Result:=-1
else if PDouble(item1)^ > PDouble(item2)^ then
Result:=1
else
Result:=0
end;
{ TIkDoubleList }
function TIkDoubleList.Add(Value: Double): Integer;
var
p:PDouble;
begin
New(p);
p^:=Value;
Result:=Inherited Add(p)
end;
//この方法だと、Extractの戻り値が使えなくなる。が、実害はなさそう。
procedure TIkDoubleList.Notify(Ptr: Pointer; Action: TListNotification);
begin
if Action = lnDeleted then
begin
Dispose(Ptr);
end;
inherited Notify(Ptr, Action);
end;
procedure TIkDoubleList.Clear;
var
i:integer;
begin
for i := 0 to Count - 1 do
Delete(0);//ClearはTListでは要素の解放をしない。ちなみにDestroyではClear呼出しが存在する。
inherited Clear;
end;
function TIkDoubleList.GetItem(Index: Integer): Double;
begin
Result:= PDouble(inherited Items[index])^;
//Items[index]をアクセスすると、TList.Getが呼ばれる
//TList.Getはポインタを返す。
//ポインタを逆参照して値を返す。
end;
procedure TIkDoubleList.SetItem(Index: Integer; const Value: Double);
begin
PDouble(inherited Items[index])^:=Value;
//Items[index]をアクセスすると、TList.Getが呼ばれる
//TList.Getはポインタを返す。
//ポインタを逆参照して値を入れる。
end;
end.
使い方
TMemoとTButtonをはりつけて、下記ソースみたくする。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,IkCustomList;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
dlist:TIkDoubleList;
i:integer;
begin
dlist:=TIkDoubleList.Create;
try
for i := 0 to 100 do
dlist.Add(Random()*100);
dlist.Sort(@CompareDouble);
for i := 0 to 100 do
Memo1.Lines.Add( FloatToStr(dlist.Items[i]));
finally
dlist.Free;
end;
end;
end.
Indy10 IdFTP
Indy
List→ListResultは、ファイル名とかになっていないので不便。
List→DirectoryListingは、便利なのだが、使おうとするといきなりエラー。
で、以下の追加が必須。
uses IdAllFTPListParsers
参考:FTPでlistがDirectoryListingに入らない。
コンポーネントのインストール方法
参考:コンポーネントのインストール方法等
インストール
Delphi2007
CodeGear RAD Studio 2007 ISO (Dec 2007)
これを入れる。以下が入っている。
December 2007 Update
February 2008 Help Update
そんでもって、「スタート→CodeGear RAD Studio→アップデートの確認」で更新をかけるとMay08 Help Updateが入る。
注意:2009→2007入れるとはまるのでやめとけー
glyFXはどこー?
きれいなアイコンglyFXは
C:\Program Files\Common Files\CodeGear Shared\Images\glyFX
C:\Program Files\Common Files\Borland Shared\Images\glyFX
引用:glyFX Embarcadero Special Edition Icon Set for Embarcadero Customers
グローバル変数、ローカルな変数
interface部に書けばグローバル。
implementationに書けばローカル。
色定数
Delphi2010
Delphi色定数の一覧
KeyPressイベント
Delphi2010
if Key = Char(VK_RETURN) then
DLL
DelphiXE2
http://www.s-m-l.org/csharp.html#DLLを呼ぶ
library testdll1;
uses
System.SysUtils,
System.Classes;
{$R *.res}
procedure func1(path: PAnsiChar; opt: LongWord); stdcall;
var
strlist:TStringList;
begin
strlist:=TStringList.Create;
try
strlist.Add(path);
strlist.SaveToFile('d:\testdll1.txt');
finally
strlist.Free;
end;
end;
exports
func1;
begin
end.
DLL呼び出し
DelphiXE2
procedure func1(path: PAnsiChar; opt: LongWord); stdcall; external 'testdll1.dll';
procedure TForm1.Button1Click(Sender: TObject);
var
str: AnsiString;
begin
str := AnsiString(Edit1.Text);
func1(PAnsiChar(str), 1);
end;
DLLの遅延ロード
Delphi2010
dll呼び出し宣言に、delayedを追加。
参考:Team Japan ≫ Delphi 2010: 新機能 delayed ディレクティブ
ディレクトリ選択ダイアログ
uses FileCtrl;
var
path:string;
begin
if SelectDirectory('Caption','',path) then //真ん中は初期パス
exec_proc(path);
end;
第16回エンバカデロ・デベロッパーキャンプ
第16回エンバカデロ・デベロッパーキャンプ - 資料ダウンロード
景品当たった!わーいw
Delphi2010での文字列処理
2010-03-10のセミナーメモ
SKRegExp
TIniFile→TMemoIniFileでEncoding指定
TStringListのLoad,Saveはエンコーディング指定を推奨
ExcelはUTF-16のCSV読み込み対応しない
SysUtils.StringOf(),WideStringOf()
MECSUtils
TStringGrid
選択範囲の取得。ClickやDoubleClickイベントで、クリックしたセルの特定にも使える。
var
rc:TGridRect;
begin
rc:=StringGrid1.Selection;
TColorとRGB
color:TColor;
r,g,b:Byte;
color:=RGB(255,128,64);
r = GetRValue(color);
g = GetGValue(color);
b = GetBValue(color);
color := RGB(r,g,b);
ダイアログ
ShowMessage を使うと簡単なメッセージ表示可能
SelectDirectory を使うと簡単にディレクトリ選択可能
MessageDlg を使うと簡単な問い合わせ可能。
if MessageDlg('確認して下さい',mtConfirmation,[mbRetry,mbAbort],0)<>mrRetry then
Exit;
end;
乱数
Randomize
Random(Range)
0 <= X < Range
DUnit
とりあえずDelphi2010でやってみる。
テストユニット実行
uses GUITestRunner
GUITestRunner.RunRegisteredTests;
テスト対象の記述(簡単なクラス)
delphi/Calc.pas
テストの記述
SetupとTearDownは、各テスト(procedure)毎に呼び出される。
delphi/TestCalc.pas
TFlowPanel
Delphiでフローレイアウト
ControlIndexで表示順序を変更可能。
Formの重なり順序
メインフォームと別のフォームの重なり順序が変更出来ない。
プロジェクトソースの以下をコメントアウトすると、順序が変更出来る。
Application.MainFormOnTaskbar := True;
参考:フォームの重なり順序を変更する方法は?
ファイル名操作
uses SysUtils
ExtractFilePath ファイル名からパスを取り出す
ChangeFileExt 拡張子を変更
IncludeTrailingPathDelimiter パス区切り文字を追加
ディレクトリ操作
ディレクトリ作成 SysUtils.ForceDirectories
ディレクトリ削除 SysUtils.RemoveDir
ディレクトリ存在確認 SysUtils.DirectoryExists
procedure TForm1.Button1Click(Sender: TObject);
var
path: string;
begin
path := tmp_path;
if DirectoryExists(path) then
begin
memo('Exists ' + path);
end
else
begin
memo('not exists ' + path);
ForceDirectories(path); // 絶対パス・複数ディレクトリ
memo('ForceDirectories ' + path);
end;
if DirectoryExists(path) then
begin
memo('Exists ' + path);
end
else
begin
memo('not exists ' + path);
ForceDirectories(path);
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
RemoveDir(tmp_path); // SysUtils
end;
procedure TForm1.memo(str: string);
begin
Memo1.Lines.Add(str);
end;
function TForm1.tmp_path: string;
begin
Result := ExtractFilePath(Application.ExeName) + 'tmp';
end;
// 似た様な処理を行う関数
// Sysutils.CreateDir
// System.MkDir
// System.RmDir
プロパティで関数
type
IxAddNewFunc = procedure (caption:String) of Object;
type
IxTest = class(TObject)
protected
FAddNew:IxNewFunc;
public
property AddNew:IxAddNewTabFunc read FAddNew write FAddNew;
end;
----
procedure add_new(caption: string);
----
var
tst:IxTest;
begin
tst:=IxTest.Create;
tst.AddNew := add_new;
便利なTStringList
CSVをデコードしたり、Name=Value形式をデコードしたり出来る。
var
strlist:TStringList;
begin
strlist:=TStringList.Create;
try
strlist.CommaText:='a=1,b=2,c=3';
memo('---- Strings[] ----');
memo(strlist.Strings[0]);
memo(strlist.Strings[1]);
memo(strlist.Strings[2]);
memo('---- Values[] ----');
memo(strlist.Values['a']);
memo(strlist.Values['b']);
memo(strlist.Values['c']);
memo(strlist.Values['d']);//エラーにはならない
finally
strlist.Free;
end;
end;
Editでキーイベント
procedure TfrmSettings.Edit2KeyPress(Sender: TObject; var Key: Char);
begin
if Ord(Key) = VK_RETURN then
begin
memo('hit return');
end;
end;
コンパイラ指令
| Delphi | C言語 | |
| {$DEFINE XYZ} | #define XYZ |
| {$I xyz.inc} | #include "xyz.inc" |
{$IFDEF XYZ} {$ENDIF} | #ifdef XYZ #endif |
{$IF exp} {$ELSE} {$IFEND} | #if exp #else #endif |
ショートカットキー
CTRL+D ソース整形
CTRL+SHIFT+C カーソル位置のクラス宣言保管(コード生成)
CTRL+SHIFT+J 同期編集(リファクタリングより軽くて便利)
選択してTAB インデント→
選択してSHIFT+TAB インデント←
メモリリーク検出
http://komish.com/delphi/memoryleak.htm
ReportMemoryLeaksOnShutdown := True
OSXで動的読み込み可能ライブラリ(dylib)を遅延読み込みできない
https://forums.embarcadero.com/thread.jspa?threadID=80777&tstart=15
リンク
CodeGear 旧Delphi FAQ
Delphi Library [Mr.XRAY] 高度なサンプル有ります。
Delphi 2009 特集 ★必読。漢字コードの問題に関してわかりやすく解説されています。
DEKOのアヤシいお部屋。 読みやすいので、ささっと目を通すだけでも役に立ちます。
CとDelphiの対比表
Delphi 7ユーザと初心者のためのDelphi 2010入門
2013-03-13 21:18:09 32400