Functional Replacement for Line Control

I have an application that extensively uses the Line Control that has been removed from the Desktop controls. The application presents the user with anatomical images and when the image changes, anatomy labels are created and positioned alongside the image, and lines are drawn connecting the anatomy labels to dots in the image. The anatomy labels are Labels (to be updated to DesktopLabel). The lines are Lines (to be updated to ?? since there is no DesktopLine). Conveniently, Labels and Lines can accept MouseDown events so the user can be presented with additional information when they click on an individual anatomy label or line. The dots themselves are associated with the Canvas that is displaying the picture. A sample image is shown below to illustrate the situation.

The anatomy labels and the lines are Controls Sets (Label & Line). The current documentation suggests that Control Sets be abandoned because they are no longer necessary. I can accept that and am prepared to update the code to use the new commands that make Control Sets unnecessary. That is a way forward with the anatomy labels.

However, in the new version of Xojo, the Line is no longer a Control. So my technique of overlying the image and the space between the anatomy labels and the Canvas with Lines is no longer kosher. I understand that I could simply ignore the whole issue and never upgrade the application to the new Desktop API but this application Is under continuous development and “improvement”, and I am uncomfortable simply relying on old versions of Xojo and deprecated entities.

Can someone suggest a strategy of creating lines such as those seen in the sample image using the tools of the current version of Xojo? What approach would you use if you were coming to this situation in the modern era?

I have thought of perhaps covering the entire Window with a Canvas and custom drawing everything there (specifically the lines). It seems sort of an extreme approach. If the entire window was covered by a same-size Canvas, could I just superimpose all the Controls on top of it? Is it acceptable to cover a Canvas with Controls? Or would I be expected to use DrawText to create the words that are now Labels? And then I would have to write code to keep track of the position and size of all the DrawText areas so I could differentiate the different MouseDown events. And I would create the lines using DrawLine or the Object2D CurveShape. Is this reasonable? Are there easier approaches that someone could suggest?

This is an extreme example from my own stable of applications. But I acutely feel the loss of the LineControl in more banal circumstances in terms of UI design in many of my aplications.

1 Like

You can make Linecontrol with Canvas subclass, and it has only 2 lines in its draw event…

one to set the color and the other draws line.

1 Like

i think i would replace this label and line controls with a class and paint this objects on top.
textshape is good to display text.

I would continue using Label / DesktopLabel for two reasons:

  1. Label has an option for text selection, which can be useful to the user
  2. Label can have accessibility features so the system speaks out what is written.

For the line control, you can either replace it with canvas as Björn suggested, or superimpose a canvas over the picture to draw all necessary lines.

1 Like

Did the old line control have mousedown events??

In a situation where I have a collection of objects which draw themselves as lines, I have a routine to find ‘which one has been clicked upon’


Dim inbox as boolean
Dim bFound as boolean
Dim Line_left , Line_right as integer
Dim Line_top , Line_bottom as integer
      Dim dfsign as double
      Dim testy as double
Dim b,returner as MyLine    //class with x1,y1  x2,y2   attributes 

for each key as variant in col_mylines.keys
  inbox= false
  b = col_mylines.value(key)

  if bfound = false then
    

    //normalise the end points in case drawn backwards or upside down
    if b.x1< b.x2 then
      Line_left = b.x1
      Line_right = b.x2
    else
      Line_left = b.x2
      Line_right = b.x1
    end if
    
    if b.y1 < b.y2 then
      Line_top = b.y1
      Line_bottom = b.y2
    else
      Line_top = b.y2
      Line_bottom = b.y1
    end if
    

    //is  click  in our bounding box?
    
    
    //better hits on vertical and horizontal
    if between (Line_left-0.1, Line_right + 0.1,x)  and  between (Line_top-0.1,Line_bottom+0.1,y) then
      'vertical line
      inbox=  true
    end if
    
    if inbox then

      //is it a vertical or horizontal?
      if abs(b.x1 - b.x2) < 0.6 then
        'vertical line
        bFound = true
      end if

      if abs(b.y1 - b.y2) < 0.6 then
        'vertical line
        bFound = true
      end if
    end if
    


    if inbox  then
      


      r1=(Line_bottom - Line_top)
      r2 = (Line_right-Line_left)
      dfsign =  r1/r2
      
      testy = (x-Line_left) * dfsign
      
      'what kind of slope?
      if ((b.x1 < b.x2) and (b.y2> b.y1)) or ((b.x1  > b.x2) and (b.y2 < b.y1)) then
        'slope is \
        testy = testy + Line_top
      else
        testy =Line_bottom - testy
      end if
      
      
      if abs(testy - y) < 0.6 then
        bFound = true
  
      end if

    end if
    
    
    if bfound then
      returner = col_mylines.value(key)
      Exit for
    end if
    
    
  end if
next
1 Like

It could have, and perhaps it should have, but in my current application using the old Xojo it did not. I never created code in the MouseDown Event of the Line. If the user clicked on the line instead of the anatomy label, nothing happened.

