programing

WinForms의 워터 마크 텍스트 상자

projobs 2021. 1. 17. 10:25
반응형

WinForms의 워터 마크 텍스트 상자


누구든지 커서가 들어갈 때 사라지는 워터 마크 텍스트를 처음에 표시하는 기본 Windows Forms TextBox의 좋은 구현을 알려줄 수 있습니까? Enter 및 Leave 이벤트를 창의적으로 사용하여 직접 만들 수 있다고 생각하지만 어딘가에 완벽하게 사용 가능한 구현이 있다고 확신합니다. WPF 구현을 보았고 필요한 경우 중첩 할 수 있지만 기본 WinForms TextBox 파생물이 더 좋습니다.

나는 지금까지 이것을 가지고있다; 아직 시도하지 않았지만 눈에 띄는 문제가있는 사람이 있습니까?

public class WatermarkTextBox:TextBox
{
    public string WatermarkText { get; set; }

    public Color WatermarkColor { get; set; }

    private Color TextColor { get; set; }

    private bool isInTransition;

    public WatermarkTextBox()
    {
        WatermarkColor = SystemColors.GrayText;
    }

    private bool HasText { get { return Text.IsNotNullOrBlankOr(WatermarkText); }}

    protected override void OnEnter(EventArgs e)
    {
        base.OnEnter(e);

        if (HasText) return;

        isInTransition = true;
        ForeColor = TextColor;
        Text = String.Empty;
        isInTransition = false;
    }

    protected override void OnForeColorChanged(EventArgs e)
    {
        base.OnForeColorChanged(e);
        if (!isInTransition) //the change came from outside
            TextColor = ForeColor;
    }

    protected override void OnLeave(EventArgs e)
    {
        base.OnLeave(e);

        if (HasText) return;

        isInTransition = true;
        ForeColor = WatermarkColor;
        Text = WatermarkText.EmptyIfNull();
        isInTransition = false;
    }
}

편집 : 위의 내용은 결국 일부 기교로 작동했지만 CueProvider가 훨씬 더 잘 작동했습니다. 최종 구현은 다음과 같습니다.

public class WatermarkTextBox:TextBox
{
    private string watermarkText;
    public string WatermarkText
    {
        get { return watermarkText; }
        set
        {
            watermarkText = value;
            if (watermarkText.IsNullOrBlank())
                CueProvider.ClearCue(this);
            else
                CueProvider.SetCue(this, watermarkText);
        }
    }
}

CueProvider 기능을 완벽하게 통합 할 수 있었지만 이것은 아름답게 작동합니다.


공식 용어는 "큐 배너"입니다. 이를 수행하는 또 다른 방법이 있습니다. TextBox를 상속하면 작업도 완료됩니다. 프로젝트에 새 클래스를 추가하고 아래 표시된 코드를 붙여 넣습니다. 엮다. 도구 상자 상단에서 새 컨트롤을 드롭하고 Cue 속성을 설정합니다.

디자이너에서 양식의 Language 속성으로 지역화 된 Cue 값의 실시간 미리보기를 볼 수 있습니다. 아주 적은 비용으로 많은 쾅하고 Winforms의 좋은 부분을 잘 보여줍니다.

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class CueTextBox : TextBox {
    [Localizable(true)]
    public string Cue {
        get { return mCue; }
        set { mCue = value; updateCue(); }
    }

    private void updateCue() {
        if (this.IsHandleCreated && mCue != null) {
            SendMessage(this.Handle, 0x1501, (IntPtr)1, mCue);
        }
    }
    protected override void OnHandleCreated(EventArgs e) {
        base.OnHandleCreated(e);
        updateCue();
    }
    private string mCue;

    // PInvoke
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, string lp);
}

상수를 도입하고 pinvoke.net 정의와 일관되게 만들고 코드가 FxCop 유효성 검사를 통과하도록하기 위해 위의 @Hans Passant가 제공 한 답변을 업데이트했습니다.

class CueTextBox : TextBox
{
    private static class NativeMethods
    {
        private const uint ECM_FIRST = 0x1500;
        internal const uint EM_SETCUEBANNER = ECM_FIRST + 1;

        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, string lParam);
    }

    private string _cue;

    public string Cue
    {
        get
        {
            return _cue;
        }
        set
        {
            _cue = value;
            UpdateCue();
        }
    }

    private void UpdateCue()
    {
        if (IsHandleCreated && _cue != null)
        {
            NativeMethods.SendMessage(Handle, NativeMethods.EM_SETCUEBANNER, (IntPtr)1, _cue);
        }
    }

    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        UpdateCue();
    }
}

