« 2007年5月 | トップページ | 2007年7月 »

☆WebBrowserでHTMLを編集する。

今まであまり興味がなく、試したことがなかったのですが、結構すごいですね。 きちんと作れば、高機能なHTMLエディタも簡単につくれそうです。 もちろん、インターフェースとかCOM系のややこしいプログラムを駆使できればの話ですけど(笑)

フォームにButton5個とWebBrowser1個を貼り付けます。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw;
type
  TForm1 = class(TForm)
    WebBrowser1: TWebBrowser;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses MSHTML, ActiveX;

// HTMLの設定
procedure TForm1.FormCreate(Sender: TObject);
begin
  WebBrowser1.Navigate('http://hiderin.air-nifty.com/');
  Button1.Caption := '編集モード';
  Button2.Caption := '閲覧モード';
  Button3.Caption := 'コピー';
  Button4.Caption := '貼り付け';
  Button5.Caption := '保存';
end;

// 編集モード
procedure TForm1.Button1Click(Sender: TObject);
begin
  (WebBrowser1.Document as IHTMLDocument2).designMode := 'on';
end;

// 閲覧モード
procedure TForm1.Button2Click(Sender: TObject);
begin
  (WebBrowser1.Document as IHTMLDocument2).designMode := 'off'
end;

// コピー
procedure TForm1.Button3Click(Sender: TObject);
begin
  (WebBrowser1.Document as IHTMLDocument2).execCommand('Copy', True, EmptyParam);
end;

// 貼り付け
procedure TForm1.Button4Click(Sender: TObject);
begin
  (WebBrowser1.Document as IHTMLDocument2).execCommand('Paste', False, EmptyParam);
end;

// ファイルに保存
//EmptyParamとすると「無題」ファイル名が設定される。
//'test.html'とかファイル名を設定してもいいみたい。
procedure TForm1.Button5Click(Sender: TObject);
begin
  (WebBrowser1.Document as IHTMLDocument2).execCommand('SaveAs', False, EmptyParam);
end;

initialization
  OleInitialize(nil);

finalization
  OleUninitialize;
end.


編集機能については、CTRL+C, CTRL+Z等の標準的なものは、プログラムしてなくても使えます。

参考にしたサイト
about.com
How to enable editing of a document in TWebBrowser
MSDN
MSHTML Editing

|

☆入力間違いを知らせる一つの方法

Yahoo!ウィジェットか何かで、ID、パスワードが違うとフォームが細かく左右に動く・・・まるで「いやいや」(関西人としては、「ちゃうちゃう」かな)してるようなものを見たことがあるので、Delphiで試してみました。

フォームにボタンを貼り付けて、試してみて下さい。
procedure TForm1.Button1Click(Sender: TObject);
const
  Wait = 50;
var
  I, J: Integer;
begin
  J := -30;
  for I := 0 to 3 do
  begin
    case I of
      0: Left := Left - 15;
      1..3: begin
              J := J * (-1);
              Left := Left + J;
            end;
    end;
    Sleep(Wait);
    Application.ProcessMessages;
  end;
  Left := Left-15;
end;

|

☆行単位でテキストを取得する。

Memoのテキストをマウス位置で行単位に取得するために、EM_CHARFROMPOS、EM_GETLINEを使えばいいことは知っていました。でもいざ使うとなると、EM_GETLINE部分で、文字化けしたりして、なかなかうまくいかなったので、今更ですが、メモしておきますね。
(Memo1.Linesを行番号で取得しようかと思ったほど、はまっていました。)

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Edit1: TEdit;
    procedure Memo1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Memo1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  I, J: Integer;
  Text : array[0..4095] of Char;
  S: String;
begin
   I := HiWord(SendMessage(Memo1.Handle, EM_CHARFROMPOS, 0, MakeLParam(X, Y)));
   Word((@Text)^) := SizeOf(Text);  //←これに注意!
   J := SendMessage(Memo1.Handle, EM_GETLINE, I, Longint(@Text));
   SetString(S, Text, J);
   Edit1.Text := S;
end;

