文字だけ表示するフォーム

解決


ofZ  2008-03-27 20:50:04  No: 30266

仕様は以下の通り
1)タイトルの通り、文字しか見えない
2)文字をクリックしてフォーム移動する
3)表示する文字は、数秒から十数秒単位で変更される
  あるホームページからテキストを読んで表示します

付箋紙21(http://www.roto21.net/pukiwiki/index.php)を使っていますが
これの「プロパティ」−「透明」みたいなことをやりたいわけです。

このようなものを作る場合、リージョン(PathToRegion, CombineRgnとか)で、やってるんでしょうか?
それとも、他にテクニックありますか?


deldel  2008-03-27 21:50:22  No: 30267

ラベルなどを貼ったフォームのBorderStyleをbsNoneにする
というのではダメなのでしょうか?
それとも文字の形のフォームを作成したいということでしょうか?


Fusa  2008-03-27 22:25:27  No: 30268

http://blog.livedoor.jp/junki560/archives/30287059.html
こちらの[3分で出来る非矩形フォーム]で
指定色を透明にしてしまえばいいのではないでしょうか?

非矩形なフォーム

というところでは、リージョンが使われているので
とても勉強になると思います。


ofZ  2008-03-27 22:27:34  No: 30269

> ラベルなどを貼ったフォームのBorderStyleをbsNoneにする
> というのではダメなのでしょうか?

なんか推敲しまくっているうちに、肝心なとこを消してしまったようです。

誤  1)タイトルの通り、文字しか見えない
正  1)タイトルの通り、文字しか見えない、背景を透過したフォーム

なので、BorderStyle = bsNone では、フォームの色が見えてしまうのでだめなのです。

> それとも文字の形のフォームを作成したいということでしょうか?
そうですね。


もにゃ  2008-03-27 23:38:42  No: 30270

win2000以降でよければalphaブレンドで半透明までサポートしてます。
これによってアンチエイリアス対応の文字だけ表示が可能になりました。
これを希望するなら以前作ったサンプルうpしますよ。
ちなみにネットを調べても見つかると思います。


ofZ  2008-03-28 00:37:12  No: 30271

> win2000以降でよければalphaブレンドで半透明までサポートしてます。
自分用PCのXP限定なのでOKです。

それで、ちょっと探してみました.
SetLayeredWindowAttributesを使ってAlphablendしてみたことはあったので、
ちょっと気になる「UpdateLayeredWindow」あたりで検索したところ
このページがヒット
http://www.geocities.jp/asumaroyuumaro/program/winapi/window.html#56

ここを読んだだけですが、カラーキーを透明色にして実行しておけばいいのでしょうか?
フォームの色をカラーキーにしておけば、それ以外の文字で透明化されると?

もにゃさん、よければサンプルお願いします。


ofZ  2008-03-28 00:50:47  No: 30272

Fusa さん
http://blog.livedoor.jp/junki560/archives/30287059.html

ありがとうございます。
参考になります。

今まで、レスあったことに気がついていませんでした。

今更ながら、Delphi 5 を使っております・・・と報告(^^;)


もにゃ  2008-03-28 02:56:00  No: 30273

これやったの4年前ですが
情報源がちゃんと書いてありました、えらいぞおれ!
リンク先は健在です。
//FDelphiより
//"不定形なフォーム(Windows2000専用)"
//http://delfusa.main.jp/delfusafloor/archive/www.nifty.ne.jp_forum_fdelphi/samples/01218.html
//
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDblClick(Sender: TObject);
  private
    { Private 宣言 }
    BMP32:TBitmap;
  public
    { Public 宣言 }
  end;

function UpdateLayeredWindow(_hwnd:HWND; dstHDC:HDC; pptDst:PPoint;
         ASize:PSize; srcHDC:HDC; pptSrc:PPoint; crKey:COLORREF;
         var bf : BLENDFUNCTION; dwFlag:DWORD):BOOL; stdcall;
const
  WS_EX_LAYERED = $80000;
  LWA_COLORKEY  = 1;
  LWA_ALPHA     = 2;
  ULW_COLORKEY  = 1;
  ULW_ALPHA     = 2;
  ULW_OPAQUE    = 4;
  AC_SRC_ALPHA  = 1;

function UpdateLayeredWindow;
  external 'user32.dll' name 'UpdateLayeredWindow';

var
  Form1: TForm1;

implementation

{$R *.dfm}
function MakeLayer(wHandle:HWND; LayerBmp:TBitmap):boolean;
var
  bf : TBlendFunction;
  zerop : TPoint;
  formsz : TSize;