편집 : PInvoke 호출을 업데이트하여 CharSet속성 을 설정 하고 안전한 쪽에서 오류를 발생시킵니다. 자세한 내용 pinvoke.netSendMessage 페이지를 참조하십시오 .


[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);

그리고 메시지 상수 :

private const uint EM_SETCUEBANNER = 0x1501;
private const uint CB_SETCUEBANNER = 0x1703;    // minimum supported client Windows Vista, minimum supported server Windows Server 2008

그리고 imho를 구현하는 가장 좋은 방법은 확장 방법입니다.
따라서 TextBox 컨트롤의 경우 구문은 다음과 같습니다.

MyTextBox.CueBanner(false, "Password");

코드에서 :

public static void CueBanner(this TextBox textbox, bool showcuewhenfocus, string cuetext)
{
    uint BOOL = 0;
    if (showcuewhenfocus == true) { BOOL = 1; }

    SendMessage(textbox.Handle, EM_SETCUEBANNER, (IntPtr)BOOL, cuetext); ;
}

다음은 TextBox힌트 (또는 워터 마크 또는 큐) 표시를 지원 하는의 구현입니다 .

  • 또한 MultiLinetrue 일 때 힌트를 표시 합니다.
  • WM_PAINT메시지 처리 및 힌트 그리기를 기반으로 합니다. 따라서 힌트를 사용자 지정하고 힌트 색상과 같은 속성을 추가하거나 오른쪽에서 왼쪽으로 그리거나 힌트 표시시기를 제어 할 수 있습니다.
using System.Drawing;
using System.Windows.Forms;
public class ExTextBox : TextBox
{
    string hint;
    public string Hint
    {
        get { return hint; }
        set { hint = value; this.Invalidate(); }
    }
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == 0xf)
        {
            if (!this.Focused && string.IsNullOrEmpty(this.Text)
                && !string.IsNullOrEmpty(this.Hint))
            {
                using (var g = this.CreateGraphics())
                {
                    TextRenderer.DrawText(g, this.Hint, this.Font,
                        this.ClientRectangle, SystemColors.GrayText , this.BackColor, 
                        TextFormatFlags.Top | TextFormatFlags.Left);
                }
            }
        }
    }
}

를 사용하면 EM_SETCUEBANNER두 가지 문제가 있습니다. 텍스트는 항상 시스템 기본 색상으로 표시됩니다. (가) 때 또한 텍스트가 표시되지 않습니다 TextBox이다 MultiLine.

페인팅 솔루션을 사용하면 원하는 색상으로 텍스트를 표시 할 수 있습니다. 컨트롤이 여러 줄인 경우 워터 마크를 표시 할 수도 있습니다.

여기에 이미지 설명 입력

다운로드

작업 예제를 복제하거나 다운로드 할 수 있습니다.


다른 컨트롤 Paint 이벤트에서 그려서 잘 작동하는 텍스트 상자 (여러 줄이든 아니든)에 워터 마크를 추가 할 수 있습니다. 예를 들면 :

    Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
        If TextBox1.Text = "" Then
            TextBox1.CreateGraphics.DrawString("Enter Text Here", Me.Font, New SolidBrush(Color.LightGray), 0, 0)
        End If
    End Sub

-OO-


내 프로젝트에 재사용 가능한 사용자 지정 컨트롤 클래스를 작성했습니다.
프로젝트에서 여러 자리 표시 자 텍스트 상자를 구현해야하는 사람에게 도움이 될 수 있습니다. 다음은 C # 및 vb.net 버전입니다.

씨#:

namespace reusebleplaceholdertextbox
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // implementation
            CustomPlaceHolderTextbox myCustomTxt = new CustomPlaceHolderTextbox(
                "Please Write Text Here...", Color.Gray, new Font("ARIAL", 11, FontStyle.Italic)
                , Color.Black, new Font("ARIAL", 11, FontStyle.Regular)
                );

            myCustomTxt.Multiline = true;
            myCustomTxt.Size = new Size(200, 50);
            myCustomTxt.Location = new Point(10, 10);
            this.Controls.Add(myCustomTxt);
        }
    }

    class CustomPlaceHolderTextbox : System.Windows.Forms.TextBox
    {
        public string PlaceholderText { get; private set; }
        public Color PlaceholderForeColor { get; private set; }
        public Font PlaceholderFont { get; private set; }

        public Color TextForeColor { get; private set; }
        public Font TextFont { get; private set; }

        public CustomPlaceHolderTextbox(string placeholdertext, Color placeholderforecolor,
            Font placeholderfont, Color textforecolor, Font textfont)
        {
            this.PlaceholderText = placeholdertext;
            this.PlaceholderFont = placeholderfont;
            this.PlaceholderForeColor = placeholderforecolor;
            this.PlaceholderFont = placeholderfont;
            this.TextForeColor = textforecolor;
            this.TextFont = textfont;
            if (!string.IsNullOrEmpty(this.PlaceholderText))
            {
                SetPlaceHolder(true);
                this.Update();
            }
        }

        private void SetPlaceHolder(bool addEvents)
        {
            if (addEvents)
            {  
                this.LostFocus += txt_lostfocus;
                this.Click += txt_click;
            }

            this.Text = PlaceholderText;
            this.ForeColor = PlaceholderForeColor;
            this.Font = PlaceholderFont;
        }

        private void txt_click(object sender, EventArgs e)
        {
            // IsNotFirstClickOnThis:
            // if there is no other control in the form
            // we will have a problem after the first load
            // because we dont other focusable control to move the focus to
            // and we dont want to remove the place holder
            // only on first time the place holder will be removed by click event
            RemovePlaceHolder();
            this.GotFocus += txt_focus;
            // no need for this event listener now
            this.Click -= txt_click;
        }

        private void RemovePlaceHolder()
        {
            this.Text = "";
            this.ForeColor = TextForeColor;
            this.Font = TextFont;
        }
        private void txt_lostfocus(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.Text))
            {
                // set placeholder again
                SetPlaceHolder(false);
            }
        }

        private void txt_focus(object sender, EventArgs e)
        {
            if (this.Text == PlaceholderText)
            {
                // IsNotFirstClickOnThis:
                // if there is no other control in the form
                // we will have a problem after the first load
                // because we dont other focusable control to move the focus to
                // and we dont want to remove the place holder
                RemovePlaceHolder();
            }
        }
    }
}


VB.NET :


Namespace CustomControls

    Public Class PlaceHolderTextBox
        Inherits System.Windows.Forms.TextBox

        Public Property PlaceholderText As String
        Public Property PlaceholderForeColor As Color
        Public Property PlaceholderFont As Font
        Public Property TextForeColor As Color
        Public Property TextFont As Font

        Public Sub New(ByVal placeholdertext As String, ByVal placeholderforecolor As Color, ByVal placeholderfont As Font, ByVal txtboxbackcolor As Color, ByVal textforecolor As Color, ByVal textfont As Font)
            Me.PlaceholderText = placeholdertext
            Me.PlaceholderFont = placeholderfont
            Me.PlaceholderForeColor = placeholderforecolor
            Me.PlaceholderFont = placeholderfont
            Me.TextForeColor = textforecolor
            Me.TextFont = textfont
            Me.BackColor = txtboxbackcolor
            If Not String.IsNullOrEmpty(Me.PlaceholderText) Then
                SetPlaceHolder(True)
                Me.Update()
            End If
        End Sub

        Private Sub SetPlaceHolder(ByVal addEvents As Boolean)
            If addEvents Then
                AddHandler Me.LostFocus, AddressOf txt_lostfocus
                AddHandler Me.Click, AddressOf txt_click
            End If

            Me.Text = PlaceholderText
            Me.ForeColor = PlaceholderForeColor
            Me.Font = PlaceholderFont
        End Sub

        Private Sub txt_click(ByVal sender As Object, ByVal e As EventArgs)
            RemovePlaceHolder()
            AddHandler Me.GotFocus, AddressOf txt_focus
            RemoveHandler Me.Click, AddressOf txt_click
        End Sub

        Private Sub RemovePlaceHolder()
            Me.Text = ""
            Me.ForeColor = TextForeColor
            Me.Font = TextFont
        End Sub

        Private Sub txt_lostfocus(ByVal sender As Object, ByVal e As EventArgs)
            If String.IsNullOrEmpty(Me.Text) Then
                SetPlaceHolder(False)
            End If
        End Sub

        Private Sub txt_focus(ByVal sender As Object, ByVal e As EventArgs)
            If Me.Text = PlaceholderText Then
                RemovePlaceHolder()
            End If
        End Sub
    End Class