end.

|

☆メモ上でマウス下のテキスト取得

ブラウザでのGoogleの翻訳機能ってどうしてるのかなという疑問から、マウス下のテキストの取得に挑戦してみましたが、ブラウザでの取得は全くわかりませんでした。ということで簡単なところから、エディットコントロールでのサンプルです(笑)

実行するとこんな感じです。






ごちゃごちゃと検索する関数です。(日本語の処理は面倒ですね)
きちんとまとめるともう少しすっきりしそうですが、サンプルということで・・・。

unit GetWordAndPhrase;

interface

uses
  Windows;

//マウス下の語句を返します。<Delimiterで区切られているか英単語単位>
//Ptには、語句の開始位置と終了位置を返します。
function GetWordAndPhraseUnderMouse(const Index: Integer;const  S: String;
  var StartPos, EndPos: Integer): String;

implementation

//半角アルファベットかどうか
function IsAlphabet(C: Byte): Boolean;
begin
  Result := (C in [65..90, 97..122]);
end;

//英単語を取得するかどうか
function IsAlphabetMode(Index: Integer; S: String): Boolean;
var
  P: PChar;
begin
  P := PChar(S);
  Result := (Ord(P[Index]) in [65..90, 97..122]);
end;

//IndexがDelimiterかどうか
function IsDelimiter(Index: Integer; S: String): Boolean;
var
  P: PChar;
  wc: Word;
begin
  Result := True;
  P := PChar(S);

  //Delimiterの場合には終了
  if Ord(P[Index]) in [9,10,13,32] then Exit;

  //全角スペースの1バイト目
  if IsDBCSLeadByte(Byte(P[Index])) then
  begin
    wc := (Byte(P[Index]) shl 8) or Byte(P[Index+1]);
    //$8140-全角スペース $8141-、$8142-。
    if (wc = $8140) or (wc = $8141) or (wc = $8142) then Exit;
  end;

  //Indexが0の場合は、全角スペースの2バイト目はありえないので処理を終了します。
  if Index = 0 then
  begin
    Result := False;
    Exit;
  end;

  //全角スペースの2バイト目
  if IsDBCSLeadByte(Byte(P[Index-1])) then
  begin
    wc := (Byte(P[Index-1]) shl 8) or Byte(P[Index]);
    //$8140-全角スペース $8141-、$8142-。
    if  (wc = $8140) or (wc = $8141) or (wc = $8142) then Exit;
  end;
  Result := False;
end;

//前方検索
function PrevCheckAlphabetMode(Index: Integer; S: String): Integer;
var
  P: PChar;
begin
  if Index = 0 then
  begin
    Result := 0;
    Exit;
  end;

  P := PChar(S);
  repeat
    // 全角かどうかのチェック -- 2バイト目かどうか
    // 前方検索なので、1バイト目が先に出てくることはない。
    // 2バイト目が確認できたら、1バイト目分も移動させる。
    if (Index > 0) and IsDBCSLeadByte(Byte(P[Index-1])) then
      begin
        //全角の場合は終了する。
        Inc(Index);
        Break;
      end
    else if not IsAlphabet(Byte(P[Index])) then
      begin
        Inc(Index);
        Break;
      end
    else if Ord(P[Index]) in [9,10,13,32] then //半角Delimiter文字のチェック
      begin
        Inc(Index); //IndexがDelimiterなら一つ戻して終了する。
        Break;
      end
    else
      Dec(Index);
  until Index <= 0;
  if Index < 0 then Index := 0;
  Result := Index;
end;

//後方検索
function NextCheckAlphabetMode(Index: Integer; S: String): Integer;
var
  P: PChar;
  max: Integer;
begin
  Result := -1;
  P := PChar(S);
  Max := Length(S);

  //Indexが全角の2バイトの場合一つ戻しておきます。
  if (Index > 0) and IsDBCSLeadByte(Byte(P[Index-1])) then Exit;

  repeat
    // 全角の場合
    if IsDBCSLeadByte(Byte(P[Index])) then //1バイト目かどうかのチェック
      Break
    else if not IsAlphabet(Byte(P[Index])) then
      Break
    else if Ord(P[Index]) in [9,10,13,32] then
      Break
    else
      Inc(Index);
  until Index >= max;  //Index=maxというのは文字列より一つ多い。
  Dec(Index);
  Result := Index;
