Avatar of Clif
Clif
Flag for United States of America asked on

RichTextBox - Setting Font and Copying RTF Not Working

I have an application that contains a RTB where I allow the user (through a button) the ability to bold selected text.

The code to bold is this:
Private Sub btnBold_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBold.Click
    rtbComments.SelectionFont = New Font(rtbComments.SelectionFont.FontFamily, rtbComments.Font.Size, rtbComments.SelectionFont.Style Xor FontStyle.Bold)
End Sub

Open in new window


Later on in the code, I pass the RTF value in the RTB to an instance of an RTB in a class like this:
Private m_rtbTarget As New RichTextBox
Public WriteOnly Property rtbTarget() As RichTextBox Implements IReport.rtbTarget
    Set(ByVal value As RichTextBox)
        m_rtbTarget.Rtf = value.Rtf
    End Set
End Property

Open in new window


The problem is the bolded font isn't being passed.

If I paste text in the original RTB from a Word document, and it has bolded text, the bolding will be pasted as well.  Then, when the rtf is passed, the bolding does get passed as well, only the bolding that gets set with the button doesn't get passed.

What gives?
Visual Basic.NET

Avatar of undefined
Last Comment
Cimperiali

8/22/2022 - Mon
Cimperiali

Private m_rtbTarget As New RichTextBox
Public WriteOnly Property rtbTarget() As RichTextBox Implements IReport.rtbTarget
    Set(ByVal value As RichTextBox)
        m_rtbTarget.Rtf = value.Rtf
    End Set
End Property
you're assigning the rtf to a  New RichTextBox, wihch probably is not the one user sees. You then reassign it back to the RichTextBox you display?
Clif

ASKER
I'm assigniong the rtf of the visible RTB to an RTB object in a class so that I can write out the text (with formatting) to a Word document.  The value goes one way, it never gets set back to the RTB on the form.

The purpose of the class is to contain code for reuse.
Cimperiali