End Namespace

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

namespace PlaceHolderTextBoxCSharp
{
    public class CTextBox : TextBox
    {
        private Panel contenedor;
        protected string texto = "PlaceHolderText";
        protected Color colorTextoDefault = Color.Gray;
        public Color colorTexto = Color.Gray;
        protected Color colorTextoObligatorio = Color.Red;
        private Font fuente;
        private SolidBrush establecerColorTexto;
        private bool obligatoriedad = false;
        private bool colorConFoco = false;
        private int vuelta = 0;

        public CTextBox()
        {
            Inicializar();
        }

        private void Inicializar()
        {
            fuente = Font;
            CharacterCasing = CharacterCasing.Upper;
            contenedor = null;

            MuestraPlaceHolder();

            Leave += new EventHandler(PierdeFoco);
            TextChanged += new EventHandler(CambiaTexto);
        }

        private void EliminaPlaceHolder()
        {
            if (contenedor != null)
            {
                Controls.Remove(contenedor);
                contenedor = null;
            }
        }

        private void MuestraPlaceHolder()
        {
            if (contenedor == null && TextLength <= 0)
            {
                contenedor = new Panel();
                contenedor.Paint += new PaintEventHandler(contenedorPaint);
                contenedor.Invalidate();
                contenedor.Click += new EventHandler(contenedorClick);
                Controls.Add(contenedor);
            }
        }

        private void contenedorClick(object sender, EventArgs e)
        {
            Focus();
        }

        private void contenedorPaint(object sender, PaintEventArgs e)
        {
            contenedor.Location = new Point(2, 0);
            contenedor.Height = Height;
            contenedor.Width = Width;
            contenedor.Anchor = AnchorStyles.Left | AnchorStyles.Right;
            establecerColorTexto = new SolidBrush(colorTexto);
            Graphics g = e.Graphics;
            g.DrawString(texto, fuente, establecerColorTexto, new PointF(-1f, 1f));
        }

        private void PierdeFoco(object sender, EventArgs e)
        {
            if (TextLength > 0)
            {
                EliminaPlaceHolder();
            }
            else
            {
                if (obligatoriedad == true)
                {
                    colorTexto = colorTextoObligatorio;
                }
                else
                {
                    colorTexto = colorTextoDefault;
                }

                Invalidate();
            }
        }

        private void CambiaTexto(object sender, EventArgs e)
        {
            if (TextLength > 0)
            {
                EliminaPlaceHolder();
            }
            else
            {
                MuestraPlaceHolder();

                vuelta += 1;

                if (vuelta >= 1 && obligatoriedad == true)
                {
                    colorTexto = colorTextoObligatorio;
                }
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            MuestraPlaceHolder();
        }

        protected override void OnInvalidated(InvalidateEventArgs e)
        {
            base.OnInvalidated(e);

            if (contenedor != null)
            {
                contenedor.Invalidate();
            }
        }

        [Category("Atributos PlaceHolder")]
        [Description("Establece el texto a mostrar.")]

        public string PlaceHolderText
        {
            get
            {
                return texto;
            }
            set
            {
                texto = value;
                Invalidate();
            }
        }

        [Category("Atributos PlaceHolder")]
        [Description("Establece el estilo de fuente del PlaceHolder.")]

        public Font PlaceHolderFont
        {
            get
            {
                return fuente;
            }
            set
            {
                fuente = value;
                Invalidate();
            }
        }

        [Category("Atributos PlaceHolder")]
        [Description("Indica si el campo es obligatorio.")]

        public bool PlaceHolderFieldRequired
        {
            get
            {
                return obligatoriedad;
            }
            set
            {
                obligatoriedad = value;
                Invalidate();
            }
        }
    }
}

Private Sub randomSubName() Handles txtWatermark.Click
   txtWatermark.text = ""
End Sub

워터 마크를 원하는대로 텍스트 상자의 기본 텍스트로 만듭니다.이 예제에서는 텍스트 상자의 이름을 txtWatermark라고 가정합니다.

이봐, 난 처음이야. 내가 게시물을 엉망으로 만들면 죄송합니다 ...이게 효과가 있는지도 모르겠어요 ...

참조 URL : https://stackoverflow.com/questions/4902565/watermark-textbox-in-winforms

반응형