end;


//前方検索 -- Delimiterのみで判定する
function PrevCheck(Index: Integer; S: String): Integer;
var
  P: PChar;
  wc: Word;
begin
  if Index = 0 then
  begin
    Result := 0;
    Exit;
  end;

  P := PChar(S);
  // Indexが2バイト目の先頭バイトの場合には、一つ進めておきます。
  if IsDBCSLeadByte(Byte(P[Index])) then
  begin
    if Index = 0 then
    begin
      Result := 0;
      Exit;
    end;
    Dec(Index);
  end;

  repeat
    // 全角かどうかのチェック -- 2バイト目かどうか
    // 前方検索なので、1バイト目が先に出てくることはない。
    // 2バイト目が確認できたら、1バイト目分も移動させる。
    if (Index > 0) and IsDBCSLeadByte(Byte(P[Index-1])) then
      begin
        wc := (Byte(P[Index-1]) shl 8) or Byte(P[Index]);
        //$8140-全角スペース $8141-、$8142-。
        if  (wc = $8140) or (wc = $8141) or (wc = $8142) then
          begin
            Inc(Index); //Indexが2バイト文字だと確認できたら一つ戻して終了する。
            Break;
          end
        else
          Index := Index - 2; //全角文字の一つ前に進める。
      end
    else if Ord(P[Index]) in [9,10,13,32] then //半角Delimiter文字のチェック
      begin
        Inc(Index); //IndexがDelimiterなら一つ戻して終了する。
        Break;
      end
    else
      Dec(Index);
  until Index <= 0;
  if Index < 0 then Index := 0;
  Result := Index;
end;

//後方検索 -- Delimiterのみ判定する
function NextCheck(Index: Integer; S: String): Integer;
var
  P: PChar;
  wc: Word;
  max: Integer;
begin
  P := PChar(S);
  Max := Length(S);

  //Indexが全角の2バイトの場合一つ戻しておきます。
  if (Index > 0) and IsDBCSLeadByte(Byte(P[Index-1])) then
    Dec(Index);

  repeat
    // 全角の場合
    if IsDBCSLeadByte(Byte(P[Index])) then //1バイト目かどうかのチェック
      begin
        //全角スペースのチェック
        wc := (Byte(P[Index]) shl 8) or Byte(P[Index+1]);
        //$8140-全角スペース $8141-、$8142-。
        if  (wc = $8140) or (wc = $8141) or (wc = $8142) then
          Break;
        Index := Index + 2;
      end
    else if Ord(P[Index]) in [9,10,13,32] then
      Break
    else
      Inc(Index);
  until Index >= max;  //Index=maxというのは文字列より一つ多い。
  Dec(Index);
  Result := Index;
end;


//マウス下の語句を返します。<Delimiterで区切られているか英単語単位>
//Ptには、語句の開始位置と終了位置を返します。
function GetWordAndPhraseUnderMouse(const Index: Integer;const  S: String;
  var StartPos, EndPos: Integer): String;
begin
  StartPos := -1;
  EndPos := -1;
  Result := '';
  if not IsDelimiter(Index,S) then
  begin
    if IsAlphabetMode(Index,S)  then
      begin
        // 英単語のみの取得
        StartPos := PrevCheckAlphabetMode(Index,S);
        EndPos := NextCheckAlphabetMode(Index,S);
      end
    else
      begin
        // delimiterによる語句の取得
        StartPos := PrevCheck(Index,S);
        EndPos := NextCheck(Index,S);
      end;
  end;
  if (StartPos = -1) and (EndPos = -1) then
    Result := ''
  else
    Result := Copy(S, StartPos+1, EndPos-StartPos+1);
end;

end.

