TCTextBox – A Homemade Textbox supports transparent background

AID: 4331
  • Status: Published

2940 points

  • Bytrestan
  • TypeGeneral
  • Posted on2011-01-06 at 14:05:02
Awards
  • Community Pick
This article introduced a TextBox that supports transparent background.

 
demo.png
  • 231 KB
  • TCTextBox demo
TCTextBox demo


Introduction



TextBox is the most widely used control component in GUI design. Most GUI controls do not support transparent background and more or less do not have the urge for it. TextBox is among one of them, but unfortunately, once in a while people want it to be transparent (such as this typical question in EE: Transparent TextBox in C#).

If you search on the internet for a solution, you will come across advices like subclassing TextBox and add the support to transparent background color, or, drawing your own background in the OnPaint event. It is rational theoretically but unfeasible practically, as revealed in the following analysis.

(For those who like fast food, you can skip the literature sections and jump to the “Using the Code” section to grab and eat. Actually I also get my hands wet immediately after a short hunting with no luck. After a couple of days working, when I decide to present this home-made component to public, I have to head back to the anatomization part to make the article complete. It costs me much more time than doing the simply coding stuff along.)

The traditional TextBox just refused to be tweaked



To verify the above common suggestions, I build a phantom class TestTextBox derived from TextBox. Again, test cases are flagged in the source code for users who like to practise by themselves.

  • Set background color as Color.transparent (Test Case 1)


The visual designer does not allow you to set the transparent color to the original TextBox. After subclassing it, you can enable it by adding:

 
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);

                                    
1:

Select allOpen in new window



When you run the program, you would be glad to see the TextBox showing the background image on the form. The image will stay there if you do not touch it. Once you start typing, the background returns back to normal color along with the text. When you refresh it, the TextBox becomes transparent again but the text is “gone”.

  • Redraw background in OnPaint (Test Case 2)


The original TextBox does not even open the OnPaint event for users to subscribe it. After you subclass it, you’d better override the event handlers rather than to subscribe the events (even when it’s available). We leave out the part on how to compose an image, simply draw a pseudo image in OnPaint.

 
protected override void OnPaint(PaintEventArgs e)
        {
            if (backgroundImage == null)
            {
                backgroundImage = this.Parent.BackgroundImage; //Pretended that you have captured the background as image.
            }
            if (backgroundImage != null)
            {
                #region Test Case 2: 
                e.Graphics.DrawImage(backgroundImage, 0,0);   //Uncomment to view the effect.
                #endregion
            }
            base.OnPaint(e);
        }

                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:

Select allOpen in new window



Don’t forget to add another SetStyle to trigger the OnPaint event:

 
SetStyle(ControlStyles.UserPaint, true);

                                    
1:

Select allOpen in new window



When you run the program, you can see the image is drawn in the TextBox. But again, you cannot get the image and text shown at the same time.

Hack the WM_PAINT  message in WndProc (Test Case 3)



We can play a lot of magic by hacking the message loop, but not this one. We put here basically the same code as those in OnPaint. The runtime performance is even worse. If you do not add a “return” after drawing the image, the base TextBox will always draw itself on top of whatever you have done. The background image will never get a chance to show up on surface. If you add the “return” to block the WM_PAINT message passing on to base, the text will never appear.

All in all, the build-in control is competing with user-drawn image on the stage.

Bob Bradley’s AlphaBlendTextBox



In the late 1990s, I was once working on an automation software for a kiosk project. It would monitor all the processes and applications running in the system. Sometimes it needed to send a mouse click or keyboard input to a certain control within a windows interface to perform actions in behalf of user, so that the user would not be confused by the system messages and focus on the internet surfing. I noticed that many GUI components actually contain more handles than they appear to be, what is so called “comprised control”. It is difficult to dissemble them apart.