begin
  result:=false;
  with bf do begin
    BlendOp:=AC_SRC_OVER;
    BlendFlags:=0;
    SourceConstantAlpha:=255; // 完全にALPHAをBITMAPに依存する場合
    AlphaFormat:=AC_SRC_ALPHA;
  end;
  //2度め以降は不要?
  SetWindowLong(wHandle, GWL_EXSTYLE, GetWindowLong(wHandle, GWL_EXSTYLE) or
                WS_EX_LAYERED);
  zerop.x:=0; zerop.y:=0;
  formsz.cx:=LayerBmp.Width; formsz.cy:=LayerBmp.Height;
  if not UpdateLayeredWindow(
        wHandle, 0,
        nil, // palleteを気にしないならnilでよろし
        @formsz, // フォームの大きさの指定 : 必須!
        LayerBmp.canvas.handle, // サーフェイスを定義するDC
        @zerop, // サーフェイスを定義する画像の開始点
        0, bf, ULW_ALPHA) then begin
    ShowMessage(SysErrorMessage(GetLastError));
    Exit;
  end;
  result:=true;
end;

procedure TForm1.Button1Click(Sender: TObject);
var x,y:integer;
    P1,P2:PByteArray;
    Alpha:Integer;
    MaskBMP:TBitmap;
    deg,i,p:Integer;
begin
  deg:=30;

  BMP32.Canvas.Font:=Label1.Font;
  BMP32.Height:=BMP32.Canvas.TextHeight(Label1.Caption)+deg;
  BMP32.Width :=BMP32.Canvas.TextWidth(Label1.Caption)+deg;
  BMP32.Canvas.Brush.Style:=bsSolid;
  BMP32.Canvas.Pen.Color:=clBlack;
  BMP32.Canvas.Brush.Color:=clBlack;
  BMP32.Canvas.Rectangle(0,0,BMP32.Width,BMP32.Height);
  BMP32.Canvas.TextOut(0,0,Label1.Caption);

  //マスクは32bitである必要ありません。(分かり易く今回は32bitです)
  MaskBMP:=TBitmap.Create;
  MaskBMP.Canvas.Font:=Label1.Font;
  MaskBMP.Assign(BMP32);
  MaskBMP.Canvas.Pen.Color:=clBlack;
  MaskBMP.Canvas.Brush.Color:=clBlack;
  MaskBMP.Canvas.Rectangle(0,0,MaskBMP.Width,MaskBMP.Height);
  MaskBMP.Canvas.Brush.Style:=bsClear;
  for i:=deg-1 downto 1 do
  begin
    p:= 255-round(255/deg)*i;
    MaskBMP.Canvas.Font.Color:=RGB(p,p,p) ;
    MaskBMP.Canvas.TextOut(i,i,Label1.Caption);
  end;

  MaskBMP.Canvas.Font.Color:=clWhite;
  MaskBMP.Canvas.TextOut(0,0,Label1.Caption);

{形の元となるビットマップは、以下のことに気をつけてください。
R=255, G=127, B=63 の点を ALPHA=100(0なら透明、255なら不透明)
で抜きたいときは、32BIT BITMAPのその点のデータを
  R = 255 * 100 div 255 = 100
  G = 127 * 100 div 255 =  49
  B =  63 * 100 div 255 =  24
  Alpha = 100
にしてください。}

  for Y:=0 to BMP32.Height-1 do
  begin
    P1 :=BMP32.ScanLine[y];
    P2 :=MaskBMP.ScanLine[y];
    for X:=0 to BMP32.Width -1 do
    begin
      //もっと美しく処理した方がいいと思いますが
      //分かりやすいようにしてあります。
      Alpha:=(P2[x*4+0 ] +
              P2[x*4+1 ] +
              P2[x*4+2 ]) div 3;
      P1[x*4+0 ]:=  P1[x*4+0 ] * Alpha div 255;
      P1[x*4+1 ]:=  P1[x*4+1 ] * Alpha div 255;
      P1[x*4+2 ]:=  P1[x*4+2 ] * Alpha div 255;
      P1[x*4+3 ]:=  Alpha;
    end;
  end;

  MakeLayer(Handle, BMP32);
  ClientHeight:=BMP32.Height;
  ClientWidth :=BMP32.Width;
  MaskBMP.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);

begin
  BMP32:=TBitmap.Create;
  BMP32.PixelFormat:=pf32bit;
  FormStyle:=fsStayOnTop;
  BorderStyle:=bsNone;

  Label1.Font.Size:=22;
  Label1.Font.Color:=clRed;
  Label1.Caption:='東京都特許許可局';
  Label1.OnDblClick:=FormDblClick;
  OnDblClick       :=FormDblClick;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  BMP32.Free;
end;

procedure TForm1.FormDblClick(Sender: TObject);
begin
  Close;