上記、関数の利用例です。
メモとタイマーを各1個ずつ配置して、それぞれの手続きを設定します。
unit Sample2_UseMemo;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Timer1: TTimer;
    procedure Memo1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    HW: THintWindow;
    procedure ShowHintWindow(X, Y: Integer; S: String);
    procedure HideHintWindow;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses GetWordAndPhrase;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  HW := THintWindow.Create(Self);
end;

var
  bkPos: TPoint;

procedure TForm1.Memo1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
const
  A = 5; //マウスの感度調整
begin
  if ((X < bkPos.X -A) or (X > bkPos.X +A)) or
     ((Y < bkPos.Y -A) or (Y > bkPos.Y +A)) then
    HideHintWindow;
end;

// ヒントウィンドウの表示
procedure TForm1.Timer1Timer(Sender: TObject);
var
  I, sp, ep: Integer;
  S: String;
  csPos,clPos: TPoint;
begin
  GetCursorPos(csPos);
  clPos := Memo1.ScreenToClient(csPos);
  bkPos := clPos;
  I := LoWord(Memo1.Perform(EM_CHARFROMPOS, 0, MakeLParam(clPos.X, clPos.Y)));
  S := GetWordAndPhraseUnderMouse(I, Memo1.Text, sp, ep);
  if (S <> '') then
  begin
    ShowHintWindow(csPos.X, csPos.Y, S);
    Timer1.Enabled := False;
  end;
end;

// ヒントウィンドウ
procedure TForm1.ShowHintWindow(X, Y: Integer; S: String);
var
  Rect: TRect;
begin
  if not HW.HandleAllocated then
    HW.HandleNeeded;

  Rect := Bounds(0, 0, 0, 0);
  DrawText(HW.Canvas.Handle, PChar(S), -1, Rect, DT_CALCRECT or DT_LEFT);
  OffsetRect(Rect, X,Y + 10);
  //ヒントウィンドウの微調整
  Inc(Rect.Right, 6);
  Inc(Rect.Bottom, 2);
  //表示
  HW.ActivateHint(Rect, S);
end;

procedure TForm1.HideHintWindow;
begin
  if HW.HandleAllocated then
  begin
    HW.ReleaseHandle;
    Timer1.Enabled := True;
  end;
end;

end.


delimiterは、全角スペース、半角スペース、改行(CRLF)、句読点(。、)としています。

|

■ツールバーのアイコン

glyFXの製品を購入したというものの、それで全てがカバーできるかというとそうでもないんですよね。
業務に関連するオリジナルな処理のアイコンがどうしても必要になります。
そこで今更ながらアイコンについて関連するリンクを挙げておきますね。

Windows Vista Icon Development Guidelines
現実の世界でもフラットなものは、フラットなアイコンにし、それ以外は2点透視図法とするとか、影の落とし方とか、とても細かく説明(規定?)されています。絵心のない私には作れなさそう・・・。

Windows XP 用アイコン作成法
ツールバーアイコンの説明部分にPhotoshopによるホットバージョンの作成方法が載っています。

(参考)ImageListのアイコンを実行時にDisable状態のアイコンに変換する。
Windows XPの場合(Vistaは知らないです)、ツールバーのDisabledImageを設定しないとボタンが無効時にはイメージが汚くなります。DisabledImageが用意されていない場合は、下記のサイトの方法で実行時に作成するといいです。
Delphi Pages
Create disabled Imagelist run time

|

☆コードを簡易HTMLにする。

このブログ、プログラム関係のくせにココログの標準設定のままというあまりに低レベルな表現しかしていなかったので、コード部分ぐらい読みやすくしようと、CSSを少し修正してみました。
ついでに、「Delphi予約語を強調文字にしたHTML」を作成するコードを書いてみました。 かなり力技&簡易なものなのですが、今後はこれを使って更新していきたいと思います。
// 文字列S中でIndex番目のSubstrの位置を返します。
function AnsiPosEx(const Substr: String; const S: String;
  Index: Integer): Integer;
var
  I,K: Integer;
  Str: String;
