Home New Help Edit

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よりも精度が悪い
Win32Win64
Double8byte8byte
Extended10byte8byte

Generics

Generics.Collections

TObjectXXXは、リスト(スタック,キュー)から削除した時に、オブジェクトを自動的に開放する。

TArray
TEnumerable

TDicitionaryキー-値ペア
TListインデックスによってアクセス出来る順序付きリスト
TQueueFIFO
TStackFILO
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;
TDictionaryで列挙してみる
var pairs: TDictionary<string, integer>; val: TPair<string, integer>; i:integer; begin pairs := TDictionary<string, integer>.Create; pairs.Add('name1', 10); pairs.Add('name2', 220); pairs.Add('name3', 11); pairs.Add('name4', 310); //ペアの列挙 for val in pairs do memo(val.Key + '=' + IntToStr(val.Value)); //値の列挙 for i in pairs.Values do memo(IntToStr(i)); end;

仮想メソッドと動的メソッド

仮想メソッド動的メソッド
virtualdynamic
実効速度最適化コードサイズ最適化

オーバーライドと隠蔽

オーバーライドした場合は、継承されたメソッドが呼び出される
隠蔽した場合は、宣言したクラスのメソッドが呼び出される。
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;

TImage画像読み込み


usesにJpeg,GIFImg,PNGImageを追加する。

参考 http://ht-deko.minim.ne.jp/tech054.html

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関数で要素数を取得

var colors: array of TColor; i: integer; begin SetLength(colors, 5); Memo1.Lines.Add('High(colors)=' + IntToStr(High(colors)));
実行時Memo1の表示
High(colors)=4

動的配列の引数渡し


procedure TForm1.test3; var buffer: TBytes; begin SetLength(buffer, 8); Memo1.Lines.Add('array of bytes : High(buffer)=' + IntToStr(High(buffer))); func_set_len(buffer); Memo1.Lines.Add('array of bytes : High(buffer)=' + IntToStr(High(buffer))); end; procedure TForm1.func_set_len(var buf: TBytes); begin SetLength(buf, 16); end;
実行時Memo1の表示
array of bytes : High(buffer)=7 array of bytes : High(buffer)=15

多次元動的配列

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初期化しない。

TMemoryStream

var ptr:PByte; ms:TMemoryStream; begin ms:=TMemoryStream.Create; ms.SetSize(256); ptr:=ms.Memory; ms.Free;

フィル

