DOBON.NET DOBON.NETプログラミング掲示板過去ログ

半透明フォームに透過文字

環境/言語:[XP,C#]
分類:[.NET]

みなさん始めまして。
初心者なので、おかしなこといっていたらどんどん突っ込んでください

今、フォームの半透明や、透過について勉強しているのですが、
WEBでみつけたコードを利用して色々ためしているのですが、
やりたいことは、黒のフォームを半透明(60%)にして、
その上にDrawStringで文字を直接描画する。
そしてこも文字は白で半透明にならないようにして、
文字以外の場所はフォームの半透明をいかしたいのですが上手くいきません。
白文字も半透明になってしまうのです。
なにとぞアドバイスをください。

現在のコードは以下です。

private void Form1_Load(object sender, EventArgs e)
{
this.ForeColor = Color.White;
this.BackColor = Color.Black;
this.Opacity = 0.60;
}

private void MyDraw(Graphics gBack)
{
Font fnt = new Font("MS ゴシック", 48);
Brush color_white = new SolidBrush(Color.FromArgb(255, 255, 255, 255));
Brush color_Black = new SolidBrush(Color.FromArgb(255, 1, 1, 1));

String s = "TESTテスト";
gBack.DrawString(s, fnt, color_Black, 11, 11);
gBack.DrawString(s, fnt, color_white, 10, 10);

color_white.Dispose();
fnt.Dispose();
}

private System.Drawing.Bitmap bmpBackBuffer_ = null;

protected override void OnPaintBackground(PaintEventArgs pevent)
{
}

protected override void OnPaint(PaintEventArgs e)
{
if (this.bmpBackBuffer_ == null)
{
this.bmpBackBuffer_ = new System.Drawing.Bitmap(this.Width, this.Height);
}
else if (this.bmpBackBuffer_.Width != this.Width || this.bmpBackBuffer_.Height != this.Height)
{
this.bmpBackBuffer_.Dispose();
this.bmpBackBuffer_ = new System.Drawing.Bitmap(this.Width, this.Height);
}
using (Graphics gBack = Graphics.FromImage(this.bmpBackBuffer_))
{
base.OnPaintBackground(new PaintEventArgs(gBack, this.ClientRectangle));
MyDraw(gBack);
}
this.bmpBackBuffer_.MakeTransparent(Color.Black);
e.Graphics.DrawImageUnscaled(this.bmpBackBuffer_, 0, 0, this.bmpBackBuffer_.Width, this.bmpBackBuffer_.Height);
}
■No23808に返信(初心者猫さんの記事)
> 白文字も半透明になってしまうのです。
“Layered Windows”の仕様です。


> そしてこも文字は白で半透明にならないようにして、
おそらく無理だと思います。

無理に実装するとなると、「文字の形にくり抜いた白いフォーム」を
TransparencyKey (または Region) プロパティを利用して作成し、
それを「黒い半透明フォーム」の上に重ねるとか。


-------------
private Form Board;

private void Form1_Load(object sender, EventArgs e)
{
    this.BackColor = Color.Black;
    this.ForeColor = Color.White;
    this.Opacity = 0.60;

    this.Board = new Form();
    this.Board.ShowInTaskbar = false;
    this.Board.ControlBox = false;
    this.Board.StartPosition = FormStartPosition.Manual;
    this.Board.FormBorderStyle = FormBorderStyle.FixedSingle;
    this.Board.BackColor = this.Board.TransparencyKey = this.BackColor;
    this.Board.ForeColor = this.ForeColor;
    this.Board.Font = new Font("MS ゴシック", 48);
    this.Board.Activated += delegate { this.Activate(); };
    this.Board.Paint += delegate(object o, PaintEventArgs p)
    {
        p.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
        using (Brush b1 = new SolidBrush(Color.FromArgb(255, 255, 255, 255)))
        using (Brush b2 = new SolidBrush(Color.FromArgb(255, 1, 1, 1)))
        {
            String s = "TESTテスト";
            p.Graphics.DrawString(s, this.Board.Font, b2, 11, 11);
            p.Graphics.DrawString(s, this.Board.Font, b1, 10, 10);
        }
    };
    this.FormClosing += delegate { this.Board.Close(); };
    this.Resize += delegate { this.Board.Size = this.ClientSize; };
    this.Move += delegate { this.Board.Location = this.PointToScreen(this.ClientRectangle.Location); };
    this.Shown += delegate { this.Board.Show(this); this.Board.Enabled = false; };
    this.Board.CreateControl();
    OnResize(EventArgs.Empty);
    OnMove(EventArgs.Empty);
}
-------------

それ以外だと、(試していないのでできるかどうかわかりませんが)
GetDC(IntPtr.Zero) に対して描画するとか、DirectDraw でオーバーレイ描画とか。
レスありがとうございます。

■No23811に返信(魔界の仮面弁士さんの記事)
> ■No23808に返信(初心者猫さんの記事)
>>白文字も半透明になってしまうのです。
> “Layered Windows”の仕様です。

仕様なのですね・・・

>>そしてこも文字は白で半透明にならないようにして、
> おそらく無理だと思います。

・・・。

> 無理に実装するとなると、「文字の形にくり抜いた白いフォーム」を
> TransparencyKey (または Region) プロパティを利用して作成し、
> それを「黒い半透明フォーム」の上に重ねるとか。

Regionをつかって・・・というのは見たことがありますが、
まだまだ勉強不足で理解が難しいかったです。

以下のコートを試してみました。
自分の思うとおりに描画されていました。
ですが、まだわからないことが多いので
1つ1つ理解していくことにします。
ありがとうございました。

> -------------
> private Form Board;
>
> private void Form1_Load(object sender, EventArgs e)
> {
> this.BackColor = Color.Black;
> this.ForeColor = Color.White;
> this.Opacity = 0.60;
>
> this.Board = new Form();
> this.Board.ShowInTaskbar = false;
> this.Board.ControlBox = false;
> this.Board.StartPosition = FormStartPosition.Manual;
> this.Board.FormBorderStyle = FormBorderStyle.FixedSingle;
> this.Board.BackColor = this.Board.TransparencyKey = this.BackColor;
> this.Board.ForeColor = this.ForeColor;
> this.Board.Font = new Font("MS ゴシック", 48);
> this.Board.Activated += delegate { this.Activate(); };
> this.Board.Paint += delegate(object o, PaintEventArgs p)
> {
> p.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
> using (Brush b1 = new SolidBrush(Color.FromArgb(255, 255, 255, 255)))
> using (Brush b2 = new SolidBrush(Color.FromArgb(255, 1, 1, 1)))
> {
> String s = "TESTテスト";
> p.Graphics.DrawString(s, this.Board.Font, b2, 11, 11);
> p.Graphics.DrawString(s, this.Board.Font, b1, 10, 10);
> }
> };
> this.FormClosing += delegate { this.Board.Close(); };
> this.Resize += delegate { this.Board.Size = this.ClientSize; };
> this.Move += delegate { this.Board.Location = this.PointToScreen(this.ClientRectangle.Location); };
> this.Shown += delegate { this.Board.Show(this); this.Board.Enabled = false; };
> this.Board.CreateControl();
> OnResize(EventArgs.Empty);
> OnMove(EventArgs.Empty);
> }
> -------------
>
> それ以外だと、(試していないのでできるかどうかわかりませんが)
> GetDC(IntPtr.Zero) に対して描画するとか、DirectDraw でオーバーレイ描画とか。
■No23811に追伸(魔界の仮面弁士の記事)
>> 白文字も半透明になってしまうのです。
> “Layered Windows”の仕様です。

これは、Form.TransparecyKey / Form.Opacity プロパティが内部で利用する
「SetLayeredWindowAttributes 関数」の仕様です。

しかし、Layered Windows を構築する API には、これとは別に
「UpdateLayeredWindow 関数」という物があり、こちらを使えば、
リージョンを使わずとも、今回のような画面を作成する事ができました。
http://msdn.microsoft.com/ja-jp/library/ms997507.aspx


>> そしてこも文字は白で半透明にならないようにして、
> おそらく無理だと思います。

UpdateLayeredWindow API を利用することで、一応それっぽくなりました。
下記にサンプルを置いておきます。
http://www.vb-user.net/junk/replySamples/2009.01.26.13.53/LayeredCS.zip

API に頼らずに実装するとなると、先の No23811 のように、
フォームを 2 枚重ねて実装するなどの対処が必要になりそうです。

DOBON.NET | プログラミング道 | プログラミング掲示板