Solved

how can I get vb.net to add spaces between the words of lines of text so that they will be fully justified in a rich edit box

Posted on 2009-06-30
19
1,059 Views
Last Modified: 2012-05-07
I have lines of text with differnt amount of characters
how can I get the computer to insert small spaces between the words of a line so that all the lines will be fully justified vb.net 2008 express
0
Comment
Question by:Dov_B
  • 8
  • 8
  • 3
19 Comments
 
LVL 48

Assisted Solution

by:jpaulino
jpaulino earned 150 total points
ID: 24744381
You can use a fixed-width fonts or try something like this http://vbcity.com/forums/topic.asp?tid=111945
0
 
LVL 39

Expert Comment

by:abel
ID: 24744604
The sad thing is, the RTF specification has the simple "\qj" command for justifying a paragraph, but despite some attempts, it won't work in the RTB control shipped with .NET 3.5 or before. Reason? I have no idea, but the underlying RichText control is version 2.0 (see http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/25045a28-b8c9-4146-9820-1231a58c5925 or try Spy++) and that version does not support justified text, even if you wanted it to.

Using a proportional font or a fixed width font, this will always be ugly and people would not be able to properly copy and paste your text anymore.

Sorry that I don't have better news for you. In the code snippet below is a simple text with format codes that you can use. Replace "\qj" with "\qr" to see that right-justify works, but full justify doesn't.

// place a small richTextBox1 on your form to test this and 

// put the following line in your form_load

richTextBox1.Rtf = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1043{\\fonttbl{\\f0\\fnil\\fcharset0 Microsoft Sans Serif;}}\r\n\\viewkind4\\uc1{\\pard\\qf\\f0\\fs17 Hello this is a little piece of text that spans at least more than one line on this richtextbox so that we can test filling out the lines\\par}\r\n\\par\r\n}\r\n";

Open in new window

0
 
LVL 48

Expert Comment

by:jpaulino
ID: 24744659
To be honest I haven't tried that! :P
0
 

Author Comment

by:Dov_B
ID: 24744676
I am working with foreign languages in unicode and cannot use a fixed width font
the link you sent me  works with english but not with foreign languages
 