One sort of cool thing with the old Line control is that when you create a diagonal line using this control, you will see a “square” outlined by little boxes in the shape of the square that would encompass the particular diagonal line you are prescribing. If you assign that Line Control a MouseDown event, it is not triggered by clicking anywhere in that “square”. Rather you have to click in close proximity to the line itself to register the MouseDown event. This makes it a little easier to have diagonal lines in fairly close proximity to one another and yet distinguish user clicks on one as opposed to the other.

Anyway, I appreciate the code you submitted, which may well inspire a version for me.

That’s basically what my code example does.
From the sounds of it, the old control must have done the same kind of thing.

But when you make a replacement “LineControl” with this technique don’t you potentially run into problems with the Canvas subclass overlying other members of the Canvas subclass? This would particularly be the case if lines were diagonally oriented and in fairly close proximity. Couldn’t you actually have a large diagonal line canvas completely overshadows a nearby short line? And possibly interfere with other controls on the layout? If the user clicked in the area, who would get the MouseDown event?

To be clear (to me) you are referring to Object2D entities that are being drawn on a Canvas with CurveShape? And the code is being run in the MouseDown event of the Canvas which is going on to figure out which line on that Canvas that the user was trying to click on?

I like this preservation of Label “capability”. For one thing, it simply preserves the ability of the user to click on an individual label and get appropriate feedback from code in the MouseDown event of that label.

Currently, in my application, the Canvas Control that shows the picture stops at the edge of the image. But as I understand your suggestion, you would expand the size of the Canvas Control to encompass the entire length of the line, but fall short of the LabelControls themselves which could remain independent and “off” the Canvas.

It brings up a point I alluded to in the original posting, is it good practice to actually place controls like Labels or Buttons on top of a Canvas? Basically end up with a stack of controls. In that situation, are they considered foremost and capture/intercept mouse clicks before they “reach” the Canvas?

In an extreme situation, one might imagine a stack of Canvases drawn on top of each other in the IDE. Who captures Mouse Events? And does that change if some of the Canvases in the pyramid are made invisible, perhaps intermittently, in code? Or is this all “bad practice”.

You would have the same problem with stacked Line controls.

1 Like

You understood my suggestion correctly.
I do not do Desktop UI design anymore as I am focused on iOS now. But in my opinion it would be easier to have one big canvas to paint the picture and all the lines.

1 Like

No, actually.
I have a collection of objects of a class that has end points.
I draw this collection myself in a loop using DrawLine when I need to

(I would rather hand it off to curveshapes but as I need to interact with other properties later, its easier for me to use a dictionary or array of objects I made)
…like Jeremie is saying

‘But in my opinion it would be easier to have one big canvas to paint the picture and all the lines.’

1 Like

use the paint of the window if overlapping controls not work.
as example
in paint event there

DrawTo g, Label1, g.Width/2, g.Height/2
DrawTo g, Label2, g.Width/2, g.Height/2
DrawTo g, Label3, g.Width/2, g.Height/2
Public Sub DrawTo(g As Graphics, Label As DesktopLabel, TargetX As Double, TargetY As Double)
  g.PenSize = 2.0
  g.DrawingColor = RGB(255,0,0)
  g.DrawLine Label.Left + Label.Width , Label.Top + Label.Height / 2.0, TargetX, TargetY
  
End Sub
1 Like

Hi there,
a rectangle with a height of 2 or a width of 2 replaces a line for me
several rectangles form a line and can be
mouse are detected
Example:
Window1.Mousedrag:
If nr = 5 Then
rectangle1.Left = x-Rectangle1.Width/2
rectangle1.top = y
rectangle2.Left = rectangle1.Left+rectangle1.Width-1
rectangle2.top = rectangle1.top+rectangle1.height-1
End If
rectangle1.mouseDown
Nr = 5

I am not much of a wiz in this area but…

Want it be better if you create your own custom control that is responsible for drawing line?

I would say: If you can create a custom control then do it!

And you can also contribute this control to the community here. If you feel like.

i think the problem is more overlapping controls can create unwanted sideeffects.
as i wrote before the window itself can also be painted by a list of x,y pairs

This makes me curious as to why they removed the Line control. Does anyone know?

The line control was something so random, that the unique answer that comes to my mind would be a bit offensive to who wrote such component. I had some of them in the past in one app, that when compiled and built, the straight horizontal line got inexplicably diagonal at runtime, another build, it returned to get straight. :crazy_face: So I was forced to remove it from the code. It took ages without anyone trying to fix it, and I can’t imagine why such simple component would be considered something so hard to fix, but instead of fixing it, seems like they preferred just to remove it. :rofl:

3 Likes

I made a program in the past that was for a Rugby scoreboard. It mirrored the top left portion of the screen to a LED billboard. I used a combination of custom images on a canvas, and rectcontrol.DrawInto to create the screen that would display to the billboard. This even works to draw controls from an opened, but visible=false window. Hope this helps.