I was looking for a way to change the z-order of UI controls in a window but couldn’t find anything definitive. Here’s an example of how it can be done if anyone is still looking for a solution:
Add three rectangles, maybe coloured white, red & blue, created in that order so the white is at back and blue at front. Make them overlap so you can see the change.
Add a button to change order when pressed
Add the following in the button’s ‘Pressed’ event. This should re-order the three rectangles so the white rectangle is at front. Sorry, I still haven’t worked out how to paste code in here
var arrayRects() As DesktopRectangle
System.DebugLog(“— order before changes —”)
for each obj as Object in self.Controls
if obj IsA DesktopRectangle then
var strName As String = DesktopRectangle(obj).Name
System.DebugLog(strName)
arrayRects.Add(DesktopRectangle(obj)) // adding this rectangle to the array
end if
next
// removing all rectangles from window
for index as Integer = 0 to arrayRects.LastIndex
arrayRects(index).Close
next
// adding rectangles back to window in new order
self.AddControl(arrayRects(1))
self.AddControl(arrayRects(2))
self.AddControl(arrayRects(0))
System.DebugLog(“— order after changes —”)
for each obj as Object in self.Controls
if obj IsA DesktopRectangle then
var strName As String = DesktopRectangle(obj).Name
System.DebugLog(strName)
end if
next
Select your code,
Paste it,
Select it in the Forum page,
Click in
That is all; now you can see the result as in Xojo IDE.
var arrayRects() As DesktopRectangle
System.DebugLog(“— order before changes —”)
for each obj as Object in self.Controls
if obj IsA DesktopRectangle then
Var strName As String = DesktopRectangle(obj).Name
System.DebugLog(strName)
arrayRects.Add(DesktopRectangle(obj)) // adding this rectangle to the array
End If
Next
// Removing all rectangles from window
For index As Integer = 0 To arrayRects.LastIndex
arrayRects(index).Close
Next
// Adding rectangles back to window in new order
Self.AddControl(arrayRects(1))
Self.AddControl(arrayRects(2))
Self.AddControl(arrayRects(0))
System.DebugLog(“— order after changes —”)
For Each obj As Object In Self.Controls
If obj IsA DesktopRectangle Then
Var strName As String = DesktopRectangle(obj).Name
System.DebugLog(strName)
End If
Next
Like what Scott said, my goal was to come up with a relatively easy way of re-ordering window controls, not necessary rectangles. I tried this with labels as well, and think it would work with any UI control. Just an idea that’s all.
One solution to complicated control overlay problems is to save the Project in .xojo_project text format, Then rearrange the controls in the .xojo_window file. Also make any other changes, such as exact positioning, at the same time.
I was first forced into doing this with a window with 60 overlapping controls, but this procedure is so fast and accurate, that I now do it routinely whenever windows don’t behave or look exactly how I want.
DesktopUIControl subclasses have a method called DrawInto which will draw the control in its current state onto a graphics context. What you could do is let the user put the layout into a design mode and overlay the editing area with a canvas. When the user clicks on the canvas, you go through the controls and see which (if any) control was clicked on. If one was, you move it off screen and use DrawInto to draw the control into the canvas as the user drags. Once they release the mouse, you put the control in the release position and stop drawing the canvas version. In this way, the dragged control would always be on top of everything else.
You’ll have to track the control, its coordinates and the drag itself, but it is doable.
The canvas items are created in order from left to right and named CanvasA, Canvas2 & Canvas3. Using the MouseDown, MouseDrag and MouseUp events I drag a playing-card by clicking the mouse on the canvas item and dragging it around the screen. If I move the CanvasA playing-card it moves behind the other two cards because it was created first and is at the back of display according to Z-Order. So, thinking I was clever, I moved CanvasA to the front of the display by making it last on the Z-Order (did that by CanvasA.close then adding it back on the window by self.AddControl(CanvasB) ).
The first MouseDown event is triggered, however once the CanvasA is closed the MouseDrag event is not triggered unless I do a second mouse down click. It appears that once I close the canvas its mouse events are suspended so it no longer detects that the mouse is down until it’s triggered again by another click.
Hmmmm… any ideas??
and just to practice pasting code, here’s the code:
MouseDown event
if objMovingCard = nil or objMovingCard <> me then
BringCardToFront(me)
me.Left = me.Left + x - (me.Width / 2)
me.Top = me.Top + y - (me.Height / 2)
end if
Return True
MouseDrag event
if objMovingCard = me then
me.Left = me.Left + x - (me.Width / 2)
me.Top = me.Top + y - (me.Height / 2)
end if
Hi Beatrix,
Thank you but I’m a Xojo beginner and not sure what you mean. Can you show me an example on how a single canvas would work with something like the playing cards example?
You can have a look at the example project I posted here. You’d create a class that represents the cards and draws their face (just like the included Rectangle and Oval). To modify the Z order, you’d change their position in the array.
Found a bug when you only change the order on a Window and save to xojo project. The Window code is not saved. (The project must be saved first)
I think this doesn’t apply to binary saving but didn’t test.
I think I found a solution (for this specific example) that isn’t too complicated. Hopefully someone gets some use out of it.
This example displays 3 DesktopCanvas items as playing-cards. The goal is to have the ability to select a card and move it around the window. When moving the selected card, it should display above the other cards (which doesn’t happen if we don’t change the z-order).
A mouse click & release over a card selects it, another mouse click & release over the same card unselects it. All three canvases use identical MouseDown and MouseMove events.
// check if this canvas is selected - select canavs with first click, unselect with second click
if canvasSelectedCard = me then
// already selected so unselect it
canvasSelectedCard = nil
else
// select this canvas
canvasSelectedCard = me
// centre canvas where mouse pointer is clicked
me.Left = me.Left + x - (me.Width / 2)
me.Top = me.Top + y - (me.Height / 2)
// bring this canvas to top of z-order
me.Close
self.AddControl(me)
end if
Return True
MouseMove event
me.MouseCursor = System.Cursors.FingerPointer
// check if this canvas is selected
if canvasSelectedCard = me then
// centre canvas where mouse pointer is
me.Left = me.Left + x - (me.Width / 2)
me.Top = me.Top + y - (me.Height / 2)
end if
Thank you for your help. I had a look and found it too complex for me for now… I found a work-around anyway. I’ll keep learning. Again thanks for your thoughts.