beg your pardon if I ask this, but do you keep your class alive avoiding to have a new m_rtbTarget each time? To test for sure, change the declaration
(Private m_rtbTarget As New RichTextBox) in Private m_rtbTarget As  RichTextBox and initialize it in a method that requires explicit call (this only for testing purpose, to be sure you retain the same object through the lifetime of your "reused code"...
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
Clif

ASKER
No, the class is disposed of when the document is complete to allow for the possibility of another class to be created.  I have (currently) three classes, one of which will be instantiated depending upon choices made by the user.  Each class has it's own RTB object.

I'm not entirely sure I understand what you're asking me to do.  Can you fomat it a little better?

Cimperiali

Ok, point is (I am quite sure you already know this, I am telling you only if it might be you forgot to ensure it) : if you lose data you might  have

instantiate the class
you assign values to a new object
...
you assign values to a new object (this is not the same of before - you losed values assigned to previous object)

so, as you have a Private m_rtbTarget As New RichTextBox, you might not be aware you are making a new m_rtbTarget  somewhere else in your code, thus losing values assigned to a previous instance. To ensure this is not happening, for testing purpose you could make a routine to "manual" instantiate the m_rtbTarget , so you have to call it to make a "New  RichTextBox" and you can see debugging if you're stepping in there more than once in between.
 
Clif

ASKER
I've been doing some investigating and have narrowed it down to a couple of lines of code.  Here is the total code black that references the RTB instance:
'Point 1
m_rtbTarget.SelectAll()
m_rtbTarget.SelectionFont = New Font("Arial Narrow", 11)

'Point 2
m_rtbTarget.Rtf = m_rtbTarget.Rtf.Replace("<<CUSTOMERNAME>>", m_strCustomer.CustomerName)
m_rtbTarget.Rtf = m_rtbTarget.Rtf.Replace("<<ISSUENAME>>", sIssueNameList)
m_rtbTarget.Rtf = m_rtbTarget.Rtf.Replace("<<STANDARD>>", m_strStandards.Number)
Application.DoEvents()

'Point 3
If m_rtbTarget.Find("Recommendations") >= 0 Then
  m_rtbTarget.Select(m_rtbTarget.Find("Recommendations"), Len("Recommendations"))
  m_rtbTarget.SelectionFont = New Font(m_rtbTarget.SelectionFont, FontStyle.Bold)
End If
If m_rtbTarget.Find("Results") >= 0 Then
  m_rtbTarget.Select(m_rtbTarget.Find("Results"), Len("Results"))
  m_rtbTarget.SelectionFont = New Font(m_rtbTarget.SelectionFont, FontStyle.Bold)
End If
If m_rtbTarget.Find(m_strStandards.Number) >= 0 Then
  m_rtbTarget.Select(m_rtbTarget.Find(m_strStandards.Number), Len(m_strStandards.Number))
  m_rtbTarget.SelectionFont = New Font(m_rtbTarget.SelectionFont, FontStyle.Italic)
End If

'Point 4
Dim oClipboard As Object = Clipboard.GetDataObject()
If m_rtbTarget.Text.EndsWith(vbLf) Then
  sText = vbCrLf
Else
  sText = vbCrLf & vbCrLf 'Add an extra one to keep the spacing correct.
End If
m_rtbTarget.SelectAll()
m_rtbTarget.Copy()
m_oWord.Selection.Paste()
Try
  Clipboard.SetDataObject(oClipboard)
Catch ex As Exception
  'Do nothing. Just prevent the app from stopping.
End Try

Open in new window


The problem appears to be at Point 1.  Irrespective of what's bold and not, I need the text to be 11 pt "Arial Narrow".  Setting this, however, causes all formatted font to be reset back to standard (not bold/italic).  How do I change the font name/size only and keep whatever may be bolded/italics?
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Nasir Razzaq

You can not do that at the end because you are RESETTING the font to same font without bold/italics.
Mike Tomlinson

There's no way to change the font for all text at once and keep any existing bold formatting.

You have to loop thru, character by character, select it, and then set the font based on whether the current selection is bolded or not.
Clif

ASKER
I ain't buying it.

You're telling me that, if I were to write a WP using the RTF control, if someone created a ten page document, fully formatted, and then wanted to change the font for the entire document from Times New Roman to Arial, my code would have to go through character by character for each character of those ten pages and look at the bold/italic and then individually set the font name and include the bolding/italic?

That just ain't right, and I refuse to believe that's my only option.
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
Nasir Razzaq

Instead of

m_rtbTarget.SelectAll()
m_rtbTarget.SelectionFont = New Font("Arial Narrow", 11)

to

m_rtbTarget.Font = New Font("Arial Narrow", 11)
Clif

ASKER
No Joy.  Same effect.
Cimperiali

No, I do believe that will not work: you substitute the font in any case. You spotted it correctly before: to preserve  formatting, the formatting must be reapplyed, thus it must be made for each single char in (rtf) text when the formatting changes
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Cimperiali

that is: loop through chars and select them while the fontStyle  is the same.
Then, when you spot it changes, apply the new family and the new size and the "old" style from first char to the one before it changes, then set the subsequent char as the new starting point till the end of selection

SOLUTION
Mike Tomlinson

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
Cimperiali

indeed you could try pasing directly rtf.
an example is here: http://www.codeproject.com/KB/cs/RTFSyntaxColour.aspx
SOLUTION
Log in to continue reading
Log In
Sign up - Free for 7 days
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Cimperiali

for example, I wrote in a rich text box "Hello, man how are you" and set only Hello as bold and the wole text as Courier new
then I grabbed the rtf in a string variable :
{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Courier New;}{\f1\fnil\fcharset0 Microsoft  San serif;}}
\viewkind4\uc1\pard\lang1040\b\fs25 hello\b0\f1\fs20 , man how are you\par
}
then substitute (replace)  Courier New with Arial and
fs + number (ie fs25) with fs+ number+5 (ie: fs30)
then reassigned the string to the RTF property of the richTextBox
give it a try.
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Cimperiali

Idle Mind, you got it before me. I do believe this is the correct direction for the quester
Clif

ASKER
Ok, let's try that direction (looping through one character at a time isn't quite working yet).