So the solution of AlphaBlendTextBox is actually using a PictureBox fully covering up the TextBox. Flooding all the keyboard and mouse to the underlying TextBox, so that the TextBox could be working as normal in the behind, then the PictureBox displays an image containing the appearance of the TextBox with Alpha blending. It’s a really smart solution and not quite so arduous as described by himself. I might simply use his diea if I had spent more time on reading his code in the beginning. So far, with my limited search on the internet resources, I guess the AlphaBlendTextBox is the only one that succeeded through the drawing approach. I may do some optimization on his code later on – if there are demands.

My Homemade TCTextBox



When developing my tiny drawing tool TCPaint, I want to support in-place text input so that users can see what they will get while typing. Since both transparent and opaque background is supported for other parts of the drawing, I would like text editing support both as well. So I write my own text box.

It is derived directly from Control:

class TCTextBox : Control
{
        public TCTextBox()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.Cursor = System.Windows.Forms.Cursors.IBeam;
            this.ImeMode = System.Windows.Forms.ImeMode.On;
        }
}  
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:

Select allOpen in new window



The first three SetStyle is to eliminate the possible flickering effect while redrawing itself. The forth SetStyle is to enable the transparent background. Then the cursor is set to IBeam as a visual indication that you can type in this control. And finally turn on the ImeMode to support multi-language input.

Now you have a transparent control looks like you can type in it. But if you are really typing, nothing will show up in the box, because the control does not process any key strike yet. There are a bunch of methods related to keyboard input:

protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
protected override void OnKeyDown(KeyEventArgs e)
protected override void OnKeyUp(KeyEventArgs e)
protected override void OnKeyPress(KeyPressEventArgs e)
protected override bool IsInputKey(Keys keyData)
protected override bool IsInputChar(char charCode)
protected override bool PreProcessMessage(ref Message msg)
protected override bool ProcessKeyEventArgs(ref Message m)
protected override bool ProcessDialogKey(Keys keyData)
protected override bool ProcessDialogChar(char charCode)

They are invented for different purposes. You can read MSDN for details. ProcessDialogChar is the proper one to intercept char input and the only one to enable multiple language IME tool. (Here is a nice guidance if you do not know what is multiple language input:How to Set Up & Use Multiple Language Input Options on Your Computer)

 
protected override bool ProcessDialogChar(char charCode)
        {
base.Text += charCode;
return true;
}

                                    
1:
2:
3:
4:
5:

Select allOpen in new window



Then display the input in OnPaint:

 
protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            e.Graphics.DrawString(Text, Font, new SolidBrush(this.ForeColor), 
                new RectangleF(0, 0, this.Width, this.Height), StringFormat.GenericDefault);
        }

                                    
1:
2:
3:
4:
5:
6:

Select allOpen in new window



Now you have a control in which you can type something and it will display what you have hit. Writing a textbox is not so terrifying at all:)

You can subclass and override the above methods from any kind of control. Then the control will be enabled to accept text input and display it. Of course you need to think about why you would do that.

I would not bore you out by the technical details. The TCTextBox currently supports:

  • Caret: I use Win32 functions to display a caret. You can draw a customized one if you like.

  • Caret position: It will go up/down, left/right when an arrow key is pressed.

  • AutoScroll: If the text is longer than the height of the display window, it will automatically scroll up or down to put the current position in the viewport.

  • Selection: You can select any length of text using mouse click and drag. The three properties: SelectionStart, SelectionLength, SelectionText, are supported.

  • Copy & Paste: You can either use short cut keys or context menu to interact with the system clipboard.

  • Background image: You can set an image in a TCTextBox as background. You can of course set your own BackColor, ForeColor, Font, Size to it. They are supported natively by the base class already.


That’s all. The remaining features of the original TextBox have not been implemented. And the supported features have not been fully tested. Use it at your own risk.

Using the Code



After adding the source file TCText.cs into your project, you should be able to see a new component in toolbox. Then you can select and use it as normal controls in Visual Designer.

The source code and a demo project can be downloaded from here:    
TCTextBoxDemo.zip
  • 113 KB
  • Source code and demo
TCTextBoxDemo.zip


And the simple drawing tool demonstrates the in-place editing:    
TCPaint.exe
  • 104 KB
  • A MSPaint like software
