?
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
Medium Priority
?
1,093 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 8
  • 3
19 Comments
 
LVL 48

Assisted Solution

by:jpaulino
jpaulino earned 600 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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

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 1400 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
 
LVL 39

Accepted Solution

by:
abel earned 1400 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

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A while ago, I was working on a Windows Forms application and I needed a special label control with reflection (glass) effect to show some titles in a stylish way. I've always enjoyed working with graphics, but it's never too clever to re-invent …
Introduction When many people think of the WebBrowser (http://msdn.microsoft.com/en-us/library/2te2y1x6%28v=VS.85%29.aspx) control, they immediately think of a control which allows the viewing and navigation of web pages. While this is true, it's a…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses
Course of the Month14 days, 12 hours left to enroll

770 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