Results 1 to 2 of 2

Thread: A RichTextBox with added text alignment: 'Justify'.

  1. #1

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    A RichTextBox with added text alignment: 'Justify'.

    Hi,

    I should like to submit this for the vb.NET code bank.

    Make a RichTextBox with added text alignment: 'Justify'.
    This was designed by Passel in December 2014 in response to a request.
    I have used it many time since but only today did I check to see if it was in the code bank.


    Start a new project.
    Add a new Class, call it: SmartBox

    Paste this code in the new class.
    Code:
    Imports System.Windows.Forms
    Imports System.Runtime.InteropServices
    
    ' Represents a standard RichTextBox with some minor added functionality.
    ' SmartBox provides methods to maintain performance while it is being updated.
    ' Additional formatting features have also been added.
    
    Public Class SmartBox
        Inherits RichTextBox
        ' Maintains performance while updating.
        ' Remember to call EndUpdate when you are finished with the update.
        ' Nested calls are supported.
        ' Calling this method will prevent redrawing.
        ' It will also setup the event mask of the underlying richedit
        ' control so that no events are sent.
    
        Public Sub BeginUpdate()
            ' Deal with nested calls.
            updating += 1
    
            If updating > 1 Then
                Return
            End If
    
            ' Prevent the control from raising any events.
            oldEventMask = SendMessage(New HandleRef(Me, Handle), EM_SETEVENTMASK, 0, 0)
    
            ' Prevent the control from redrawing itself.
            SendMessage(New HandleRef(Me, Handle), WM_SETREDRAW, 0, 0)
        End Sub
    
    
        Public Sub EndUpdate()
            ' Resumes drawing and event handling.
            ' This method should be called every time a call is made
            ' made to BeginUpdate. It resets the event mask to it's
            ' original value and enables redrawing of the control.
    
            updating -= 1     ' Deal with nested calls.
    
            If updating > 0 Then
                Return
            End If
            SendMessage(New HandleRef(Me, Handle), WM_SETREDRAW, 1, 0) ' Allow the control to redraw itself.
            SendMessage(New HandleRef(Me, Handle), EM_SETEVENTMASK, 0, oldEventMask)
            ' Allow the control to raise event messages.
        End Sub
    
        Public Shadows Property SelectionAlignment() As TextAlign
            ' Gets or sets the alignment to apply to the current selection or insertion point.
            ' Replaces the SelectionAlignment from RichTextBox
    
            Get
                Dim fmt As New PARAFORMAT()
                fmt.cbSize = Marshal.SizeOf(fmt)
    
                ' Get the alignment.
                SendMessage(New HandleRef(Me, Handle), EM_GETPARAFORMAT, SCF_SELECTION, fmt)
    
                ' Default to Left align.
                If (fmt.dwMask And PFM_ALIGNMENT) = 0 Then
                    Return TextAlign.Left
                End If
    
                Return CType(fmt.wAlignment, TextAlign)
            End Get
    
            Set(value As TextAlign)
                Dim fmt As New PARAFORMAT()
                fmt.cbSize = Marshal.SizeOf(fmt)
                fmt.dwMask = PFM_ALIGNMENT
                fmt.wAlignment = CShort(value)
    
                ' Set the alignment.
                SendMessage(New HandleRef(Me, Handle), EM_SETPARAFORMAT, SCF_SELECTION, fmt)
            End Set
        End Property
    
        Protected Overrides Sub OnHandleCreated(e As EventArgs)
            ' This member overrides OnHandleCreated.
            MyBase.OnHandleCreated(e)
    
            ' Enable support for justification.
            SendMessage(New HandleRef(Me, Handle), EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY)
        End Sub
    
        Private updating As Integer = 0
        Private oldEventMask As Integer = 0
    
        ' Constants from the Platform SDK.
        Private Const EM_SETEVENTMASK As Integer = 1073         '1073 
        Private Const EM_GETPARAFORMAT As Integer = 1085        '1085
        Private Const EM_SETPARAFORMAT As Integer = 1095        '1095
        Private Const EM_SETTYPOGRAPHYOPTIONS As Integer = 1226 '1226
        Private Const WM_SETREDRAW As Integer = 11              '11
        Private Const TO_ADVANCEDTYPOGRAPHY As Integer = 1      '1
        Private Const PFM_ALIGNMENT As Integer = 8              '8 
        Private Const SCF_SELECTION As Integer = 1              '1
    
        ' It makes no difference if we use PARAFORMAT or
        ' PARAFORMAT2 here, so I have opted for PARAFORMAT2.
        <StructLayout(LayoutKind.Sequential)> _
        Private Structure PARAFORMAT
            Public cbSize As Integer
            Public dwMask As UInteger
            Public wNumbering As Short
            Public wReserved As Short
            Public dxStartIndent As Integer
            Public dxRightIndent As Integer
            Public dxOffset As Integer
            Public wAlignment As Short
            Public cTabCount As Short
            <MarshalAs(UnmanagedType.ByValArray, SizeConst:=32)> _
            Public rgxTabs As Integer()
    
            ' PARAFORMAT2 from here onwards.
            Public dySpaceBefore As Integer
            Public dySpaceAfter As Integer
            Public dyLineSpacing As Integer
            Public sStyle As Short
            Public bLineSpacingRule As Byte
            Public bOutlineLevel As Byte
            Public wShadingWeight As Short
            Public wShadingStyle As Short
            Public wNumberingStart As Short
            Public wNumberingStyle As Short
            Public wNumberingTab As Short
            Public wBorderSpace As Short
            Public wBorderWidth As Short
            Public wBorders As Short
        End Structure
    
        <DllImport("user32", CharSet:=CharSet.Auto)> _
        Private Shared Function SendMessage(hWnd As HandleRef, msg As Integer, wParam As Integer, lParam As Integer) As Integer
        End Function
    
        <DllImport("user32", CharSet:=CharSet.Auto)> _
        Private Shared Function SendMessage(hWnd As HandleRef, msg As Integer, wParam As Integer, ByRef lp As PARAFORMAT) As Integer
        End Function
    End Class
    
    Public Enum TextAlign
        ' Specifies how text in a SmartBox is horizontally aligned.
    
        Left = 1 ' The text is aligned to the left.
        Right = 2 ' The text is aligned to the right.
        Center = 3 ' The text is aligned in the center.
        Justify = 4 ' The text is justified.
    End Enum
    ________________________________________________________________________________________________

    Make only Form1: Private Sub Form1_Load. DO NOT write any code in it.
    Declare the SmartBox thus:

    Code:
    Public Class Form1
    
    Public SmartBox As SmartBox = New SmartBox
    
     Private Sub Form1_Load. 
    
    End Sub
    End Class
    Now run the project (and stop it)

    A control called SmartBox will now be in the ToolBox for this project, you will be able to use the new control in this or any other form.
    Use this control as any other TextBox or RichTextBox with the added advantage of being able to justify large amounts of text.


    Poppa
    Along with the sunshine there has to be a little rain sometime.

  2. #2

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: A RichTextBox with added text alignment: 'Justify'.

    There have been occaisions when I've wanted to place a heading or cautionary note in the center of a long text, in a user guide for instance, at first I'd just make two or more SmartBoxes with a Center aligned TextBox between them. That's ok, but you have to juggle the positions and sizes carefully or put the different boxes in a TableLayoutPanel to make a neat presentation, but then, things don't always work as expected when different resolution screens display the same layout. TableLayoutPanels don't always resolve the problem.

    Subheadings are straight forward enough, justified text are basically left aligned when the text line is shorter than the control width, but for centralised text I now use this little Function...
    Code:
        Public Function Gap(ByVal msg As String, ctrl As Control) As Int32
            Dim num, spc As Int32
            num = 0 : spc = 0
            msg += "."                   'Ensure at least two characters.
            While spc < ctrl.Width
                msg = msg.Insert(1, " ") ' Insert a space into the string.
                num += 1                 ' Count the added spaces.
                Using gr As Graphics = ctrl.CreateGraphics
                    spc = CInt(gr.MeasureString(msg, ctrl.Font).Width) ' Measure the new string.
                End Using
            End While
            ' We only need half the number of spaces to centralise the original text.
            num \= 2 : If num < 1 then num = 1 ' In case the string is too long anyway.
            Return num
        End Function
    ... Like this example from a game:
    Code:
           
            Dim midBit, txt as String    
            txt  = "By default the game allows a player to 'Drag' the cursor from square to "
            txt += "square by keeping the mouse button down whilst moving." & vbCrLf 
            txt += "On the  'Hall Of Fame'  page you will find a control to disable this feature. "
            txt += "With 'No Drag' selected, should you realise BEFORE you've released the "
            txt += "Left button, that you had meant to use the Right button you can correct "
            txt += "the error with a Right Click or by sliding into another square.  Changing the "
            txt += "state of this control will Not affect your current game." & vbCrLf & vbCrLf 
            midBit = "The mines are set totally at random for every game, therefore there's no "
            midBit += "guarantee that this game can be solved by logic alone."
            txt += Space(Gap(midBit, SmartBox1)) & midBit & vbCrLf & vbCrLf
            midBit = "Clear all the field and find all the mines to win the game."
            txt += Space(Gap(midBit, SmartBox1)) & midBit
            SmartBox1.Text = txt
    Poppa
    Last edited by Poppa Mintin; Jun 27th, 2020 at 08:08 AM.
    Along with the sunshine there has to be a little rain sometime.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width