begin
  Str := S;
  Result := 0;
  K := 0;
  repeat
    Inc(K);
    I := AnsiPos(Substr, Str);
    if I =  0 then
    begin
      Result := 0;
      Break;
    end;
    if K = 1 then
      Result := I
    else
      Result := Result + I +Length(Substr) -1;
    Str := Copy(Str, I + Length(Substr) , Length(Str)-I+Length(Substr) +1);
  until K = Index;
end;


function TForm1.MakeHTML(const Str: String): String;
const
  S1 = '-----------------------------------';
  S2 = '-----------------------------------';
var
  I, J, K, L,M: Integer;
  DefineSL, SrcSL: TStringList;
  S, FileName : String;
begin
  FileName := ExtractFilePath(Application.ExeName) + 'define.txt';
  if not FileExists(FileName) then Exit;

  DefineSL := TStringList.Create;
  SrcSL := TStringList.Create;
  try
    DefineSL.LoadFromFile(FileName);
    SrcSL.Text := Str;

    SrcSL.Text := StringReplace(Str,'<', '<',[rfReplaceAll]);
    SrcSL.Text := StringReplace(SrcSL.Text,'>', '>',[rfReplaceAll]);

    for I := 0 to SrcSL.Count - 1 do
    begin
      for J := 0 to DefineSL.Count - 1 do
      begin
        S := '';
        M := 0;
        L := 1;
        while True do
        begin
          {M番目の文字列位置を取得します。}
          Inc(M);
          K := AnsiPosEx(DefineSL[J],SrcSL[I],M);
          if K = 0 then
            begin
              S := S + Copy(SrcSL[I], L , 1000);
              Break;
            end
          else
            begin
              S := S + Copy(SrcSL[I], L , K-L) +
                   '<strong>' + DefineSL[J] + '</strong>';
              L := K + Length(DefineSL[J]);
            end;
        end;
        SrcSL[I] := S;
      end;
    end;

    S := '<pre class=code>'+ #13#10 + SrcSL.Text + #13#10 + '</pre>';
    Result := '<HTML><BODY>'+#13#10+ S1 + #13#10+ S
       +#13#10+S2+#13#10+'</BODY><HTML>';
  finally
    SrcSL.Free;
    DefineSL.Free;
  end;
end;

define.txtの中身は・・・
function 
implementation
if 
 then
else
try
finally
begin
end;
end.
var
string
 do
 and 
repeat
until 
while 
class
const
string
interface
stdcall
external
nil
for 
to 
downto 
case 
 of
というような感じのテキストファイルです。

|

■TMS Advanced ToolBars & Menusアップデート

先日購入したTMS Advanced ToolBars & Menus が v2.8.0.3 から v2.9.0.0 にアップデートされました。Office 2007 style statusbarが追加されたようで、見た目的には、ますますいい感じになりそうです(笑)

tmssoftware.com

|

■glyFXのセール

Borland Developer Studio 2006 にも glyFX Borland Edition というアイコンが含まれているので、glyFXという会社は、みなさんご存知でしょうね。オーストラリアのアイコン屋さん(表現が失礼?)なのですが、2007年7月8日まで 35%オフのセール中です。(ICON BOXという製品は除くらしい)
私は、TMSSoftwareのユーザーなので、TMS価格で更に安く購入することができました。
「馬子にも衣装」という感じで今までのソフトがちょっといい感じになりました(笑)

glyFX
tmssoftware.com

|

☆TreeViewでのテキスト選択状態の取得

TreeViewのテキスト編集で文字列が選択状態かどうかを判断します。
(ツールバーの有効/無効の判定に使っています。)
var
  StartPos, EndPos: Word;
begin
  if TreeView1.IsEditing then
    begin
      StartPos := LOWORD(SendMessage(
            TreeView_GetEditControl(TreeView1.Handle), EM_GETSEL, 0, 0));
      EndPos   := HIWORD(SendMessage(
            TreeView_GetEditControl(TreeView1.Handle), EM_GETSEL, 0, 0));
      acCut.Enabled := (StartPos <> EndPos);
    end
  else
    acCut.Enabled := (TreeView1.Selected <> nil) and
             (TreeView1.Selected.Level <> 0);