Friend Class clsRichTextJustify
 

    Private Const WM_USER As Short = &H400S

    Private Const EM_EXSETSEL As Integer = (WM_USER + 55)

    Private Const EM_SETSEL As Short = &HB1S

    Private Const EM_GETSEL As Short = &HB0S

    Private Const EM_GETPARAFORMAT As Integer = (WM_USER + 61)

    Private Const EM_SETPARAFORMAT As Integer = (WM_USER + 71)

    Private Const EM_GETSELTEXT As Integer = (WM_USER + 62)

    Private Const EM_SETTYPOGRAPHYOPTIONS As Integer = (WM_USER + 202)

    Private Const EM_GETTYPOGRAPHYOPTIONS As Integer = (WM_USER + 203)

    Private Const TO_ADVANCEDTYPOGRAPHY As Short = &H1S

    Private Const TO_SIMPLELINEBREAK As Integer = &H2

    Private Const PFM_ALIGNMENT As Short = &H8S

    Private Const PFM_TABSTOPS As Short = &H10S

    Private Const PFM_STYLE As Short = &H400S

    Private Const PFA_LEFT As Short = 1

    Private Const PFA_RIGHT As Short = 2

    Private Const PFA_CENTER As Short = 3

    Private Const PFA_JUSTIFY As Short = &H4S

    Private Const PS_SOLID As Short = 0

    Private Const PFA_FULL_GLYPHS As Short = 7

    Private Const mZERO As Integer = &H0

    Private Declare Function SendMessageLong Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal uMgs As Integer, ByVal wParam As Integer, ByRef lParam As PARAFORMAT2) As Integer 'I made change in this line _Lars9 
 

    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal uMgs As Integer, ByVal wParam As Integer, ByRef lParam As Charrange) As Integer 'I made change in this line _Lars9 
 
 

    Private Structure Charrange

        Dim cpMin As Integer

        Dim cpMax As Integer

    End Structure
 
 
 

    Private Structure PARAFORMAT2

        Dim cbsize As Short

        Dim dwpad As Short

        Dim dwMask As Integer

        Dim wNumbering As Short

        Dim wReserved As Short

        Dim dxStartIndent As Integer

        Dim dxRightIndent As Integer

        Dim dxOffset As Integer

        Dim wAlignment As Short

        Dim cTabCount As Short

        <VBFixedArray(31)> Dim lTabstops() As Integer

        Dim dySpaceBefore As Integer

        Dim dySpaceAfter As Integer

        Dim dyLineSpacing As Integer

        Dim sStyle As Short

        Dim bLineSpacingRule As Byte

        Dim bOutlineLevel As Byte

        Dim wShadingWeight As Short

        Dim wShadingStyle As Short

        Dim wNumberingStart As Short

        Dim wNumberingStyle As Short

        Dim wNumberingTab As Short

        Dim wBorderSpace As Short

        Dim wBorderWidth As Short

        Dim wBorders As Short
 

        Public Sub Initialize()

            ReDim lTabstops(31)

        End Sub

    End Structure

    Public Sub Justify(ByVal hwndr As IntPtr, ByRef intStart As Short, ByRef intEnd As Short)

        Dim myparaf As PARAFORMAT2

        Dim cr As Charrange

        Dim lngRet As Integer

        myparaf.cbsize = Len(myparaf)

        ' paragraph selection points to character before and 

        ' character after position from beginning of the RichText Box 

        cr.cpMax = intEnd

        cr.cpMin = intStart

        ' Select the text if you don't want to see it make the RichText invisible first 

        SendMessage(hwndr, EM_EXSETSEL, mZERO, cr)

        lngRet = SendMessageLong(hwndr, EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY)
 

        If lngRet = 1 Then 'only do this if version 3.0 
 

            lngRet = SendMessageLong(hwndr, EM_GETTYPOGRAPHYOPTIONS, mZERO, mZERO)

            lngRet = SendMessage(hwndr, EM_GETPARAFORMAT, mZERO, myparaf)

            If myparaf.wAlignment = PFA_LEFT Then

                myparaf.dwMask = PFM_ALIGNMENT

                myparaf.wAlignment = PFA_JUSTIFY
 

                lngRet = SendMessage(hwndr, EM_SETPARAFORMAT, mZERO, myparaf)

            Else

                System.Diagnostics.Debug.WriteLine("Centre")

            End If

        Else

            System.Diagnostics.Debug.WriteLine("FAIL")

        End If

        cr.cpMin = 0

        cr.cpMax = 0

        SendMessage(hwndr, EM_EXSETSEL, mZERO, cr)

    End Sub
 
 

    Public Sub Settabs(ByVal hwndr As IntPtr, ByRef lngArrTabs() As Integer, ByRef rwidth As Integer, Optional ByRef lngstart As Integer = 0, Optional ByRef lngEnd As Integer = 0)

        'sets tabs in twips careful not to exceed the width of the rich text box rwidth 

        ' pass in the tabs in an array base 1 

        Dim myparaf As PARAFORMAT2

        Dim lngRet As Integer

        Dim intCnt As Short

        Dim cr As Charrange

        Dim intCum As Short

        Dim lngTabs As Integer

        lngEnd = lngEnd + 4

        'set the selection 

        If lngstart = 0 And lngEnd = 0 Then

            'cr.cpMax = Len(frmName.richtb.Text) 'put appropriate source in here 

            cr.cpMin = 0

        Else

            cr.cpMax = lngEnd

            cr.cpMin = lngstart

        End If
 

        'first select all the text or nothing will happen 

        SendMessage(hwndr, EM_EXSETSEL, 0, cr)
 

        'setup the tab array 

        lngTabs = UBound(lngArrTabs)

        myparaf.cbsize = Len(myparaf)

        lngRet = SendMessage(hwndr, EM_GETPARAFORMAT, 0, myparaf)
 

        For intCnt = 0 To lngTabs - 1

            If lngArrTabs(intCnt + 1) <= rwidth Then '(rwidth * Screen.TwipsPerPixelX) - lngSize Then 

                myparaf.lTabstops(intCnt) = lngArrTabs(intCnt + 1)

                myparaf.cTabCount = intCnt + 1

            End If

        Next intCnt
 

        'Now do the tabs 

        myparaf.dwMask = PFM_TABSTOPS

        lngRet = SendMessage(hwndr, EM_SETPARAFORMAT, 0, myparaf)

        cr.cpMax = 0

        cr.cpMin = 0
 

        'clean up setting selection to zero 

        SendMessage(hwndr, EM_EXSETSEL, 0, cr)

    End Sub

