dev/delphi
*Delphi memo 2008年4月30日〜 [[index]] [[firemonkey]] はこちら [[https://github.com/mikekoma/DelphiLabo]] テストコード置き場 あちこち勘違いな所もあったりするので、ごめんなさい。と、逃げをうっておく。 [[https://docwiki.embarcadero.com/]] 本家DocWiki [[RAD Studio 11 Alexandria ヘルプ>https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8]] [[RAD Studio 10.4 Sydney ヘルプ>http://docwiki.embarcadero.com/RADStudio/Sydney/ja/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8]] #contents **Assign [[delphi_assign]] **型 [[10.1Berlin 内部データ形式>http://docwiki.embarcadero.com/RADStudio/Berlin/ja/%E5%86%85%E9%83%A8%E3%83%87%E3%83%BC%E3%82%BF%E5%BD%A2%E5%BC%8F%EF%BC%88Delphi%EF%BC%89]] 符号付き |Int8,ShortInt|符号付き8bit |Int16,SmallInt|符号付き16bit |Int32,LongInt|符号付き32bit |Int32,Integer|符号付き32bit |Int64|符号付き32bit 符号無し |UInt8,Byte|符号無し8bit |UInt16,Word|符号無し16bit |UInt32,LongWord|符号無し32bit |UInt64|符号無し32bit 要注意 Win64のExtendedは、Win32よりも精度が悪い ||Win32|Win64 |Double|8byte|8byte |Extended|10byte|8byte **volatile >volatile 属性は、別のスレッドにより変更される可能性があるフィールドにマークを付けて、そのフィールドの値をレジスタまたは別の一時メモリ領域にコピーする操作がコード生成の際に最適化されないようにするために使用されます。 [[RADStudio⇒Alexandria⇒コンパイラ属性>https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E5%B1%9E%E6%80%A7]] >type > TMyClass = class(TObject) > private > [volatile] count:integer; > end; **列挙型 CでいうところのEnum >type > TGohan = (ghAsaGohan,ghHiruGohan,ghBanGohan); この場合、Ord(ghAsaGohan)は0、Ord(ghHiruGohan)は1を返す。 名前衝突の回避 例えばghAsaGohanの名前衝突が起きた場合。 Gohan:=MyUnit.ghAsaGohan; 参照 [[単純型 → 列挙型>http://docwiki.embarcadero.com/RADStudio/ja/%E5%8D%98%E7%B4%94%E5%9E%8B#.E5.88.97.E6.8C.99.E5.9E.8B]] **集合 >type > TGohan = set of (ghAsaGohan,ghHiruGohan,ghBanGohan); > > if ghAsaGohan in gohan then > nattou.mazemaze; 空集合は[]で表す。 > Grid.Options := Grid.Options + [goEditing]; **構造体,Record > type > PNS_HEAD = ^NOTE_TO_SH; > NOTE_TO_SH = record > lMitei2Size:Longint; > lVerUpStartAddress:Longword; > cYobi:array[0..31] of char; > end; レコードと、レコードを返す関数 > type > TIxSerial = record > Used: boolean; > Value: UInt64; > end; > > function IxSerial(val: UInt64; Used: boolean): TIxSerial; > begin > Result.Value := val; > Result.Used := Used; > end; **Generics [[ジェネリックスの概要>http://docwiki.embarcadero.com/RADStudio/Tokyo/ja/%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AE%E6%A6%82%E8%A6%81]] ***定義の例 >type > TIxBuffer
= class(TObject) > protected > FValue: T; > public > procedure Push(Value: T); > function Pop: T; > end; > >function TIxBuffer
.Pop: T; >begin > Result := FValue; >end; > >procedure TIxBuffer
.Push(Value: T); >begin > FValue := Value; >end; ***使い方例 >var > buf_str: TIxBuffer
; > buf_int: TIxBuffer
; >begin > buf_str := TIxBuffer
.Create; > try > buf_str.Push('abcd'); > memo(buf_str.Pop); > finally > buf_str.Free; > end; > > buf_int := TIxBuffer
.Create; > try > buf_int.Push(10); > memo(buf_int.Pop.toString); > finally > buf_int.Free; > end; > >end; **System.Generics.Collections 汎用コンテナユニット [[http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.Generics.Collections]] TObjectXXXは、リスト(スタック,キュー)から削除した時に、オブジェクトを自動的に開放する。 TArray TEnumerable |TDicitionary|キー-値ペア |TList|インデックスによってアクセス出来る順序付きリスト |TQueue|FIFO |TStack|FILO |TObjectList|オブジェクトのメモリ管理してくれる。Delete,Remove,Clear,Freeでオブジェクト解放。 TObjectDictionary TObjectQueue TObjectStack [[スレッド間データ受け渡し>http://www.s-m-l.org/dev/delphi.html#スレッド間データ受け渡し]] -TThreadedQueue 受け渡しにロック操作不要 -TThreadList 追加・削除にロック操作不要、Listアクセス時ロック >uses Generics.Collections; >var > MemoQueue: TThreadedQueue
; >begin > MemoQueue := TThreadedQueue
.Create(100, 1, 1);//キュー深さ、Pushタイムアウト、Popタイムアウト。タイムアウト指定無しはタイムアウト無しになる。 > > MemoQueue.PushItem('hello'); > >//別スレッド >var > str:string; >begin > if MemoQueue.PopItem(str)=wrSignaled then > Memo1.Lines.Add(str);//wrSignaledの時str有効。タイムアウト時間はCreate時指定。 >uses Generics.Collections; >var > xlist:TList
; >begin > xlist:=TList
.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
; > val: TPair
; > i:integer; >begin > pairs := TDictionary
.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; ***ソートTArray.Sort 動的配列をソートする [[山本隆の開発日誌 - TArray.Sortで配列をソートする>http://www.gesource.jp/weblog/?p=6043]] [[System.Generics.Defaults.TComparer.Compare>http://docwiki.embarcadero.com/Libraries/XE7/ja/System.Generics.Defaults.TComparer.Compare]] >uses System.Generics.Collections, System.Generics.Defaults; > >type > TPointFComparer = class(TComparer
) > public > function Compare(const Left, Right: TPointF): Integer; override; > end; > >function TPointFComparer.Compare(const Left, Right: TPointF): Integer; >begin > if Left.X < Right.X then > Result := -1 > else if Left.X > Right.X then > Result := +1 > else if Left.Y < Right.Y then > Result := -1 > else if Left.Y > Right.Y then > Result := +1 > else > Result := 0; >end; > >procedure TForm1.Button1Click(Sender: TObject); >var > i: Integer; > pt: TPointF; > arr: array of TPointF; >begin > // ----------------------------------------- > // init > // ----------------------------------------- > Randomize; > > SetLength(arr, 10); > for i := Low(arr) to High(arr) do > begin > arr[i].X := Random(100); > arr[i].Y := Random(100); > end; > > // ----------------------------------------- > // show > // ----------------------------------------- > ListBox1.Clear; > for pt in arr do > begin > ListBox1.Items.Add(FloatToStr(pt.X) + ' ' + FloatToStr(pt.Y)); > end; > > // ----------------------------------------- > // sort > // ----------------------------------------- > TArray.Sort
(arr, TPointFComparer.Create); > > // ----------------------------------------- > // show > // ----------------------------------------- > ListBox2.Clear; > for pt in arr do > begin > ListBox2.Items.Add(FloatToStr(pt.X) + ' ' + FloatToStr(pt.Y)); > end; > >end; ***ソートTObjectList.Sort ****比較するクラスを作る TObjectListをソートするには、比較するクラスを作ってやる。 TCompareはGenerics.Defaults >unit Unit1; > >interface > >uses > System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, > FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, > FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo, > Generics.Collections, Generics.Defaults; > >type > TIxPoint = class(TObject) > public > Text: string; > X: Single; > Y: Single; > end; > >type > TIxPointComparer = class(TComparer
) > public > function Compare(const Left, Right: TIxPoint): Integer; override; > end; > >type > TForm1 = class(TForm) > Memo1: TMemo; > Button1: TButton; > procedure Button1Click(Sender: TObject); > private > { private 宣言 } > public > { public 宣言 } > end; > >var > Form1: TForm1; > >implementation > >{$R *.fmx} > >function TIxPointComparer.Compare(const Left, Right: TIxPoint): Integer; >begin > Result := Round(Left.Text.ToSingle - Right.Text.ToSingle); >end; > >procedure TForm1.Button1Click(Sender: TObject); >var > objlist: TObjectList
; > obj: TIxPoint; >begin > objlist := TObjectList
.Create; > try > obj := TIxPoint.Create; > obj.Text := '2'; > objlist.Add(obj); > > obj := TIxPoint.Create; > obj.Text := '3'; > objlist.Add(obj); > > obj := TIxPoint.Create; > obj.Text := '1'; > objlist.Add(obj); > > Memo1.Lines.Add('---- before sort ----'); > for obj in objlist do > begin > Memo1.Lines.Add(obj.Text); > end; > > objlist.Sort(TIxPointComparer.Create); > > Memo1.Lines.Add('---- after sort ----'); > for obj in objlist do > begin > Memo1.Lines.Add(obj.Text); > end; > > finally > objlist.Free; > end; > >end; > >end. ****無名メソッド版1 クラスを宣言しなくても、無名メソッドでこうもかける。が、宣言した方が使うのは簡単だと思うのでうーん。 > objlist.Sort(TComparer
.Construct( > function(const Item1, Item2: TIxPoint): Integer > begin > Result := Round(Item1.Text.ToSingle - Item2.Text.ToSingle); > end)); ****無名メソッド版2 Delphi11.3 値が数値でなくても比較可能とかいいつつ、以下の例は数値比較だけど。 >type > TIxItem = class(TObject) > public > Value: Integer; > end; > >uses System.Generics.Collections; > >procedure TForm1.Button1Click(Sender: TObject); >var > objlst: TObjectList
; > item: TIxItem; >begin > // 生成 > objlst := TObjectList
.Create; > try > for var i := 0 to 5 do > begin > item := TIxItem.Create; > item.Value := Round(Random(100)); > objlst.Add(item); > end; > > // ソート前 > Memo1.Lines.Add('before sort.'); > for item in objlst do > begin > Memo1.Lines.Add(item.Value.ToString); > end; > > // ソート > objlst.Sort(System.Generics.Defaults.TComparer
.Construct( > function(const L, R: TIxItem): Integer > begin > if L.Value = R.Value then > Result := 0 > else if L.Value < R.Value then > Result := -1 > else > Result := 1; > end)); > > // ソート後 > Memo1.Lines.Add('after sort.'); > for item in objlst do > begin > Memo1.Lines.Add(item.Value.ToString); > end; > > finally > objlst.Free; > end; >end; **インライン変数 変数の型は型推論で決定される。 > for var i:=0 to 3 do [[インライン変数>https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/%E3%82%A4%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%B3%E5%A4%89%E6%95%B0%E5%AE%A3%E8%A8%80]] **デフォルトパラメータ 引数を省略 制限いろいろあるみたい→[[パラメータ(Delphi)>http://docwiki.embarcadero.com/RADStudio/XE6/ja/%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%EF%BC%88Delphi%EF%BC%89]] > procedure FillArray(A: array of Integer; Value: Integer = 0); **仮想メソッドと動的メソッド |仮想メソッド|動的メソッド |virtual|dynamic |実効速度最適化|コードサイズ最適化 **静的クラスメソッド 関数をクラス内に宣言出来る。 ただし、クラスメンバにアクセスできない。関数がクラス内に入れられるだけ。 あまりメリット無い? わかりやすい解説 [[関数ポインタとメソッドポインタの相互代入のおはなし。→クラスメソッド(静的な意味で>https://lyna.hateblo.jp/entry/20121205/1354636256]] [[docwiki メソッド→静的クラスメソッド>https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%EF%BC%88Delphi%EF%BC%89#.E9.9D.99.E7.9A.84.E3.82.AF.E3.83.A9.E3.82.B9_.E3.83.A1.E3.82.BD.E3.83.83.E3.83.89]] **手続き・関数・メソッド 手続きは戻り値の無いルーチン 関数は戻り値の有るルーチン メソッドはクラスに関連付けられた手続き・関数 [[docwiki 手続きと関数>https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/%E6%89%8B%E7%B6%9A%E3%81%8D%E3%81%A8%E9%96%A2%E6%95%B0%EF%BC%88Delphi%EF%BC%89]] **オーバーライドと隠蔽 オーバーライドした場合は、継承されたメソッドが呼び出される 隠蔽した場合は、宣言したクラスのメソッドが呼び出される。 > 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 > 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; [[http://docwiki.embarcadero.com/RADStudio/Seattle/ja/%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89]] **メッセージ TMessagingManagerというのを使うと簡単にメッセージ処理を追加可能。 参考:[[TMessageManagerってこんなの。>http://d.hatena.ne.jp/tales/20130622/1371894728]] 以下はほぼサンプルまま。メッセージハンドラに、無名メソッドを登録している。 >uses System.Messaging; >var > SubscriptionId: Integer; > MessageManager: TMessageManager; > >procedure TForm1.FormCreate(Sender: TObject); >begin > MessageManager := TMessageManager.DefaultManager; > > SubscriptionId := MessageManager.SubscribeToMessage(TMessage
, > procedure(const Sender: TObject; const M: TMessage) > begin > ShowMessage((M as TMessage
).Value); > end); >end; > >procedure TForm1.FormDestroy(Sender: TObject); >begin > MessageManager.Unsubscribe(TMessage
,SubscriptionId); >end; > >procedure TForm1.Button1Click(Sender: TObject); >var > msg: TMessage
; >begin > MessageManager := TMessageManager.DefaultManager; > msg := TMessage
.Create('This is a string message.'); > MessageManager.SendMessage(Sender, msg, True); >end; **インターフェース ***インターフェースを用いたSingletonの実装 Printerみたいなやつ [[【Delphi】 Interface による Singleton>https://qiita.com/pik/items/179897de81657292699c]] **TImage画像読み込み usesにJpeg,GIFImg,PNGImageを追加する。 参考 [[http://ht-deko.minim.ne.jp/tech054.html]] **PNG読み込み 10.2tokyo FireMonkeyだとTBitmap.LoadFromFileでPNG読み込み出来る。 VCLだと、読み込めないのでこうする。 >uses PngImage; >var > png: TPngImage; > ext: string; >begin > ext := ExtractFileExt(opt_src_fname); > if ext = '.bmp' then > begin > bmp_src.LoadFromFile(opt_src_fname); > end > else if ext = '.png' then > begin > png := TPngImage.Create; > try > png.LoadFromFile(opt_src_fname); > bmp_src.SetSize(png.Width, png.Height); > bmp_src.Canvas.Draw(0, 0, png); > finally > png.Free; > end; > 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)>http://cc.embarcadero.com/item/26950]] **配列 [[配列、動的配列>http://kakinotane.s7.xrea.com/delphi/faq/f001.html]] わかりやすい 動的配列の実体はポインタなんだけど、逆参照演算子'^'使っちゃいけいないそうだ。→ObjectPascal言語ガイド &img(pointer.png); ***配列の型宣言 静的配列 TByteArray >type TByteArray = array [0..32767] of Byte; 動的配列 TBytes > TArray
= array of T; ***動的配列の要素数 SetLength関数で要素数を設定 High関数で要素数-1を取得。要素数が0の時は、-1を返す。 Length関数で要素数を取得 ****要素数取得の例1 >var > colors: array of TColor; > i: integer; >begin > SetLength(colors, 5); > Memo1.Lines.Add('High(colors)=' + IntToStr(High(colors))); 実行時Memo1の表示 >High(colors)=4 ****要素数取得の例2 >var > buf1: array [0 .. 9] of Byte; > buf2: array [0 .. 9] of Word; > buf3:array of Byte; > buf4:array of Word; >begin > SetLength(buf3,10); > SetLength(buf4,10); > memo('SizeOf(buf1)='+IntToStr(SizeOf(buf1))); > memo('SizeOf(buf2)='+IntToStr(SizeOf(buf2))); > memo('SizeOf(buf3)='+IntToStr(SizeOf(buf3))); > memo('SizeOf(buf4)='+IntToStr(SizeOf(buf4))); > memo('Length(buf1)='+IntToStr(Length(buf1))); > memo('Length(buf2)='+IntToStr(Length(buf2))); > memo('Length(buf3)='+IntToStr(Length(buf3))); > memo('Length(buf4)='+IntToStr(Length(buf4))); >end; 実行結果 >SizeOf(buf1)=10 >SizeOf(buf2)=20 >SizeOf(buf3)=4 >SizeOf(buf4)=4 >Length(buf1)=10 >Length(buf2)=10 >Length(buf3)=10 >Length(buf4)=10 ***動的配列の引数渡し >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 > SIZEH = 3; > SIZEW = 8; > > procedure TForm1.Button1Click(Sender: TObject); > var > arr1: array [0 .. SIZEH - 1] of array [0 .. SIZEW - 1] of integer; > arr2: array of array of integer; > i, j, k: integer; > str: string; > begin > SetLength(arr2, SIZEH, SIZEW); > //( > // (0,1,2,3,4,5,6,7), > // (0,1,2,3,4,5,6,7), > // (0,1,2,3,4,5,6,7) > //) > > k := 0; > for i := 0 to SIZEH - 1 do > begin > for j := 0 to SIZEW - 1 do > begin > arr1[i, j] := k; > arr2[i, j] := k; > inc(k); > end; > end; > > for i := 0 to SIZEH - 1 do > begin > str := ''; > for j := 0 to SIZEW - 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初期化しない。 ***ポインタが指すメモリの初期化 Winapi.Windows.pasのFillMemory関数を使う→実体はFillCharなんだけど(XE8の時) [[https://msdn.microsoft.com/ja-jp/library/cc430045.aspx]] ***TMemoryStream >var > ptr:PByte; > ms:TMemoryStream; >begin > ms:=TMemoryStream.Create; > ms.SetSize(256); > ptr:=ms.Memory; > ms.Free; ***TByteArray 便利だけど要注意なやつ。サイズが固定。 実装はこうなっている。 [[http://docwiki.embarcadero.com/Libraries/Sydney/en/System.SysUtils.TByteArray]] >type TByteArray = array [0..32767] of Byte; ***フィル メモリの初期化 > FillChar(m_Buffer^,total_size,$FF); 動的配列の場合 ちょっとわかりにくいが、こうみたい。 > FillChar(Buffer[0],total_size,$FF); > FillChar(Buffer[0],Length(Buffer),$FF); > FillChar(PByte(Buffer)^,Length(Buffer),$FF);//これでもいける ***コピー [[System.Copy>http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.Copy]] 例 >var >src:TBytes; >dst:TBytes; >begin >dst := Copy(src);//動的配列はIndex,Size指定いらない 最後にNULを付加するので、MaxLen+1のDestが必要 >SysUtils.StrLCopy(Dest,Source,MaxLen) 名前は移動だけどコピー 引数は、arr[0]の様に要素番号を書く。 > 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 ***配列のバイナリファイル書き込み 静的配列・動的配列・メモリーストリームをファイルに書き込む >var > barr: TByteArray; > darr: array of Integer; > ms: TMemoryStream; > fs: TFileStream; > wptr: PWord; >begin >fs := TFileStream.Create('test.bin', fmCreate); >try > > barr[0] := 1; > barr[1] := 2; > barr[2] := 3; > barr[3] := 4; > fs.Write(barr, 4); > > SetLength(darr, 4); > darr[0] := $12345670 + 1; > darr[1] := $12345670 + 2; > darr[2] := $12345670 + 3; > darr[3] := $12345670 + 4; > fs.Write(@darr[0], 4 * sizeof(Integer));//バッファがTBytesの時は変数名をそのまま書く > > ms := TMemoryStream.Create; > try > ms.SetSize(4 * sizeof(Word)); > wptr := ms.Memory; > wptr^ := $89A0+ 1; > inc(wptr); > wptr^ := $89A0 + 2; > inc(wptr); > wptr^ := $89A0 + 3; > inc(wptr); > wptr^ := $89A0 + 4; > fs.Write(ms.Memory, ms.Size) > finally > ms.Free; > end; > >finally > fs.Free; >end; ***スタックサイズ 配列が大きくてスタックオーバーフローする場合は、スタックを大きくする。という手も有る。 [[メモリ割り当てサイズ(Delphi) - RAD Studio XE2>http://docwiki.embarcadero.com/RADStudio/ja/%E3%83%A1%E3%83%A2%E3%83%AA%E5%89%B2%E3%82%8A%E5%BD%93%E3%81%A6%E3%82%B5%E3%82%A4%E3%82%BA%EF%BC%88Delphi%EF%BC%89]] >{$M minstacksize,maxstacksize} {$MINSTACKSIZE number} {$MAXSTACKSIZE number} >{$M 16384,1048576} **文字列・バイト配列 ***文字(配列)操作 >FillChar >Move ***文字列からバイト配列(ANSI)に変換 DelphiXE7 「012」をTEncoding.ANSIに変換して、バイナリ表示 >procedure TForm1.btnStringStreamDecodeClick(Sender: TObject); >var > ss: TStringStream; > i: integer; > ptr: PByte; > begin > ss:=TStringStream.Create('012', TEncoding.ANSI); > try > ptr := ss.Memory; > for i := 0 to ss.Size - 1 do > begin > Memo1.Lines.Add('$' + IntToHex(ptr^, 2)); > inc(ptr); > end; > > finally > ss.Free; > end; >end; ***バイト配列(ANSI)から文字列に変換 DelphiXE7 Memo1.Lines.Add('ANSIバイナリ($82,$A0,$82,$A2,$82,$A4,$30,$31,$32)を、読み込んでstringに変換 >procedure TForm1.btnStringStreamEncodeClick(Sender: TObject); >var > ss: TStringStream; > arr: array of Byte; >begin > SetLength(arr, 9); > arr[0] := $82; > arr[1] := $A0; > arr[2] := $82; > arr[3] := $A2; > arr[4] := $82; > arr[5] := $A4; > arr[6] := $30; > arr[7] := $31; > arr[8] := $32; > > ss := TStringStream.Create('', TEncoding.ANSI); > try > ss.WriteData(arr, High(arr) + 1); > Memo1.Lines.Add(ss.DataString); > finally > ss.Free; > end; >end; ***文字列からバイト列に変換 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に変換 DelphiXE10.1 TEncoding.GetString()を使う >var > strarr: TBytes; > str: string; >begin > SetLength(strarr, 8); > strarr[0] := $30; > str := TEncoding.ANSI.GetString(strarr, 0, 1); strには'0'が入る ***バイト配列から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; ***静的配列からstringに変換 Delphi10.1Seatle TStringStreamを使った変換だと、配列内のゴミまで変換していたので、やり方を変えてみた。 >var > serialnumber_buf: array [0 .. 63] of AnsiChar; > FillChar(serialnumber_buf[0], 64, 0); > > serialnumber_buf[0]:=適当な値 > serialnumber_buf[1]:=適当な値 > >SerialNumber := String(AnsiString(serialnumber_buf)); ***文字列を数値に変換する TryStrToIntDef を使うと例外を出さずに数値変換出来る。 Delphiは、'$'と'0x'に対応する!! [[http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.SysUtils.TryStrToInt]] ***文字列処理とUnicode(Delphi2009以降) Delphi2009以降は、VCLがUnicode化されたため、既存ソースの移行は、いろいろとあります。 [[Delphi 2009 特集>http://totonica.s41.xrea.com/doc/delphi_tiburon/]] ★必読。わかりやすいのでお勧め。 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を入れた場合 >□ □の部分は、見た目がそうなるという事で、□のコードに変換されたわけでは無いです。 **数値文字列変換 Formatの使い方 FDelphi過去ログ:[[形式文字列を使うFormatは便利ですが、ヘルプの説明から形式文字列を作成 するのは骨が折れます。例示があると大変助かりますが。 >http://delfusa.main.jp/delfusafloor/archive/www.nifty.ne.jp_forum_fdelphi/faq/00149.htm]] 上記URLの内容をコピー→[[delphi_format]] Format >Format('%.2d',[value]); // 00 数値を2桁で0埋め有り FormatFloatの例 > FormatFloat('0##.0', value); // 000.0 必ず整数部3桁小数部1桁を表示 **文字列処理 Ansi付き関数は、日本語使える Ansi無しは日本語つかうと駄目な時有る ***指定文字で分割 >uses System.Types, System.StrUtils; >var >sda:TStringDynArray; >begin >sda:=SplitString('abc def ghi', ' '); ***比較 > 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 System.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 System.RegularExpressions; procedure TForm1.btnTestRegularexpressionClick(Sender: TObject); >var > match: TMatch; > input_str: string; > pattern_str: string; > i: Integer; >begin > input_str := 'abcd123.scn'; > pattern_str := '(\d+)\.'; > input_str := 'aaabb(COM12)'; > pattern_str := '\(COM(\d+)\)$'; > match := TRegEx.match(input_str, pattern_str); > if match.Success then > begin > Memo('success'); > Memo('Input=' + input_str); > Memo('Pattern=' + pattern_str); > Memo('match.Value=' + match.Value); > Memo('match.Groups.Count=' + match.Groups.Count.ToString); > for i := 0 to match.Groups.Count - 1 do > begin > Memo('match.Groups.Item[' + IntToStr(i) + '].Value=' + match.Groups.Item[i].Value); > end; > end > else > begin > Memo('fail'); > end; >end; 使用例1 >success >Input=aaabb(COM12) >Pattern=\(COM(\d+)\)$ >match.Value=(COM12) >match.Groups.Count=2 >match.Groups.Item[0].Value=(COM12) >match.Groups.Item[1].Value=12 使用例2 >success >Input=abcd123.scn >Pattern=(\d+)\. >match.Value=123. >match.Groups.Count=2 >match.Groups.Item[0].Value=123. >match.Groups.Item[1].Value=123 連番ファイル名の、先頭部分を取得 >function get_file_head(fname: string): string; >var > head: string; > match: TMatch; >begin > head := ExtractFileName(fname); > head := ChangeFileExt(head, ''); > match := TRegEx.match(head, '([^0123456789])+'); > if match.Success then > begin > Result := match.Value; > end > else > begin > Result := ''; > raise Exception.Create('ファイル名の解析に失敗 TIxViewObjectFrames.get_file_head'); > end; >end; ****正規表現 置換 >uses System.RegularExpressions, System.StrUtils; >function TForm1.ReplaceCount(const Match: TMatch): string; >var > valstr: string; > vallen: Integer; > val: Integer; >begin > if Match.Success then > begin > valstr := Match.Groups.Item[1].Value; > vallen := Length(valstr); > val := StrToInt(valstr); > inc(val); > Result := RightStr('000000' + IntToStr(val), vallen) + Match.Groups.Item[2].Value; > end > else > Result := ''; >end; > >procedure TForm1.btnTestRegExReplaceClick(Sender: TObject); >var > regex: TRegEx; > myEval: TMatchEvaluator; > input_str: string; > i: Integer; >begin > input_str := 'abcd000123.scn'; > regex.Create('(\d+)(\.)'); > myEval := ReplaceCount; > for i := 0 to 4 do > begin > if regex.Match(input_str).Success then > begin > Memo('Match=' + input_str); > input_str := regex.Replace(input_str, myEval); > Memo('next=' + input_str); > end > else > begin > Memo('Match fail'); > break; > end; > end; >end; 出力 >abcd000124.scn >abcd000125.scn >abcd000126.scn >abcd000127.scn >abcd000128.scn ***文字列の繰り返し 文字や文字列の繰り返しを生成する。下記は「hello!hello!hello!」になる。 >uses System.StrUtils; >str = DupeString('hello!',3); ***CSV [[958_デリミタによる文字列の分割>http://mrxray.on.coocan.jp/Delphi/plSamples/958_SplitDelimiter.htm]] ****TSTringList.CommaText >var >csv:TStringList; >begin >csv:=TStringList.Create; >csv.CommaText:='aa,bb,c' >Memo1.Lines.Add(csv.Strings[0]); ****SplitString あくまで指定文字で分解するので、CSVのダブルクォーテーションとかには対応していない >uses System.Types, System.StrUtils; >var > sda: TStringDynArray; > prms: TStringDynArray; >begin > sda := SplitString(line, ' '); > if Length(sda) = 2 then > begin > memo('------> APPL ' + sda[1]); > prms := SplitString(sda[1], ','); > if Length(prms) >= 1 then > begin > voltage := StrToFloat(prms[0]); > **BCD ソース 変換結果は上位からMSB、Fraction[0]に収まる。 >uses Data.FMTBcd; > >procedure TForm1.Button1Click(Sender: TObject); >var > hour, min, sec, msec: Word; > year, month, day: Word; > yyyy: TBcd; > mm: TBcd; > dd: TBcd; > hh: TBcd; > nn: TBcd; > ss: TBcd; > dt: TDateTime; > str: string; >begin > dt := Now; > > DateTimeToString(str, 'yyyy-mm-dd hh:nn:ss', dt); > Memo1.Lines.Add(str); > > DecodeDate(dt, year, month, day); > DecodeTime(dt, hour, min, sec, msec); > yyyy := CurrencyToBcd(year); > mm := CurrencyToBcd(month); > dd := CurrencyToBcd(day); > hh := CurrencyToBcd(hour); > nn := CurrencyToBcd(min); > ss := CurrencyToBcd(sec); > Memo1.Lines.Add('yyyy.Fraction[0]=' + IntToHex(yyyy.Fraction[0], 2)); > Memo1.Lines.Add('yyyy.Fraction[1]=' + IntToHex(yyyy.Fraction[1], 2)); > Memo1.Lines.Add('mm.Fraction[0]=' + IntToHex(mm.Fraction[0], 2)); > Memo1.Lines.Add('dd.Fraction[0]=' + IntToHex(dd.Fraction[0], 2)); > Memo1.Lines.Add('hh.Fraction[0]=' + IntToHex(hh.Fraction[0], 2)); > Memo1.Lines.Add('nn.Fraction[0]=' + IntToHex(nn.Fraction[0], 2)); > Memo1.Lines.Add('ss.Fraction[0]=' + IntToHex(ss.Fraction[0], 2)); >end; 実行結果 > 2023-07-23 12:01:22 > yyyy.Fraction[0]=20 > yyyy.Fraction[1]=23 > mm.Fraction[0]=70 ←1桁なのでMSBによっている > dd.Fraction[0]=23 > hh.Fraction[0]=12 > nn.Fraction[0]=10 > ss.Fraction[0]=22 **初期化 initialization >var > uid:integer; >implementation > : > : >initialization > uid:=0; >end. **終了時実行 finalization [[http://docwiki.embarcadero.com/RADStudio/Seattle/ja/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%A8%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88#finalization_.E3.82.BB.E3.82.AF.E3.82.B7.E3.83.A7.E3.83.B3]] >finalization **ラベルと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!!'); ***デフォルト例外処理 DLLはデフォルト例外処理を行わないので、デフォルト例外処理を行いたい時は、別途処理を追加する。 [[VCL でのデフォルト例外処理>http://docwiki.embarcadero.com/RADStudio/Berlin/ja/VCL_%E3%81%A7%E3%81%AE%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E4%BE%8B%E5%A4%96%E5%87%A6%E7%90%86]] FireMonkeyは、FMX.Forms.TApplication **浮動小数点(double,float)を文字列に変換 その1 >uses SysUtils; > Memo1.Lines.Add(FloatToStrF(12.3456, ffFixed, 15, 3));//15が精度、3が小数の桁数 > Memo1.Lines.Add(FloatToStrF(12.345, ffFixed, 15, 3));//15が精度、3が小数の桁数 > Memo1.Lines.Add(FloatToStrF(12.345, ffFixed, 15, 2));//15が精度、2が小数の桁数 >//出力 >12.346 >12.345 >12.35 その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 **日付時刻 ***TDateTimeを年月日時分秒ミリ秒に分解 [[http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.SysUtils.DecodeDate]] [[http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.SysUtils.DecodeTime]] >var > hour, min, sec, msec: Word; > year, month, day: Word; >begin > DecodeDate(dt, year, month, day); > DecodeTime(dt, hour, min, sec, msec); ***文字列から日付時刻を生成 現在のロケール形式で文字列に変換します。従って環境によって文字列変わります。 日本語環境ならば、下記の形式になると思います。 (なぜかStringToDateTimeみたいな関数が無い) yyyy/mm/dd hh:nn:ss >StrToDateTimeDef(Value, 0.0); ***EncodeDateTime 年月日から日付時刻を生成 引数は年、月、日、時、分、秒、msec >uses SysUtils; > dt := EncodeDateTime(2012,8,29,0,0,0,0); ***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 ミリ秒まで表示する例 > DatetimeToString(str, 'mm/dd hh:nn:ss zzz : ', Now); ***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| |IncSecond|年月日時分秒もある ***TDateTime置き換え RecodeXXXで、年、月、日、時、分、秒、ミリ秒(msec)を個別に置き換え >uses System.DateUtils; > >RecodeMilliSecond >RecodeSecond >RecodeHour >RecodeDay >RecodeMonth >RecodeYear ミリ秒を切り捨てる >uses System.DateUtils; >cur_time := RecodeMilliSecond(Now, 0); ***ファイルの日付取得 > function get_file_date(fname: string): integer; > var > FileHnd: integer; > begin > { ファイルのハンドルを取得 } > FileHnd := FileOpen(fname, fmOpenRead); > try > { ファイルのタイムスタンプを取得 } > Result := FileGetDate(FileHnd); > { タイムスタンプを日付型に変換 } > finally > FileClose(FileHnd); > end; > end; **ファイル読み書き |TFileStream|write,read使用してアクセス |TStreamWriter|テキストファイルの書き込み。WriteLine使える。 **ファイル読み書き 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; ****配列に読み込み > 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; ****record(構造体)に読み込み > var > fs: TFileStream; > header: TIxANIPOVRomHeaderV5; > begin > fs := TFileStream.Create(fname, fmOpenRead); > try > fs.Read(header,sizeof(header)); > 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; ***write ****配列(array of Byte)をファイルに保存 > procedure TIxAnipov2RomGen.SaveToFile(fname: string); > var > fs: TFileStream; > slave_data_chunk: array of Byte; > begin > if EnalbeSlaveChunk then > begin > // Chunkヘッダ > SetLength(slave_data_chunk, 8); > slave_data_chunk[0] := $53; // S > slave_data_chunk[1] := $4C; // L > slave_data_chunk[2] := $41; // A > slave_data_chunk[3] := $56; // V > slave_data_chunk[4] := 0; > slave_data_chunk[5] := 1; > slave_data_chunk[6] := 2; > slave_data_chunk[7] := 3; > end; > > // ROMデータそのもの > fs := TFileStream.Create(fname, fmCreate); > try > fs.Write(slave_data_chunk[0], 8); > finally > fs.Free; > end; > end; ****配列(array of UInt16)をファイルに保存 >Buffer: array of UInt16; >SetLength(Buffer, 1024); >fs.Write(Pointer(Buffer)^, 10); //write_sizeはバイト数 ****配列(TByteArray)をファイルに保存 > procedure TIxAnipov2RomGen.gen_sd_file(frame_interval: integer; rom_fname: string); > var > fname: string; > sd_file_header: TByteArray; > begin > num_of_slave := fnames.Count; > > sd_file_header[0] := $46; // F > sd_file_header[1] := $4B; // K > sd_file_header[2] := $42; // B > sd_file_header[3] := $4D; // M > sd_file_header[4] := 8; // chunk size(4byte) > sd_file_header[5] := 0; > sd_file_header[6] := 0; > sd_file_header[7] := 0; > sd_file_header[8] := num_of_slave; // num of slave(2byte) > sd_file_header[9] := 0; > sd_file_header[10] := frame_interval; // frame interval(2byte) > sd_file_header[11] := 0; > sd_file_header[12] := $FF; // reserved > sd_file_header[13] := $FF; // reserved > sd_file_header[14] := $FF; // reserved > sd_file_header[15] := $FF; // reserved > > dst := TFileStream.Create(rom_fname, fmCreate); > try > // write header > dst.Write(sd_file_header, 16); > finally > dst.Free; > end; > end; ****Pointerで示しているバッファをファイルに保存 >procedure WriteBuffer(buf: Pointer; write_size: integer); >begin > fs.Write(buf^, write_size); ****PCharのバッファをファイルに保存 > m_Buffer:PChar; > GetMem(m_Buffer,LARGE_BUF_SIZE); > 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; **ファイル読み書き TextFile,AssignFile,Append,WriteLn,CloseFile > var > fout: TextFile; > begin > FileMode := fmOpenWrite or fmShareDenyWrite; // 共有モード:他のアプリケーションは読み込み用に開く事が出来る。書き込み用に開く事は出来ない。 > AssignFile(fout, file_name); > try > if FileExists(file_name) then > Append(fout) > else > ReWrite(fout); > WriteLn(fout, csv_val); > finally > CloseFile(fout) > end; **テキストファイルから行読み込み TStreamReader > procedure TForm1.load_from_file(fname: string); > var > fs: TStreamReader; > line: string; > begin > fs := TStreamReader.Create(fname); > try > while not fs.EndOfStream do > begin > line := fs.ReadLine; > end; > finally > fs.Free; > end; > end; **ファイル操作 ***ファイルコピー >uses System.IOUtils; >TFile.Copy(src,dst); **ZIPファイル 10.2Tokyo > uses System.Zip; >procedure TForm1.btnDecompZipClick(Sender: TObject); >var > ZipFileName: string; > ZippedFileIndex: Integer; > ZipFile: TZipFile; > DownloadedStream, DecompressionStream: TStream; > LocalHeader: TZipHeader; > bmp: TBitmap; > strlist: TStringList; >begin > ZipFileName := 'genzip.zip'; > ZippedFileIndex := 0; > > DownloadedStream := TFileStream.Create(ZipFileName, fmOpenRead); > try > ZipFile := TZipFile.Create; > try > ZipFile.Open(DownloadedStream, zmRead); > ZipFile.Read(ZippedFileIndex, DecompressionStream, LocalHeader); > > try > bmp := TBitmap.Create; > try > bmp.LoadFromStream(DecompressionStream); > finally > bmp.SaveToFile('zip1.bmp'); > bmp.Free; > Image1.Picture.LoadFromFile('zip1.bmp'); > end; > finally > DecompressionStream.Free; > end; > > ZipFile.Read('2/zip2.bmp', DecompressionStream, LocalHeader); > try > bmp := TBitmap.Create; > try > bmp.LoadFromStream(DecompressionStream); > finally > bmp.SaveToFile('2_zip2.bmp'); > bmp.Free; > Image2.Picture.LoadFromFile('2_zip2.bmp'); > end; > finally > DecompressionStream.Free; > end; > > ZipFile.Read('readme.txt', DecompressionStream, LocalHeader); > try > strlist := TStringList.Create; > try > strlist.LoadFromStream(DecompressionStream); > finally > strlist.SaveToFile('dst.txt'); > strlist.Free; > Memo1.Lines.LoadFromFile('dst.txt'); > end; > finally > DecompressionStream.Free; > end; > > finally > ZipFile.Free; > end; > finally > DownloadedStream.Free; > end; > >end; > >procedure TForm1.btnGenZipClick(Sender: TObject); >var > ZipFile: TZipFile; > UploadStream: TStream; > fs: TFileStream; >begin > UploadStream := TFileStream.Create('genzip.zip', fmCreate); > try > > ZipFile := TZipFile.Create; > try > > // src1.bmpをzip1.bmpとして追加 > ZipFile.Open(UploadStream, zmWrite); > fs := TFileStream.Create('src1.BMP', fmOpenRead); > try > ZipFile.Add(fs, 'zip1.bmp'); > finally > fs.Free; > end; > > // src2.bmpを2/zip2.bmpとして追加 > fs := TFileStream.Create('src2.BMP', fmOpenRead); > try > ZipFile.Add(fs, '2/zip2.bmp'); > finally > fs.Free; > end; > > // src.txtをreadme.txtとして追加 > fs := TFileStream.Create('src.txt', fmOpenRead); > try > ZipFile.Add(fs, 'readme.txt'); > finally > fs.Free; > end; > > finally > ZipFile.Free; > end; > > finally > UploadStream.Free; > 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; **マウスボタン >procedure TForm1.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); >var > tx, ty: Integer; >begin > tx := X div Zoom; > ty := Y div Zoom; > if Button = mbLeft then > Image.Canvas.Pixels[tx, ty] := clBlack > else if Button = mbRight then > Image.Canvas.Pixels[tx, ty] := clWhite; > > PaintBox1.Refresh; >end; **グローバルマウスフック アプリにフォーカス無くてもマウスイベント取得 [[MouseHook>https://github.com/mikekoma/DelphiLabo/tree/master/MouseHook]] GitHub **グローバルキーフック アプリにフォーカス無くてもキーイベント取得 [[KeyHook>https://github.com/mikekoma/DelphiLabo/tree/master/KeyHook]] GitHub **TChart(TeeChart) ***サンプルソース [[Delphi TChart Sample>https://github.com/mikekoma/TChartSample]] GitHub &img(tchart_sample.png); ***サンプルソース2 UDPで送ったデータを受信して、TChartでグラフ表示 [[IndyUDPandTChart>https://github.com/mikekoma/DelphiLabo/tree/master/IndyUDPandTChart]] GitHub &img(indyudptchart.png); ***TChartのヘルプ なんか、どう探してもインストールされていない様な気がします(RAD Studio 2007)。 しかたないので、CODE GEARからTeeChartをダウンロード、インストールして、その中に有るヘルプを見ています。 2022-02-03 これまた仕方なくここみてる [[http://teechart.net/docs/teechart/vclfmx/lib/html/]]] ***TChartの情報 [[TeeChart Pro version 8 VCL / CLX>http://www.steema.net/teechartdocs/]] [[ニュートンQ&A(TeeChart Pro 7J VCL)>http://www.newtone.co.jp/support/suqatc7vcl.html]] ***シリーズ動的生成 > uses VclTee.Series; >procedure TForm1.Button1Click(Sender: TObject); >var > t: integer; > total_t: integer; > series: TLineSeries; >begin > Chart1.SeriesList.Clear; > series := TLineSeries.Create(Chart1); > total_t := 48000; > for t := 0 to total_t - 1 do > begin > series.AddXY(t, cos(2 * pi * (double(t) / double(total_t)))); > end; > Chart1.AddSeries(series); >end; ***シリーズの名前 右側にシリーズの一覧が表示される(Legend)、その名前の指定方法 >var > ser: TLineSeries; >begin > ser := TLineSeries.Create(Chart1); > ser.Legend.Text:='cos'; ***Legendsのチェックボックス シリーズ一覧(Legends)は、チェックボックスを表示して、シリーズの表示オン・オフ切り替えができる 下記は実行するたびに、チェックボックス自体の表示オン・オフ切り替え > Chart1.Legend.CheckBoxes := not Chart1.Legend.CheckBoxes; &img(legend_check_hide.png); &img(legend_check_show.png); ***PointerのStyle &img(tchart_pointer_style_invisible.png); &img(tchart_pointer_style_visible.png); ↓こんな雰囲気 > TLineSeries.Pointer.Style:=TSeriesPointerStyle(cmbPointerStyle.ItemIndex); > TLineSeries.Pointer.Visible:=chkPointerVisible.Checked; ↓実際はこう。VisibleをTrueにしないと見えない。 > Series1.Pointer.Style:=psCircle; > Series1.Pointer.Visible:=True; ***棒グラフ これで棒3本 > Series1.AddBar(10000, '1', clRed); > Series1.AddBar(20000, '2', clRed); > Series1.AddBar(30000, '3', clRed); 最初の棒を5000に変更する > Series1.YValue[0]:=5000; ***縦右軸を使う(ソース) > Series1.VertAxis := aRightAxis; ***縦右軸を使う(IDE) IDEで設定する場合 Editing Chart1 -> Series -> Series2 -> General -> Options -> Vertical AxisをRightにする。 ***TCharHelperの使い方 Delphi10.1 Seatle System.Character.IsDigit使おうとすると、非推奨で、TCharHelper使えと言われる。 > c:TChar; > c.IsDigit > c.IsControl ***スクロールするグラフ TLineSeriesをスクロール表示する >procedure TForm1.add_series(val: double); >begin > Series1.AddXY(graph_x_count, val); > inc(graph_x_count); > if Series1.Count > 1000 then > Series1.Delete(0); >end; ***TChartの画面をpngに保存する > uses Vcl.Imaging.pngimage; > procedure TForm1.Button5Click(Sender: TObject); > var > fname: string; > png: TPngImage; > bmp:TBitmap; > begin > png := TPngImage.Create; > try > fname := 'test ChartTemp.bmp'; > bmp:=ChartTemp.TeeCreateBitmap; > png.Assign(bmp); > png.SaveToFile(ChangeFileExt(fname, '.png')); > finally > bmp.Free; > png.Free; > end; > end; ***TChartの画面自動更新を止めて、描画速度を上げる > Chart1.AutoRepaint := false; // 自動更新を停止して描画速度を上げる > : > チャートの更新処理 > : > Chart1.AutoRepaint := true; // 自動更新再開 > Chart1.Invalidate; // 自動更新を再開しただけだと今回の更新がきかないので明示的に再描画 ***TChartのX軸を90度回転して日付時刻にする Delphi11.3 TChartの設定 > Chart1.Axes.Bottom.LabelsAngle := 90; // ラベルの角度指定 > Chart1.BottomAxis.DateTimeFormat := 'hh:mm:ss'; // 日付時刻の書式 シリーズ生成 > var > tgtser: TLineSeries; > begin > tgtser := TLineSeries.Create(Chart1); > tgtser.Pointer.Visible := true; > tgtser.Pointer.Style := psCircle; > tgtser.XValues.DateTime := true; //これで日付時刻にする 参考。Delhpi11だとプロパティ違う [[https://steema.com/docs/teechart/net/lib/html/SteemaTeeChartAxisLabelsDateTimeFormatProperty.htm]] **終了コード 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,WinApi.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]] **エクスプローラからドラッグドロップ ***FMXコンポーネントのTDropTarget TDropTargetをフォーム上に配置 Fileterに任意のフィルターを設定 >*.txt OnDragDropイベント記述 >procedure TForm1.DropTarget1DragDrop(Sender: TObject; const Data: TDragObject; const Point: TPointF); >begin > memo(Data.Files[0]); >end; 参考 [[DelphiXE3 [FMX]ドロップ先(DropTarget)>http://afsoft.jp/program/delxe3/p12_142.html]] ***コードでドロップ受け入れ Delphi11.3 > type > TForm1 = class(TForm) > private > { Private 宣言 } > procedure WMDropFiles(var Msg: TWMDropFiles); Message WM_DropFiles; > end; > > implementation > > uses WinApi.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; 参考 [[https://www.blackcat.xyz/article.php/ProgramingFAQ_del0059]] [[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') **タイトルバーの無いフォームの移動(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 メソッド>http://docs.codegear.com/docs/radstudio/radstudio2007/RS2007_helpupdates/HUpdate3/JA/html/delphivclwin32/delphivclwin32/ComCtrls_TCustomListView_GetNextItem.html]] **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 ***UDPテキスト通信例 10.2Tokyo TIdUDPClient,TIdUDPServer,TMemo,TEditをフォーム上にドロップ。 >procedure TForm1.Button1Click(Sender: TObject); >begin > IdUDPClient1.Send(Edit1.Text); >end; > >procedure TForm1.FormCreate(Sender: TObject); >begin > IdUDPClient1.Host := '127.0.0.1'; > IdUDPClient1.Port := 55555; > IdUDPClient1.Active := true; > > IdUDPServer1.DefaultPort := 55555; > IdUDPServer1.Active := true; >end; > >procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle); >var > str: string; >begin > str := TEncoding.ASCII.GetString(AData); > Memo1.Lines.Add('UDPRead = ' + str); >end; ***UDPバイナリ通信例 11.3 Alexandria TIdUDPClient,TIdUDPServer,TMemo,TEditをフォーム上にドロップ。 >procedure TForm1.btnStartClick(Sender: TObject); >var >portno:UInt16; >begin > portno:=5555; > > // Client > IdUDPClient1.Host := '127.0.0.1'; > IdUDPClient1.Port := portno; > IdUDPClient1.Active := true; > > // Server > IdUDPServer1.DefaultPort := portno; > IdUDPServer1.Active := true; >end; > >procedure TForm1.btnSendClick(Sender: TObject); >var > data: TIdBytes; >begin > SetLength(data, 4); > for var i := Low(data) to High(data) do > data[i] := i; > > IdUDPClient1.SendBuffer(data); >end; > >procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle); >var > str: string; >begin > Memo1.Lines.Add('Length(AData)=' + Length(AData).ToString); > str := ''; > for var i := Low(AData) to High(AData) do > begin > str := str + IntToHex(AData[i], 2) + ' '; > end; > Memo1.Lines.Add('AData = ' + str); >end; ***UDPバイナリ通信例2 UDPで送ったデータを受信して、TChartでグラフ表示 [[IndyUDPandTChart>https://github.com/mikekoma/DelphiLabo/tree/master/IndyUDPandTChart]] GitHub &img(indyudptchart.png); ***TCP通信例 ボタン2個、メモ1個、IdTcpServer 1個、IdTcpClient 1個 をフォーム上に置く。 >unit Unit1; > >interface > >uses > Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, > Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdContext, Vcl.StdCtrls, Vcl.ExtCtrls, > IdCustomTCPServer, IdTCPServer, IdCmdTCPServer, IdBaseComponent, IdComponent, > IdTCPConnection, IdTCPClient, IdCmdTCPClient; > >type > TForm1 = class(TForm) > Memo1: TMemo; > Button1: TButton; > Button2: TButton; > IdTCPClient1: TIdTCPClient; > IdTCPServer1: TIdTCPServer; > procedure FormCreate(Sender: TObject); > procedure FormDestroy(Sender: TObject); > procedure Button1Click(Sender: TObject); > procedure Button2Click(Sender: TObject); > procedure IdTCPServer1Execute(AContext: TIdContext); > private > { Private 宣言 } > public > { Public 宣言 } > procedure memo(str: string); > end; > >var > Form1: TForm1; > >implementation > >{$R *.dfm} > >procedure TForm1.FormCreate(Sender: TObject); >begin > IdTCPClient1.Host := '127.0.0.1'; > IdTCPClient1.Port := 2268; > > IdTCPServer1.DefaultPort := 2268; > IdTCPServer1.Active := true; > > memo('ServerPort = ' + IdTCPServer1.DefaultPort.ToString); > IdTCPClient1.Connect; >end; > >procedure TForm1.FormDestroy(Sender: TObject); >begin > IdTCPClient1.Disconnect; >end; > >procedure TForm1.Button1Click(Sender: TObject); >begin > IdTCPClient1.IOHandler.WriteLn('hello'); // 送信する >end; > >procedure TForm1.Button2Click(Sender: TObject); >var > text: String; >begin > text := IdTCPClient1.IOHandler.ReadLn; > memo(text); >end; > >procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); >var > text: string; >begin > text := AContext.Connection.IOHandler.ReadLn; // 受信する > memo(text); > AContext.Connection.IOHandler.WriteLn('hi [' + text + ']'); // 応答を返す >END; > >procedure TForm1.memo(str: string); >begin > Memo1.Lines.Add(str); >end; > >end. ***TCPとUDPの通信例 [[ソケットライブラリのIndyを利用したクリップボード共有ソフト>http://codezine.jp/article/detail/197]] Delphi7+Indy9 [[ソケットライブラリのIndy10を利用してみよう>http://www7.atpages.jp/rudo/indytcp.html]] C++Builder2007+Indy10 ***Indy10 IdFTP [[Indy>http://www.indyproject.org/]] List→ListResultは、ファイル名とかになっていないので不便。 List→DirectoryListingは、便利なのだが、使おうとするといきなりエラー。 で、以下の追加が必須。 >uses IdAllFTPListParsers 参考:[[FTPでlistがDirectoryListingに入らない。>http://d.hatena.ne.jp/kanata_ail/20060414/1144990851]] ***TIdHTTPServer.AutoSession INDY10 XE5 こうしないとAutoSession有効にならない? AutoSession=true SessionState=true SessionTimeOut=1以上 ***TIdTCPServer.OnExecuteでポート番号 >procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); >begin > memo(AContext.Binding.Port.toString); ***TIdTCPServerの接続数 未確認だがこれっぽい? >memo(IntToStr(IDTCPServer1.Contexts.Count)); ***iOS,Indy,XML [[http://blogs.embarcadero.com/teamj/2013/05/16/3877/]] Indy Delphi XE5 -> Indy 10.6.0.5122 Delphi XE6 -> Indy 10.6.0.5040 2014-05-10 release -> Indy 10.6.0.5138 ***TIdHttpServer XE6 OnConnect,OnDisconnectにコンポーネントアクセスするような処理入れておくと、serverが終了しない。(例外が発生したりなんだりと...) 様な気がする。 ***Indy.TIdHttpでSSL通信が失敗する Delphi11.3 IndyのTIdHttpでhttpsのポストをするとエラーが発生する。 「SSL routinessl3_read_bytes:tlsv1 allert protocol version.」 &img(fail_ssl.png); 解決方法:[[Indy ネットワーク接続のセキュリティ保護>https://docwiki.embarcadero.com/RADStudio/Sydney/ja/Indy_%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E6%8E%A5%E7%B6%9A%E3%81%AE%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E4%BF%9D%E8%AD%B7]] 以下手順 libeay32.dllと、ssleay32.dllをダウンロード、DLLをexeと同じフォルダに置く [[http://indy.fulgan.com/SSL/]] フォームにTIdSSLIOHandlerSocketOpenSSL を配置 TIdHttpのIOHandlerに配置したTIdSSLIOHandlerSocketOpenSSLを割り当て TIdSSLIOHandlerSocketOpenSSL.SSLOptions.SSLVersions=sslvTLSv1_2に変更 これで動く。 **コンポーネントのインストール方法 参考:[[コンポーネントのインストール方法等>http://homepage2.nifty.com/Mr_XRAY/Delphi/CompoInstall/index.htm]] **インストール ***Delphi2007 [[CodeGear RAD Studio 2007 ISO (Dec 2007)>http://cc.embarcadero.com/item/26067]] これを入れる。以下が入っている。 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>http://www.glyfx.com/embarcadero/]] **グローバル変数、ローカルな変数 interface部に書けばグローバル。 implementationに書けばローカル。 **色定数 Delphi2010 [[Delphi色定数の一覧>../delphi2010_colors.html]] **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 ディレクティブ>http://blogs.embarcadero.com/teamj/2009/08/26/770/]] **ディレクトリ選択ダイアログ >uses FileCtrl; >var >path:string; >begin >if SelectDirectory('Caption','',path) then //真ん中は初期パス > exec_proc(path); >end; **第16回エンバカデロ・デベロッパーキャンプ [[第16回エンバカデロ・デベロッパーキャンプ - 資料ダウンロード >http://edn.embarcadero.com/article/40483]] 景品当たった!わーいw **文字列処理とエンコーディング ***Delphi2010での文字列処理 2010-03-10のセミナーメモ SKRegExp TIniFile→TMemoIniFileでEncoding指定 TStringListのLoad,Saveはエンコーディング指定を推奨 ExcelはUTF-16のCSV読み込み対応しない SysUtils.StringOf(),WideStringOf() MECSUtils ***UTF-8エンコーディング指定して保存。BOM無し。 10.2tokyo >var >strlist:TStringList; >begin >strlist:=TStringList.Create; >strlist.Add('あいう'); >strlist.WriteBOM:=false; >strlist.SaveToFile('tmp.txt', TEncoding.UTF8); **TStringGrid **表示が従来と違う。サンプル例とかと違う。 DrawingStyleをgdsThemedからgdsClassicにする **値が変更できない、Edit出来ない Options->goEditing=true にする。 **選択範囲の取得 ClickやDoubleClickイベントで、クリックしたセルの特定にも使える。 >var >rc:TGridRect; >begin >rc:=StringGrid1.Selection; **TColorとRGB >uses Windows; >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); **ダイアログ XE10.1 ShowMessage を使うと簡単なメッセージ表示可能 SelectDirectory を使うと簡単にディレクトリ選択可能 MessageDlg を使うと簡単な問い合わせ可能。※FMXでは非推奨 定義 System.UITypes.TMsgDlgType.mtConfirmation System.UITypes.TMsgDlgBtn.mbRetry > if MessageDlg('実行しますか?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) <> mrYes > Exit; >end; FMXでは非推奨なのでこっちを使う >uses FMX.DialogService.Sync; > if TDialogServiceSync.MessageDialog('ファイルの先頭から検索を始めますか', TmsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], > TMsgDlgBtn.mbYes, 0) = mrYes then > begin > // > end; **乱数 Randomize Random(Range) 0 <= X < Range **DUnit とりあえずDelphi2010でやってみる。 テストユニット実行 > uses GUITestRunner > > GUITestRunner.RunRegisteredTests; テスト対象の記述(簡単なクラス) [[delphi/Calc.pas]] テストの記述 SetupとTearDownは、各テスト(procedure)毎に呼び出される。 [[delphi/TestCalc.pas]] **TFlowPanel [[Delphiでフローレイアウト>http://edn.embarcadero.com/article/33622]] ControlIndexで表示順序を変更可能。 **Formの重なり順序 メインフォームと別のフォームの重なり順序が変更出来ない。 プロジェクトソースの以下をコメントアウトすると、順序が変更出来る。 > Application.MainFormOnTaskbar := True; 参考:[[フォームの重なり順序を変更する方法は?>http://gimite.net/bcbqtree/qtreemain.cgi?mode=thread&thread=1291]] **ファイル名操作 uses SysUtils ExtractFilePath ファイル名からパスを取り出す ChangeFileExt 拡張子を変更 IncludeTrailingPathDelimiter パス区切り文字を追加 uses System.IOUtils TPath.Combine(path1,path2) 二つのパスを結合する **ファイルとフォルダの有無確認 ファイルの有無確認は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; **ディレクトリ操作 ディレクトリ作成 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 **パス取得 特殊フォルダのパスを取得 [[サポートされているターゲット プラットフォームに適した標準の RTL パス関数>http://docwiki.embarcadero.com/RADStudio/Berlin/ja/%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%82%BF%E3%83%BC%E3%82%B2%E3%83%83%E3%83%88_%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AB%E9%81%A9%E3%81%97%E3%81%9F%E6%A8%99%E6%BA%96%E3%81%AE_RTL_%E3%83%91%E3%82%B9%E9%96%A2%E6%95%B0]] TPathは System.IOUtils にて定義。 [[torutkの日記→Windowsのディレクトリ構成ガイドライン>http://d.hatena.ne.jp/torutk/20110604/p1]] [[Mr.XRAY→アプリケーション固有のデータの置き場所>http://mrxray.on.coocan.jp/Delphi/Others/Windows_Guidelines.htm]] Delphi10.1 + Windows7 |TPath.GetHomePath|C:\Users\{ユーザー名}\AppData\Roaming|設定データ Roaming/{CompanyName}/{AppName} |TPath.GetCachePath|C:\Users\{ユーザー名}\AppData\Local|消えても良いデータ |TPath.GetTempPath|C:\Users\{ユーザー名}\AppData\Local\Temp\|アプリケーション終了後に消えても良いデータ |TPath.GetLibraryPath|D:\data\trunk\Lab\Delphi10\path\Win32\Debug\| |TPath.GetDocumentsPath|C:\Users\{ユーザー名}\Documents| |TPath.GetSharedDocumentsPath|C:\Users\Public\Documents| |TPath.GetPicturesPath|C:\Users\{ユーザー名}\Pictures| |TPath.GetSharedPicturesPath|C:\Users\Public\Pictures| |TPath.GetPublicPath|C:\ProgramData| |TPath.GetCameraPath|C:\Users\{ユーザー名}\Pictures| |TPath.GetMusicPath|C:\Users\{ユーザー名}\Music| |TPath.GetSharedMusicPath|C:\Users\Public\Music| |TPath.GetMoviesPath|C:\Users\{ユーザー名}\Videos| |TPath.GetSharedMoviesPath|C:\Users\Public\Videos| |TPath.GetAlarmsPath|C:\Users\{ユーザー名}\Music| |TPath.GetSharedAlarmsPath|C:\Users\Public\Music| |TPath.GetRingTonesPath|C:\Users\{ユーザー名}\Music| |TPath.GetSharedRingTonesPath|C:\Users\Public\Music| |TPath.GetDownloadsPath|C:\Users\{ユーザー名}\AppData\Local| |TPath.GetSharedDownloadsPath|C:\ProgramData| **時間を計るTStopWatch [[http://ht-deko.com/techf021.html]] ***msec単位で計測 >uses System.Diagnostics >var >sw:TStopWatch; >begin >sw:=TStopWatch.StartNew; >//処理色々 >//: >//: >sw.Stop; >memo(sw.ElapsedMilliseconds.ToString); >//swはrecordなので、Freeしなくても良い ***高解像度で計測 > uses System.Diagnostics; > var > sw: TStopWatch; > tm: Double; > begin > sw := TStopWatch.StartNew; > sleep(100); > sw.Stop; > Memo1.Lines.Add('sw.ElapsedMilliseconds=' + sw.ElapsedMilliseconds.ToString); > Memo1.Lines.Add('sw.ElapsedTicks=' + sw.ElapsedTicks.ToString); > Memo1.Lines.Add('sw.Frequency=' + sw.Frequency.ToString); > tm := (1.0 / sw.Frequency) * sw.ElapsedTicks; > Memo1.Lines.Add('高精度時間(sec)=' + FloatToStr(tm)); > end; 実行結果 > sw.ElapsedMilliseconds=111 > sw.ElapsedTicks=1113758 > sw.Frequency=10000000 > 高精度時間(sec)=0.1113758 **プロパティで関数 >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; **スレッド [[<1> スレッドオブジェクト (Delphi コンカレントプログラミング)>https://qiita.com/ht_deko/items/39da99a10202589e002c]] リンク切れ [[Delphi Tips - マルチスレッドアプリケーション>http://support.embarcadero.com/jp/article/35961]] スレッドの書き方。だいたいのこと書いてある。 [[System.Clases.TThreadd>http://docwiki.embarcadero.com/Libraries/Seattle/ja/System.Classes.TThread]] [[スレッド管理ルーチン>http://docwiki.embarcadero.com/RADStudio/Seattle/ja/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E7%AE%A1%E7%90%86%E3%83%AB%E3%83%BC%E3%83%81%E3%83%B3]] [[System.SyncObjs>http://docwiki.embarcadero.com/Libraries/Seattle/ja/System.SyncObjs]] ***無名メソッドとスレッド [[無名メソッドとスレッド >http://edn.embarcadero.com/article/39701]] 無名メソッドでスレッドのSynchronizeを書く 利点:引数を渡すために別途変数を定義する必要がなくなる 欠点:速度的に若干のペナルティ、構文知らないと読めない [[Delphiで非同期プログラミング>http://vanillasky-room.cocolog-nifty.com/blog/2012/04/delphi-93dd.html]] ***TAnonymousThread Samples\Delphi\RTL\CrossPlatform Utils\AnonThread.pas +ジェネリクスを使っている為、スレッド処理の戻り値を指定可能 +終了処理は、通常の終了と、例外の2種類を記述可能 +終了処理は、TThread.OnTerminateから呼び出されるので、Synchronizeがいらない。[[System.Classes.TThread.OnTerminate>http://docwiki.embarcadero.com/Libraries/XE5/ja/System.Classes.TThread.OnTerminate]] +メイン中に記述すれば、受け渡しの変数を作成しなくても済む とかかなー。便利そう。 ****TAnonymouseThread.Startの例 関数をスレッドとして呼び出し >type > TForm1 = class(TForm) > private > master_counter: integer; > run_model_thread: boolean; > procedure ModelThread; > { Private 宣言 } > public > { Public 宣言 } > end; > >// ************************************************************************* >procedure TForm1.FormCreate(Sender: TObject); >begin > master_counter := 0; >end; > >// ************************************************************************* >procedure TForm1.btnStartClick(Sender: TObject); >begin > run_model_thread := true; > TThread.CreateAnonymousThread(ModelThread).Start; // スレッド開始 >end; > >// ************************************************************************* >procedure TForm1.btnStopClick(Sender: TObject); >begin > run_model_thread := false; // スレッド停止 >end; > >// ************************************************************************* >procedure TForm1.ModelThread; >var > i: integer; >begin > i := 0; > while run_model_thread do > begin > sleep(10); > inc(i); > if i >= 10 then > begin > i := 0; > inc(master_counter); > end; > end; >end; [[Cross platform anonymous threads and progress notification>https://blogs.embarcadero.com/cross-platform-anonymous-threads-and-progress-notification/]] Samplesに入っているTAnonymousThreadの解説 TAnonymousThreadは、MAC,iOSではTNSAutoreleasePoolを実装しています。 [[iPhoneアプリ開発時のメモリ管理で気をつけること(マルチスレッド編)>http://d.hatena.ne.jp/glass-_-onion/20110218/1297963007]] TNSAutoreleasePoolをスレッド毎に実装しないとメモリリークする。 ***スレッドの同期 [[スレッドの調整>http://docwiki.embarcadero.com/RADStudio/Seattle/ja/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E3%81%AE%E8%AA%BF%E6%95%B4%EF%BC%9A%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9]] [[タスクが完了するまで待つ>http://docwiki.embarcadero.com/RADStudio/Seattle/ja/%E3%82%BF%E3%82%B9%E3%82%AF%E3%81%8C%E5%AE%8C%E4%BA%86%E3%81%99%E3%82%8B%E3%81%BE%E3%81%A7%E5%BE%85%E3%81%A4]] [[Eventオブジェクト>http://docwiki.embarcadero.com/Libraries/Seattle/ja/System.SyncObjs.TEvent]] ****名前付きイベントを使ったスレッド例 名前付きイベントは、別アプリケーションとも名前を共有するので要注意。 名前はGUID使った方がよいと思います。 >unit IxNamedEventThread; >interface >uses > System.Classes, System.SyncObjs; > >type > TIxNamedEventThread = class(TThread) > protected > event: TEvent; > procedure Execute; override; > end; > >implementation >uses Unit1; > >procedure TIxNamedEventThread.Execute; >begin > event := TEvent.Create(nil, false, false, EVENT_NAME_SAMPLE); > while not Terminated do > begin > if event.WaitFor(200) = wrSignaled then > begin > Break; > end; > end; >end; > >end. ****名前付きイベント発行例 (名前なくても同じだけど...) >unit Unit1; > >const > EVENT_NAME_SAMPLE = '{BBCF957F-05C4-460C-9EE1-00FA6184E57F}'; > >var > event_named: TEvent; > event_thread: TIxEventThread; > >procedure TForm1.FormCreate(Sender: TObject); >begin > event_named := TEvent.Create(nil, false, false, EVENT_NAME_SAMPLE); > named_event_thread := TIxNamedEventThread.Create; >end; > >procedure TForm1.btnNamedEventEndClick(Sender: TObject); >begin > event_named.SetEvent; >end; ***クリティカルセクション lock,unlock,ロック,アンロック >uses System.SyncObjs; >var >FLock:TCriticalSection; >: > FLock := TCriticalSection.Create; >: > FLock.Acquire; > try > //競合する処理 > finally > FLock.Release; > end; [[クリティカル セクションを使用する>https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/%E3%82%AF%E3%83%AA%E3%83%86%E3%82%A3%E3%82%AB%E3%83%AB_%E3%82%BB%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B]] ちなみに Acquire = Enter Release = Leave ***SynchronizeとQueue メインスレッドと同期を取るには、SynchronizeとQueueがある。 どちらも無名メソッドを利用して書くことが出来る。 [[http://www.gesource.jp/weblog/?p=538]] ***スレッドの終了処理でリーク OnTerminateに定義するのが正規のやりかたっぽいのですが、ReportMemoryLeaksOnShutdown=Trueにして、FormDestroyでスレッドをTerminateすると、リーク判定されてしまう。 >type > TIxDataThread = class(TThread) > protected > public > ViewManager: TIxViewManager; > constructor Create; > procedure OnTerminateExecute(Sender: TObject); > > end; > >implementation > >{ IxDataThread } > >constructor TIxDataThread.Create; >begin > ViewManager := TIxViewManager.Create; > OnTerminate := OnTerminateExecute; > > inherited Create(true); // true:生成時停止(Startで開始) false:生成時即実行 > FreeOnTerminate := true; // 終了時解放 >end; > >procedure TIxDataThread.OnTerminateExecute(Sender: TObject); >begin > ViewManager.Free; >end; ***スレッドの終了処理 スレッドで例外しても、メイン側でちゃんと終了させる。 [[>EurekaLogメモ→スレッドの例外を補足する>https://www.s-m-l.org/eurekalog.html#%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E3%81%AE%E4%BE%8B%E5%A4%96%E3%82%92%E8%A3%9C%E8%B6%B3%E3%81%99%E3%82%8B]] ***スレッド間データ受け渡し [[System.Generics.Collections>http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.Generics.Collections]] -TThreadedQueue 受け渡しにロック操作不要 -TThreadList 追加・削除にロック操作不要、Listアクセス時ロック [[TThreadedQueue>http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.Generics.Collections.TThreadedQueue]] -メソッド PushItem,PopPItem -キュー内の個数は不明 -PushItem,PopItemにタイムアウト設定可能(INFINITEも有り) -DoShutdownでロック解放 >var > Queue: TThreadedQueue
; // 実体 生データが入る。Executeで待つ > >constructor TIxThreadDataPacker.Create; >begin > Queue := TThreadedQueue
.Create(1000, INFINITE, 100); // Depth, PushTimeout, PopTimeout >end; > >procedure xyz; >var > data: TIxRawData; > wr: TWaitResult; >begin > while true do > begin > // 待ち > wr := Queue.PopItem(data); > if (wr = TWaitResult.wrSignaled) and (data <> nil) then //★キューをdoShutdownした時、wrSignaledでdata=nilになる > begin > // Signaledの時はデータ有効 > end > else > begin > break; > end; [[TThreadList>http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.Classes.TThreadList]] -メソッド Add,Remove,Clear -プロパティ Dupulicates※dupAcceptしないと遅い(そうだよね) -アイテム個数は不明 -LockList,UnlockListでTListを取得してアイテムにアクセス ***スレッド同期 TCriticalSection >uses System.SyncObjs; > > var > DataLock:TCriticalSection; > >procedure TFormMain.FormCreate(Sender: TObject); >begin > DataLock := TCriticalSection.Create; >end; > > procedure TFormMain.FormDestroy(Sender: TObject); > begin > DataLock.Free; > end; > > procedure TFormMain.lamp_red_on; > var > str: string; > begin > DataLock.Acquire; > try > memo('ランプ点灯'); > finally > DataLock.Release; > end; > end; *** TThread,TThreadedQueueサンプル Delphi11.3 スレッドのキューに文字列を渡す スレッドの処理が終わるまでボタンダウンの関数を抜けない フォーム作成時にスレッド作成、フォーム破棄時にスレッド停止 TThread TThreadedQueue IFMXCursorService [[https://github.com/mikekoma/DelphiLabo/tree/master/Thread1]] *** TThread,TQueueサンプル Delphi11.3 スレッドのキューに文字列を渡す スレッドの処理が終わるまでボタンダウンの関数を抜けない 処理毎にスレッド生成、処理終了時にスレッド破棄 TThread [[https://github.com/mikekoma/DelphiLabo/tree/master/Thread2]] **デバッグ出力 表示→デバッグ→イベントログ > uses Windows; > OutputDebugString(PWideChar(index+' '+IntToStr(ofs)+' = '+Result)); keyword dbgout **TActionList ***別フォームのActionを使う Actionを使いたいFormで、Actionを定義しているフォームをUsesする。 そうすると、ActionのプロパティでForm1.Action1見たいに表示される。 **コンパイラ指令 |Delphi|C言語 |{$DEFINE XYZ}|#define XYZ |{$I xyz.inc}|#include "xyz.inc" |{$IFDEF XYZ}&br;{$ENDIF}|#ifdef XYZ&br;#endif |{$IF exp}&br;{$ELSE}&br;{$IFEND}|#if exp&br;#else&br;#endif [[条件付きコンパイル(Delphi)>http://docwiki.embarcadero.com/RADStudio/XE5/ja/%E6%9D%A1%E4%BB%B6%E4%BB%98%E3%81%8D%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%EF%BC%88Delphi%EF%BC%89]]定義済みのシンボル DebugとReleaseで条件コンパイルする DEBUG,RELEASEは、プロジェクト→オプション→Delphiコンパイラ→条件定義で定義してある >{$IFDEF DEBUG} >{$ENDIF} >{$IFDEF RELEASE} >{$ENDIF} 使いそうなの |MSWINDOWS|Windows、WIN32,WIN64よりこっち使う |MACOS|Mac OS **ソースコードの折りたたみ リージョン >{$REGION 'コメント'} >{$ENDREGION} [[REGION>https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/REGION]] **ショートカットキー ***ソース整形,フォーマッタ CTRL+D 改行文字数は ツール⇒オプション⇒言語⇒フォーマッタ⇒Delphi⇒改行⇒右マージン で指定する &img(formatter_newline.png); [[ソース コードを整形する>https://docwiki.embarcadero.com/RADStudio/Athens/ja/%E3%82%BD%E3%83%BC%E3%82%B9_%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%95%B4%E5%BD%A2%E3%81%99%E3%82%8B]] ***カーソル位置のクラス宣言補完(コード生成) CTRL+SHIFT+C ***同期編集(リファクタリングより軽くて便利) CTRL+SHIFT+J 選択してTAB インデント→ 選択してSHIFT+TAB インデント← [[デフォルトのキーボード ショートカット>https://docwiki.embarcadero.com/RADStudio/Sydney/ja/%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AE%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89_%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88]] **OSXで動的読み込み可能ライブラリ(dylib)を遅延読み込みできない [[https://forums.embarcadero.com/thread.jspa?threadID=80777&tstart=15]] **DeleteFileでワーニング usesの順序が重要。順序によってはH2443のワーニングが出る。 正しい順序 Windows, SysUtils, Classes, **タイプライブラリの取り込み [[タイプライブラリの取り込み>http://mrxray.on.coocan.jp/Delphi/CompoInstall/TypeLibraryD2009.htm]] **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) [[クロスプラットフォーム アプリケーションのデバッグ>http://docwiki.embarcadero.com/RADStudio/XE5/ja/%E3%82%AF%E3%83%AD%E3%82%B9%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0_%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E3%83%87%E3%83%90%E3%83%83%E3%82%B0]](新しいリモート デバッグ方法) +paserverをインストール +paserverを実行 +接続プロファイルを作成 ***paserverのインストール >C:\Program Files\Embarcadero\RAD Studio\n.n\PAServer\setup_paserver.exe >n.n はリリース バージョン(XE5 では 12.0)を表します。 参考:[[Windows でのプラットフォーム アシスタントのインストール>http://docwiki.embarcadero.com/RADStudio/XE5/ja/Windows_%E3%81%A7%E3%81%AE%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0_%E3%82%A2%E3%82%B7%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%88%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB]] ***paserverの実行 >C:\Program Files\Embarcadero\RADPAServer\n.n\paserver.exe >n.n はリリース バージョン(XE5 では 12.0)を表します。 参考:[[Windows でのプラットフォーム アシスタントの実行>http://docwiki.embarcadero.com/RADStudio/XE5/ja/Windows_%E3%81%A7%E3%81%AE%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0_%E3%82%A2%E3%82%B7%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%88%E3%81%AE%E5%AE%9F%E8%A1%8C]] ***接続プロファイルの作成 メニュー→ツール→オプション→環境オプション→接続プロファイルマネージャ 参考:[[接続プロファイル マネージャ>http://docwiki.embarcadero.com/RADStudio/XE5/ja/%EF%BC%BB%E6%8E%A5%E7%B6%9A%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB_%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3%EF%BC%BD]] ***アプリケーションの配置 アプリケーションと、その他ファイルをリモートに配置するには、配置マネージャを使用します。 メニュー→プロジェクト→配置 配置マネージャで、配置(緑右矢印)をクリックすると、接続プロファイルを割り当てできる。 配置マネージャで、リモートマシンに接続(PCが2台)をクリックすると、リモートマシンに接続 F9を押すと、配置して実行される。 ***リモートデバッグからもとに戻す プロジェクトマネージャ→ファイル→ProjectGroup1→XXX.exe→ターゲットプラットフォーム→32ビットウィンドウズ を右クリックして、「デフォルトの接続に戻す」を選択。 **メモリリーク検出 ***FastMM Delphi11 + FastMM-4993 FastMMでメモリーリークを確認してみる Delphi11 Update2 [[FastMM4>https://github.com/pleriche/FastMM4]] サンプルソースを参考にする >FastMM4\Replacement BorlndMM DLL\Delphi ****手順 ソースフォルダにファイルこぴってくる - FastMMDebugSupport.pas プロジェクトソース変更 >program testFastMM; > >uses > ShareMem,★追加 > System.StartUpCopy, > FMX.Forms, > Unit1 in 'Unit1.pas', {Form1} > FastMMDebugSupport in 'FastMMDebugSupport.pas';★追加 > >{$R *.res} > >begin > Application.Initialize; > Application.CreateForm(TForm1, Form1); > Application.Run; >end. exeの実行フォルダにDLLをコピー - BorlndMM.dll - FastMM_FullDebugMode.dll 確認用にボタンにリークする処理追加 >procedure TForm1.Button1Click(Sender: TObject); >begin > TObject.Create; >end; 実行して、ボタンクリック後終了するとメモリーリーク検知してダイアログ表示される。 実行フォルダにはログが出力される。 今回の場合は「testFastMM_MemoryManager_EventLog.txt」 ***FastMM DelphiXE6 + FastMM-4991 ****リークの検出(Delphi2006以降) プロジェクトソースに1行追加するだけ >begin > ReportMemoryLeaksOnShutdown := True; > Application.Initialize; > Application.CreateForm(TForm1, Form1); > Application.Run; >end. [[Delphiアプリケーションのメモリリーク検出法 >http://edn.embarcadero.com/jp/article/33696]] ****リークの検出方法(詳細) [[http://fastmm.sourceforge.net]] ダウンロードはここから。 FastMMDebugSupport.pasをプロジェクトフォルダにコピー BorlndMM.dll,FastMM_FullDebugMode.dllをDebugフォルダ(exe生成フォルダ)にコピー プロジェクトソースにShareMem追加 >program test_fastmm; > >uses > ShareMem, > Vcl.Forms, こうすると、終了時にリークを表示し、ログファイルも生成してくれる。 {プロジェクト名}_MemoryManager_EventLog.txt ログから、自分のソースファイル名とか検索すれば、リークしているメモリを確保している場所がわかる。 ***メモリリーク検出(Delphi200x) [[http://komish.com/delphi/memoryleak.htm]] >ReportMemoryLeaksOnShutdown := True **DLL,dylibをダイナミックロード 動的にロードする方法 [[http://d.hatena.ne.jp/nullpobug/20130616/1371314885]] **キー入力の仮想キーコード [[http://docwiki.embarcadero.com/Libraries/Seattle/ja/System.UITypes]] **マウスカーソルを隠す(非表示) ShowCursor関数の戻り値が、0未満の時にマウスカーソルが非表示になる。 非表示になるのは、自分のウィンドウ >uses Windows; > ShowCursor(false); **Canvas.FillRect 四角塗りつぶし Delphi11.3 > bmp.Canvas.Brush.Color := clWhite; > bmp.Canvas.Brush.Style := bsSolid; > bmp.Canvas.FillRect(Rect(grad_hi, 0, bmp.Width, bmp.Height)); **Canvas.CopyRect CopyRectと、裏画面のサンプル [[https://github.com/mikekoma/DelphiLabo/tree/master/CopyRect]] &img(copyrect.png); **TRectの当たり判定とか演算 色々あるんだ...[[http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.Types.TRect_Methods]] 四角と点[[http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.Types.TRectF.Contains]] 四角同士[[http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.Types.TRectF.IntersectsWith]] 四角形の大きさを拡張 Inflate [[http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.Types.TRect.Inflate]] **32bitのOSで印刷出来ない Delphi2010,Delphi10.1 Win7 32bit,Win10 32bit 32ビットアプリを作成し、32ビットOSで印刷しようとすると例外が発生する。 印刷ダイアログを出そうとすると例外が発生する。 全てのプリンタではなく、プリンタによって発生する。 調べてみるとDocumentProperties(Win32API)の呼び出しで例外発生。 &img(printer_fail_x32.png); 対策 浮動小数点の制御を変更する。 検索したらここへ [[http://stackoverflow.com/questions/3090439/problems-running-a-32-bit-delphi-app-on-a-64-bit-windows-platform]] ↓ここからここへ [[http://delphigroups.info/2/4/973047.html]] Nard Moseley (Digital Metaphors)のソース >var > lSaveCW: Word; >begin > lSaveCW := Default8087CW; > Set8087CW(Default8087CW or $3f); > try > myReport.Print; > finally > Set8087CW(lSaveCW); > end; >end; $3fをorすると、浮動小数点演算の例外を全てマスク出来る。 docwiki [[System.Set8087CW>http://docwiki.embarcadero.com/Libraries/Tokyo/ja/System.Set8087CW]] **GUIDの生成 [[GUID およびインターフェイス サポート ルーチン>http://docwiki.embarcadero.com/RADStudio/Tokyo/ja/GUID_%E3%81%8A%E3%82%88%E3%81%B3%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%82%A4%E3%82%B9_%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88_%E3%83%AB%E3%83%BC%E3%83%81%E3%83%B3]] >var > guid: TGUID; >begin > if CreateGUID(guid) = S_OK then > begin > memo(GUIDToString(guid)); > end > else > begin > memo('GUIDの生成に失敗。'); > end; **コードの折りたたみ [[REGION>http://docwiki.embarcadero.com/RADStudio/Berlin/ja/REGION]] >{$REGION 'コメント'} > : >{$ENDREGION} **ブレークポイントがずれる 10.2.3 Tokyo ブレークポイントが、ソースとずれる現象が発生。リビルドしようがDCU消そうが、何しようがダメ。 原因は、ソースファイル(pas)の改行コード異常だった。 改行コードに$0A$0Dが混ざっていて、それを$0D$0Aに修正したところ、正常にブレーク可能になった。 図:ブレーク位置異常 &img(break_ng.png); 改行コードが異常なソース(address=$000B,$0238) &simg(break_fail.png); 改行コードが正常なソース &simg(break_ok.png); **なんか例外出る0xFEEEFEEE ファイルをダイアログで開いて、スレッドで読み込みして少し経過後例外が出る。 ファイル読み込みに使用したfsは、fs.freeしている。 ↓ 対策 ↓ fs.free後fs:=nilしたら出なくなった。ような気がしたがやっぱりたまに出てる。 なんか↓に似ている [[http://rarara.cafe.coocan.jp/cgi-bin/lng/vc/vclng.cgi?print+201205/12050011.txt]] **リソースからファイル読み込み メニューのプロジェクト→リソースと画像 テキストファイルを追加 追加すると、プロジェクトにも追加される。 下の例のResource_1は読み込んだ時の識別子にする >procedure TForm1.Button1Click(Sender: TObject); >var > List: TStringList; > Stream: TResourceStream; >begin > Stream := TResourceStream.Create(HInstance, 'Resource_1', RT_RCDATA); > try > List := TStringList.Create; > try > List.LoadFromStream(Stream); > Memo1.Text := List.Text; > finally > List.Free; > end; > finally > Stream.Free; > end; >end; **バージョン管理対象 [[RAD Studio によって生成されるファイルの拡張子>https://docwiki.embarcadero.com/RADStudio/Sydney/ja/RAD_Studio_%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E7%94%9F%E6%88%90%E3%81%95%E3%82%8C%E3%82%8B%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%8B%A1%E5%BC%B5%E5%AD%90]] 必須 |*.pas|Pascalソース |*.dfm|VCLフォーム |*.fmx|FMXフォーム |*.dpr|プロジェクトファイル |*.dproj|プロジェクトファイル。コンパイル設定やリソース設定が入る |*.groupproj|プロジェクトグループ。グループ依存無ければなくても良い **EurekaLog ***EurekaLogでスレッド [[eurekalog]] ** DelphiとPython 手順はこちらの通り [[Delphi のフォームを Python から使う方法>https://qiita.com/iihi/items/9dc35a2435591b5d3bb1]] Pythonでコードを追加したいイベントは、Delphiで空のイベントを定義しておく。 Delphi11.3 Ubuntu22.04.2 LTS Python 3.10.6 delphifmx 1.0.6 &simg(delphifmx.png); > import os > from delphifmx import * > > class Form1(Form): > > def __init__(self, owner): > self.Panel1 = None > self.Button1 = None > self.Edit1 = None > self.ListBox1 = None > self.CheckBox1 = None > self.GroupBox1 = None > self.RadioButton1 = None > self.RadioButton2 = None > self.RadioButton3 = None > self.CheckBox2 = None > self.AniIndicator1 = None > self.Button2 = None > self.Button3 = None > self.Splitter1 = None > self.Memo1 = None > self.OpenDialog1 = None > self.SaveDialog1 = None > self.Calendar1 = None > self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "Unit1.pyfmx")) > > def Button1Click(self, Sender): > str = self.Edit1.Text > self.Edit1.Text = "" > self.ListBox1.Items.Add(str) > self.Memo1.Lines.Add(str) > > def CheckBox1Change(self, Sender): > self.AniIndicator1.Enabled = not self.AniIndicator1.Enabled > > def Button2Click(self, Sender): > self.Memo1.Lines.SaveToFile('test.txt'); > > def Button3Click(self, Sender): > self.Memo1.Lines.LoadFromFile('test.txt'); > > def main(): > Application.Initialize() > Application.Title = 'Form1' > Application.MainForm = Form1(Application) > Application.MainForm.Show() > Application.Run() > Application.MainForm.Destroy() > > if __name__ == '__main__': > main() **出力ディレクトリの指定 dproj削除したりすると、出力ディレクトリ指定が無くなって、dprと同じディレクトリにexeが出来たりする。 プロジェクト⇒オプション⇒ビルド⇒Delphiコンパイラ⇒出力ディレクトリ(と、ユニットの出力ディレクトリ)を指定する >.\$(Platform)\$(Config) &img(outputdir.png); **高DPI対応 Delphi12 [[RAD Studio 11の新機能:「はっきり、くっきり」表示の高DPI対応IDEとフォームデザイン>https://blogs.embarcadero.com/ja/new-in-rad-studio-11-high-dpi-ide-and-form-designing-ja/]] [[RAD Studio 12 Athens アプリケーションマニフェスト>https://docwiki.embarcadero.com/RADStudio/Athens/ja/%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3_%E3%83%9E%E3%83%8B%E3%83%95%E3%82%A7%E3%82%B9%E3%83%88]] [[RAD Studio 12 Athens Application Manifest>https://docwiki.embarcadero.com/RADStudio/Athens/en/Application_Manifest]] ざっくりいうと、拡大時いまいちなアプリケーションは、GDIスケーリングに設定したほうがよいかも。 詳細は↓ [[dev/dpiawareness]] **リンク [[Idera.Inc, Registered Products Portal>https://my.embarcadero.com/]] 登録製品ポータル [[CodeGear 旧Delphi FAQ>http://support.codegear.com/jp/article/36488]] [[Delphi Library [Mr.XRAY]>http://mrxray.on.coocan.jp/index.htm]] 高度なサンプル有ります。 [[Delphi 2009 特集>http://totonica.s41.xrea.com/doc/delphi_tiburon/]] ★必読。漢字コードの問題に関してわかりやすく解説されています。 [[DEKOのアヤシいお部屋。>http://homepage1.nifty.com/ht_deko/]] 読みやすいので、ささっと目を通すだけでも役に立ちます。 [[CとDelphiの対比表>http://www.geocities.jp/fjtkt/program/2003_0024.html]] [[Delphi 7ユーザと初心者のためのDelphi 2010入門>http://edn.embarcadero.com/article/images/40483/1C.pdf]] [[ホワイトペーパー: モバイル開発のためのDelphi言語>http://www.embarcadero.com/images/jp/dm/technical-papers/the_delphi_language_for_mobile_development_wp_jp.pdf]] Delphi言語仕様変わる [[RAD Studio / Delphi / C++Builder 11.0 Alexandria スタートアップ FAQ>https://qiita.com/ht_deko/items/4dbdfef678430c26d4ad?utm_campaign=post_article&utm_medium=twitter&utm_source=twitter_share]] [[Delphi Community Edition→参考になるページ>https://qiita.com/pik/items/1db2b6d2f9972d953df4#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%AA%E3%82%8B%E3%83%9A%E3%83%BC%E3%82%B8]] @pikさんのページ end.
2025-01-29 09:44:34 32400