end;
※基本的なことですが、思い出すまでに随分時間がかかりました(^^;

|

☆Docuworks SDKを利用する。

Fuji XeroxのDocuworksには、Docuworksと連携するための開発キットが公開されています。その内容は、各APIの細かな解説と簡単なサンプルコードがあり、とても丁寧にわかりやすく作られています。しかしながら、当然のようにC++向けとなっており、Delphiからそのまま使うことはできません。 とりあえず、サンプルにある「イメージファイルからDocuWorks文書を作成する」をDelphiで試してみました。(ヘッダーを全てDelphi向けに作ればいいんでしょうけど・・・面倒)

DocuWorks Development Tool Kit 6.2 日本語版


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  XDW_GI_DWINPUTPATH = 10;
  XDW_GI_DWDESKPATH = 11;

type
  XDW_CREATE_OPTION = record
  	nSize: Integer;
  	nFitImage: Integer;
  	nCompress: Integer;
  	nZoom: Integer;
   	nWidth: Integer;
   	nHeight: Integer;
   	nHorPos: Integer;
   	nVerPos: Integer;
  end;

  function XDW_GetInformation(nIndex: Integer; lpszOutput: PAnsiChar;
    nSize: Integer; reserved : Pointer): Integer; stdcall; external 'xdwapi.dll';

  function XDW_CreateXdwFromImageFile(const lpszInputPath: PAnsiChar;
    const lpszOutputPath: PAnsiChar; var pOption: XDW_CREATE_OPTION): Integer;
    stdcall; external 'xdwapi.dll';


procedure TForm1.Button1Click(Sender: TObject);
var
  Desk_Path, lpszOutput: array[0..MAX_PATH-1] of Char;
  Check: Integer;
  InputFile, OutputFile: String;
  pOption: XDW_CREATE_OPTION;
begin
  if not OpenDialog1.Execute then Exit;
  InputFile := OpenDialog1.FileName; // Jpeg,Bmp,Tiffのみ

  // 下記で取得するフォルダにファイルを作成すると、Docuworksを起動させたときに
  // 自動的に読み込み、表示しているフォルダにそのファイルを移動させます。
  // ちょっとややこしい仕様ですね。
  Check := XDW_GetInformation(XDW_GI_DWINPUTPATH, lpszOutput, MAX_PATH, nil);
  if (Check > -1) then
  begin
    OutputFile := String(lpszOutput) + '\aaa.xdw';

    pOption.nSize := SizeOf(XDW_CREATE_OPTION);
    pOption.nFitImage := 1;
    pOption.nCompress := 0;
    pOption.nZoom	:= 0;
    pOption.nWidth := 0;
    pOption.nHeight := 0;
    pOption.nHorPos := 0;
    pOption.nVerPos := 0;

    Check := XDW_CreateXdwFromImageFile(PAnsiChar(InputFile),
      PAnsiChar(OutputFile), pOption);
    if (Check > -1) then
    begin
      XDW_GetInformation(XDW_GI_DWDESKPATH, Desk_Path, MAX_PATH, nil);
      WinExec(Desk_Path, SW_SHOW);
    end;
  end;
end;

end.

|

■Delphi and C++Builder Roadmap

2008年前半の製品(Codename: Tiburón)でようやくVCLがUnicode対応になるようですね。
(目指しているだけ?)
Delphiのこれからが載っています。ぜひご一読を・・・。

Delphi and C++Builder Roadmap

|

■ComboBox Ctl3D プロパティ

ComboBoxのCtl3Dプロパティは、動作しないので、フラットなコンボボックスは、自作コンポを使っていました。
し、しかし、本日発見してしまいました。ComboBoxにBevelKindというプロパティがあることを。しかもそれを bkFlat にするだけでフラットなコンボボックスにできるということを。
今更何を言ってるのかと言われそうですが、私は全く知りませんでした。
このプロパティ、どのバージョンからあったの?
※ちなみにTEditにもありました。

|

« 2007年5月 | トップページ | 2007年7月 »