End Class

Open in new window

0
 

Author Comment

by:Dov_B
ID: 24744713
perhaps there is a way using code that evaluates each line and gets its width and then computes how many spaces to add between each word to make the lenghts of each line equal
could you help me with that there is a command I forgot what it is that when you give it the font and the string can figure out
0
 
LVL 48

Expert Comment

by:jpaulino
ID: 24744822
You could try using Graphics and MeasureString() method, but never tried using that on a RichTextBox and also don't know if it's possible.
0
 
LVL 39

Assisted Solution

by:abel
abel earned 350 total points
ID: 24745149
jpaulino is correct, you can use MeasureString. But there's a difference between GDI and GDI+ methods of measuring strings, which has to deal with the methods they display strings. One is MeasureText and DrawText, the other is MeasureString and DrawString. See for details my answer here: http://www.experts-exchange.com/Q_24213592.html

It can be done, but I'd recommend looking into wrapping the RichText 4.0 version which is available on XP and higher by default. It supports this and other features natively.

-- Abel --
0
 

Author Comment

by:Dov_B
ID: 24745208
okay i found the following code that computes the width can you help me with inserting blank spaces to justify the lines
how do I find the character index of the spaces between each word?
how do I insert a blank space there?

dim lineNum

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim lineText As String

        Dim drawFont As New Font("Cooper Black", 16)

        lineNum = lineNum + 1

        Dim textLen = (RichTextBox1.GetFirstCharIndexFromLine(linenum + 1) - 1) - RichTextBox1.GetFirstCharIndexFromLine(linenum)

        RichTextBox1.Select(RichTextBox1.GetFirstCharIndexFromLine(linenum), textLen)
 

        lineText = RichTextBox1.SelectedText

        Label1.Text = (GetStringWidth(lineText, drawFont))

        RichTextBox1.Focus()
 

    End Sub

    Public Function GetStringWidth(ByVal sStr As String, _

                               ByVal fFont As Font) _

                               As Single

        Dim g As Graphics = Me.CreateGraphics

        Dim TextWidth As Single

        TextWidth = g.MeasureString(sStr, fFont).Width()

        'Clean up

        g.Dispose() : g = Nothing

        Return TextWidth

    End Function

Open in new window

0
 

Author Comment

by:Dov_B
ID: 24745309
dear abel
what do you mean by ....
 wrapping the RichText 4.0 version which is available on XP and higher by default. It supports this and other features natively
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 39

Accepted Solution

by:
abel earned 350 total points
ID: 24745314
What about Regex.Replace(yourStringForOneLine, " ", "  ") which will effectively double each one. Then you can recalculate.

it's probably easier to first calculate the width of a space. Then you can add exactly enough spaces where you want them. You can get the index of a space using IndexOf. You can use ToCharArray to loop though all characters one by one. You'll have to decide on an algorithm here to find out the best way of outlining.

But whatever you try, it will not get pretty. The left border will stay straight, the right border will always remain wobbly, no matter how hard you try. The only sure-fire way is to change the approach and not resorting to inserting spaces.

-- Abel --
0
 
LVL 39

Expert Comment

by:abel
ID: 24745337
> what do you mean by ....
In an earlier comment I explained to you the .NET wraps a very old version of the RTF control, version 2.0, which is why using justified text doesn't work. Using either Win32 API functions to instantiate a different version, or by using an ActiveX (or third party .NET Assembly) that support the 4.0 version, you do not need to jump through hoops to get a ragged right-aligned justified text.
0
 

Author Comment

by:Dov_B
ID: 24745401
darn I used some api stuff jpaulino linked but it would not work with foreign fonts
and I cant afford the zillions the activex guys are asking for their controls
0
 
LVL 39

Expert Comment

by:abel
ID: 24745594
Here's a way to use the RTB 5.0 version: http://social.msdn.microsoft.com/forums/en-US/winforms/thread/194f563c-205f-41a1-9582-4f03fd3a53c2/  (second post)

I tried with another control, which is said to be a version 6 activex control, but that supports the same subset. I didn't try with the code above yet, but it seems promising.
0
 