My problem with the solution of modifying the rtf directly is how to find every possible font name to replace with the correct one?  Then there is the same issue with the font size (including partial sizes like 11.5)

I'm sure the answer would have something to do with Regular Expressions, but I was sick the day they talked about that back in college.
ASKER CERTIFIED SOLUTION
Log in to continue reading
Log In
Sign up - Free for 7 days
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Cimperiali

Regular Expressions of course, would be nice. But me too was sick that day, so I do RegEx only when really I cannot avoid. A tip: search for "Expresso Regular Expression" : it is a free tool that could help you write RegEx. ...But I was sick...
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Cimperiali

Clif

ASKER
Your example:
{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Courier New;}{\f1\fnil\fcharset0 Microsoft  San serif;}}
\viewkind4\uc1\pard\lang1040\b\fs25 hello\b0\f1\fs20 , man how are you\par
}

I need to convert *all* font names to "Arial Narrow", so I would need to replace both "Courier New" and "Microsoft  San serif" with "Arial Narrow".

I also need to convert all sizes to 11, so I would ned to replace fs25 and fs20 to fs11.

Thanks for the tool.  One of these months, when I have nothing to do, I might learn how to use it.  :)  It looks like you need to know regular expressions first, though.
Nasir Razzaq

Did you explore my idea? http:#36357847
Your help has saved me hundreds of hours of internet surfing.
fblack61
Clif

ASKER
No, I didn't.  I'm not entirely sure how to do what you suggest.
Clif

ASKER
Ok, I took what C did and expanded on it till I got to here:
Function fixRTF(ByVal RTF As String) As String
    Dim sRetVal As String = RTF
    Dim nPtr1 As Integer = -1
    Dim nPtr2 As Integer = 0
    Dim arrReplace() As String
    Dim nArrCount As Integer = 0

    ReDim arrReplace(nArrCount)

    nPtr1 = sRetVal.IndexOf("fcharset")
    Do Until nPtr1 = -1
        nPtr1 = sRetVal.IndexOf("fcharset", nPtr1)
        If nPtr1 > -1 Then
            nPtr1 = sRetVal.IndexOf(" ", nPtr1)
            If nPtr1 > -1 Then
                nPtr1 += 1
                nPtr2 = sRetVal.IndexOf(";", nPtr1)
                If nPtr2 > -1 Then
                    nArrCount += 1
                    ReDim Preserve arrReplace(nArrCount)
                    arrReplace(nArrCount) = sRetVal.Substring(nPtr1, nPtr2 - nPtr1)
                End If
            End If
        End If
    Loop
    For i As Integer = 1 To UBound(arrReplace)
        sRetVal = sRetVal.Replace(arrReplace(i), "Arial Narrow")
    Next

    nArrCount = 0
    ReDim arrReplace(nArrCount)
    nPtr1 = sRetVal.IndexOf("fs")
    Do Until nPtr1 = -1
        nPtr1 = sRetVal.IndexOf("fs", nPtr1)
        If nPtr1 > -1 Then
            nPtr1 += 2
            nPtr2 = sRetVal.IndexOf(" ", nPtr1)
            If nPtr2 > -1 Then
                nArrCount += 1
                ReDim Preserve arrReplace(nArrCount)
                arrReplace(nArrCount) = sRetVal.Substring(nPtr1, nPtr2 - nPtr1)
            End If
        End If
    Loop
    For i As Integer = 1 To UBound(arrReplace)
        sRetVal = sRetVal.Replace("fs" & arrReplace(i), "fs22")
    Next

    Return sRetVal
End Function

Open in new window


It works well.  The only thing that concerns me is that, to get the correct Font Size, instead of using fs11, I had to double it so that it's fs22.

Does that sound right?  Is the fs number half of the actual font size?
Clif

ASKER
Well, no further comments, so I guess I'd better close this out before the weekend.

Thanks for the help.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Cimperiali

Let me say I do believe Idle Mind deserved points, as he was the  first to mention Rtf, and of course, CodeCruiser showed a good more common alternative.
About Sans Serif, that should be the default of richText, it was here from the start.
About size, seems as if  you're right: look here  (and search for \fs) http://www.pindari.com/rtf1.html