\

Školení Návrhové vzory, OOP a UML


 Wednesday, February 04, 2009
Textbox nepodporující výběr textu a další specialitky

Někdy se hodí mít textbox, u kterého je skrytý "caret" (netuší někdo, jak se termín caret překládá - pouze kurzor?) a současně nepodporuje označování textu. Také můžete chtít, aby se textbox choval podobně jako při nastavení vlastnosti ReadOnly na true, ale bez "zašedlého" zobrazení textboxu, což je  většinou nechtěný průvodní jev textových polí označených pouze pro čtení.

Kód je pro Compact .Net Framework, nic vám ale nebrání přenést jej na "velký" NF. Ke zpracování Windows zpráv je použita třída NativeWindow, která je součástí OpenNetCF frameworku. Opravdu jen tato podivná sekvence zpracování Windows zpráv byla v CNF ta pravá.

 

using System;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using OpenNETCF.Windows.Forms;

namespace HideCaret
{
    public class NativeTxtWrapper : NativeWindow
    {
        [DllImport("CoreDll.dll")]
        private static extern bool ShowCaret(IntPtr hWnd);

        [DllImport("CoreDll.dll")]
        private static extern bool HideCaret(IntPtr hWnd);

        private TextBox m_txtBox;
        private bool m_hasFullFocus;
        
        
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_MOUSEMOVE = 0x0200;
        private const int WM_CHAR = 0x0102;
        private const int WM_COMMAND = 0x0111;
        private const int WM_LBUTTONUP = 0x0202;
        private const int WM_LBUTTONDBLCLK = 0x0203;
        private const int WM_PAINT = 0x000F;
        private const int WM_KILLFOCUS = 0x0008;
        private const int WM_SETFOCUS  = 0x0007;
        




        




        public NativeTxtWrapper(TextBox txtBox)
        {
            init(txtBox);
            m_hasFullFocus = false;
        }
        private void init(TextBox txtBox)
        {
            if (txtBox == null)
            {
                throw new ArgumentNullException("txtBox");
            }

            if (txtBox.Handle != IntPtr.Zero)
            {

                AssignHandle(txtBox.Handle);
            }

            txtBox.HandleCreated += ((sender, e) => AssignHandle(((Form)sender).Handle));
            txtBox.HandleDestroyed += ((sender, e) => ReleaseHandle());
            m_txtBox = txtBox;
        }


        protected override void WndProc(ref Microsoft.WindowsCE.Forms.Message m)
        {
            if (m.Msg == WM_CHAR)
            {
                m_hasFullFocus = true;
            }

            if (m.Msg == WM_MOUSEMOVE || m.Msg == WM_LBUTTONDBLCLK)
            {
                return;
            }
            
            if (((m.Msg == WM_LBUTTONUP) ||
                (m.Msg == WM_LBUTTONDOWN)) && m_hasFullFocus)
            {
                return;
            }
            if (m.Msg == WM_SETFOCUS)
            {
                base.WndProc(ref m);
                HideCaret(m_txtBox.Handle);
                return;
                //m_hasFocus = false;    
            }
            
            if (m.Msg == WM_KILLFOCUS)
            {
                m_hasFullFocus = false;
            }

            base.WndProc(ref m);
        }

    }
}

   

Jestliže chcete textbox pouze pro čtení, stačí  nepředat ke zpracování bázové třídě (base.WndProc) zprávu WM_CHAR.

 

Objektem NativeTxtWrapper lze oddekorovat jakýkoli textbox, nebo můžete vytvořit potomka třídy Textbox, který před klienty třídy skryje použití objektu NativeTextWrapper

private void Form1_Load(object sender, EventArgs e)
        {
            m_wrapper = new NativeTxtWrapper(textBox1);
            textBox1.Focus();
            
        }

Podobnou třídu mám i pro nativní projekty psané v MFC, možná se někomu z vás bude hodit. Přepsat kód do Windows API z MFC je také trivální.

 

#pragma once

#include "afxwin.h"

 

class CTextBoxEx :

    public CEdit

{

 

private:

    bool m_hasFullFocus;

 

public:

 

    CTextBoxEx(void);

    ~CTextBoxEx(void);

    virtual LRESULT WindowProc(UINT message, WPARAM wparam, LPARAM lparam);

 

};

#include "StdAfx.h"

#include "TextBoxEx.h"

 

 

 

CTextBoxEx::CTextBoxEx(void) : m_hasFullFocus(false)

{

}

 

CTextBoxEx::~CTextBoxEx(void)

{

}

 

LRESULT CTextBoxEx::WindowProc(UINT message, WPARAM wparam, LPARAM lparam)

{

 

//Readonly textbox

            if (message == WM_CHAR)

            {

                return 1;

            }

//end Readonly textbox

 

            POINT mousePoint;

            GetCursorPos(&mousePoint);

            ScreenToClient(&mousePoint);

            RECT clientRect;

            GetClientRect(&clientRect);

            BOOL isMouseInRect = PtInRect(&clientRect, mousePoint);

 

            if (((message == WM_MOUSEMOVE) || (message == WM_LBUTTONDBLCLK)) && isMouseInRect)

            {

                return 1;

            }

 

            if (((message == WM_LBUTTONUP) ||

                (message== WM_LBUTTONDOWN)) && m_hasFullFocus && isMouseInRect)

            {

                return 1;

            }

 

            if (message == WM_SETFOCUS)

            {              

                m_hasFullFocus = true;

                HideCaret();

                return 1;

 

            }

 

            if (message == WM_KILLFOCUS)

            {

                m_hasFullFocus = false;

            }

 

            return CEdit::WindowProc(message, wparam, lparam);

 

}



Wednesday, February 04, 2009 4:52:26 PM (Central Europe Standard Time, UTC+01:00)       
Comments [6]  .NET Framework | Compact .Net Framework | Nativní kód | Windows Forms


Wednesday, February 04, 2009 6:19:29 PM (Central Europe Standard Time, UTC+01:00)
Ještě že už dělám ve WPF;)
dkl
Wednesday, February 04, 2009 6:24:39 PM (Central Europe Standard Time, UTC+01:00)
:) Já mám také pár věci ve WPF, ale pro WM WPF neni a občas si u WPF říkám - sice "eye candy", ale některé věci se lépe dělají stále ve Windows Forms. Ale verze 3 WPF bude jako tradičně u MS určitě výborná :)
Wednesday, February 04, 2009 6:44:40 PM (Central Europe Standard Time, UTC+01:00)
Podle Oxfordu se "caret" překládá skutečně kurzor a "cursor" myši je ukazatel.
Wednesday, February 04, 2009 6:46:57 PM (Central Europe Standard Time, UTC+01:00)
Dušan Jánošík: Díky - já jsem se snažil někde teorii caret=kurzor ověřit, ale žádné relevantní odkazy jsem nenašel.
Thursday, February 05, 2009 9:06:03 AM (Central Europe Standard Time, UTC+01:00)
Trochu offtopic: Kdyby jste věděl jak ve WPF zobrazit obrázek (GIF, PNG) tak, aby za žádných okolností nebyl rozmazaný, byl bych vám nesmírně vděčný:-))

Device-independent pixel je sice úžasný koncept ale bitmapy prostě potřebujeme.
dkl
Thursday, February 05, 2009 9:32:07 AM (Central Europe Standard Time, UTC+01:00)
dkl: Za takovy tip bych byl take vdecny. ;)BTW: Obcas mi vadi ve WPF vadi i rozmazane pismo.
Comments are closed.