LVL 39

Expert Comment

by:abel
ID: 24745698
Tried it, and it renders to RichEdit50W now, but apparently it still does not support justified text. Sorry for putting you in the wrong direction, according to internet sources I understood that the newer versions were smarter. Maybe they are, but they do not implement the \qj (justify) RTF command.

Then all that's left is either your own method, which will look ragged (sorry about that) or a third party control or... I don't know...

-- Abel --
0
 

Author Comment

by:Dov_B
ID: 24745736
thank you I am realy in experienced
I translated the c sharp code to vb.net but got one error in the line abot 19 lines down
>>>
Dim createParams As CreateParams = MyBase.CreateParams
saying create Params already declared in current block
I will post the translated code
also I added this class to my project but how do I use it ?
I am really new
I amusing vb.net 2008 express

Imports System

Imports System.ComponentModel

Imports System.Windows.Forms

Imports System.Runtime.InteropServices
 

Public Class RichTextBox5

    Inherits RichTextBox

    Private Shared moduleHandle As IntPtr
 

    Protected Overloads Overrides ReadOnly Property CreateParams() As CreateParams

        Get

            If moduleHandle = IntPtr.Zero Then

                moduleHandle = LoadLibrary("msftedit.dll")

                If CLng(moduleHandle) < &H20 Then

                    Throw New Win32Exception(Marshal.GetLastWin32Error(), "Could not load Msftedit.dll")

                End If

            End If

            Dim createParams As CreateParams = MyBase.CreateParams

            createParams.ClassName = "RichEdit50W"

            If Me.Multiline Then

                If ((Me.ScrollBars And RichTextBoxScrollBars.Horizontal) <> RichTextBoxScrollBars.None) AndAlso Not MyBase.WordWrap Then

                    createParams.Style = createParams.Style Or &H100000

                    If (Me.ScrollBars And DirectCast(&H10, RichTextBoxScrollBars)) <> RichTextBoxScrollBars.None Then

                        createParams.Style = createParams.Style Or &H2000

                    End If

                End If

                If (Me.ScrollBars And RichTextBoxScrollBars.Vertical) <> RichTextBoxScrollBars.None Then

                    createParams.Style = createParams.Style Or &H200000

                    If (Me.ScrollBars And DirectCast(&H10, RichTextBoxScrollBars)) <> RichTextBoxScrollBars.None Then

                        createParams.Style = createParams.Style Or &H2000

                    End If

                End If

            End If

            If (BorderStyle.FixedSingle = MyBase.BorderStyle) AndAlso ((createParams.Style And &H800000) <> 0) Then

                createParams.Style = createParams.Style And -8388609

                createParams.ExStyle = createParams.ExStyle Or &H200

            End If

            Return createParams

        End Get

    End Property

    ' P/Invoke declarations

    <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _

    Private Shared Function LoadLibrary(ByVal path As String) As IntPtr

    End Function
 

End Class

Open in new window

0
 

Author Comment

by:Dov_B
ID: 24745776
ok sorry I just got your new post
0
 
LVL 39

Expert Comment

by:abel
ID: 24745954
> also I added this class to my project but how do I use it ?
add it as a component and you can immediately use it. But like I said in my previous post, it was a dead end, unfortunately. So far, the only conclusion one can make is that Microsoft has not bothered yet with implementing justified text for RTF controls.
0
 

Author Comment

by:Dov_B
ID: 24767065
I dont know what you mean by adding it as a component
do you mean adding a class and pasting the code into it?
0
 
LVL 39

Expert Comment

by:abel
ID: 24767249
in the solution explorer, on the project, rightclick > Add > Add Component.

But, see my two previous comments where I tried to explain you that you shouldn't bother: there is no support for justified alignment in any of the richtextbox controls Microsoft supplies, even though they are the inventors and maintainers of the RTF standard... Sorry that I can't give you better news.
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Well, all of us have seen the multiple EXCEL.EXE's in task manager that won't die even if you call the .close, .dispose methods. Try this method to kill any excels in memory. You can copy the kill function to create a check function and replace the …
Introduction As chip makers focus on adding processor cores over increasing clock speed, developers need to utilize the features of modern CPUs.  One of the ways we can do this is by implementing parallel algorithms in our software.   One recent…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now