RSS구독하기:SUBSCRIBE TO RSS FEED
즐겨찾기추가:ADD FAVORITE
글쓰기:POST
관리자:ADMINISTRATOR
'워터마크'에 해당되는 글 1

텍스트 박스에 값을 입력하지 않으면 배경에 특정 메시지를 보여주고, 값을 입력하면 보이지 않게 해달라는 요청을 받았습니다.

그런데!!

텍스트박스는 OnPaint를 기본적으로 쉽게 사용할 수 없습니다. SetStyle 메서드에서 UserPaint 플래그를 설정하면 가능하지만, 글씨 같은 부분도 모두 처리해 줘야되기 때문에 여간 번거로운게 아닙니다. 제가 원하는건 오직 배경에 뭔가 처리!’ 그것 뿐이라구요..ㅠㅡㅠ

 

그래서 WndProc 를 재정의해서 이벤트를 받아오는 방법을 사용했습니다. 주의라고 까진 아니지만, 유심히 보실 부분은 WM_KILLFOCUS 도 처리해주고 있는것인데요. 텍스트 박스를 멀티라인 지원으로 해놓으면, WM_PAINT 가 발생을 하지 않더군요. 그래서 WM_PAINT 에서도 처리를 해주었습니다.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace TextBoxPaintSample.Controls
{
    public class TextBoxExt : TextBox
    {
        private string waterMarkText = string.Empty; // 워터마크로 사용할 문자열
        private Color waterMarkColor = Color.Gray;   // 워터마크로 사용할 문자색

        protected override void WndProc(ref Message m)
        {
            // base.WndProc 중복 호출을 피하기 위해서
            bool isCallAlready = false;

            // WM_PAINT 메세지를 받아서 처리
            if (m.Msg == 0x000F) // WM_PAINT = 0x000F
            {
                // 원래 처리해야될 로직을 먼저 호출해서 처리해줌
                base.WndProc(ref m);
                isCallAlready = true;

                DrawWaterMarkText();
            }
            // Multiline == true 일때는 포커스 빠질때 WM_PAINT가 발생 안하므로
            else if (m.Msg == 0x0008 && this.Multiline) // WM_KILLFOCUS = 0x0008
            {
                DrawWaterMarkText();
            }

            if (false == isCallAlready)
                base.WndProc(ref m);
        }

        // 텍스트박스의 크기를 계산해서 워터마크를 그려줌
        private void DrawWaterMarkText()
        {
            if (string.IsNullOrEmpty(this.Text) &&
                false == string.IsNullOrEmpty(this.WaterMarkText) &&
                this.IsHandleCreated &&
                false == this.Focused &&
                this.Visible)
            {
                using (Graphics g = Graphics.FromHwnd(this.Handle))
                {
                    // 텍스트의 vertical 정렬을 하기 위한 계산들
                    StringFormat sf = new StringFormat();
                    float textHeight = g.MeasureString(this.WaterMarkText, this.Font, this.Width, sf).Height;
                    float textY = ((float)this.Height - textHeight) / (float)2.0;
                    RectangleF bounds = new RectangleF(
                        0, textY, (float)this.Width, (float)this.Height - (textY * (float)2.0));

                    g.DrawString(this.WaterMarkText, this.Font, new SolidBrush(this.WaterMarkColor), bounds, sf);
                }
            }
        }

        public string WaterMarkText
        {
            get { return waterMarkText; }
            set { waterMarkText = value; }
        }

        public Color WaterMarkColor
        {
            get { return waterMarkColor; }
            set { waterMarkColor = value; }
        }

    }
}


실행 결과
사용자 삽입 이미지

이러한 코드를 바탕으로 텍스트 박스의 배경으로 이미지를 넣는다던지 하는 처리도 가능하리라 생각됩니다.

소스코드 전체를 첨부합니다. VS2005에서 작성 및 테스트되었습니다.


ps. 사실, 이 포스트의 내용은 제가 원래 작성하고자 했던 내용은 아닙니다만, 문제해결의 과정을, 혹은 진짜 이 내용이 필요하신분을 위해서 먼저 작성하였습니다. 다음 포스트에서는 TextBox를 상속받을 수 없는경우, 즉 다른 사람이 만든 TextBox에서 컨트롤만 얻어올 수 있을때의 대처 방법을 포스팅 하겠습니다.


2009/04/08 21:23 2009/04/08 21:23
http://lemonwidz.com/tc/trackback/23
kwangho  | 2009/04/28 16:44
오오~~ 훈스타고 왔는 데 워터마크 기능이되네요.
잘은 모르겠으나 재정의하는 거 같은데 신기하네요
지송  | 2010/07/15 00:06
안녕하세요. ^^;
다름이 아니오라. 위 워터마크효과를 이용해서 제 텍스트박스기능에 붙였는데...
다른창이 텍스트박스 위로 올라갔다 내려갔다를 몇차례 반복하면 잔상이 남게 되는 현상이 발견되어서
해결 방법을 찾아서 댓글 남겨드립니다.

TextRenderer.DrawText(g, waterMarkText, Font, Rectangle.Truncate(bounds), waterMarkColor, BackColor, TextFormatFlags.Default);

글을 이렇게 쓰시면 잔상이 생기진 않더라고요. ^^ 더운 여름 잘 보내시고요. 컨트롤 잘쓸께요.
유쾌한냐옹이  | 2012/02/28 09:33
훈스에서 퇴근5초전 님 추천받아왔는데 정말 유익하군요.

왔사 겁내 저한테 필요한 정보에욬ㅋㅋㅋㅋㅋㅋㅋㅋㅋ
have a gd day 에용~
멋져부러
유쾌한냐옹이  | 2012/02/28 10:33
이미지를 올려놓을 경우 엄청 뻔쩍거리네요..;;ㅠㅠ
전체 (23)
사진이야기 (4)
프로그래밍 (18)
  1. Nyaonge's Home  2011
    [C#] ?? 연산자(물음표 두개)
  1. 2012/03 (1)
  2. 2011/12 (2)
  3. 2009/07 (1)
  4. 2009/04 (1)
  5. 2009/03 (9)