TCPaint.exe
    Asked On
    2011-01-06 at 14:05:02ID4331
    Tags

    Textbox transparent background C#

    Topic

    C# Programming Language

    Views
    1744

    Comments

    Expert Comment

    by: systan on 2011-01-15 at 11:57:54ID: 22869

    hi
    Did you really develop this function or you just copied from another link and add some ideas?
    Sorry for that, but I've seen this already, maybe your the one's in the link author.

    Author Comment

    by: trestan on 2011-01-16 at 08:32:13ID: 22895

    systan, would you mind post the link where you see the same TXTextBox? Did you compare the source code bwtween the two?

    It's also normal that not only one person think about the needs and create something similar:)

    Expert Comment

    by: mac-will on 2011-02-25 at 14:14:55ID: 24113

    You aren't Disposing your 'SolidBrush' object.

    You should wrap the new solidbrush in a using.

    Add your Comment

    Please Sign up or Log in to comment on this article.

    Join Experts Exchange Today

    Gain Access to all our Tech Resources

    Get personalized answers

    Ask unlimited questions

    Access Proven Solutions

    Search 3.2 million solutions

    Read In-Depth How-To Guides

    1000+ articles, demos, & tips

    Watch Step by Step Tutorials

    Learn direct from top tech pros

    And Much More!

    Your complete tech resource

    See Plans and Pricing

    30-day free trial. Register in 60 seconds.

    Loading Advertisement...

    Top C# Experts

    1. kaufmed

      566,376

      Sage

      500 points yesterday

      Profile
      Rank: Genius
    2. BuggyCoder

      240,764

      Guru

      10 points yesterday

      Profile
      Rank: Sage
    3. navneethegde

      158,560

      Guru

      0 points yesterday

      Profile
      Rank: Wizard
    4. CodeCruiser

      140,708

      Master

      2,000 points yesterday

      Profile
      Rank: Genius
    5. TheLearnedOne

      137,350

      Master

      2,800 points yesterday

      Profile
      Rank: Savant
    6. wdosanjos

      124,511

      Master

      3,500 points yesterday

      Profile
      Rank: Genius
    7. AndyAinscow

      107,357

      Master

      0 points yesterday

      Profile
      Rank: Genius
    8. Dhaest

      98,335

      Master

      0 points yesterday

      Profile
      Rank: Genius
    9. Idle_Mind

      91,914

      Master

      0 points yesterday

      Profile
      Rank: Savant
    10. tommyBoy

      90,068

      Master

      0 points yesterday

      Profile
      Rank: Genius
    11. nishantcomp2512

      89,000

      Master

      0 points yesterday

      Profile
      Rank: Wizard
    12. MlandaT

      86,553

      Master

      0 points yesterday

      Profile
      Rank: Genius
    13. Chinmay_Patel

      80,818

      Master

      0 points yesterday

      Profile
      Rank: Genius
    14. ddayx10

      66,538

      Master

      0 points yesterday

      Profile
      Rank: Sage
    15. anarki_jimbel

      66,132

      Master

      2,000 points yesterday

      Profile
      Rank: Genius
    16. ambience

      63,764

      Master

      0 points yesterday

      Profile
      Rank: Sage
    17. ukerandi

      62,593

      Master

      1,000 points yesterday

      Profile
      Rank: Guru
    18. apeter

      60,772

      Master

      0 points yesterday

      Profile
      Rank: Sage
    19. JamesBurger

      60,305

      Master

      0 points yesterday

      Profile
      Rank: Sage
    20. sedgwick

      52,750

      Master

      1,600 points yesterday

      Profile
      Rank: Genius
    21. emoreau

      50,917

      Master

      0 points yesterday

      Profile
      Rank: Genius
    22. ged325

      50,311

      Master

      2,000 points yesterday

      Profile
      Rank: Genius
    23. anuradhay

      49,977

      2,500 points yesterday

      Profile
      Rank: Guru
    24. techChallenger1

      47,638

      0 points yesterday

      Profile
      Rank: Guru
    25. mas_oz2003

      43,540

      0 points yesterday

      Profile
      Rank: Genius

    Hall Of Fame