メモリの初期化
FillChar(m_Buffer^,total_size,$FF);
動的配列の場合
ちょっとわかりにくいが、こうみたい。
FillChar(Buffer[0],total_size,$FF); FillChar(Buffer[0],Length(Buffer),$FF); FillChar(PByte(Buffer)^,Length(Buffer),$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

TBytesからStringに変換 Delphi2009

TEncoding.GetString()を使う
バイナリからの文字列生成

バイト配列から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用

正規表現

uses RegularExpressions; procedure TForm1.Button1Click(Sender: TObject); var match:TMatch; i:integer; begin match:=TRegEx.Match(Edit1.Text,Edit2.Text); if match.Success then begin memo('success'); memo('value='+match.Value); for i := 0 to match.Groups.Count-1 do begin memo(match.Groups.Item[i].Value); end; end else begin memo('fail'); end; end;
使用例
Edit1.Text := 'aaabb(COM12)';
Edit2.Text := '\(COM(\d+)\)$';
この場合
match.Groups.Item[0].Valueに'12'が入る


初期化 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

TDateTime置き換え

RecodeXXXで、年、月、日、時、分、秒を個別に置き換え
RecodeMilliSecond RecodeSecond RecodeHour RecodeDay RecodeMonth RecodeYear

ファイルの日付取得

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

Windowsは、SW_xx,SHELLAPIは、APIいろいろの定義
バッチファイルから終了コードを返したい場合は、「exit 1」とかで指定可能です。

uses Windows,SHELLAPI; 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');
ファイル操作
uses System.IOUtils TFile.Copy TFile.Move TFile.Delete TFile.Exists //FileExistsと同じ?

ファイルの列挙

深い階層まで検索したい場合は、再帰呼び出しを実装する必用有り。

procedure get_file_list(items: TStrings; find_str: string); // 1階層のみ var SearchRec: TSearchRec; begin // FindFirst が成功した場合のみ FindClose を呼ぶ必要がある if 0 = FindFirst(find_str, faAnyFile, SearchRec) then begin try repeat if (SearchRec.Attr and faDirectory) = 0 then begin // ファイル items.Add(SearchRec.Name) end; until 0 <> FindNext(SearchRec); finally FindClose(SearchRec); end; end; end;

タイトルバーの無いフォームの移動(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.

Indy

TCPとUDPの通信例

ソケットライブラリのIndyを利用したクリップボード共有ソフト Delphi7+Indy9
ソケットライブラリのIndy10を利用してみよう C++Builder2007+Indy10

Indy10 IdFTP

Indy
List→ListResultは、ファイル名とかになっていないので不便。

List→DirectoryListingは、便利なのだが、使おうとするといきなりエラー。
で、以下の追加が必須。
uses IdAllFTPListParsers
参考:FTPでlistがDirectoryListingに入らない。

TIdHTTPServer.AutoSession

INDY10 XE5
こうしないとAutoSession有効にならない?
AutoSession=true
SessionState=true
SessionTimeOut=1以上

コンポーネントのインストール方法

参考:コンポーネントのインストール方法等

インストール

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;

スレッド


無名メソッドとスレッド 無名メソッドでスレッドのSynchronizeを書く
利点:引数を渡すために別途変数を定義する必要がなくなる
欠点:速度的に若干のペナルティ、構文知らないと読めない

Delphiで非同期プログラミング

TAnonymousThread

Samples\Delphi\RTL\CrossPlatform Utils\AnonThread.pas

  1. ジェネリクスを使っている為、スレッド処理の戻り値を指定可能
  2. 終了処理は、通常の終了と、例外の2種類を記述可能
  3. 終了処理は、TThread.OnTerminateから呼び出されるので、Synchronizeがいらない。System.Classes.TThread.OnTerminate
  4. メイン中に記述すれば、受け渡しの変数を作成しなくても済む とかかなー。便利そう。

Cross platform anonymous threads and progress notification Samplesに入っているTAnonymousThreadの解説
TAnonymousThreadは、MAC,iOSではTNSAutoreleasePoolを実装しています。
iPhoneアプリ開発時のメモリ管理で気をつけること(マルチスレッド編) TNSAutoreleasePoolをスレッド毎に実装しないとメモリリークする。

コンパイラ指令

DelphiC言語
{$DEFINE XYZ}#define XYZ
{$I xyz.inc}#include "xyz.inc"
{$IFDEF XYZ}
{$ENDIF}
#ifdef XYZ
#endif
{$IF exp}
{$ELSE}
{$IFEND}
#if exp
#else
#endif

条件付きコンパイル(Delphi)定義済みのシンボル

ショートカットキー

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

DeleteFileでワーニング

usesの順序が重要。順序によってはH2443のワーニングが出る。
正しい順序
Windows,
SysUtils,
Classes,

タイプライブラリの取り込み

タイプライブラリの取り込み

JSONを使う

DelphiXE4

uses Data.DBXJSON, //これ追加 Data.DBXPlatform; //for in do 使うのにこれあった方が良い procedure TForm1.Button1Click(Sender: TObject); var json_obj: TJSONObject; begin json_obj := TJSONObject.Create; try json_obj.AddPair('key1', 'val1'); json_obj.AddPair('key2', 'val2'); Memo1.Lines.Add(json_obj.ToString); finally json_obj.Free; end; end; procedure TForm1.Button2Click(Sender: TObject); var json_obj: TJSONObject; pair: TJSONPair; begin json_obj := TJSONObject.ParseJSONValue('{"key1": "val1", "key2": 123}') as TJSONObject; // パース失敗するとnil try for pair in json_obj do begin Memo1.Lines.Add(pair.JsonString.Value + '->' + pair.JsonValue.Value); end; finally json_obj.Free; end; end;
Button1を押した結果
{"key1":"val1","key2":"val2"}
Button2を押した結果
key1->val1 key2->123
DBXPlatform無い時のヒント
[dcc32 ヒント] Unit1.pas(51): H2443 インライン関数 'TJSONPairEnumerator.GetCurrent' はユニット 'Data.DBXPlatform' が USES リストで指定されていないため展開されません
http://d.hatena.ne.jp/nullpobug/20121025/1351170571

リモートデバッグ(paserver)

クロスプラットフォーム アプリケーションのデバッグ(新しいリモート デバッグ方法)

  1. paserverをインストール
  2. paserverを実行
  3. 接続プロファイルを作成


paserverのインストール


C:\Program Files\Embarcadero\RAD Studio\n.n\PAServer\setup_paserver.exe n.n はリリース バージョン(XE5 では 12.0)を表します。
参考:Windows でのプラットフォーム アシスタントのインストール


paserverの実行

C:\Program Files\Embarcadero\RADPAServer\n.n\paserver.exe n.n はリリース バージョン(XE5 では 12.0)を表します。
参考:Windows でのプラットフォーム アシスタントの実行

接続プロファイルの作成

メニュー→ツール→オプション→環境オプション→接続プロファイルマネージャ

参考:接続プロファイル マネージャ

アプリケーションの配置

アプリケーションと、その他ファイルをリモートに配置するには、配置マネージャを使用します。
メニュー→プロジェクト→配置

配置マネージャで、配置(緑右矢印)をクリックすると、接続プロファイルを割り当てできる。

配置マネージャで、リモートマシンに接続(PCが2台)をクリックすると、リモートマシンに接続

F9を押すと、配置して実行される。

リモートデバッグからもとに戻す

プロジェクトマネージャ→ファイル→ProjectGroup1→XXX.exe→ターゲットプラットフォーム→32ビットウィンドウズ を右クリックして、「デフォルトの接続に戻す」を選択。

DLL,dylibをダイナミックロード

動的にロードする方法
http://d.hatena.ne.jp/nullpobug/20130616/1371314885

マウスカーソルを隠す(非表示)

ShowCursor関数の戻り値が、0未満の時にマウスカーソルが非表示になる。
非表示になるのは、自分のウィンドウ
uses Windows; ShowCursor(false);

iOS,Indy,XML

http://blogs.embarcadero.com/teamj/2013/05/16/3877/

リンク

CodeGear 旧Delphi FAQ
Delphi Library [Mr.XRAY] 高度なサンプル有ります。
Delphi 2009 特集 ★必読。漢字コードの問題に関してわかりやすく解説されています。
DEKOのアヤシいお部屋。 読みやすいので、ささっと目を通すだけでも役に立ちます。
CとDelphiの対比表
Delphi 7ユーザと初心者のためのDelphi 2010入門
ホワイトペーパー: モバイル開発のためのDelphi言語 Delphi言語仕様変わる

Home New Help Edit
2014-04-12 13:57:34 32400