<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ContainerControl &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/containercontrol/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Thu, 07 Mar 2024 22:07:43 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Tutorial: Design a Control to Dynamically Preview Images and PDF Files</title>
		<link>https://blog.xojo.com/2024/03/11/tutorial-design-a-control-to-dynamically-preview-images-and-pdf-files/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 11 Mar 2024 15:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Composition]]></category>
		<category><![CDATA[ContainerControl]]></category>
		<category><![CDATA[Control]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=12601</guid>

					<description><![CDATA[In this tutorial learn to design a cross-platform control that dynamically previews images and PDF files. Files can dragged and dropped onto the control, opened from the standard file selection dialog, and, in the case of images, added using Copy and Paste. The file path will be displayed below the addendum file. ]]></description>
										<content:encoded><![CDATA[
<p>A few days ago, I received a request from a user about how to solve a problem he was facing in a control for one of the desktop applications used by his company. This is the scenario:</p>



<ul class="wp-block-list">
<li>The control should show previews of images and PDF documents.</li>



<li>The documents to be displayed can be dragged and dropped onto the control, or opened from the standard file selection dialog.</li>



<li>In the case of images, they can also be added to the control using Copy and Paste.</li>



<li>In any of the above cases, the path of the file in question must be received so that future actions can be carried out.</li>
</ul>



<p>As an additional point, since we are using Xojo, the control will be cross-platform and functional on macOS, Windows and Linux.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><a href="https://drive.google.com/file/d/1TCFB8fNq2bZu7i1KMhWYCV26LdXK6Ykz/view?usp=share_link">Download the Example Project</a>.</p>
</blockquote>



<h2 class="wp-block-heading">Preparation</h2>



<p>Taking into account these requirements, as well as considering that the same problem may have more than one solution, this tutorial will show you how to create a control using the <a href="https://en.wikipedia.org/wiki/Composition_over_inheritance">Composition technique</a>. Using this technique, several graphical interface controls will be used internally and their use will be transparent to users who use it globally, either when creating their own applications or when using the control on any desktop platform.</p>



<p>When it comes to creating a control using the Composition technique, the DesktopContainerControl is the best candidate. A new ContainerControl-based class would internally use the following core controls:</p>



<ol class="wp-block-list">
<li>The DesktopImageWell control which is ideal for displaying images. </li>



<li>The DesktopHTMLViewer control which is ideal for displaying the preview of PDF documents.</li>
</ol>



<p>Now, while DesktopImageWell supports displaying images directly using Drag and Drop, this is not the case with the DesktopHTMLViewer control; so if the user of the control tried to drag and drop a PDF document or image when the HTMLViewer is displaying the control, it wouldn&#8217;t work.</p>



<p>To solve this situation it is common to add a third control. We&#8217;ll use a DesktopCanvas that will be, at all times, the top layer regardless of which underlying control (either the ImageWell or the HTMLViewer) is displayed. Thus, the DesktopCanvas would capture the event corresponding to the user dragging a file onto the global control (the class based on ContainerControl). Since it is transparent, it will not prevent the preview of the image or PDF file to be seen in the bottom layer control, at least on macOS.</p>



<p>But the Canvas is not transparent on Windows, in this case we need to use conditional compilation at various points in the class to modify the user interface of the main ContainerControl so that it adds a special area located under the controls preview (ImageViewer or HTMLViewer), and which will be used by the user of the control to drag and drop the corresponding files. For this we will use an additional DesktopCanvas.</p>



<p>Of course, we will also have to add a button to our control that will be responsible for opening the standard file selection dialog box so that the user can choose the file to preview.</p>



<p>To deal with another small difference between macOS and Windows, we will add a DesktopRectangle to be used as the base layer of the control (Z axis), so that it displays the typical Focus ring when the control is active and selected.</p>



<h2 class="wp-block-heading">Designing the Control</h2>



<p>With all that in mind, start a new Desktop project in Xojo. Drag a DesktopContainer from the Library onto the Navigator. It will look like this:</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1024x774.png" alt="" class="wp-image-12602" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-2048x1548.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>With the new Desktop Container1 instance selected in the Navigator, use the Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> ImagePDFContainer </li>



<li><strong>Size &gt; Width</strong>: 220 </li>



<li><strong>Size &gt; Height:</strong> 200</li>
</ul>



<p>Next, add the Drag and Drop area which, remember, will be shown only when the control is executed on Windows. To do this, drag a DesktopCanvas from the Library and drop it in the area of the Layout Editor corresponding to the Design Editor, placing it right under the container for our own convenience.</p>



<p>With Canvas1 selected, use the Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> DropArea</li>



<li><strong>Position &gt; Left:</strong> 1</li>



<li><strong>Position &gt; Top:</strong> 221</li>



<li><strong>Position &gt; Width:</strong> 216</li>



<li><strong>Position &gt; Height:</strong> 100</li>
</ul>



<p>The design should look like this:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1024x774.png" alt="" class="wp-image-12603" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-2048x1548.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now, add the background layer. This is the layer that will be in charge of displaying the focus ring for the control in Windows. To do this, drag a DesktopRectangle from the Library and drop it on the ContainerControl in the Layout Editor. The ContainerControl should show a red box indicating that the dragged control will be contained as a child control in the Container itself. Next, with DesktopRectangle1 still selected in the Layout Editor, use the Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> BacktroundRect</li>



<li><strong>Position &gt; Left:</strong> 0</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 220</li>



<li><strong>Position &gt; Height:</strong> 200</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>Next, add the button responsible for displaying the standard dialog box for selecting the file to preview. Drag a DesktopPushButton from the Library and drop it onto the bottom of the Container in the Layout Editor. The Container should display a red box to indicate that the button will be added as a child control in the Container itself.</p>



<p>Then, with Button1 still selected in the Layout Editor, use the associated Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> OpenFileButton</li>



<li><strong>Position &gt; Left:</strong> 0</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 178</li>



<li><strong>Position &gt; Height:</strong> 22</li>



<li><strong>Locking:</strong> Closes the left, right and bottom locks. Open the lock on the top edge.</li>



<li><strong>Mac Button Style:</strong> Recessed</li>



<li><strong>Caption:</strong> Open File…</li>
</ul>



<p>At this point, the control layout should look something like this:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1024x774.png" alt="" class="wp-image-12604" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-2048x1548.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now, add the instance of the DesktopImageViewer control responsible for previewing the images. As in previous steps, drag the DesktopImageViewer control from the Library and drop it on the Layout Editor, in the upper right part of the Container; then, with ImageViewer1 still selected, use the associated Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name: </strong>ImagePreviewer</li>



<li><strong>Position &gt; Left: </strong>238</li>



<li><strong>Position &gt; Top:</strong> -219</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 198</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>Drag a DesktopHTMLViewer from the Library onto the free area of the Layout Editor, just below the ImageViewer added in the previous step; Then, with HTMLViewer1 still selected in the Layout Editor, use the associated Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> HTMLPDF</li>



<li><strong>Position &gt; Left:</strong> 238</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 198</li>



<li><strong>Locking: </strong>Lock all four padlocks.</li>
</ul>



<p>At this point, the control layout should look something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1024x774.png" alt="" class="wp-image-12605" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Finally, add the overlay to be used only when the control is executed on macOS and that is responsible for capturing the action of &#8220;Drag and Drop&#8221; files by the user. Drag a new DesktopCanvas over the Container in the Layout Editor. The Container should display a red box to indicate that the new control is being added as a child of the Container itself. With Canvas1 still selected in the Layout Editor, use the associated Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> CanvasOverlay</li>



<li><strong>Position &gt; Left:</strong> 1</li>



<li><strong>Position &gt; Top:</strong> 1</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 179</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>To make sure that all the &#8220;layers&#8221; (order of the controls on the Z axis) are as we expect, click on the &#8220;Show Tab Order&#8221; button in the Layout Editor toolbar. If they do not match the order shown in the image below, drag and drop each element to the correct position in the list:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1024x774.png" alt="" class="wp-image-12606" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Add Functionality</h2>



<p>With the design of the control now complete, it is time to add its functionality. To do this, select ImagePDFContainer in the Navigator and add the following properties along with the values indicated in the Inspector Panel:</p>



<p>The first will be in charge of containing the message to be displayed in the &#8220;Drag and Drop&#8221; area:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> DropFileMessage</li>



<li><strong>Type:</strong> String </li>



<li><strong>Scope:</strong> Public</li>
</ul>



<p>The second will be the property in charge of storing the reference to the file (FolderItem instance) whose image/PDF is being previewed:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FileDropped</li>



<li><strong>Type:</strong> FolderItem </li>



<li><strong>Scope:</strong> Private</li>
</ul>



<p>The last property will be responsible for containing the color to be used as the focus ring:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FocusColor</li>



<li><strong>Type:</strong> Color </li>



<li><strong>Scope:</strong> Public</li>
</ul>



<p>Next, add the events that the control needs to consume for its operation. With ImagePDFContainer still selected in the Navigator, add the following Event Handlers along with the associated code:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre id="Xojo" class="wp-block-code"><code>HTMLPDF.Visible = False
ImagePreviewer.Visible = False

#If TargetWindows Then
  DropArea.Top = Me.Height - 50
  DropArea.Height = 50
  DropArea.Width = BackgroundRect.Width
  DropArea.Left = BackgroundRect.Left
  BackgroundRect.Height = BackgroundRect.Height - 50
  
  HTMLPDF.Height = BackgroundRect.Height - 2
  ImagePreviewer.Height = BackgroundRect.Height - 2
#EndIf

RaiseEvent Opening</code></pre>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre id="Xojo" class="wp-block-code"><code>Me.SetFocus
Return True</code></pre>



<h4 class="wp-block-heading">FocusReceived:</h4>



<pre class="wp-block-code"><code>#If TargetWindows Then
  FocusColor = Color.Blue
  BackgroundRect.BorderColor = FocusColor
  DropArea.Refresh
#EndIf</code></pre>



<h4 class="wp-block-heading">FocusLost:</h4>



<pre class="wp-block-code"><code>#If TargetWindows Then
  FocusColor = Color.Black
  BackgroundRect.BorderColor = FocusColor
  DropArea.Refresh
#EndIf</code></pre>



<p>Since the Opening event is used by our ImagePDFContainer subclass, add an event definition with the same name so that instances created from it can also add their own Opening event handler and include any additional code to execute as desired.</p>



<p>Then, add an additional event definition (FileDropped) that will be the one sent by the ImagePDFContainer subclass to the instances created from it, and that implement it, to pass them as a parameter the FolderItem corresponding to the file opened / dragged and dropped / or , in the case of images, that have been pasted on the control.</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FileDropped</li>



<li><strong>Parameters:</strong> file As FolderItem</li>
</ul>



<p>Since we want to support pasting images onto the control, we also need to add a MenuHandler to the ImagePDFContainer subclass. To do this, with ImagePDFContainer still selected in the Navigator, select the option Add to &#8220;ImagePDFContainer&#8221; &gt; Menu Handler&#8230;</p>



<p>Use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>MenuItem Name:</strong> EditPaste</li>
</ul>



<p>And add the following code in the Code Editor associated with the Menu Handler:</p>



<pre id="Xojo" class="wp-block-code"><code>Var pb As New Clipboard
If pb.PictureAvailable Then
  Var f As FolderItem = SpecialFolder.Temporary.Child("temp-pict.png")
  If f.Exists Then f.Remove
  If f &lt;&gt; Nil Then
    pb.Picture.Save(f, Picture.Formats.PNG)
    FileDropped = f
    PreviewFile(FileDropped)
  End If
  Return True
End If

Return False</code></pre>



<p>To complete this section, add a new method to ImagePDFContainer and use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Method Name:</strong> PreviewFile</li>



<li><strong>Parameters:</strong> f As FolderItem</li>
</ul>



<p>Add the following code in the associated Code Editor:</p>



<pre id="Xojo" class="wp-block-code"><code>FileDropped = f

If f &lt;> Nil Then
  
  If FileDropped.Name.EndsWith(".pdf") Then
    ImagePreviewer.Visible = False
    HTMLPDF.Visible = True
    
    HTMLPDF.Top = BackgroundRect.Top + 1
    HTMLPDF.Left = BackgroundRect.Left + 1
    
    #If TargetWindows Then
      HTMLPDF.Height = BackgroundRect.Height - OpenFileButton.Height
    #Else
      HTMLPDF.Height = Self.Height - OpenFileButton.Height
    #EndIf
    
    HTMLPDF.LoadPage(FileDropped)
    
  Else
    
    Var p As Picture = Picture.Open(FileDropped)
    
    If p &lt;> Nil Then
      ImagePreviewer.Top = BackgroundRect.Top + 1
      ImagePreviewer.Left = BackgroundRect.Left + 1
      
      #If TargetWindows Then
        ImagePreviewer.Height = BackgroundRect.Height - OpenFileButton.Height
      #Else
        ImagePreviewer.Height = Self.Height - OpenFileButton.Height
      #EndIf
      
      ImagePreviewer.Image = p
      HTMLPDF.Visible = False
      ImagePreviewer.Visible = True
      
    End If
    
  End If
  
  RaiseEvent FileDropped(FileDropped)
  
Else
  HTMLPDF.Visible = False
  ImagePreviewer.Visible = False
End If</code></pre>



<h2 class="wp-block-heading">Add Functionality to Controls</h2>



<p>Now it&#8217;s time to add functionality to the controls. Select the CanvasOverlay item in the Navigator and add the following Event Handlers along with the code given below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.AcceptFileDrop("application/pdf")
Me.AcceptFileDrop("image/png")
Me.AcceptFileDrop("image/jpg")

#If TargetWindows Then
  Me.Visible = False
#EndIf</code></pre>



<h4 class="wp-block-heading">DropObject:</h4>



<pre class="wp-block-code"><code>#Pragma Unused action

If obj.FolderItemAvailable Then
  PreviewFile(obj.FolderItem)
End If</code></pre>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Now select the DropArea item in the Navigator and add the following Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.AcceptFileDrop("application/pdf")
Me.AcceptFileDrop("image/png")
Me.AcceptFileDrop("image/jpg")

#If TargetMacOS Then
  Me.Visible = False
#EndIf</code></pre>



<h4 class="wp-block-heading">DropObject:</h4>



<pre class="wp-block-code"><code>#Pragma Unused action

If obj.FolderItemAvailable Then
  PreviewFile(obj.FolderItem)
End If</code></pre>



<h4 class="wp-block-heading">Paint:</h4>



<pre class="wp-block-code"><code>#Pragma Unused areas

g.DrawingColor = FocusColor
g.PenSize = 2.0
g.DrawRectangle(0, 0, g.Width, g.Height)
g.PenSize = 1.0

If DropFileMessage &lt;> "" Then
  
  g.DrawingColor = Color.Black
  
  Var textLength As Double = g.TextWidth(DropFileMessage)
  Var x, y As Double
  
  x = Me.Width / 2 - textLength / 2
  y = Me.Height / 2 + g.TextHeight / 2
  
  g.DrawText(DropFileMessage, x, y)
  
End If</code></pre>



<p>Now select the HTMLPDF item in the Navigator and add the Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Next, select the ImagePreviewer item in the Navigator and add the following Event Handlers along with the code below:</p>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Finally, select the OpenFileButton item in the Navigator and add the following Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">Pressed:</h4>



<pre class="wp-block-code"><code>Var f As FolderItem = FolderItem.ShowOpenFileDialog("")

If f &lt;> Nil Then
  Self.PreviewFile(f)
End If</code></pre>



<h2 class="wp-block-heading">Testing the ImagePDFContainer Control</h2>



<p>We have completed the design and added the required functionality to our control, now it is time to add an instance to the project window so we can test its operation.</p>



<p>Select Window1 in the Navigator so that the associated Layout Editor is displayed. Next drag ImagePDFContainer from the Navigator and drop it onto the Layout Editor, using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Size &gt; Width: </strong>220</li>



<li><strong>Size &gt; Height:</strong> 200</li>



<li><strong>Locking:</strong> Lock all four padlocks</li>



<li><strong>Appearance &gt; Allow Focus Ring:</strong> Enabled </li>



<li><strong>Behavior &gt; Allow Focus: </strong>Enabled.</li>



<li><strong>Behavior &gt; Allow Tabs:</strong> Enabled.</li>
</ul>



<p>With ImagePDFContainer1 selected in the Navigator, add the following Event Handlers along with the code below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.DropFileMessage = "Drop Files Here"</code></pre>



<h4 class="wp-block-heading">FileDropped:</h4>



<pre class="wp-block-code"><code>LastFolderItemNameLabel.Text = file.NativePath</code></pre>



<p>As you can see, this is referring to the LastFolderItemNameLabel control that we have not yet added to the window layout yet; So, let&#8217;s do that.</p>



<p>Select Window1 in the Navigator to access the associated Layout Editor. Drag a Label control from the Library and drop it onto the bottom of the window in the Layout Editor, then use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> Label1</li>



<li><strong>Position &gt; Left:</strong> 28</li>



<li><strong>Position &gt; Top: </strong>360</li>



<li><strong>Position &gt; Width:</strong> 150</li>



<li><strong>Position &gt; Height:</strong> 20</li>



<li><strong>Locking:</strong> Lock the left and bottom padlock. Unlock the top and right locks.</li>



<li><strong>Text:</strong> Last FolderItem Path:</li>
</ul>



<p>Add a second Label from the Library to the right of the previous one, using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> LastFolderItemNameLabel</li>



<li><strong>Position &gt; Left: </strong>190</li>



<li><strong>Position &gt; Top:</strong> 360</li>



<li><strong>Position &gt; Width:</strong> 390</li>



<li><strong>Position &gt; Height:</strong> 20</li>



<li><strong>Locking: </strong>Locks the left, bottom and right padlocks. Unlock the top lock.</li>



<li><strong>Text:</strong> (empty)</li>
</ul>



<h2 class="wp-block-heading">Run the Application</h2>



<p>Ready! Run the application and try dragging and dropping image files (JPEG or PNG), as well as PDF files on the control. You should see the change on the fly, showing the most appropriate viewer for each type of file. It will also display the path of the file at the bottom of the window.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="886" src="https://blog.xojo.com/wp-content/uploads/2024/02/Final-1024x886.png" alt="" class="wp-image-12607" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Final-1024x886.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-300x260.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-768x665.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-1536x1329.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Final.png 1648w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>You can also click on the button to select the file to display or try copying images and pasting them directly on the control. If you do this, a temporary file will be created so that one of the initial requirements is satisfied: being able to continue working with the file corresponding to the image or PDF document.</p>



<p>As I mentioned at the beginning, this is just one of the possible implementations. I hope you have learned a few things along the way in, for example:</p>



<ul class="wp-block-list">
<li>Redefine Events consumed by a base class.</li>



<li>Create your own Class Events and how to launch them to &#8220;pass&#8221; information to the instances created from said class.</li>



<li>Capture and work with Menu Handlers.</li>



<li>Use of Conditional Compilation so that certain sections of code run only on one platform or another.</li>



<li>And, of course, how to make several UI controls cooperate and present themselves as a single control to the developer and end user who are going to use them.</li>
</ul>



<p>I hope you found it interesting. You are welcome to modify and expand the project to better suit your purposes!</p>



<p>Have fun and keep coding with Xojo!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ContainerControl: Composed User Interface Components</title>
		<link>https://blog.xojo.com/2021/05/20/containercontrol-composed-user-interface-components/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 20 May 2021 14:48:50 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[ContainerControl]]></category>
		<category><![CDATA[User Interface]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=8459</guid>

					<description><![CDATA[Through this tutorial we practiced  the basics of using ContainerControls in Desktop projects: adding them to the project, using them at design time, how to forward values from the container's controls to the window where these can be added, how to create a ContainerControl subclass that shares its method and events with any ContainerControl subclassed from it, how to add new ContainerControl instances to a window at runtime, and also how to delegate the execution of a event so it can be handled by a window method.]]></description>
										<content:encoded><![CDATA[<p>Xojo&#8217;s Library offers a good amount of UI controls ready to use: buttons, input text controls, lists, popup menus, progress bars, panels, labels, a control to play movies, etc. However, sometimes we need to display exactly the same combination of controls, using the same layout, in several windows of an app. What&#8217;s the best approach in these cases?<span id="more-8459"></span></p>
<p>Obviously, adding the same bunch of controls again and again on each window is not the best solution; even less so when we consider the need to add the exact same code in each of these controls.</p>
<p>The ContainerControl is your best bet to avoid these repetitive tasks. The ContainerControl is a component half way between the available controls in the Library (inherited from the Control class) and a Window. If you look at the properties, methods and events offered by the <a href="http://documentation.xojo.com/api/deprecated/containercontrol.html"><strong>ContainerControl</strong></a> you&#8217;ll find many of these are the same ones available in the Window class.</p>
<blockquote><p><a href="https://bit.ly/3huMxzs">Download the Example Project for this tutorial</a></p></blockquote>
<h2>ContainerControl Layout</h2>
<p>Adding other controls to a ContainerControl couldn&#8217;t be simpler. Start by adding a new ContainerControl from the Library to the Navigator (by default, it will be named <code>ContainerControl1</code>), select it in the Navigator to access the Layout Editor. You can use the Inspector Panel to setup the properties. Please note, control&#8217;s locks will act on the top, left, right and bottom sides of <em>the ContainerControl</em> they are embedded on; as opposed to using the locks on the ContainerControl itself which locks the position of the container over the top, left, right and bottom sides of <em>the Window</em> where the container is used.</p>
<p><figure id="attachment_8460" aria-describedby="caption-attachment-8460" style="width: 300px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-8460 size-medium" src="https://blog.xojo.com/wp-content/uploads/2021/05/ControlLock-300x201.jpg" alt="" width="300" height="201" srcset="https://blog.xojo.com/wp-content/uploads/2021/05/ControlLock-300x201.jpg 300w, https://blog.xojo.com/wp-content/uploads/2021/05/ControlLock-1024x685.jpg 1024w, https://blog.xojo.com/wp-content/uploads/2021/05/ControlLock-768x514.jpg 768w, https://blog.xojo.com/wp-content/uploads/2021/05/ControlLock.jpg 1154w" sizes="auto, (max-width: 300px) 100vw, 300px" /><figcaption id="caption-attachment-8460" class="wp-caption-text">Locked ContainerControl</figcaption></figure></p>
<p><figure id="attachment_8461" aria-describedby="caption-attachment-8461" style="width: 300px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-8461 size-medium" src="https://blog.xojo.com/wp-content/uploads/2021/05/ContainerLock-300x227.jpg" alt="" width="300" height="227" srcset="https://blog.xojo.com/wp-content/uploads/2021/05/ContainerLock-300x227.jpg 300w, https://blog.xojo.com/wp-content/uploads/2021/05/ContainerLock-1024x774.jpg 1024w, https://blog.xojo.com/wp-content/uploads/2021/05/ContainerLock-768x581.jpg 768w, https://blog.xojo.com/wp-content/uploads/2021/05/ContainerLock.jpg 1107w" sizes="auto, (max-width: 300px) 100vw, 300px" /><figcaption id="caption-attachment-8461" class="wp-caption-text">Locked Window</figcaption></figure></p>
<h2></h2>
<h2>Using ContainerControls in the Window Layout</h2>
<p>Now that the layout of the ContainerControl is done, it&#8217;s time to add it to the Windows or Panels. Select a Window to access the associated Layout Editor and then drag the ContainerControl from the Navigator to the desired position onto the window frame displayed on the Layout Editor. Once done, that instance will be added under the <code>Controls</code> section for the Window in the Navigator (by default it will be named <code>ContainerControl11</code> because is an instance from <code>ContainerControl1</code>).</p>
<p>Something interesting to observe is that once you add the container to the Window, you won&#8217;t be able to change the position or behavior of the embedded controls in the container from the Window Layout Editor. The controls embedded in the container are displayed as &#8220;disabled&#8221;.</p>
<p><img loading="lazy" decoding="async" class="size-large wp-image-8462 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2021/05/ContainerOnWindow-1024x565.png" alt="" width="1024" height="565" srcset="https://blog.xojo.com/wp-content/uploads/2021/05/ContainerOnWindow-1024x565.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/05/ContainerOnWindow-300x166.png 300w, https://blog.xojo.com/wp-content/uploads/2021/05/ContainerOnWindow-768x424.png 768w, https://blog.xojo.com/wp-content/uploads/2021/05/ContainerOnWindow-1536x848.png 1536w, https://blog.xojo.com/wp-content/uploads/2021/05/ContainerOnWindow-2048x1131.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p>Select the item <code>ContainerControl1</code> in the Navigator to change the layout, add new UI controls, and change the position, size or behavior.</p>
<p>Since we only can add Event Handlers to the controls added to <code>ContainerControl1</code>, but not when those containers are added to a window or panel, how do you &#8220;communicate&#8221; with the windows using these containers? There are several approaches to achieve this. In this example, set the Scope to Public so the Window can access the controls added to a ContainerControl.</p>
<p>If we had added a ListBox control (default name <code>ListBox1</code>) to our <code>ContainerControl1</code>, setting its <code>Scope</code> property as <code>Public</code> in the Inspector Panel, it can be accessed using the usual dot notation. For example, from the Open Event Handler added to the <code>Window1</code> item:</p>
<pre>Me.ContainerControl11.ListBox1.AddRow("New Item")</pre>
<p>This solves one of the communication problems; but, how can the controls embedded in a container &#8220;communicate&#8221; with the Window containing the container? That is, how do we send the value of the selected row in the <code>ListBox1</code> control to the Window?</p>
<p>Let&#8217;s think about that scenario for a moment: the Window <code>Window1</code> knows the name of the ContainerControl added to it (<code>ContainerControl11</code>), and also the names of the controls added to that container because their Scope has been set to Public. On the other hand, the controls know about the ContainerControl they are embedded in, but they don&#8217;t know in advance the name of the Window where such ContainerControls can be added as part of the layout. In addition, the ContainerControl knows the name of the controls added to it, but it doesn&#8217;t know in advance the name of the Window or Panels where the container can be displayed. Moreover, it is possible to add ContainerControls to a Window or Panel layout in Design Mode (in the IDE), as well as at runtime!</p>
<p>Considering all of this, the simple solution to communicate between the controls added to a ContainerControl and the Window or Windows that will be using that container is by adding new methods and new Event Definitions on that ContainerControl (in this example, the one named <code>ContainerControl1</code>). There are other techniques, but we are going to use this one in this tutorial.</p>
<p>Continuing with our example,  add a new method to <code>ContainerControl1</code> using the following method signature:</p>
<pre>RowSelected(value As String)</pre>
<p>Next, with <code>ContainerControl1</code> still selected in the Navigator, choose the Insert &gt; Event Definition option in order to create a Event using the following signature:</p>
<pre>RowSelected(value As String)</pre>
<p>Click on the method added previously to access the associated Code Editor and type the following line of code:</p>
<pre>RaiseEvent RowSelected(value)</pre>
<p>The method will simply raise the defined event passing along the received value as the argument.</p>
<p>Now, select the <code>ListBox1</code> item on the <code>ContainerControl1</code> item, and add the <code>Changed</code> Event Handler. This is the event raised every time the user changes the selected row in the ListBox. Type the following code in the associated Code Editor:</p>
<pre>If Me.SelectedRowIndex &lt;&gt; -1 Then
    Self.RowSelected(Me.SelectedRowValue)
End if</pre>
<p>Add the <code>Open</code> event to the <code>ListBox1</code> item, type the following code in the associated Code Editor:</p>
<pre>For n As Integer = 0 To 10
    Me.AddRow(n.ToString)
Next</pre>
<p>Now, add the defined event in <code>ContainerControl1</code> to the <code>ContainerControl11</code> instance added to the <code>Window1</code> layout. Select that item and choose the Add &gt; Event Handler option. Choose the <code>SelectedRow</code> event handler and confirm the selection clicking the &#8220;OK&#8221; button.</p>
<p>Type the following line of code in the associated Code Editor:</p>
<pre>MessageBox("Selected value: " + value)</pre>
<p>Of course, you can do something more useful with the received value; but this is useful enough to show how the values can be sent from the ListBox control to any window where the container can be used.</p>
<h2>Subclassing ContainerControl</h2>
<p>Some projects may require using several ContainerControls, and many of them may be using a ListBox. As it is when using any other class, it would be great to have both the <code>SelectedRow</code> method and the <code>SelectedRow</code> Event Definition in their own ContainerControl subclass, and they are available by default to any ContainerControl added to the project and embedding a ListBox. The good news is that it is also possible to create a subclass for a ContainerControl, as it is explained in the <a href="https://documentation.xojo.com/topics/user_interface/desktop/desktop_controls/container.html_Control">User Guide</a>.</p>
<p>Add a new Class to the project and use the Inspector Panel to change its name to <code>MyContainerClass</code> and the Super field to <code>ContainerControl</code>.</p>
<p>Next, select the <code>SelectedRow</code> method and the Event Definition with the same name in <code>ControlContainer1</code>, cut them (Edit &gt; Cut), select <code>MyContainerClass</code> and paste them (Edit &gt; Paste). Both the method and the event definition are now available under <code>MyContainerClass</code>.</p>
<p>Select <code>ContainerControl1</code> in the Navigator and use the Inspector Panel to change its <code>Super</code> field to <code>MyContainerClass</code>. Add a second ContainerControl from the Library to the Navigator (by default it will be named <code>ContainerControl2</code>). With the new item selected in the Navigator, use the Inspector Panel to change its <code>Super</code> field to <code>MyContainerClass</code>. Add the ListBox control from the Library to the layout of the new container and type the following code in the <code>Open</code> event for the <code>ListBox1</code> item:</p>
<pre>For n As Integer = 0 To 10
    me.AddRow(n.ToString)
Next</pre>
<p>Add the <code>Changed</code> event to <code>ListBox1</code> and type the following code:</p>
<pre>If Me.SelectedRowIndex &lt;&gt; -1 Then
    Self.SelectedRow(Me.SelectedRowValue)
End If</pre>
<p>Next, add the second container <code>ContainerControl2</code> to the project window <code>Window1</code>. The layout could be similar to that of this screenshot:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-8463 size-medium" src="https://blog.xojo.com/wp-content/uploads/2021/05/TwoContainersLayout-300x223.png" alt="" width="300" height="223" srcset="https://blog.xojo.com/wp-content/uploads/2021/05/TwoContainersLayout-300x223.png 300w, https://blog.xojo.com/wp-content/uploads/2021/05/TwoContainersLayout-1024x762.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/05/TwoContainersLayout-768x572.png 768w, https://blog.xojo.com/wp-content/uploads/2021/05/TwoContainersLayout.png 1494w" sizes="auto, (max-width: 300px) 100vw, 300px" /></p>
<p>Select the <code>ContainerControl21</code> item under Window1 &gt; Controls and add the <code>SelectedRow</code> event handler. Add this line of code to display the received value in a message box:</p>
<pre>MessageBox("Selected value: " + value)</pre>
<p>As you can see, both <code>ContainerControl1</code> and <code>ContainerControl21</code> do not include the <code>SelectedRow</code> method. These are inherited from their super class: <code>MyContainerClass</code>.</p>
<h2>Adding ContainerControls at Runtime</h2>
<p>Xojo also lets you add ContainerControls at runtime, something that is really interesting and makes Xojo apps flexible and powerful. Let&#8217;s do that in a simple example:</p>
<p>Select the <code>Window1</code> item in the Navigator and delete the <code>ContainerControl11</code> and <code>ContainerControl21</code> items. With <code>Window1</code> still selected, add a new property using the following values in the Inspector Panel:</p>
<ul>
<li><strong>Name:</strong> Containers()</li>
<li><strong>Type:</strong> MyContainerClass</li>
</ul>
<p>Add the <code>Open</code> event to <code>Window1</code>, type the following code in the associated Code Editor:</p>
<pre>Var leftContainer As New ContainerControl1

leftContainer.Width = 200
leftContainer.LockTop = True
leftContainer.LockRight = False
leftContainer.LockBottom = False
leftContainer.LockLeft = True

leftContainer.EmbedWithin(Me, 20, 20)

Containers.Add(leftContainer)

Var rightContainer As New ContainerControl2

rightContainer.Width = 200
rightContainer.LockLeft = True
rightContainer.LockTop = True
rightContainer.LockBottom = True
rightContainer.LockRight = True
rightContainer.EmbedWithin(Me, Me.Width - 20 - rightContainer.Width, 20)

Containers.Add(rightContainer)</pre>
<p>Run the app, change the window size and you&#8217;ll notice how the container at the right side adjusts its height and width to match the changes made in the window while the container at the left side keeps its original position.</p>
<p>Try to change the selected row in any of the ListBoxes. Nothing happens! As you may remember, in order to &#8220;forward&#8221; the selected row value from the ListBox to the window we needed to add the <code>SelectedRow</code> event handler. This is something we can&#8217;t do when adding new container instances at runtime. In order to do that we need to use the <a href="http://documentation.xojo.com/api/code_execution/addhandler.html"><code>AddHandler</code></a> keyword. This lets us redirect an event handler to a delegated method. Quit the app to return to the IDE and, with <code>Window1</code> still selected in the Navigator, add a new method using the following signature:</p>
<pre>ListBoxSelectedRow(item As MyContainerClass, value As String)</pre>
<p>Notice that the first parameter will contain a reference to the instance of the <code>MyContainerClass</code> raising the event, while the second parameter will contain the value itself.</p>
<p>The only thing left is to associate the event name with the memory address of the method that will handle it for each of the Container instances added at runtime. Again, select the <code>Open</code> event tied to the <code>Window1</code> item and change its code like so:</p>
<pre>Var leftContainer As New ContainerControl1

leftContainer.Width = 200
leftContainer.LockTop = True
leftContainer.LockRight = False
leftContainer.LockBottom = False
leftContainer.LockLeft = true

AddHandler leftContainer.SelectedRow, WeakAddressOf ListBoxSelectedRow

leftContainer.EmbedWithin(Me, 20, 20)

Containers.Add(leftContainer)

Var rightContainer As New ContainerControl2

AddHandler rightContainer.SelectedRow, WeakAddressOf ListBoxSelectedRow

rightContainer.Width = 200
rightContainer.LockLeft = True
rightContainer.LockTop = True
rightContainer.LockBottom = True
rightContainer.LockRight = True
rightContainer.EmbedWithin(Me, Me.Width - 20 - rightContainer.Width, 20)

Containers.Add(rightContainer)</pre>
<p>The lines of code really are interesting:</p>
<pre>AddHandler leftContainer.SelectedRow, WeakAddressOf ListBoxSelectedRow
AddHandler rightContainer.SelectedRow, WeakAddressOf ListBoxSelectedRow</pre>
<p>As you can see, through <code>AddHandler</code> we are instructing the <code>SelectedRow</code> event from every container instance to be handled by the <code>ListBoxSelectedRow</code> method added to <code>Window1</code>.</p>
<p>On the other hand, <code>WeakAddressOf</code> is a Xojo programming language operator allowing us to get a &#8220;weak&#8221; reference to the memory address where the <code>ListboxSelectedRow</code> is found so it can be invoked.</p>
<h2>Summary</h2>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-8464 size-medium" src="https://blog.xojo.com/wp-content/uploads/2021/05/RunningApp-300x212.jpg" alt="" width="300" height="212" srcset="https://blog.xojo.com/wp-content/uploads/2021/05/RunningApp-300x212.jpg 300w, https://blog.xojo.com/wp-content/uploads/2021/05/RunningApp-1024x724.jpg 1024w, https://blog.xojo.com/wp-content/uploads/2021/05/RunningApp-768x543.jpg 768w, https://blog.xojo.com/wp-content/uploads/2021/05/RunningApp.jpg 1248w" sizes="auto, (max-width: 300px) 100vw, 300px" /></p>
<p>Through this tutorial we practiced some of the basics of using ContainerControls in Desktop projects: adding them to the project, using them at design time, how to forward values from the container&#8217;s controls to the window where these can be added, how to create a ContainerControl subclass that shares its method and events with any ContainerControl subclassed from it, how to add new ContainerControl instances to a window at runtime, and also how to delegate the execution of a event so it can be handled by a window method.</p>
<p>Questions? Ask me on Twitter <a href="https://twitter.com/xojoes">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary">Xojo Forum</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Control Sets and ContainerControl: A New Approach</title>
		<link>https://blog.xojo.com/2019/03/08/control-sets-and-containercontrol-a-new-approach/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Fri, 08 Mar 2019 10:00:32 +0000</pubDate>
				<category><![CDATA[Learning]]></category>
		<category><![CDATA[ContainerControl]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=5456</guid>

					<description><![CDATA[The Array control is the feature to use when there are several instances in a Window's layout and you need to command (or access them) from code, both for those available by default in the Framework and the ones based on your own graphic classes. The main inconvenience of this feature is that you can't use it when the graphic controls are placed on a ContainerControl, due to the way ContainerControls are considered. The good news is that this problem has an easy solution!]]></description>
										<content:encoded><![CDATA[<p>A <a href="https://documentation.xojo.com/topics/user_interface/desktop/desktop_controls/control_sets.html">Control Set</a> is <em>the</em> feature to use when there are several instances in a Window&#8217;s layout and you need to command (or access them) from code, both for those available by default in the Framework and ones based on your own graphic classes. For example, this allows us to invoke a method in a concrete instance, based on its control index, or invoke the same method to all of them (iteration). All of this without knowing in advance, at runtime, how many of such instances are placed in the layout.</p>
<p>An inconvenience of this feature is that you can&#8217;t use it when the graphic controls are placed on a <b>ContainerControl</b> due to the way ContainerControls are implemented. The good news is that this problem has an easy solution! Read on to learn about it:</p>
<p><span id="more-5456"></span></p>
<h2>Creating Subclasses</h2>
<p>First, create subclasses from those Framework controls you want to use as a Control <em>Set;</em> this also applies when creating your own graphic controls from scratch.</p>
<p>For that, add a new <b>Class</b> to a Xojo project from the <b>Insert</b> menu and use the Inspector to set the class name and the Parent class it is derived from. For this example, use the following values:</p>
<ul>
<li><b>Name</b>: MMButton</li>
<li><b>Super</b>: PushButton</li>
</ul>
<p>(Obviously, you can change these for any others you need.)</p>
<h2>Creating an array to keep references to the instances</h2>
<p>Next, we will need a data type acting as a storage reference for every instance (in our example, buttons) we want to add to our UI layout. For this, nothing is better than adding a <b>Property</b> to our class whose data type is an array storing objects from our class. With the created class still selected, add a new <b>Shared Property</b> from the <b>Insert</b> menu and use the Inspector with the following values:</p>
<ul>
<li><b>Name</b>: ClassButtons()</li>
<li><b>Type</b>: MMButton</li>
<li><b>Scope</b>: Private</li>
</ul>
<p>The fact that this is a Shared Property means that it (and its stored values) will be available for all the class instances (objects) created from the class; while the regular properties allows us to store distinct values for each class instance.</p>
<p>Another detail is that, in this case, we have limited the Scope for the Shared Property to <b>Private</b>. That means that this will be visible only from the code executed inside the class.</p>
<h2>Setting an index for every object</h2>
<p>Of course, we need a way to reference every instance created from the class; for example, when we need to send a message to only one of them and not to all the available instances. For this, nothing works better than setting a new Property (this time, a regular or instance Property) and assigning its data type as Integer:</p>
<ul>
<li><b>Name</b>: ButtonIndex</li>
<li><b>Type</b>: Integer</li>
<li><b>Scope</b>: Private</li>
</ul>
<h2>Knowing how many objects are in use</h2>
<p>We also need to know in runtime how many instances we are using. A good way to learn this is using the <b>Open Event</b>, so during the instance initialization it has the opportunity to add itself to the shared array and also to set its own index value.</p>
<p>To do that, add the <b>Open Event Handler</b> to the class and write the following snippet of code in the associated Code Editor:</p>
<pre>Sub Open() Handles Open
  ClassButtons.Append Me
  Me.ButonIndex = ClassButtons.Ubound
  RaiseEvent Open
End Sub</pre>
<p>What does <b>RaiseEvent Open</b> mean? Notice that we are setting our class behavior so if we are using the Open Event on it, this Event will not be available for implementation for any of the instances created from the class.</p>
<p>Fixing this is really simple: add a new <b>Event Definition</b> to the class using the following values in the associated Inspector:</p>
<ul>
<li><b>Event Name</b>: Open</li>
</ul>
<p>This way, RaiseEvent Open will call the Open Event to the instance and will let our class user write and execute additional code during the control initialization.</p>
<h2>Setting the Behavior</h2>
<p>In order to see our example in action, we need to create a method letting us direct the available instances to do something. For this example, we are going to display a simple message whose content is the Caption set to the button index passed as parameter and that has been created from our class.</p>
<p>As is the case with the <b>Shared Properties</b>, the <b>Shared Method</b> is the resource provided by the Xojo language that lets us set a behavior for the Class itself, instead of being called from a concrete class instance. So, add a new Shared Method to the class using the following values in the associated Inspector:</p>
<ul>
<li><b>Method Name</b>: SayHello</li>
<li><b>Parameter</b>: Index as Integer</li>
</ul>
<p>Next, write the following line of code in the Code Editor for the Shared Method:</p>
<pre>if ClassButtons.ubound &lt;&gt; -1 and index &gt;= 0 and index &lt;= ClassButtons.Ubound then MsgBox ClassButtons(index).Caption</pre>
<h2>Testing the Class</h2>
<p>We are set to test the class. For this, drag and drop as many instances of the class as you want from the Navigator to the Window Layout Editor (select previously a Window!). For our testing app, we also need an additional PushButton (it can be one from the standard Library) and a TextField.</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5459 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2019/02/Layout.jpg" alt="" width="800" height="570" /></p>
<p>The TextField will let us to write the <b>index</b> number whose instance we want to send the message to, while the additional button will be in charge of calling the shared method from the class, passing the index value as parameter. Add the <b>Action Event Handler</b> to the regular PushButton placed in the Window1 Layout, and write the following line of code:</p>
<pre>MMButton.SayHello( TextField1.Text.val - 1)</pre>
<p>As you can see, when we call the method we are using the name of the class and not the name from the instances.</p>
<p>Of course, this technique not only works when you add the UI controls to a Windows, it also works when they are placed on a ContainerControl that you want to use in your Windows layouts.</p>
<p><em>Javier Rodri­guez has been the Xojo Spanish Evangelist since 2008, he’s also a Developer, Consultant and Trainer who has be using Xojo since 1998. He manages <a href="http://www.aprendexojo.com">AprendeXojo.com</a> and is the developer behind the GuancheMOS plug-in for Xojo Developers, Markdown Parser for Xojo, HTMLColorizer for Xojo and the Snippery app, among others.</em></p>
<p>*<a href="https://www.aprendexojo.com/2019/02/arrays-de-controles-y-containercontrol/?fbclid=IwAR2HUZ7wWS-hV10Tv0QiTezQINGLgfdP3F7TSh_gysClVPyyugNwaZo5BgI">Read this post in Spanish</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>#JustCode Challenge Week 8 &#8211; JumpStart App Launcher</title>
		<link>https://blog.xojo.com/2018/08/10/justcode-challenge-week-8-jumpstart-app-launcher/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Fri, 10 Aug 2018 10:10:46 +0000</pubDate>
				<category><![CDATA[Fun]]></category>
		<category><![CDATA[#JustCode]]></category>
		<category><![CDATA[Atari]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[ContainerControl]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=4815</guid>

					<description><![CDATA[Replicating an app launcher he originally made for the Atari, Paul's JumpStart app for week 8 of #JustCode demonstrates save/load JSON, ContainerControl and Canvas-based Buttons in Xojo.]]></description>
										<content:encoded><![CDATA[<p>A long, long time ago (1989) one of the first apps I ever made was an app launcher for the Atari ST. I called it JumpSTART. I originally wrote it in <a href="https://en.wikipedia.org/wiki/GFA_BASIC">GFA BASIC</a> and then later re-implemented it in <a href="https://en.wikipedia.org/wiki/Pascal_(programming_language)">Pascal</a> (<a href="https://archive.org/details/OSSPersonalPascal">OSS Personal Pascal</a>, technically).</p>
<p>When I got my first modem I went online with <a href="https://en.wikipedia.org/wiki/GEnie">Genie</a> and <a href="https://en.wikipedia.org/wiki/Delphi_(online_service)">Delphi</a> and uploaded JumpSTART as freeware. Even though it was freeware, I got a few checks in the mail from people that liked it.</p>
<p>I was reminded of JumpSTART when I saw my dock getting crowed. I thought replicating JumpSTART in Xojo would be a good project for week 8 of #JustCode. Though let&#8217;s just call it JumpStart this time around.</p>
<p><span id="more-4815"></span></p>
<p>This is what JumpSTART looked like on monochrome 640&#215;480 screen:</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-4816 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2018/08/2018-08-09_14-06-09.png" alt="" width="640" height="434" /></p>
<p>JumpStart in Xojo is greatly simplified and looks like this:</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-4817 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2018/08/2018-08-09_14-10-06.png" alt="" width="680" height="392" /></p>
<p>The Xojo version automatically saves and loads the apps you&#8217;ve added so there was no need for separate Load/Save, Re-Read buttons. Technically they don&#8217;t have to be apps as even a document file can be launched as well.</p>
<p>You can right-click on an app button after you&#8217;ve added it to Rename, Change or Clear it so that also removed the need for some UI controls. And you just click on an empty button to add an app to it. When you click on a button with an app assigned, the app is launched and JumpStart hides itself.</p>
<p>This Xojo app demonstrates the use of a Canvas-based button, ContainerControls added dynamically to a window, and saving/loading JSON. The Canvas-based button will let me tweak the display, colors and maybe display an icon there.</p>
<p>You can <a href="http://files.xojo.com/JustCode/JumpStart.xojo_binary_project.zip">download the project</a> or <a href="https://gitlab.com/xojo/JumpStart">check it out on GitLab</a>.</p>
<p>As an added code treat, I&#8217;ve posted the <a href="https://github.com/paullefebvre/JumpSTART-AtariST">original JumpSTart Pascal code to GitHub</a>. FWIW, the original Pascal source is just over 1300 lines of code. The Xojo version is about 180.</p>
<p>Add your #JustCode project to the <a href="https://forum.xojo.com/49298-just-code-challenge-week-8-projects">week 8 forum conversation</a>.</p>
<p>Download and check out earlier projects:</p>
<ul>
<li>Week 7: <a href="https://blog.xojo.com/2018/08/03/justcode-challenge-week-7-pitch-tracker/">Pitch Tracker</a></li>
<li>Week 6: <a href="https://blog.xojo.com/2018/07/27/justcode-challenge-week-6-bubble-popper/">Bubble Popper</a></li>
<li>Week 5: <a href="https://blog.xojo.com/2018/07/20/justcode-challenge-week-5-math-quiz/">Math Quiz</a></li>
<li>Week 4: <a href="https://blog.xojo.com/2018/07/13/justcode-challenge-week-4-mini-golf-scorekeeper/">Mini-Golf ScoreKeeper</a></li>
<li>Week 3: <a href="https://blog.xojo.com/2018/07/06/just-code-challenge-week3/">Dogs Up!</a></li>
<li>Week 2: <a href="https://blog.xojo.com/2018/06/29/just-code-challenge-week2/">Password Generator</a></li>
<li>Week 1: <a href="https://blog.xojo.com/2018/06/22/just-code-challenge-week1/">Color Picker</a></li>
</ul>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
