הערה
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות להיכנס או לשנות מדריכי כתובות.
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות לשנות מדריכי כתובות.
Question
Tuesday, January 6, 2015 1:51 PM | 1 vote
Hi, I can't find the paint event of TextBox.
I try to use:
AddHandler TextBox1.Paint, AddressOf TextBoxPaint
Private Sub TextBoxPaint(sender As Object, e As PaintEventArgs)
e.Graphics.DrawLine(Pens.Black, 1, 1, 10, 10)
End Sub
But the code not call the Sub TextBoxPaint
All replies (11)
Tuesday, January 6, 2015 2:13 PM ✅Answered
According to the docs the paint event is "not relevant" for textbox.
What is it you want to do exactly that you need to draw in the text box? Maybe there is a better control to use. Maybe an RTB which lets you do more?
Wednesday, January 7, 2015 2:13 PM ✅Answered | 4 votes
Textbox is not really meant to be painted and so does not perform well when you try to force it.
You can inherit text box as below:
Public Class LinedTextBox
Inherits TextBox
Const WM_PAINT = &HF
Const WM_NCPAINT = &H85
Const WM_COMMAND = &H111
Const WM_USER = &H400
Const WM_REFLECT = WM_USER + &H1C00
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
Select Case m.Msg
Case WM_REFLECT + WM_COMMAND, WM_PAINT, WM_NCPAINT
PaintLines(m.HWnd)
End Select
End Sub
Private Sub PaintLines(handle As IntPtr)
Using g As Graphics = Graphics.FromHwnd(handle)
For i = 0 To Me.Lines.Count - 1
Dim pt As Point = Me.GetPositionFromCharIndex(Me.GetFirstCharIndexFromLine(i))
Dim txt As String = Me.Lines(i)
If txt.Length = 0 Then
txt = " "
End If
pt.Offset(0, TextRenderer.MeasureText(txt, Me.Font).Height)
g.DrawLine(Pens.Red, 0, pt.Y, Me.Width, pt.Y)
Next
End Using
End Sub
End Class
or if you already have textbox's on your form that you don't wish to remove and replace then you can simply add a nativewindow class to intercept the messages as below
Public Class TextBoxLines
Inherits NativeWindow
Const WM_PAINT = &HF
Const WM_NCPAINT = &H85
Const WM_COMMAND = &H111
Const WM_USER = &H400
Const WM_REFLECT = WM_USER + &H1C00
Private Owner As TextBox
Public Sub New(textbox As TextBox)
Me.Owner = textbox
Me.AssignHandle(textbox.Handle)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
Select Case m.Msg
Case WM_REFLECT + WM_COMMAND, WM_PAINT, WM_NCPAINT
PaintLines(m.HWnd)
End Select
End Sub
Private Sub PaintLines(handle As IntPtr)
Using g As Graphics = Graphics.FromHwnd(handle)
For i = 0 To Owner.Lines.Count - 1
Dim pt As Point = Owner.GetPositionFromCharIndex(Owner.GetFirstCharIndexFromLine(i))
Dim txt As String = Owner.Lines(i)
If txt.Length = 0 Then
txt = " "
End If
pt.Offset(0, TextRenderer.MeasureText(txt, Owner.Font).Height)
g.DrawLine(Pens.Red, 0, pt.Y, Owner.Width, pt.Y)
Next
End Using
End Sub
End Class
You would then simply create an instance of this nativewindow class in the forms constructor passing a reference to the textbox you wish to associate it with:
Dim liner As TextBoxLines
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.liner = New TextBoxLines(Me.TextBox1)
End Sub
Mick Doherty
http://dotnetrix.co.uk
http://glassui.codeplex.com
Tuesday, January 6, 2015 2:42 PM
I wanted to draw a lines
RTB does not want to draw too
Tuesday, January 6, 2015 2:51 PM
I wanted to draw a lines
RTB does not want to draw too
You can underline the font in a RTB if that is what you want. Can you show a picture of what you want? Maybe you need to use a graphics control like picturebox if it is just a small piece of text.
Tuesday, January 6, 2015 3:47 PM
I wanted to selected for eyes user all lines. That would not miss the unnecessary lines at the end of the field.
And the user can see and remove unnecessary empty lines. But do implement from Control or PictureBox very long time.
Tuesday, January 6, 2015 4:49 PM
I wanted to selected for eyes user all lines. That would not miss the unnecessary lines at the end of the field.
And the user can see and remove unnecessary empty lines. But do implement from Control or PictureBox very long time.
This is all I can come up with if you can work out how to draw it in every event. Keep in mind the second time you draw over the first time it erases - that's the reversible part. I was trying to set a flag for the first paint and then draw it twice but there are too many events erasing the textbox.
Seems there may be a way to get to the paint event or create one. I don't know. If you unmark my first post as the answer you may get more looks. Or post again and show your picture.
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
Dim p1 As Point = PointToScreen(New Point(TextBox1.Left, TextBox1.Top))
For y = p1.Y + 30 To p1.Y + 100 Step 30
ControlPaint.DrawReversibleLine(New Point(p1.X + 10, y), New Point(p1.X + TextBox1.Width - 10, y), Color.White)
Next
End Sub
Wednesday, January 7, 2015 12:38 PM | 1 vote
There is no paint event of course for a TextBox. But you can paint in it using graphics and the TextBox's handle.
The real issue is that different font sizes may not provide accurate information for drawing the lines. For example the font "Book Antiqua" (or probably any other font) with a font size of 11 seems to work fine with regard to the information returned by MeasureString for the vertical line "|" character or "M" or "W" which I believe are the tallest characters able to be measured. But if you alter the font size to 8 then after some numbers of lines the characters are becoming overdrawn by lines.
Although I believe if you could get the Carets height then always drawing the lines correctly should be no issue since you could probably figure out how to perform the line drawings for the Carets height. But I've no idea how to get a carets height. Perhaps if you could get a lines height that could work too.
Option Strict On
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Left = 10
Me.Top = 10
TextBox1.Font = New Font("Book Antiqua", 11)
TextBox1.Anchor = CType(AnchorStyles.Bottom + AnchorStyles.Left + AnchorStyles.Right + AnchorStyles.Top, AnchorStyles)
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
DrawLinesInTextBox1()
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown
DrawLinesInTextBox1()
End Sub
Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
DrawLinesInTextBox1()
End Sub
Private Sub DrawLinesInTextBox1()
TextBox1.Refresh()
If TextBox1.Text <> "" Then
Using g As Graphics = Graphics.FromHwnd(TextBox1.Handle)
Dim HeightToUse As Single = g.MeasureString("|", TextBox1.Font).Height
For i = 1 To TextBox1.Lines.Count
g.DrawLine(Pens.Red, 0, i * HeightToUse, TextBox1.ClientRectangle.Width, i * HeightToUse)
Next
End Using
End If
End Sub
End Class
La vida loca
Wednesday, January 7, 2015 12:50 PM
Good one Monkey.
I came up with making a class to get a paint event. But, I am drawing lines but as you press enter apparently the part that draws the text is erasing the lines.
Not sure how to fix that?
Public Class Form4
Private WithEvents TextEx1 As New TextBoxEX
Private Sub Form4_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Controls.Add(TextEx1)
TextEx1.Multiline = True
TextEx1.Dock = DockStyle.Fill
End Sub
Public Class TextBoxEX
Inherits TextBox
Public Sub New()
MyBase.SetStyle(ControlStyles.UserPaint Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.DoubleBuffer, True)
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
For y = 30 To Me.Height Step 30
e.Graphics.DrawLine(Pens.Red, 10, y, Me.Width - 10, y)
Next
End Sub
End Class
End Class
Wednesday, January 7, 2015 1:41 PM
I tried the same thing, for a few hours. I couldn't figure it out. So finally I went the route I posted.
I was even providing the created textbox with handlers to try to get it to refresh and everything. Which when the code I posted worked made me wonder even more why the class wouldn't work.
I even used ControlPaint.DrawGrid and the grid would go away. I suspect it has to do with not handling the drawing of both the text and lines within the TextBox perhaps but I gave up! :)
La vida loca
Wednesday, January 7, 2015 7:09 PM
So can you draw on most any control by creating a graphics object with the handle?
Using g As Graphics = Graphics.FromHwnd(TextBox1.Handle)
Wednesday, January 7, 2015 9:19 PM
So can you draw on most any control by creating a graphics object with the handle?
Using g As Graphics = Graphics.FromHwnd(TextBox1.Handle)
Sure. The problem is not painting, the problem is persisting the painting (i.e. painting every time the control needs it, which is not always obvious).
Whenever there is a Paint method exposed for use then it should be used, along with the graphics object passed with it.
Mick Doherty
http://dotnetrix.co.uk
http://glassui.codeplex.com