end;

end.


ofZ  2008-03-28 04:44:07  No: 30274

もにゃさんありがとうございます。

ちょっと試してみましたが、UpdateLayeredWindowで
「ハンドルが無効です(GetLastError = 6)」とか
「パラメータが間違っています(GetLastError=87)」とか出て、
思った動作になりません。

もにゃさんが参考にしたリンク先では、画像ファイルをロードしてやっている
ことから、単純に画像にTextOutしたものを作成し、MakeLayerに渡しました。
だから、この程度のコードです

  bmp := TBitmap.Create;
  bmp.PixelFormat := pf32bit;
  bmp.Width  := ClientWidth;
  bmp.Height := ClientHeight;
  bmp.Canvas.TextOut(Label1.Left, Label1.Top, Label1.Caption);
  MakeBitmapLayer(Handle, bmp);

1)GetLastError=87 が出るのは、SetLayeredWindowAttributesを使ってしまっていたとき。
2)GetLastError = 6 が出るのは、使わなかったとき。

今は、じっくり腰を落ち着けてやる時間がないので、また後日試してみます。

何か報告できることがあれば報告しますが、とりあえず解決にして、がんばります。
ありがとうございました。


ofZ  2008-03-28 04:48:03  No: 30275

うそ書いた(^^;)

> 2)GetLastError = 6 が出るのは、使わなかったとき。
これは、勘違いでした。
エラーじゃないときにもGetLastErrorしてました。
エラーにならずにできていました。

ホントに解決とします。


KHE00221  2008-03-28 05:54:35  No: 30276

Formのプロパティを設定するだけで・・・・

BorderStyle := bsNone
TransparentColor := True;
TransparentColorValue := フォームの色


Fusa  URL  2008-03-28 09:35:24  No: 30277

D5では、TransparentColor はなかった気がするのと

切り抜かれた文字部分を、タイトルバーみたいに
ドラッグしてFormが動かせるように、
WM_NCHITTEST を処理するコードを
書く必要がありそうですね。


ofZ  2008-03-28 17:26:29  No: 30278

KHE00221さん、Fusaさんレスありがとうございます。

D5にTransparentColorはありません。
ちょっとしたプログラムなので、D6Personalとか、TurboDelphiExplorerなら、
簡単に済ませることができそう・・・と、思ったので、試しにD6Personalでやってみたところ、
なんとも簡単にできてしまいましたorz

UpdateLayeredWindowの使い方も勉強になったし、今は満足しています。


ofZ  2008-03-28 17:49:51  No: 30279

そして、どうも、複雑に考えすぎていたようです。
今回フォームには、TLabelしかないのですが、以下の6行で済みました。

const
  WS_EX_LAYERED = $80000;
  LWA_COLORKEY  = 1;

exStyle := GetWindowLong(aHandle, GWL_EXSTYLE);
SetWindowLong(Handle, GWL_EXSTYLE, exStyle or WS_EX_LAYERED);
SetLayeredWindowAttributes(Handle, 透過する色, 255, LWA_COLORKEY);

もっと高度な処理をする場合に、UpdateLayeredWindowが必要になるようですね。


もにゃ  2008-03-28 21:23:29  No: 30280

UpdateLayeredWindowでは半透明を表現できます。
これは単に文字に影をつけるのにも有効ですし、
アンチエイリアス処理された文字の場合、
背景と文字の中間色を表現できます。
日本語だとメイリオしかサポートされてませんが、
MSゴシックを必要以上に大きく描画して、バイキュービック法等で縮小してやると仮想アンチエイリアスが可能です。
ちなみに、サンプルコピペで動かなかったのですかね?
環境を教えていただければできる限り対応してみます。


ofZ  2008-03-28 22:07:00  No: 30281

もにゃさん、再度のレスありがとうございます。
# 後日と言いつつ、しっかりここに張り付いている俺(^^;)

> ちなみに、サンプルコピペで動かなかったのですかね?
> 環境を教えていただければできる限り対応してみます。
サンプルはコピペしていないです。

理解不十分のままでしたが、もにゃさんのサンプルはじめ、ネットに転がっている
各種サンプルを参考にしながら、適当なBitmapを使ってテストしたり、
自分でBitmapを動的に作成してやったり、いろいろテストしました。
使い方とか勘違いとかいろいろありましたが、最終的に、文字まで
半透明にする必要ないかな?ということで、解決としました。

また今度、このあたりでこだわりをみせたいときがあり、わからないことがあれば、
別で質問あげるので、よければおつきあいください。

# 「仮想アンチエイリアス」とか、おもしろそうだけど、
# そこまで遊んでる時間がなくて・・・


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加