Detect click on HTMLViewer Control

Mohave 10.14.6
Xojo 2019 3.1

I want to display some text with some of the characters having a background color. The only way I can figure this out is to use an HTMLViewer and pass it some HTML that shows the characters with a background color. This works (although a little fiddly)

But now I would like to be able to detect if the user clicks over the HTMLViewer Control. Text Areas and Text FIelds have a MouseDown event so I can detect if the user clicks over these types of controls. But HTMLViewers do not have this event. So I cannot figure out how to detect if the user clicks on the control.

Is there a trick to do this?

I tried putting an invisible canvas control over the HTMLViewer and detect the MouseDown event of the invisible canvas. This seems to work.

Is this an appropriate solution or is there something more straight-forward.

you should use the executejavascript method, in conjunction with the statuschanged event

jsSrc = "document.getElementById("""+anElementID+""").click();" ExecuteJavaScript(jsSrc)

Xojo documentation for ExecuteJavaScript.

[quote]This method is only available for Web applications[/quote]?

My application is a Desktop app. And does some HTMLViewer in a Desktop app have “anElementID”? I do not mean to be obtuse, but I do not know exactly how to make this work.

And not to be argumentative, is there something wrong or undesirable about putting a transparent canvas over the control and using its events?

Thanks for your help.

Yes.

It’s HTMLViewer hacking. It requires a little bit of knowledge with Javascript and some fun workarounds in Xojo code. It’s definitely the better route, but you shouldn’t be using HTMLViewer for such simple text drawing.

Is there a reason you don’t just draw the text and background color yourself with a Canvas? That would be the best method for this.

The image shows the effect I am trying to achieve. I want a programmatically determined word within a sentence that is passed to be shown with a larger font and a background color. I can do this in an HTMLViewer, but I do not see a graphics text command to specify a background color for text in a canvas.

Nor was I able to see a way to display a sentence and then single out words (for example words beginning with “p”) and showing them in a different color/size.

sorry I did not explain enough. you may use htmlviewer.executejavascript in a desktop app.
I’m pretty sure I found an example here on the forum but I can’t remember where.

Robert, you are looking at the wrong item.
In LR search for HTMLViewer, and in its Methods you’ll find executejavascript.

You need to have some javascript in the HTMLviewer. This javascript should handle the click event (or mouse event, I can’t remember which) and end with this:

document.title = "some string";

This will cause the TitleChanged event for the HTMLViewer to fire on the Xojo side.

This presupposes that you control what is loaded into the HTMLviewer.

You can use these tools to achieve that effect on a canvas:
https://documentation.xojo.com/api/graphics/graphics.html#graphics-fontSize will let you change the font size
https://documentation.xojo.com/api/deprecated/deprecated_class_members/graphics.stringheight.html will tell you the height of the string based on the current font size
https://documentation.xojo.com/api/deprecated/deprecated_class_members/graphics.stringwidth.html will tell you the width of the string based on the current font size
https://documentation.xojo.com/api/deprecated/deprecated_class_members/graphics.fillrect.html will fill a rectangle with the color
https://documentation.xojo.com/api/deprecated/deprecated_class_members/graphics.drawstring.html will draw the string, do this after drawing the background highlight

You get out of it what you put into it really. If you want to use HTMLViewer, it requires a lot of overhead and a hack to get the functionality you want out of it. If draw the text with Canvas, it is more efficient and exposes the mouse events to you within the Xojo framework. Choose what works best for you.

There are many of us here happy to answer questions when you can’t find what you’re looking for. The hardest part sometimes is figuring out the right question to ask.

Thanks, Parnell. When I was looking through the forum I found an old post of yours

I know no JavaScript whatsoever, so many of the contributions submitted, however much appreciated, were really over my head. But I took to heart your idea to just stay within the Xojo framework and work with a canvas and draw strings there.
Your suggestion to put a rectangle behind the text to be highlighted with a background color was also key. I would note that my idea of an invisible canvas (to capture the MouseDown event) over the HTMLViewer was actually working. Parnell said bluntly that was a bad idea, but did not elaborate. I am curious why it is considered a bad idea.

I ultimately created a subclass of Canvas. The subclass has three properties:
lengthHighlight (the length of the word which was to be highlighted - 7 in the example)
startHighlight (the position in the string where the highlighted word started - 27 in the example)
theString (the string that was to be displayed -Maloney in the example)

This is what the Canvas displays:

Now that it is a simple Canvas, rather than an HTMLViewer, I can capture the MouseDown event

For future me and others who might like to see the implementation, I include the code that is in the paint event of the Canvas. The exact position of the highlight rectangle has to be adjusted to deal with descenders. the “bottom” of text is at the level of the bottom of characters that do not have descenders. The background rectangle has to be pushed down a little to highlight the descenders. I apologize in advance for any coding clumsiness.

The part of the string that is to be highlighted is shown in a slightly larger font size and with a background color as seen in the image.

[code]Var theString As String = Me.theString
Var theStart As Integer = Me.startHighlight
Var theLength As Integer = Me.lenghHighlight

Var lengthEntire As Integer = theString.Length
// to do anything, these values have to be consistent and describe something to highlight
If lengthEntire < theStart + theLength Then Return
If theStart <= 0 Then Return
If theLength <= 0 Then Return

Const FONT_DISPLAY As String = “Andale Mono”
Const FONT_SIZE_BEGIN_END As Integer = 18
Const FONT_SIZE_MIDDLE As Integer = 24
Const PAD As Integer = 8
Var COLOR_BACKGROUND As Color = RGB(256, 215, 0) // Gold
Const DESCENDER_FRACTION As Double = .25// descenders are roughly 1/4 the height of the string
Const START_TEXT_X As Integer = 10 // where the left edge of the text is in the Canvas
Const START_TEXT_Y As Integer = 30 // where the bottom of text is to be placed in the Canvas ignoring descenders

Var str1 As String // before highlight
Var str2 As String // to be highlighted
Var str3 As String // after highlight

Var widthstr1, widthstr2, widthstr3 As Double
// TextHeight is calculated as the maximum height for the font itself and not the actual height of the text. Actual text irrelevant
// For example, with “a” vs. “A”, both return the same TextHeight even though “A” has a greater height than “a”.
Var heightstr1_3, heightstr2 As Double
Var descenderProblem2 As Double
str1 = theString.Left(theStart)
str2 = theString.Middle(theStart, theLength)
str3 = theString.Right(lengthEntire - (theStart + theLength))

// figure out the height and width of the parts of the string
g.TextFont = FONT_DISPLAY
g.TextSize = FONT_SIZE_BEGIN_END
widthstr1 = g.TextWidth(str1)
heightstr1_3 = g.TextHeight()
widthstr3 = g.TextWidth(str3)
g.TextSize = FONT_SIZE_MIDDLE
widthstr2 = g.TextWidth(str2)
heightstr2 = g.TextHeight()
descenderProblem2 = heightstr2 * DESCENDER_FRACTION

// draw the text before the highlight
g.TextSize = FONT_SIZE_BEGIN_END
g.DrawingColor = Color.Black
g.DrawString(str1, START_TEXT_X, START_TEXT_Y)

// highlight background rectangle
Var startRectX As Integer
Var widthRectX As Integer
g.DrawingColor = COLOR_BACKGROUND
startRectX = START_TEXT_X + widthstr1 + PAD
widthRectX = widthstr2
g.FillRectangle(startRectX, START_TEXT_Y - heightstr2 + descenderProblem2, widthstr2, heightstr2) // upper left X, upper left Y, width, height

// draw the highlighted text
g.DrawingColor = Color.Black
g.TextSize = FONT_SIZE_MIDDLE
g.DrawString(str2, (START_TEXT_X + widthstr1 + PAD), START_TEXT_Y)

// draw the text after the highlight
g.TextSize = FONT_SIZE_BEGIN_END
g.DrawingColor = Color.Black
g.DrawString(str3, (START_TEXT_X + widthstr1 + PAD + widthstr2 + PAD), START_TEXT_Y)[/code]

Ah, you hadn’t asked why and I was trying to tiptoe around it as a recommendation by another user. I was trying to be brief, not blunt, I apologize.

The reason I said “yes” to “is there something wrong or undesirable about putting a transparent canvas over the control and using its events?” is because there were better solutions. In addition, overlapping controls on Windows tends to have some major issues. Having since tested, due to the pseudo-transparency system on Windows this method doesn’t work. I’m surprised by your results.

Specific technical notes that come to mind:
The recommendation to use a Canvas uses fewer controls and is more efficient in drawing.
The recommendation to use Javascript uses existing functionality within the HTML Viewer control and doesn’t need additional controls.

Edit: the person that tends to recommend “put an invisible canvas over it” didn’t strike in this thread heh