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.
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
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.
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 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.
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.â
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
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 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
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. 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.
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.