<?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>Custom Classes &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/custom-classes/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Wed, 08 Oct 2025 15:54:32 +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>How To Create a Custom Button Control in Xojo – Part 5: Adding Text Alignment</title>
		<link>https://blog.xojo.com/2025/10/08/how-to-create-a-custom-button-control-in-xojo-part-5-adding-text-alignment/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Wed, 08 Oct 2025 15:54:00 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Custom Button Design]]></category>
		<category><![CDATA[Custom Classes]]></category>
		<category><![CDATA[Custom Control Design]]></category>
		<category><![CDATA[DesktopCanvas]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15436</guid>

					<description><![CDATA[In our previous installment, we successfully wired up keyboard focus to our custom&#160;DesktopCanvas subclass, making it fully accessible and user-friendly. Now, we’re going to tackle&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In our previous installment, we successfully wired up keyboard focus to our custom&nbsp;<code>DesktopCanvas</code> subclass, making it fully accessible and user-friendly.</p>



<p>Now, we’re going to tackle another key feature: customizable text alignment. By the end of this tutorial, you’ll be able to set the button’s text to align left, center, or right, and we’ll introduce a small amount of padding to keep the text from touching the edges when it’s not centered. This approach uses a strongly typed&nbsp;<code>Enumeration</code>&nbsp;to ensure we only accept valid alignment values, maintaining the high quality of our custom control.</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="314" height="182" src="https://blog.xojo.com/wp-content/uploads/2025/09/Screenshot-2025-09-30-150534.png" alt="" class="wp-image-15440" srcset="https://blog.xojo.com/wp-content/uploads/2025/09/Screenshot-2025-09-30-150534.png 314w, https://blog.xojo.com/wp-content/uploads/2025/09/Screenshot-2025-09-30-150534-300x174.png 300w" sizes="(max-width: 314px) 100vw, 314px" /></figure>



<h3 class="wp-block-heading" id="define-the-text-alignment-options">1. Define the Text Alignment Options</h3>



<p>To make our alignment property easy to use and type-safe, we will define a new enumeration inside the&nbsp;<code>CanvasButton</code>&nbsp;class.</p>



<p>Inside your&nbsp;<code>CanvasButton</code>&nbsp;class, go to&nbsp;<strong>Insert &gt; Enumeration</strong>&nbsp;and add the following:</p>



<pre class="wp-block-code"><code>  Left = 0
  Center = 1
  Right = 2</code></pre>



<h3 class="wp-block-heading" id="add-new-properties-for-alignment-and-padding">2. Add New Properties for Alignment and Padding</h3>



<p>Next, we need two new properties in the&nbsp;<code>CanvasButton</code>&nbsp;class to store the selected alignment and the padding value.</p>



<p>The&nbsp;<code>TextAlignment</code>&nbsp;property will use our new&nbsp;<code>TextAlign</code>&nbsp;enumeration, and, crucially, it defaults to&nbsp;<code>TextAlign.Center</code>.<br>The&nbsp;<code>TextPadding</code>&nbsp;property provides an adjustable inner margin, which is especially important for left and right alignment.</p>



<pre class="wp-block-code"><code>Public Property TextAlignment As TextAlign = TextAlign.Center
Public Property TextPadding As Integer = 8</code></pre>



<h3 class="wp-block-heading" id="update-the-paint-method">3. Update the Paint Method</h3>



<p>The core of this change happens in the&nbsp;<code>Paint</code>&nbsp;event handler. We need to modify the logic that calculates the horizontal position of the text (<code>tx</code>) to respect the value of our new&nbsp;<code>TextAlignment</code>&nbsp;property.</p>



<p>Locate the&nbsp;<code>Paint</code>&nbsp;event and replace the existing code with the following:</p>



<pre class="wp-block-code"><code>Sub Paint(g As Graphics, areas() As Rect) Handles Paint
  #Pragma unused areas
  
  // Use the custom CornerRadius property.
  Var currentCornerRadius As Integer = CornerRadius
  
  // Declare variables for the colors used in drawing.
  Var currentBgColor As Color
  Var currentBorderColor As Color
  Var currentTextColor As Color
  
  // Determine colors based on the button's current state (enabled, pressed, hovered).
  If Enabled Then
    If IsPressed Then
      // Use highlight color if pressed.
      currentBgColor = HighlightColor
      currentBorderColor = BorderColor
      currentTextColor = TextColor
    ElseIf IsHovered Then // Check for hover only if not pressed
      // Use hover color if hovered.
      currentBgColor = HoverColor
      currentBorderColor = BorderColor
      currentTextColor = TextColor
    Else
      // Use the custom background color for the default state.
      currentBgColor = BackgroundColor
      currentBorderColor = BorderColor
      currentTextColor = TextColor
    End If
  Else
    // Use appropriate system or standard gray colors for the disabled state.
    currentBgColor = Color.LightGray
    currentBorderColor = Color.Gray
    currentTextColor = Color.DisabledTextColor // Use system disabled text color
  End If
  
  // Set the drawing color and draw the background shape with rounded corners.
  g.DrawingColor = currentBgColor
  g.FillRoundRectangle(0, 0, g.Width, g.Height, currentCornerRadius, currentCornerRadius)
  
  // Set the drawing color and pen size for the border.
  g.DrawingColor = currentBorderColor
  g.PenSize = 2
  // Draw the border shape just inside the background rectangle.
  g.DrawRoundRectangle(0, 0, g.Width, g.Height, currentCornerRadius, currentCornerRadius)
  
  // Draw the focus ring
  If IsFocused And AllowFocusRing Then
    g.DrawingColor = Color.HighlightColor
    g.PenSize = 1
    g.DrawRoundRectangle(2, 2, g.Width-4, g.Height-4, CornerRadius-2, CornerRadius-2)
  End If
  
  // Enable anti-aliasing for smoother text rendering.
  g.AntiAliasMode = Graphics.AntiAliasModes.HighQuality
  g.AntiAliased = True
  // Calculate the width and height of the button text.
  Var tw As Double = g.TextWidth(ButtonText)
  Var th As Double = g.TextHeight
  // Calculate the X position to center the text horizontally.
  // Updated: compute X based on TextAlignment (Left, Center, Right) while preserving centered behavior as default.
  Var tx As Double
  Select Case TextAlignment
  Case TextAlign.Left
    tx = TextPadding
  Case TextAlign.Right
    tx = g.Width - tw - TextPadding
  Case TextAlign.Center
    tx = (g.Width - tw) / 2
  End Select
  // Calculate the Y position to center the text vertically, with a small adjustment.
  Var ty As Double = (g.Height + th) / 2 - 3
  // Set the drawing color for the text.
  g.DrawingColor = currentTextColor
  // Draw the button text at the calculated centered position.
  g.DrawText(ButtonText, tx, ty)
End Sub</code></pre>



<p>The magic happens at line 60 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h3 class="wp-block-heading" id="inspector-integration">4. Inspector Integration</h3>



<p>If you want the alignment to be easily adjustable in the Xojo Inspector, you should expose the&nbsp;<code>TextAlignment</code>&nbsp;and&nbsp;<code>TextPadding</code>&nbsp;properties. For&nbsp;<code>TextAlignment</code>, because it uses an&nbsp;<code>Enumeration</code>, Xojo will automatically display a helpful dropdown menu with Left, Center, and Right options once you expose it through the Inspector Behavior editor.</p>



<ul class="wp-block-list">
<li>Right-click the&nbsp;<code>CanvasButton</code>&nbsp;class in the Project Navigator.</li>



<li>Select ‘Inspector Behavior…’</li>



<li>Scroll through the property list and check the checkboxes for both&nbsp;<code>TextAlignment</code>&nbsp;and&nbsp;<code>TextPadding</code>.</li>
</ul>



<h3 class="wp-block-heading" id="try-it-out">Try It Out</h3>



<p>You can now set the text alignment directly in the code or via the Inspector.</p>



<p>For example, to set alignment in code:</p>



<pre class="wp-block-code"><code>// Set the button to right-aligned text
MyCanvasButton.TextAlignment = CanvasButton.TextAlign.Right</code></pre>



<p>Since the default value for&nbsp;<code>TextAlignment</code>&nbsp;is&nbsp;<code>Center</code>, no existing code needs to be modified, and all your current custom buttons will continue to render perfectly centered unless you explicitly change the alignment property.</p>



<p>Hope this update was useful.</p>



<p>You can grab the latest source on GitHub:&nbsp;<a href="https://github.com/xolabsro/CanvasButton">GitHub – CanvasButton</a></p>



<p>More in this series:</p>



<ul class="wp-block-list">
<li><a href="https://blog.xojo.com/2025/05/02/how-to-create-a-custom-button-control-in-xojo/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo</a></li>



<li><a href="https://blog.xojo.com/2025/05/14/how-to-create-a-custom-button-control-in-xojo-part-2/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 2</a></li>



<li><a href="https://blog.xojo.com/2025/05/28/how-to-create-a-custom-button-control-in-xojo-part-3-make-your-controls-inspector-friendly/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 3: Make Your Controls Inspector-Friendly</a></li>



<li><a href="https://blog.xojo.com/2025/06/23/how-to-create-a-custom-button-control-in-xojo-part-4-adding-focus/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 4: Adding Focus</a></li>



<li><a href="https://blog.xojo.com/2025/10/08/how-to-create-a-custom-button-control-in-xojo-part-5-adding-text-alignment/" target="_blank" rel="noreferrer noopener">How to Create a Custom Button Control in Xojo &#8211; Part 5: Adding Text Alignment</a></li>
</ul>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</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>How To Create a Custom Button Control in Xojo – Part 4: Adding Focus</title>
		<link>https://blog.xojo.com/2025/06/23/how-to-create-a-custom-button-control-in-xojo-part-4-adding-focus/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Mon, 23 Jun 2025 22:35:31 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Beginner Tips]]></category>
		<category><![CDATA[Custom Button Design]]></category>
		<category><![CDATA[Custom Classes]]></category>
		<category><![CDATA[Custom Control Design]]></category>
		<category><![CDATA[DesktopCanvas]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15007</guid>

					<description><![CDATA[In part 3 of this series&#160;we made our&#160;CanvasButton&#160;inspector-friendly by exposing all our colors, corner radius and other properties. Today we’re going to wire up real&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In <a href="https://blog.xojo.com/2025/05/28/how-to-create-a-custom-button-control-in-xojo-part-3-make-your-controls-inspector-friendly/" target="_blank" rel="noreferrer noopener">part 3 of this series</a>&nbsp;we made our&nbsp;<code>CanvasButton</code>&nbsp;inspector-friendly by exposing all our colors, corner radius and other properties. Today we’re going to wire up real keyboard focus so that you can:</p>



<ul class="wp-block-list">
<li>Tab to the button</li>



<li>See a neat focus ring when it has focus</li>



<li>Grab focus on click</li>
</ul>



<figure class="wp-block-video"><video height="254" style="aspect-ratio: 332 / 254;" width="332" autoplay loop muted preload="auto" src="https://blog.xojo.com/wp-content/uploads/2025/06/CanvasButton-Focus-Demo.mp4" playsinline></video></figure>



<h3 class="wp-block-heading" id="track-the-focus-state">1. Track the Focus State</h3>



<p>Add a private property to keep track of whether the button has focus:</p>



<pre class="wp-block-code"><code>  Private IsFocused As Boolean = False</code></pre>



<h3 class="wp-block-heading" id="respond-to-focus-events">2. Respond to Focus Events</h3>



<p>Implement&nbsp;<code>FocusReceived</code>&nbsp;and&nbsp;<code>FocusLost</code>&nbsp;so we can set/clear the flag and force a redraw:</p>



<pre class="wp-block-code"><code>  Sub FocusReceived()
    If Enabled And AllowFocusRing Then
      IsFocused = True
      Refresh(False)
    End If
  End Sub

  Sub FocusLost()
    If Enabled And AllowFocusRing Then
      IsFocused = False
      Refresh(False)
    End If
  End Sub</code></pre>



<h3 class="wp-block-heading" id="grab-focus-on-mouse-click">3. Grab Focus on Mouse Click</h3>



<p>Modify your&nbsp;<code>MouseDown</code>&nbsp;to call&nbsp;<code>SetFocus</code>. Now clicking the button also gives it focus immediately:</p>



<pre class="wp-block-code"><code>  Function MouseDown(x As Integer, y As Integer) As Boolean
    #Pragma unused x
    #Pragma unused y

    If Enabled Then
      IsPressed = True
      SetFocus       // ← new
      Refresh(False)
      Return True
    Else
      Return False
    End If
  End Function</code></pre>



<h3 class="wp-block-heading" id="draw-an-inset-focus-ring">4. Draw an Inset Focus Ring</h3>



<p>In the&nbsp;<code>Paint</code>&nbsp;event, after drawing the border, add:</p>



<pre class="wp-block-code"><code>// … after the border code …
If IsFocused And AllowFocusRing Then
  g.DrawingColor = Color.HighlightColor
  g.PenSize = 1
  // Inset by 2px so it sits inside the border
  g.DrawRoundRectangle(2, 2, g.Width-4, g.Height-4, CornerRadius-2, CornerRadius-2)
End If</code></pre>



<h3 class="wp-block-heading" id="enable-canvas-focus">5. Enable Canvas Focus</h3>



<p>By default,&nbsp;<code>DesktopCanvas</code>&nbsp;won’t accept focus, so make sure to check&nbsp;AllowFocusRing&nbsp;in the Inspector when you drop&nbsp;<code>CanvasButton</code>&nbsp;onto a window.</p>



<h2 class="wp-block-heading" id="try-it-out">Try It Out</h2>



<ol class="wp-block-list">
<li>Run the app:
<ul class="wp-block-list">
<li>Tab to the button → you’ll see the focus ring</li>
</ul>
</li>
</ol>



<h2 class="wp-block-heading" id="what’s-next">What’s Next?</h2>



<p>Stay tuned for more awesome updates!</p>



<p>You can grab the latest source on GitHub: <a href="https://github.com/xolabsro/CanvasButton" target="_blank" rel="noreferrer noopener">GitHub &#8211; CanvasButton</a></p>



<p>More in this series:</p>



<ul class="wp-block-list">
<li><a href="https://blog.xojo.com/2025/05/02/how-to-create-a-custom-button-control-in-xojo/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo</a></li>



<li><a href="https://blog.xojo.com/2025/05/14/how-to-create-a-custom-button-control-in-xojo-part-2/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 2</a></li>



<li><a href="https://blog.xojo.com/2025/05/28/how-to-create-a-custom-button-control-in-xojo-part-3-make-your-controls-inspector-friendly/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 3: Make Your Controls Inspector-Friendly</a></li>



<li><a href="https://blog.xojo.com/2025/06/23/how-to-create-a-custom-button-control-in-xojo-part-4-adding-focus/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 4: Adding Focus</a></li>



<li><a href="https://blog.xojo.com/2025/10/08/how-to-create-a-custom-button-control-in-xojo-part-5-adding-text-alignment/" target="_blank" rel="noreferrer noopener">How to Create a Custom Button Control in Xojo &#8211; Part 5: Adding Text Alignment</a></li>
</ul>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</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>
					
		
		<enclosure url="https://blog.xojo.com/wp-content/uploads/2025/06/CanvasButton-Focus-Demo.mp4" length="227730" type="video/mp4" />

			</item>
		<item>
		<title>How To Create a Custom Button Control in Xojo – Part 3: Make Your Controls Inspector-Friendly</title>
		<link>https://blog.xojo.com/2025/05/28/how-to-create-a-custom-button-control-in-xojo-part-3-make-your-controls-inspector-friendly/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Wed, 28 May 2025 17:54:20 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Beginner Tips]]></category>
		<category><![CDATA[Custom Button Design]]></category>
		<category><![CDATA[Custom Classes]]></category>
		<category><![CDATA[Custom Control Design]]></category>
		<category><![CDATA[DesktopCanvas]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=14925</guid>

					<description><![CDATA[In&#160;Part 1, we built a custom button control in Xojo by subclassing&#160;DesktopCanvas. In&#160;Part 2, we enhanced it with customizable colors, corner radius, and a disabled&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In&nbsp;<a href="https://blog.xojo.com/2025/05/02/how-to-create-a-custom-button-control-in-xojo/">Part 1</a>, we built a custom button control in Xojo by subclassing&nbsp;<code>DesktopCanvas</code>. In&nbsp;<a href="https://blog.xojo.com/2025/05/14/how-to-create-a-custom-button-control-in-xojo-part-2/">Part 2</a>, we enhanced it with customizable colors, corner radius, and a disabled state.</p>



<p>Now, let’s make the&nbsp;<code>CanvasButton</code>&nbsp;control even easier to use in the Xojo IDE by leveraging the&nbsp;<strong><a href="https://documentation.xojo.com/topics/custom_controls/changing_properties_with_the_inspector.html" target="_blank" rel="noreferrer noopener">Inspector Behavior</a></strong>&nbsp;feature. This allows you (and anyone using your control) to configure its appearance and behavior at design time, right in the Properties panel.</p>



<h2 class="wp-block-heading" id="why-inspector-behavior-matters">Why Inspector Behavior Matters</h2>



<p>When you create a custom control, its custom properties will not appear in the Inspector by default.&nbsp;<strong>Inspector Behavior</strong>&nbsp;lets you choose which properties are shown and how they’re grouped. This makes your control feel polished and professional, and saves users from digging into code to tweak settings.</p>



<h2 class="wp-block-heading" id="step-1-open-inspector-behavior">Step 1: Open Inspector Behavior</h2>



<p>To customize Inspector options for your&nbsp;<code>CanvasButton</code>:</p>



<ol class="wp-block-list">
<li>In the Xojo IDE, select the&nbsp;<code>CanvasButton</code>&nbsp;class in the Project Navigator.</li>



<li>Right-click it and choose&nbsp;<strong>Inspector Behavior…</strong></li>
</ol>



<figure class="wp-block-image size-full"><img decoding="async" width="342" height="512" src="https://blog.xojo.com/wp-content/uploads/2025/05/inspector_behavior_01.jpg" alt="Inspector Behavior menu" class="wp-image-14929" srcset="https://blog.xojo.com/wp-content/uploads/2025/05/inspector_behavior_01.jpg 342w, https://blog.xojo.com/wp-content/uploads/2025/05/inspector_behavior_01-200x300.jpg 200w" sizes="(max-width: 342px) 100vw, 342px" /></figure>



<h2 class="wp-block-heading" id="step-2-expose-and-organize-properties">Step 2: Expose and Organize Properties</h2>



<p>In the Inspector Behavior dialog, you’ll see a list of all public properties (inherited and custom).</p>



<ul class="wp-block-list">
<li><strong>Make the following properties visible:</strong>
<ul class="wp-block-list">
<li><code>ButtonText</code></li>



<li><code>CornerRadius</code></li>



<li><code>BackgroundColor</code>,&nbsp;<code>HoverColor</code>,&nbsp;<code>HighlightColor</code>,&nbsp;<code>BorderColor</code>,&nbsp;<code>TextColor</code>&nbsp;(all grouped under a custom “Button Colors” section)</li>
</ul>
</li>



<li><strong>Organize properties into logical groups</strong>&nbsp;for clarity.</li>
</ul>



<figure class="wp-block-image size-full"><img decoding="async" width="640" height="687" src="https://blog.xojo.com/wp-content/uploads/2025/05/inspector_behavior_02.jpg" alt="Inspector Behavior window" class="wp-image-14930" srcset="https://blog.xojo.com/wp-content/uploads/2025/05/inspector_behavior_02.jpg 640w, https://blog.xojo.com/wp-content/uploads/2025/05/inspector_behavior_02-279x300.jpg 279w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Tip:</strong>&nbsp;Defining default values for your properties in the class code means they will be automatically populated in Inspector Behavior. However, Xojo gives you even more flexibility. You can override these default values directly in the Inspector Behavior dialog, so you have full control over what new instances of your control will look like by default.</p>
</blockquote>



<h2 class="wp-block-heading" id="step-3-enjoy-design-time-customization">Step 3: Enjoy Design-Time Customization</h2>



<p>With Inspector Behavior set up, you (or other developers) can now:</p>



<ul class="wp-block-list">
<li><strong>Change the button text</strong>&nbsp;right in the Properties panel.</li>



<li><strong>Pick custom colors</strong>&nbsp;for normal, hover, pressed, border, and text states using the color picker.</li>



<li><strong>Adjust the corner radius</strong>&nbsp;visually.</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="297" height="466" src="https://blog.xojo.com/wp-content/uploads/2025/05/inspector_03.jpg" alt="Xojo Inspector showing custom CanvasButton properties" class="wp-image-14931" srcset="https://blog.xojo.com/wp-content/uploads/2025/05/inspector_03.jpg 297w, https://blog.xojo.com/wp-content/uploads/2025/05/inspector_03-191x300.jpg 191w" sizes="auto, (max-width: 297px) 100vw, 297px" /></figure>



<h2 class="wp-block-heading" id="step-4-best-practices-and-tips">Step 4: Best Practices and Tips</h2>



<ul class="wp-block-list">
<li><strong>Use clear group names</strong>&nbsp;(like “Button Colors”) to help users find related properties.</li>



<li><strong>Set sensible defaults</strong>&nbsp;for all properties in your code, but remember you can override them in Inspector Behavior.</li>
</ul>



<h2 class="wp-block-heading" id="conclusion">Conclusion</h2>



<p>With Inspector Behavior, your custom controls feel like first-class citizens in Xojo. You and others can now design beautiful, custom buttons by simply dragging, dropping, and tweaking settings in the Inspector. No code required!</p>



<p><strong>Stay tuned for future parts</strong>&nbsp;where we’ll explore even more advanced features.</p>



<p id="block-59a92dbb-c0d1-4b75-b250-f331b6ceb4c4">More in this series:</p>



<ul id="block-c7594468-ed0c-4be1-a999-04ef9789f34c" class="wp-block-list">
<li><a href="https://blog.xojo.com/2025/05/02/how-to-create-a-custom-button-control-in-xojo/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo</a></li>



<li><a href="https://blog.xojo.com/2025/05/14/how-to-create-a-custom-button-control-in-xojo-part-2/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 2</a></li>



<li><a href="https://blog.xojo.com/2025/05/28/how-to-create-a-custom-button-control-in-xojo-part-3-make-your-controls-inspector-friendly/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 3: Make Your Controls Inspector-Friendly</a></li>



<li><a href="https://blog.xojo.com/2025/06/23/how-to-create-a-custom-button-control-in-xojo-part-4-adding-focus/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 4: Adding Focus</a></li>



<li><a href="https://blog.xojo.com/2025/10/08/how-to-create-a-custom-button-control-in-xojo-part-5-adding-text-alignment/" target="_blank" rel="noreferrer noopener">How to Create a Custom Button Control in Xojo &#8211; Part 5: Adding Text Alignment</a></li>
</ul>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</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>How To Create a Custom Button Control in Xojo &#8211; Part 2</title>
		<link>https://blog.xojo.com/2025/05/14/how-to-create-a-custom-button-control-in-xojo-part-2/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Wed, 14 May 2025 15:00:00 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Beginner Tips]]></category>
		<category><![CDATA[Custom Button Design]]></category>
		<category><![CDATA[Custom Classes]]></category>
		<category><![CDATA[Custom Control Design]]></category>
		<category><![CDATA[DesktopCanvas]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=14898</guid>

					<description><![CDATA[In the first part of this tutorial, we built a basic custom button control using the&#160;DesktopCanvas&#160;class, giving it a custom appearance and handling the basic&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In the <a href="https://blog.xojo.com/2025/05/02/how-to-create-a-custom-button-control-in-xojo/" data-type="post" data-id="14858" target="_blank" rel="noreferrer noopener">first part of this tutorial</a>, we built a basic custom button control using the&nbsp;<code>DesktopCanvas</code>&nbsp;class, giving it a custom appearance and handling the basic mouse events to provide visual feedback and raise a&nbsp;<code>Pressed</code>&nbsp;event when clicked.</p>



<p>In this second part, we will enhance our&nbsp;<code>CanvasButton</code>&nbsp;by adding more customization with new properties to:</p>



<ul class="wp-block-list">
<li>set the button&#8217;s colors for different states (default, hovered, pressed)</li>



<li>adjust the corner radius of the button</li>



<li>implement a disabled state</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="278" height="146" src="https://blog.xojo.com/wp-content/uploads/2025/05/CanvasButton.gif" alt="" class="wp-image-14914"/></figure>



<p>Let&#8217;s get started!</p>



<h3 class="wp-block-heading" id="adding-new-properties-for-customization">Adding New Properties for Customization</h3>



<p>We need to add several properties to our&nbsp;<code>CanvasButton</code>&nbsp;class to store the custom colors for different states, the border color, the text color, the corner radius, and the enabled state.</p>



<ol class="wp-block-list">
<li>In the Project Navigator, select your&nbsp;<code>CanvasButton</code>&nbsp;class.</li>



<li>Go to&nbsp;<strong>Insert &gt; Property</strong>&nbsp;(or right-click the class and select Add to &#8220;CanvasButton&#8221; &gt; Property).</li>



<li>Add the following properties with the specified names, types, and default values:
<ul class="wp-block-list">
<li><strong>Name:</strong>&nbsp;<code>BackgroundColor</code>&nbsp;<strong>Type:</strong>&nbsp;<code>Color</code>&nbsp;<strong>Default Value:</strong>&nbsp;<code>&amp;c5e2d8b</code></li>



<li><strong>Name:</strong>&nbsp;<code>HoverColor</code>&nbsp;<strong>Type:</strong>&nbsp;<code>Color</code>&nbsp;<strong>Default Value:</strong>&nbsp;<code>&amp;c729fcf</code></li>



<li><strong>Name:</strong>&nbsp;<code>HighlightColor</code>&nbsp;<strong>Type:</strong>&nbsp;<code>Color</code>&nbsp;<strong>Default Value:</strong>&nbsp;<code>&amp;c628eff</code></li>



<li><strong>Name:</strong>&nbsp;<code>BorderColor</code>&nbsp;<strong>Type:</strong>&nbsp;<code>Color</code>&nbsp;<strong>Default Value:</strong>&nbsp;<code>&amp;c525252</code></li>



<li><strong>Name:</strong>&nbsp;<code>TextColor</code>&nbsp;<strong>Type:</strong>&nbsp;<code>Color</code>&nbsp;<strong>Default Value:</strong>&nbsp;<code>&amp;ceeeeee</code></li>



<li><strong>Name:</strong>&nbsp;<code>CornerRadius</code>&nbsp;<strong>Type:</strong>&nbsp;<code>Integer</code>&nbsp;<strong>Default Value:</strong>&nbsp;<code>4</code></li>
</ul>
</li>
</ol>



<p>These properties will hold the values that determine the button’s appearance and behavior.</p>



<h3 class="wp-block-heading" id="updating-event-handlers-for-the-enabled-state">Updating Event Handlers for the Enabled State</h3>



<p>We need to modify the existing mouse event handlers (<code>MouseDown</code>,&nbsp;<code>MouseEnter</code>,&nbsp;<code>MouseExit</code>,&nbsp;<code>MouseUp</code>) to check if the button is&nbsp;<code>Enabled</code>&nbsp;before processing any mouse actions.</p>



<p>Select each of the following event handlers in the&nbsp;<code>CanvasButton</code>&nbsp;class and update the code as shown:</p>



<p><strong><code>MouseDown(x As Integer, y As Integer) As Boolean</code></strong></p>



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

// Only process if the button is enabled.
If Enabled Then
  // Set internal state to indicate the button is being pressed.
  IsPressed = True
  // Refresh the control to show the pressed state visually.
  Refresh(False)
  // Return True to indicate that this event was handled.
  Return True
Else
  // If disabled, do not handle the event.
  Return False
End If</code></pre>



<p><strong><code>MouseEnter()</code></strong></p>



<pre class="wp-block-code"><code>// Only process if the button is enabled.
If Enabled Then
  // Set internal state to indicate the mouse is hovering over the button.
  IsHovered = True
  // Refresh the control to show the hover state visually.
  Refresh(False)
End If</code></pre>



<p><strong><code>MouseExit()</code></strong></p>



<pre class="wp-block-code"><code>// Only process if the button is enabled.
If Enabled Then
  // Set internal state to indicate the mouse is no longer hovering.
  IsHovered = False
  // Reset pressed state if mouse leaves while pressed (prevents accidental clicks).
  IsPressed = False
  // Refresh the control to revert from the hover state.
  Refresh(False)
End If</code></pre>



<p><strong><code>MouseUp(x As Integer, y As Integer) As Boolean</code></strong></p>



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

// Only process if the button is enabled.
If Enabled Then
  // Check if the button was pressed down AND the mouse is still hovering over it.
  If IsPressed And IsHovered Then
    // If true, the button was successfully clicked. Raise the custom Pressed event.
    RaiseEvent Pressed
  End If
  // Reset the pressed state regardless of whether the click was successful.
  IsPressed = False
  // Refresh the control to revert from the pressed state.
  Refresh(False)
End If</code></pre>



<p>In these updated event handlers, we added an&nbsp;<code>If Enabled Then</code>&nbsp;check at the beginning. If the button is not enabled, the code inside the&nbsp;<code>If</code>&nbsp;block is skipped, preventing the button from reacting to mouse interactions. We also added&nbsp;<code>#Pragma unused</code>&nbsp;to the parameters&nbsp;<code>x</code>&nbsp;and&nbsp;<code>y</code>&nbsp;in&nbsp;<code>MouseDown</code>&nbsp;and&nbsp;<code>MouseUp</code>&nbsp;as they are not used in the code, which helps avoid compiler warnings. In&nbsp;<code>MouseExit</code>, we added&nbsp;<code>IsPressed = False</code>&nbsp;to ensure the pressed state is reset if the mouse leaves the button while the mouse button is held down.</p>



<h3 class="wp-block-heading" id="updating-the-paint-event-for-enhanced-appearance">Updating the Paint Event for Enhanced Appearance</h3>



<p>The most significant changes will be in the&nbsp;<code>Paint</code>&nbsp;event where we will use the new properties to draw the button based on its current state (enabled/disabled, hovered, and pressed).</p>



<p>Select the&nbsp;<code>Paint(g As Graphics, areas() As Rect)</code>&nbsp;event handler and replace its content with the following code:</p>



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

// Use the custom CornerRadius property.
Var currentCornerRadius As Integer = CornerRadius

// Declare variables for the colors used in drawing.
Var currentBgColor As Color
Var currentBorderColor As Color
Var currentTextColor As Color

// Determine colors based on the button's current state (enabled, pressed, hovered).
If Enabled Then
  If IsPressed Then
    // Use highlight color if pressed.
    currentBgColor = HighlightColor
    currentBorderColor = BorderColor
    currentTextColor = TextColor
  ElseIf IsHovered Then // Check for hover only if not pressed
    // Use hover color if hovered.
    currentBgColor = HoverColor
    currentBorderColor = BorderColor
    currentTextColor = TextColor
  Else
    // Use the custom background color for the default state.
    currentBgColor = BackgroundColor
    currentBorderColor = BorderColor
    currentTextColor = TextColor
  End If
Else
  // Use appropriate system or standard gray colors for the disabled state.
  currentBgColor = Color.LightGray
  currentBorderColor = Color.Gray
  currentTextColor = Color.DisabledTextColor // Use system disabled text color
End If

// Set the drawing color and draw the background shape with rounded corners.
g.DrawingColor = currentBgColor
g.FillRoundRectangle(0, 0, g.Width, g.Height, currentCornerRadius, currentCornerRadius)

// Set the drawing color and pen size for the border.
g.DrawingColor = currentBorderColor
g.PenSize = 2
// Draw the border shape just inside the background rectangle.
g.DrawRoundRectangle(1, 1, g.Width-2, g.Height-2, currentCornerRadius, currentCornerRadius)

// Enable anti-aliasing for smoother text rendering.
g.AntiAliasMode = Graphics.AntiAliasModes.HighQuality
g.AntiAliased = True
// Calculate the width and height of the button text.
Var tw As Double = g.TextWidth(ButtonText)
Var th As Double = g.TextHeight
// Calculate the X position to center the text horizontally.
Var tx As Double = (g.Width - tw) / 2
// Calculate the Y position to center the text vertically, with a small adjustment.
Var ty As Double = (g.Height + th) / 2 - 3
// Set the drawing color for the text.
g.DrawingColor = currentTextColor
// Draw the button text at the calculated centered position.
g.DrawText(ButtonText, tx, ty)</code></pre>



<p>Let’s break down the changes in the&nbsp;<code>Paint</code>&nbsp;event:</p>



<ul class="wp-block-list">
<li>We now use the&nbsp;<code>CornerRadius</code>&nbsp;property instead of a static constant for drawing the rounded rectangles.</li>



<li>We introduced an&nbsp;<code>If Enabled Then ... Else</code>&nbsp;block.</li>



<li>Inside the&nbsp;<code>If Enabled Then</code>&nbsp;block, we have a nested&nbsp;<code>If IsPressed Then ... ElseIf IsHovered Then ... Else</code>&nbsp;structure. This determines the&nbsp;<code>currentBgColor</code>:
<ul class="wp-block-list">
<li>If&nbsp;<code>IsPressed</code>&nbsp;is True,&nbsp;<code>currentBgColor</code>&nbsp;is set to&nbsp;<code>HighlightColor</code>.</li>



<li>If&nbsp;<code>IsPressed</code>&nbsp;is False but&nbsp;<code>IsHovered</code>&nbsp;is True,&nbsp;<code>currentBgColor</code>&nbsp;is set to&nbsp;<code>HoverColor</code>.</li>



<li>If neither&nbsp;<code>IsPressed</code>&nbsp;nor&nbsp;<code>IsHovered</code>&nbsp;is True,&nbsp;<code>currentBgColor</code>&nbsp;is set to&nbsp;<code>BackgroundColor</code>.</li>



<li>The&nbsp;<code>currentBorderColor</code>&nbsp;and&nbsp;<code>currentTextColor</code>&nbsp;are set directly from the&nbsp;<code>BorderColor</code>&nbsp;and&nbsp;<code>TextColor</code>&nbsp;properties when the button is enabled.</li>
</ul>
</li>



<li>Inside the&nbsp;<code>Else</code>&nbsp;block (when&nbsp;<code>Enabled</code>&nbsp;is False), we set the colors to standard gray values (<code>Color.LightGray</code>&nbsp;for background,&nbsp;<code>Color.Gray</code>&nbsp;for border, and&nbsp;<code>Color.DisabledTextColor</code>&nbsp;for text) to give the button a disabled appearance.</li>



<li>Finally, the drawing commands use these&nbsp;<code>currentBgColor</code>,&nbsp;<code>currentBorderColor</code>,&nbsp;<code>currentTextColor</code>, and&nbsp;<code>currentCornerRadius</code>&nbsp;variables.</li>
</ul>



<h3 class="wp-block-heading" id="using-the-enhanced-custom-control">Using the Enhanced Custom Control</h3>



<p>Now that our&nbsp;<code>CanvasButton</code>&nbsp;has more customization options and supports a disabled state, let’s see how to use these features.</p>



<ol class="wp-block-list">
<li>If you don’t already have an instance, drag the&nbsp;<code>CanvasButton</code>&nbsp;class from the Project Navigator onto a window in the Layout Editor.</li>



<li>You can now access and set the new properties programmatically. For example, in a button’s&nbsp;<code>Opening</code>&nbsp;event, you could add code like this:</li>
</ol>



<pre class="wp-block-code"><code>// Customize colors
Me.BackgroundColor = Color.RGB(200, 50, 50) // A shade of red
Me.HoverColor = Color.RGB(255, 100, 100) // A lighter red for hover
Me.HighlightColor = Color.RGB(150, 0, 0) // A darker red for pressed
Me.BorderColor = Color.Black
Me.TextColor = Color.White

// Adjust corner radius
Me.CornerRadius = 10</code></pre>



<p>You can experiment with different values to see how they affect the button’s appearance. To test the disabled state, you can set the&nbsp;<code>Enabled</code>&nbsp;property to&nbsp;<code>False</code>.</p>



<h3 class="wp-block-heading" id="conclusion">Conclusion</h3>



<p>We&#8217;ve now taken our custom button to the next level by adding extensive color customization, adjustable corners, and a disabled state.</p>



<p>This project can be downloaded from GitHub at:&nbsp;<a href="https://github.com/xolabsro/CanvasButton" target="_blank" rel="noreferrer noopener">https://github.com/xolabsro/CanvasButton</a></p>



<p>Hope you enjoyed making the button your own! While it&#8217;s much more flexible now, there might be other features we could add down the road, so stay tuned!</p>



<p id="block-59a92dbb-c0d1-4b75-b250-f331b6ceb4c4">More in this series:</p>



<ul id="block-c7594468-ed0c-4be1-a999-04ef9789f34c" class="wp-block-list">
<li><a href="https://blog.xojo.com/2025/05/02/how-to-create-a-custom-button-control-in-xojo/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo</a></li>



<li><a href="https://blog.xojo.com/2025/05/14/how-to-create-a-custom-button-control-in-xojo-part-2/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 2</a></li>



<li><a href="https://blog.xojo.com/2025/05/28/how-to-create-a-custom-button-control-in-xojo-part-3-make-your-controls-inspector-friendly/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 3: Make Your Controls Inspector-Friendly</a></li>



<li><a href="https://blog.xojo.com/2025/06/23/how-to-create-a-custom-button-control-in-xojo-part-4-adding-focus/" target="_blank" rel="noreferrer noopener">How To Create a Custom Button Control in Xojo – Part 4: Adding Focus</a></li>



<li><a href="https://blog.xojo.com/2025/10/08/how-to-create-a-custom-button-control-in-xojo-part-5-adding-text-alignment/" target="_blank" rel="noreferrer noopener">How to Create a Custom Button Control in Xojo &#8211; Part 5: Adding Text Alignment</a></li>
</ul>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</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>How To Create a Custom Button Control in Xojo</title>
		<link>https://blog.xojo.com/2025/05/02/how-to-create-a-custom-button-control-in-xojo/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Fri, 02 May 2025 14:00:00 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Beginner Tips]]></category>
		<category><![CDATA[Custom Button Design]]></category>
		<category><![CDATA[Custom Classes]]></category>
		<category><![CDATA[Custom Control Design]]></category>
		<category><![CDATA[DesktopCanvas]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=14858</guid>

					<description><![CDATA[This tutorial demonstrates how to create a custom button control in Xojo using the&#160;DesktopCanvas&#160;class. It covers defining properties, handling mouse events for visual feedback, and&#8230;]]></description>
										<content:encoded><![CDATA[
<p>This tutorial demonstrates how to create a custom button control in Xojo using the&nbsp;<code>DesktopCanvas</code>&nbsp;class. It covers defining properties, handling mouse events for visual feedback, and drawing the control in the&nbsp;<code>Paint</code>&nbsp;event.</p>



<p>You can read more about <code>DesktopCanvas</code> <a href="https://documentation.xojo.com/api/user_interface/desktop/desktopcanvas.html" target="_blank" rel="noreferrer noopener">in the Xojo Docs.</a></p>



<p>Let&#8217;s begin!</p>



<h3 class="wp-block-heading" id="add-a-custom-class">Add a Custom Class:</h3>



<ul class="wp-block-list">
<li>In the Project Navigator, add a new&nbsp;<strong>Class</strong>.</li>



<li>Name it&nbsp;<code>CanvasButton</code>.</li>



<li>Set its&nbsp;<strong>Super</strong>&nbsp;class to&nbsp;<code>DesktopCanvas</code>.</li>
</ul>



<h4 class="wp-block-heading" id="add-properties">Add Properties:</h4>



<ul class="wp-block-list">
<li><code>ButtonText As String</code>&nbsp;(Set Scope to&nbsp;<code>Public</code>, Default Value to&nbsp;<code>"Click Me"</code>. To make this property visible in the Inspector, right-click the&nbsp;<code>CanvasButton</code>&nbsp;class in the Project Navigator, select ‘Inspector Behaviour…’, scroll through the property list to find the&nbsp;<code>ButtonText</code>&nbsp;variable, and make sure its checkbox is checked.)</li>



<li><code>IsHovered As Boolean</code>&nbsp;(Set Scope to&nbsp;<code>Private</code>, Default Value to&nbsp;<code>False</code>)</li>



<li><code>IsPressed As Boolean</code>&nbsp;(Set Scope to&nbsp;<code>Private</code>, Default Value to&nbsp;<code>False</code>)</li>
</ul>



<h4 class="wp-block-heading" id="define-pressed-custom-event">Define&nbsp;<code>Pressed</code>&nbsp;Custom Event:</h4>



<ul class="wp-block-list">
<li>Go to&nbsp;<strong>Insert &gt; Event Definition</strong>.</li>



<li>Name the event&nbsp;<code>Pressed</code>. This is the event that will be raised when the button is clicked.</li>
</ul>



<h4 class="wp-block-heading" id="add-event-handlers">Add Event Handlers:</h4>



<ul class="wp-block-list">
<li>Select the&nbsp;<code>CanvasButton</code>&nbsp;class in the Project Navigator.</li>



<li>Go to&nbsp;<strong>Insert &gt; Event Handler</strong>. Add the following event handlers and paste the corresponding code into each:</li>
</ul>



<p><strong><code>MouseDown(x As Integer, y As Integer)</code></strong></p>



<pre class="wp-block-code"><code>// Set internal state to indicate the button is being pressed.
IsPressed = True
// Refresh the control to show the pressed state visually.
Me.Refresh(False)
// Return True to indicate that this event was handled.
Return True</code></pre>



<p><strong><code>MouseEnter</code></strong></p>



<pre class="wp-block-code"><code>// Set internal state to indicate the mouse is hovering over the button.
IsHovered = True
// Refresh the control to show the hover state visually.
Me.Refresh(False)</code></pre>



<p><strong><code>MouseExit</code></strong></p>



<pre class="wp-block-code"><code>// Set internal state to indicate the mouse is no longer hovering.
IsHovered = False
// Refresh the control to revert from the hover state.
Me.Refresh(False)</code></pre>



<p><strong><code>MouseUp(x As Integer, y As Integer)</code></strong></p>



<pre class="wp-block-code"><code>// Check if the button was pressed down AND the mouse is still hovering over it.
If IsPressed And IsHovered Then
   // If true, the button was successfully clicked. Raise the custom Pressed event.
  RaiseEvent Pressed
End If
// Reset the pressed state regardless of whether the click was successful.
IsPressed = False
// Refresh the control to revert from the pressed state.
Me.Refresh(False)</code></pre>



<p><strong><code>Paint(g As Graphics, areas() As Rect)</code></strong></p>



<pre class="wp-block-code"><code>// Corner radius of the button shape.
Static CornerRadius As Integer = 4

 // Declare variables for the colors used in drawing.
Var bgColor As Color
Var borderColor As Color = Color.DarkBevelColor
Var TextColor As Color = Color.LightTingeColor

 // Determine the background color based on the button's current state (pressed or hovered).
If IsPressed Or IsHovered Then
  // Use a highlight color if pressed or hovered.
  bgColor = Color.HighlightColor
Else
  // Use the accent theme color for the default state.
  bgColor = Color.AccentThemeColor
End If

// Set the drawing color and draw the background shape with rounded corners.
g.DrawingColor = bgColor
g.FillRoundRectangle(0, 0, g.Width, g.Height, CornerRadius, CornerRadius)

// Set the drawing color and pen size for the border.
g.DrawingColor = borderColor
g.PenSize = 2
// Draw the border shape just inside the background rectangle.
g.DrawRoundRectangle(1, 1, g.Width-2, g.Height-2, CornerRadius, CornerRadius)

// Enable anti-aliasing for smoother text rendering.
g.AntiAliasMode = Graphics.AntiAliasModes.HighQuality
g.AntiAliased = True
// Calculate the width and height of the button text.
Var tw As Double = g.TextWidth(ButtonText)
Var th As Double = g.TextHeight
// Calculate the X position to center the text horizontally.
Var tx As Double = (g.Width - tw) / 2
 // Calculate the Y position to center the text vertically, with a small adjustment.
Var ty As Double = (g.Height + th) / 2 - 3
// Set the drawing color for the text.
g.DrawingColor = TextColor
// Draw the button text at the calculated centered position.
g.DrawText(ButtonText, tx, ty)</code></pre>



<p><strong>Use the Custom Control:</strong></p>



<ul class="wp-block-list">
<li>Open&nbsp;<code>Window1</code>.</li>



<li>Drag the&nbsp;<code>CanvasButton</code>&nbsp;class from the Project Navigator onto the window.</li>
</ul>



<p><strong>Handle the Click Event:</strong></p>



<ul class="wp-block-list">
<li>Double-click the&nbsp;<code>CanvasButton</code>&nbsp;instance on the window layout.</li>



<li>Add the custom&nbsp;<code>Pressed</code>&nbsp;event handler.</li>



<li>Add code inside this handler:&nbsp;<code>MessageBox("Custom Button Clicked!")</code>.</li>
</ul>



<h4 class="wp-block-heading" id="run-the-project">Run the Project:</h4>



<ul class="wp-block-list">
<li>Run the project. Test the button by hovering, pressing, and clicking to see the visual feedback and trigger the&nbsp;<code>Pressed</code>&nbsp;event.</li>
</ul>



<p>And just like that, you’ve built your own custom button! Hope you had fun following along. Keep an eye out for our next tutorials, where we’ll take this button and give it some awesome upgrades!</p>



<p>This project can be downloaded from GitHub at: <a href="https://github.com/xolabsro/CanvasButton" target="_blank" rel="noreferrer noopener">https://github.com/xolabsro/CanvasButton</a></p>



<p id="block-59a92dbb-c0d1-4b75-b250-f331b6ceb4c4">More in this series:</p>



<ul id="block-c7594468-ed0c-4be1-a999-04ef9789f34c" class="wp-block-list">
<li><a href="https://blog.xojo.com/2025/05/02/how-to-create-a-custom-button-control-in-xojo/">How To Create a Custom Button Control in Xojo</a></li>



<li><a href="https://blog.xojo.com/2025/05/14/how-to-create-a-custom-button-control-in-xojo-part-2/">How To Create a Custom Button Control in Xojo – Part 2</a></li>



<li><a href="https://blog.xojo.com/2025/05/28/how-to-create-a-custom-button-control-in-xojo-part-3-make-your-controls-inspector-friendly/">How To Create a Custom Button Control in Xojo – Part 3: Make Your Controls Inspector-Friendly</a></li>



<li><a href="https://blog.xojo.com/2025/06/23/how-to-create-a-custom-button-control-in-xojo-part-4-adding-focus/">How To Create a Custom Button Control in Xojo – Part 4: Adding Focus</a></li>
</ul>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</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>Log4Xojo: A more powerful way to manage your app logging</title>
		<link>https://blog.xojo.com/2024/11/26/log4xojo-a-more-powerful-way-to-manage-your-app-logging/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Tue, 26 Nov 2024 14:00:00 +0000</pubDate>
				<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Advanced Logging]]></category>
		<category><![CDATA[Custom Classes]]></category>
		<category><![CDATA[Debugging Tools]]></category>
		<category><![CDATA[Diagnostics Tools]]></category>
		<category><![CDATA[Error Handling]]></category>
		<category><![CDATA[File Logging]]></category>
		<category><![CDATA[Log Rotation]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=14052</guid>

					<description><![CDATA[Logging is an essential part of software development. Whether you’re debugging issues during development or monitoring application performance in production, a robust logging solution is&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Logging is an essential part of software development. Whether you’re debugging issues during development or monitoring application performance in production, a robust logging solution is critical. Xojo provides two excellent built-in methods for logging:&nbsp;<code>System.DebugLog</code>&nbsp;and&nbsp;<code>System.Log</code>. These methods are simple to use, highly effective, and suitable for most types of projects.</p>



<p>However, as your applications grow in complexity, you may encounter scenarios where more advanced logging features are required. Developers working with other programming languages often turn to frameworks like&nbsp;Log4J&nbsp;or&nbsp;Log4Net&nbsp;for flexible and powerful logging solutions. Inspired by these tools, let&#8217;s create&nbsp;Log4Xojo, a powerful and flexible logging utility designed specifically for the Xojo language.</p>



<p>With Log4Xojo, you can:</p>



<ul class="wp-block-list">
<li>Save logs to files for long-term storage and analysis.</li>



<li>Automatically rotate log files when they grow too large.</li>



<li>Log messages to multiple destinations (e.g., Debugger, system logs, and files) simultaneously.</li>



<li>Filter log messages by severity to reduce noise in production environments.</li>
</ul>



<p>Log4Xojo complements Xojo&#8217;s built-in logging methods by extending their capabilities and making it easier to manage logs in larger or more complex applications. Whether you&#8217;re a seasoned Xojo developer or coming from other tools like Log4J or Log4Net, Log4Xojo provides a familiar, robust solution for advanced logging needs.</p>



<h2 class="wp-block-heading"><strong>Xojo’s Built-In Logging Methods</strong></h2>



<p>Xojo provides two built-in methods for logging: <code>System.DebugLog</code> and <code>System.Log</code></p>



<ol class="wp-block-list">
<li><code>System.DebugLog</code> &#8211; <a href="https://documentation.xojo.com/api/os/system.html#system-debuglog" target="_blank" rel="noreferrer noopener">check here for the documentation</a></li>



<li><code>System.Log</code> &#8211; <a href="https://documentation.xojo.com/api/os/system.html#system-log" target="_blank" rel="noreferrer noopener">check here for the documentation</a></li>
</ol>



<p>These methods are simple to use and provide an effective way to track issues during development or monitor application behavior in production environments.</p>



<h3 class="wp-block-heading"><strong>1. System.DebugLog</strong></h3>



<p>The <code>System.DebugLog</code> method outputs messages to Xojo&#8217;s <strong>Message Log</strong> in the <a target="_blank" rel="noreferrer noopener" href="https://documentation.xojo.com/getting_started/using_the_ide/find-_errors-_messages_panels.html#getting-started-using-the-ide-find-errors-messages-panels-find"><strong>Messages Panel</strong></a> during development. This allows developers to generate their own logging messages to assist with debugging and testing. Additionally, <code>System.DebugLog</code> writes to the system log, making it viewable in tools such as:</p>



<ul class="wp-block-list">
<li><strong>Console</strong> on macOS</li>



<li><strong>DebugView</strong> on Windows</li>



<li><strong>StdErr</strong> on Linux</li>
</ul>



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



<pre class="wp-block-code"><code>System.DebugLog("This is a debug message.")</code></pre>



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



<ul class="wp-block-list">
<li>Outputs directly to the <strong>Messages Panel</strong> in the Xojo IDE during debugging, providing real-time insight into your application.</li>



<li>Also logs to the system log, which is accessible outside of the Xojo IDE for further analysis.</li>
</ul>



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



<ul class="wp-block-list">
<li>While <code>System.DebugLog</code> is versatile, its output cannot be directed to custom log files within your application without additional handling.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>2. System.Log</strong></h3>



<p>The <code>System.Log</code> method writes log messages to the system’s logging mechanism. This is particularly useful for monitoring application behavior in production environments, as it integrates seamlessly with system-level logging tools.</p>



<h4 class="wp-block-heading"><strong>How It Works</strong>:</h4>



<ul class="wp-block-list">
<li><strong>On macOS and Linux</strong>: Messages are written to the system logger, typically located at <code>/var/log</code>. These logs can be accessed using tools like <code>Console</code> (macOS) or <code>Syslog</code> (Linux).</li>



<li><strong>On Windows</strong>: Messages are sent to the Event Logger, which can be viewed using the Windows Event Viewer.</li>
</ul>



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



<pre class="wp-block-code"><code>System.Log(System.LogLevelNotice, "This is a notice message.")</code></pre>



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



<ul class="wp-block-list">
<li>Integrates with the system’s logging infrastructure, allowing log messages to persist outside of the Xojo IDE.</li>



<li>Useful for production environments, where logs can be reviewed using system tools like Console (macOS), Event Viewer (Windows), or Syslog (Linux).</li>
</ul>



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



<ul class="wp-block-list">
<li>Messages may not be portable across platforms due to system-specific log storage locations.</li>



<li>Not supported in mobile projects.</li>



<li>On <strong>macOS</strong>, messages logged with the following levels do not appear in the system log due to a macOS limitation:
<ul class="wp-block-list">
<li><code>LogLevelDebug</code></li>



<li><code>LogLevelInformation</code></li>



<li><code>LogLevelSuccess</code></li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Why Use the Built-In Methods?</strong></h3>



<p>The built-in logging methods are excellent for most projects. They are simple, efficient, and integrate seamlessly with Xojo. If your project doesn’t require file logging, log rotation, or multi-destination support, these methods might be all you need.</p>



<h2 class="wp-block-heading"><strong>Introducing our custom class: Log4Xojo</strong></h2>



<p>While Xojo’s built-in methods are excellent for many projects, some applications demand more advanced logging features. Log4Xojo is designed to complement Xojo’s built-in methods and extend their functionality to handle more complex requirements.</p>



<h3 class="wp-block-heading"><strong>What is Log4Xojo?</strong></h3>



<p>Log4Xojo is a custom-built logging class that expands Xojo’s logging capabilities with features like:</p>



<ul class="wp-block-list">
<li><strong>File Logging</strong>: Save logs to files for later analysis.</li>



<li><strong>Log Rotation</strong>: Automatically manage log file sizes and create backups.</li>



<li><strong>Multi-Destination Logging</strong>: Log messages to the Debugger, system logs, and files simultaneously.</li>



<li><strong>Log Level Filtering</strong>: Control which messages are logged based on severity (e.g., only log warnings and errors in production).</li>



<li><strong>Named Logs</strong>: Assign each log instance a unique name, making it easier to organize and differentiate log files.</li>



<li><strong>Thread-Safe Logging</strong>: Use a background thread to process logs efficiently without blocking your application.</li>
</ul>



<p>These features make Log4Xojo an excellent choice for larger or more complex projects, as well as applications with strict monitoring or reporting requirements.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>When Should You Use Log4Xojo?</strong></h3>



<p>Consider using Log4Xojo if your project requires:</p>



<ul class="wp-block-list">
<li>Persistent logging to files for long-term storage or analysis.</li>



<li>Automatic log management to prevent files from growing too large.</li>



<li>Logging to multiple destinations simultaneously (e.g., Debugger, system logs, and files).</li>



<li>Filtering logs by severity to reduce noise in production environments.</li>



<li>Thread-safe, asynchronous logging for improved performance in multi-threaded applications. By processing logs asynchronously in a background thread, Log4Xojo ensures that your application’s performance remains smooth, even when handling a large volume of log messages.</li>
</ul>



<p>Log4Xojo is not meant to replace the built-in logging methods but to complement them. It builds on the foundation of <code>System.DebugLog</code> and <code>System.Log</code> by adding advanced features for developers who need more flexibility and control.</p>



<h2 class="wp-block-heading"><strong>How to Use Log4Xojo</strong></h2>



<p>Using Log4Xojo is simple! Follow these steps to get started.</p>



<h3 class="wp-block-heading"><strong>Step 1: Add Log4Xojo to Your Project</strong></h3>



<ol class="wp-block-list">
<li>Download the <code>Log4Xojo</code> class file from GitHub <a href="https://github.com/xojo/log4xojo" target="_blank" rel="noreferrer noopener">https://github.com/xojo/log4xojo</a> or <a href="https://drive.google.com/file/d/1huAoi2Fh1nAEiI6Y7--hZTd_RJEAjAUy/view?usp=sharing" target="_blank" rel="noreferrer noopener">click here to download the Xojo example project</a>.</li>



<li>Drag the <code>Log4Xojo</code> class file into your Xojo project.</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Step 2: Create a Log Instance</strong></h3>



<p>Create an instance of the Log4Xojo class. Each log requires a name, which is used to identify it and organize log files.</p>



<pre class="wp-block-code"><code>Var l4x As New Log4Xojo("AppLog")</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Step 3: Configure the Log</strong></h3>



<p>Set up the logging destinations, file path, log level, and other settings. For example:</p>



<pre class="wp-block-code"><code>// Set destinations (Debugger and File)
l4x.SetLogDestinations(Log4Xojo.LogDestination.DebugLog, Log4Xojo.LogDestination.FileLog)

// Set the base folder for the log file
l4x.SetLogFilePath(SpecialFolder.Desktop)

// Set the log level to Warning and above
l4x.SetLogLevel(Log4Xojo.LogLevel.Warning)

// Configure log rotation
l4x.SetMaxBackupFiles(5)
l4x.SetMaxLogFileSize(1024)</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Step 4: Log Messages</strong></h3>



<p>Log messages with varying severity levels:</p>



<pre class="wp-block-code"><code>l4x.Log("Application started.", Log4Xojo.LogLevel.Info, CurrentMethodName)
l4x.Log("This is a debug message.", Log4Xojo.LogLevel.Debug, CurrentMethodName)
l4x.Log("Warning: Low disk space.", Log4Xojo.LogLevel.Warning, CurrentMethodName)
l4x.Log("Error: File not found.", Log4Xojo.LogLevel.Error, CurrentMethodName)</code></pre>



<p>The optional location parameter (<code>CurrentMethodName</code> above) allows you to include the context of the log message, such as the method or class where it originated. This makes it easier to pinpoint the source of issues when reviewing logs.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Step 5: Stop Logging</strong></h3>



<p>When your application shuts down, make sure to stop logging to ensure all queued messages are processed:</p>



<pre class="wp-block-code"><code>l4x.StopLogging()</code></pre>



<h2 class="wp-block-heading"><strong>Use Case Scenarios for Log4Xojo</strong></h2>



<p>To better understand how <code>Log4Xojo</code> can enhance your Xojo applications, here are some practical use cases:</p>



<h4 class="wp-block-heading"><strong>1. Monitoring Application Performance in Production</strong></h4>



<p>In a production environment, it’s essential to keep track of your application’s behavior without impacting performance. With <code>Log4Xojo</code>, you can:</p>



<ul class="wp-block-list">
<li>Log important application events (e.g., user activity, API calls).</li>



<li>Use <strong>file logging</strong> to store these logs persistently for later analysis.</li>



<li>Filter logs by severity to avoid unnecessary noise (e.g., only warnings, errors, and critical issues).</li>
</ul>



<p><strong>Example:</strong></p>



<pre class="wp-block-code"><code>Var l4x As New Log4Xojo("ProductionLog")
l4x.SetLogDestinations(Log4Xojo.LogDestination.FileLog)
l4x.SetLogLevel(Log4Xojo.LogLevel.Warning)

// Log application events
l4x.Log("User logged in", Log4Xojo.LogLevel.Info) // Ignored (below warning level)
l4x.Log("Database connection failed", Log4Xojo.LogLevel.Error) // Logged
l4x.Log("Critical: Payment gateway unreachable", Log4Xojo.LogLevel.Critical) // Logged</code></pre>



<p>Outcome: Only warnings, errors, and critical messages are logged to a file for postmortem analysis without overwhelming the log with lower-priority messages.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>2. Creating a Diagnostic Tool for End Users</strong></h4>



<p>When troubleshooting issues reported by end users, having detailed logs can be invaluable. With <code>Log4Xojo</code>, you can:</p>



<ul class="wp-block-list">
<li>Log messages to a file on the user&#8217;s machine.</li>



<li>Include optional location tags to pinpoint where issues occur in your code.</li>



<li>Use <strong>log rotation</strong> to prevent log files from consuming too much disk space.</li>
</ul>



<p><strong>Example:</strong></p>



<pre class="wp-block-code"><code>Var l4x As New Log4Xojo("UserDiagnostics")
l4x.SetLogDestinations(Log4Xojo.LogDestination.FileLog)
l4x.SetLogFilePath(SpecialFolder.Documents)
l4x.SetMaxLogFileSize(1 * 1024 * 1024) // 1 MB
l4x.SetMaxBackupFiles(3)

// Log diagnostic information
l4x.Log("Application launched", Log4Xojo.LogLevel.Info, CurrentMethodName)
l4x.Log("Error: File not found", Log4Xojo.LogLevel.Error, "FileManager.LoadFile")
l4x.Log("User clicked 'Submit'", Log4Xojo.LogLevel.Debug, "MainWindow.HandleSubmit")</code></pre>



<p>Outcome: You can ask users to send the log files stored in their Documents folder for review, helping you quickly diagnose and fix issues.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>3. Tracking User Activity in Enterprise Applications</strong></h4>



<p>In enterprise applications, logging user activity is often a requirement for auditing or compliance purposes. With <code>Log4Xojo</code>, you can:</p>



<ul class="wp-block-list">
<li>Use <strong>multi-destination logging</strong> to send activity logs to both the system logs and a central log file.</li>



<li>Include relevant context for each log entry (e.g., user ID, method).</li>
</ul>



<p><strong>Example:</strong></p>



<pre class="wp-block-code"><code>Var l4x As New Log4Xojo("AuditLog")
l4x.SetLogDestinations(Log4Xojo.LogDestination.SystemLog, Log4Xojo.LogDestination.FileLog)
l4x.SetLogFilePath(SpecialFolder.Documents)

// Log user activity
Var userID As String = "User123"
l4x.Log(userID + " logged in", Log4Xojo.LogLevel.Info, "AuthManager.Login")
l4x.Log(userID + " updated profile", Log4Xojo.LogLevel.Info, "ProfileManager.UpdateProfile")
l4x.Log(userID + " attempted unauthorized access", Log4Xojo.LogLevel.Warning, "SecurityManager.CheckPermissions")</code></pre>



<p>Outcome: Both system logs and a persistent file log are updated with the user&#8217;s activities, ensuring compliance and easy traceability.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>4. Handling Errors and Crashes Gracefully</strong></h4>



<p>When an application crashes, logs are often the only way to understand what went wrong. <code>Log4Xojo</code> can:</p>



<ul class="wp-block-list">
<li>Capture error and critical logs leading up to a crash.</li>



<li>Rotate logs to avoid losing older, relevant logs.</li>



<li>Save logs to a file for recovery after a crash.</li>
</ul>



<p><strong>Example:</strong></p>



<pre class="wp-block-code"><code>Var l4x As New Log4Xojo("CrashLogs")
l4x.SetLogDestinations(Log4Xojo.LogDestination.FileLog)
l4x.SetMaxBackupFiles(5)
l4x.SetMaxLogFileSize(1 * 1024 * 1024) // 1 MB

Try
  // Simulate application logic
  Raise New RuntimeException("Simulated crash")
Catch e As RuntimeException
  l4x.Log("Critical error: " + e.Message, Log4Xojo.LogLevel.Critical, CurrentMethodName)
End Try</code></pre>



<p>Outcome: The log files can be used to investigate the cause of the crash.</p>



<h2 class="wp-block-heading"><strong>The Structure of the Log4Xojo Class</strong></h2>



<p>Log4Xojo includes several constants, enums, properties, and methods that provide its advanced functionality. Let’s break them down:</p>



<h3 class="wp-block-heading"><strong>Constants</strong></h3>



<ol class="wp-block-list">
<li><code>MaxQueueSize</code>
<ul class="wp-block-list">
<li>Defines the maximum number of log messages that can be stored in the logging queue before processing.</li>



<li>Default: <code>10,000</code>.</li>
</ul>
</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Enums</strong></h3>



<ol class="wp-block-list">
<li><code>LogDestination</code>
<ul class="wp-block-list">
<li>Specifies where log messages should be sent:
<ul class="wp-block-list">
<li><code>DebugLog</code>: Logs to the Xojo Debugger using <code>System.DebugLog</code>.</li>



<li><code>SystemLog</code>: Logs to the system&#8217;s logging framework using <code>System.Log</code>.</li>



<li><code>FileLog</code>: Logs to a file.</li>



<li><code>All</code>: Logs to all destinations.</li>
</ul>
</li>
</ul>
</li>



<li><code>LogLevel</code>
<ul class="wp-block-list">
<li>Defines the severity levels for log messages:
<ul class="wp-block-list">
<li><code>Debug</code>: Detailed debugging information.</li>



<li><code>Info</code>: General informational messages.</li>



<li><code>Warning</code>: Potential issues that don’t interrupt program flow.</li>



<li><code>Error</code>: Errors requiring attention.</li>



<li><code>Critical</code>: Critical issues that may cause application failure.</li>
</ul>
</li>
</ul>
</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Properties</strong></h3>



<ol class="wp-block-list">
<li><code>mLogName</code>
<ul class="wp-block-list">
<li>The name of the log. This is required during initialization and is used to identify logs and organize log files.</li>
</ul>
</li>



<li><code>mCurrentLogLevel</code>
<ul class="wp-block-list">
<li>The minimum severity level of messages to log. Messages below this level are ignored.</li>
</ul>
</li>



<li><code>mLogDestinations</code>
<ul class="wp-block-list">
<li>An array of <code>LogDestination</code> values specifying where logs should be sent.</li>
</ul>
</li>



<li><code>mLogFilePath</code>
<ul class="wp-block-list">
<li>The file path for logs. This is automatically generated based on the log name and current date but can also be customized.</li>
</ul>
</li>



<li><code>mMaxBackupFiles</code>
<ul class="wp-block-list">
<li>The maximum number of backup log files to retain. Default: <code>10</code>.</li>
</ul>
</li>



<li><code>mMaxLogFileSize</code>
<ul class="wp-block-list">
<li>The maximum size of the log file in bytes before rotation occurs. Default: <code>1 MB</code>.</li>
</ul>
</li>



<li><code>mLogQueue</code>
<ul class="wp-block-list">
<li>A queue for temporarily storing log messages before they are processed.</li>
</ul>
</li>



<li><code>mLogQueueMutex</code>
<ul class="wp-block-list">
<li>A mutex used to ensure thread safety when accessing the log queue. <a href="https://documentation.xojo.com/api/language/mutex.html#mutex" target="_blank" rel="noreferrer noopener">Check mutex documentation here</a>.</li>
</ul>
</li>



<li><code>mLogThread</code>
<ul class="wp-block-list">
<li>A background thread that processes log messages. <a href="https://documentation.xojo.com/api/language/thread.html#properties" target="_blank" rel="noreferrer noopener">Check thread documentation here</a>.</li>
</ul>
</li>



<li><code>mRunning</code>
<ul class="wp-block-list">
<li>A flag indicating whether the logging thread is running.</li>
</ul>
</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Methods</strong></h3>



<p>The <code>Log4Xojo</code> class provides several methods to configure logging behavior and manage log messages. Let’s go through each one in detail:</p>



<h4 class="wp-block-heading"><strong>1. Constructor(Name As String)</strong></h4>



<p><strong>Purpose</strong>: The constructor initializes a new instance of the <code>Log4Xojo</code> class with a required log name. This name is used to identify the log instance and organize log files.</p>



<p><strong>Usage</strong>:</p>



<pre class="wp-block-code"><code>Var l4x As New Log4Xojo("AppLog")</code></pre>



<p><strong>Details</strong>:</p>



<ul class="wp-block-list">
<li>The <code>Name</code> parameter is required and cannot be empty. If you pass an empty string, the class will raise an <code>InvalidArgumentException</code>.</li>



<li>The log name is used to generate log file names (e.g., <code>AppLog_2024-11-01.txt</code>).</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>2. Log(message As String, level As LogLevel, Optional location As String = &#8220;&#8221;)</strong></h4>



<p><strong>Purpose</strong>: Logs a message with a specified log level and an optional location string.</p>



<p><strong>Usage</strong>:</p>



<pre class="wp-block-code"><code>l4x.Log("This is an informational message.", Log4Xojo.LogLevel.Info)
l4x.Log("Warning: Low disk space.", Log4Xojo.LogLevel.Warning, CurrentMethodName)</code></pre>



<p><strong>Details</strong>:</p>



<ul class="wp-block-list">
<li><code>message</code>: The log message you want to record.</li>



<li><code>level</code>: The severity level of the message. This determines whether the message will be logged, based on the current log level (<code>mCurrentLogLevel</code>).</li>



<li><code>location</code> (optional): A string to provide context for the log message, such as the method or class where it originated. This is especially useful for tracing the source of issues. Using <code>CurrentMethodName</code> is more than enough, unless you need to specify something else.</li>



<li>If the log level is below the configured <code>mCurrentLogLevel</code>, the message is ignored.</li>
</ul>



<p><strong>Example Output</strong>:</p>



<pre class="wp-block-code"><code>&#91;2023-10-01 12:34:56] &#91;INFO] This is an informational message.
&#91;2023-10-01 12:35:00] &#91;WARNING] &#91;Code-Location] Warning: Low disk space.</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>3. SetLogDestinations(ParamArray destinations As LogDestination)</strong></h4>



<p><strong>Purpose</strong>: Specifies where log messages should be sent (e.g., Debugger, system logs, files, or all destinations).</p>



<p><strong>Usage</strong>:</p>



<pre class="wp-block-code"><code>l4x.SetLogDestinations(Log4Xojo.LogDestination.DebugLog, Log4Xojo.LogDestination.FileLog)</code></pre>



<p><strong>Details</strong>:</p>



<ul class="wp-block-list">
<li>Accepts one or more <code>LogDestination</code> values as parameters.</li>



<li>Supported destinations:
<ul class="wp-block-list">
<li><code>LogDestination.DebugLog</code>: Logs to the Xojo Debugger using <code>System.DebugLog</code>.</li>



<li><code>LogDestination.SystemLog</code>: Logs to the system&#8217;s logging framework using <code>System.Log</code>.</li>



<li><code>LogDestination.FileLog</code>: Logs to a file.</li>



<li><code>LogDestination.All</code>: Logs to all destinations simultaneously.</li>
</ul>
</li>



<li>You can mix and match destinations to suit your needs.</li>
</ul>



<p><strong>Example</strong>:</p>



<ul class="wp-block-list">
<li>To log messages only to a file:<code>l4x.SetLogDestinations(Log4Xojo.LogDestination.FileLog)</code></li>



<li>To log messages to both the Debugger and system logs:<code>l4x.SetLogDestinations(Log4Xojo.LogDestination.DebugLog, Log4Xojo.LogDestination.SystemLog)</code></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>4. SetLogFilePath(baseLocation As FolderItem)</strong></h4>



<p><strong>Purpose</strong>: Sets the folder where log files should be stored.</p>



<p><strong>Usage</strong>:</p>



<pre class="wp-block-code"><code>Var folder As FolderItem = SpecialFolder.Desktop
l4x.SetLogFilePath(folder)</code></pre>



<p><strong>Details</strong>:</p>



<ul class="wp-block-list">
<li><code>baseLocation</code>: A <code>FolderItem</code> representing the folder where log files will be saved.</li>



<li>The folder must exist and be writable. If the folder is invalid, the method will raise an <code>InvalidArgumentException</code>.</li>



<li>The log file name is automatically generated based on the log name and current date (e.g., <code>AppLog_2024-11-01.txt</code>).</li>
</ul>



<p><strong>Example</strong>:</p>



<ul class="wp-block-list">
<li>To store logs in the Documents folder:<code>l4x.SetLogFilePath(SpecialFolder.Documents)</code></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>5. SetLogLevel(level As LogLevel)</strong></h4>



<p><strong>Purpose</strong>: Sets the minimum severity level for messages to be logged.</p>



<p><strong>Usage</strong>:</p>



<pre class="wp-block-code"><code>l4x.SetLogLevel(Log4Xojo.LogLevel.Warning)</code></pre>



<p><strong>Details</strong>:</p>



<ul class="wp-block-list">
<li><code>level</code>: A <code>LogLevel</code> value that determines which log messages will be recorded.</li>



<li>Messages with a severity lower than the set level are ignored.</li>
</ul>



<p><strong>Supported Log Levels</strong>:</p>



<ul class="wp-block-list">
<li><code>Log4Xojo.LogLevel.Debug</code>: Detailed debugging information.</li>



<li><code>Log4Xojo.LogLevel.Info</code>: General informational messages.</li>



<li><code>Log4Xojo.LogLevel.Warning</code>: Potential issues that don’t interrupt program flow.</li>



<li><code>Log4Xojo.LogLevel.Error</code>: Errors requiring attention.</li>



<li><code>Log4Xojo.LogLevel.Critical</code>: Critical issues that may cause application failure.</li>
</ul>



<p><strong>Example</strong>: If you set the log level to <code>LogLevel.Warning</code>, only warnings, errors, and critical messages will be logged:</p>



<pre class="wp-block-code"><code>l4x.SetLogLevel(Log4Xojo.LogLevel.Warning)
l4x.Log("This is a debug message.", Log4Xojo.LogLevel.Debug) // Ignored
l4x.Log("This is a warning message.", Log4Xojo.LogLevel.Warning) // Logged</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>6. SetMaxBackupFiles(max As Integer)</strong></h4>



<p><strong>Purpose</strong>: Configures the maximum number of backup log files to retain.</p>



<p><strong>Usage</strong>:</p>



<pre class="wp-block-code"><code>l4x.SetMaxBackupFiles(5)</code></pre>



<p><strong>Details</strong>:</p>



<ul class="wp-block-list">
<li><code>max</code>: The maximum number of backup files to keep. Older backups are automatically deleted when the limit is reached.</li>



<li>When the current log file exceeds the size limit (set via <code>SetMaxLogFileSize</code>), it is renamed as a backup (e.g., <code>AppLog_Date_1.txt</code>), and a new log file is created.</li>
</ul>



<p><strong>Example</strong>: If <code>max = 5</code>, the backups will look like this:</p>



<pre class="wp-block-code"><code>AppLog_Date_1.txt
AppLog_Date_2.txt
AppLog_Date_3.txt
AppLog_Date_4.txt
AppLog_Date_5.txt</code></pre>



<p>Once the 6th backup is created, <code>AppLog_Date_1.txt</code> is deleted to make room for it.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>7. SetMaxLogFileSize(sizeInBytes As Integer)</strong></h4>



<p><strong>Purpose</strong>: Defines the maximum size of the log file before it is rotated.</p>



<p><strong>Usage</strong>:</p>



<pre class="wp-block-code"><code>l4x.SetMaxLogFileSize(1 * 1024 * 1024) // 1 MB</code></pre>



<p><strong>Details</strong>:</p>



<ul class="wp-block-list">
<li><code>sizeInBytes</code>: The maximum size of the log file in bytes.</li>



<li>When the log file exceeds this size, it is renamed as a backup, and a new log file is created.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>8. StopLogging()</strong></h4>



<p><strong>Purpose</strong>: Stops the logging thread and processes any remaining messages in the queue.</p>



<p><strong>Usage</strong>:</p>



<pre class="wp-block-code"><code>l4x.StopLogging()</code></pre>



<p><strong>Details</strong>:</p>



<ul class="wp-block-list">
<li>Use this method when your application is shutting down to ensure that all log messages are written to their destinations.</li>



<li>The method waits for a short period to process any remaining messages in the queue before terminating the logging thread.</li>
</ul>



<h2 class="wp-block-heading"><strong>Conclusion</strong></h2>



<p>Xojo’s built-in logging methods, <code>System.DebugLog</code> and <code>System.Log</code>, are excellent built-in tools for debugging and monitoring application behavior. They are simple, effective, and suitable for most types of projects.</p>



<p>For applications with more advanced requirements, the Log4Xojo class provides a powerful complement to these methods. With features like file logging, log rotation, multi-destination support, and log level filtering, Log4Xojo is the perfect solution for larger or more complex projects.</p>



<p class="has-text-align-center">Download Log4Xojo from GitHub <a href="https://github.com/xojo/log4xojo" target="_blank" rel="noreferrer noopener">https://github.com/xojo/log4xojo</a> or as a <a href="https://drive.google.com/file/d/1huAoi2Fh1nAEiI6Y7--hZTd_RJEAjAUy/view?usp=sharing" data-type="link" data-id="https://drive.google.com/file/d/1huAoi2Fh1nAEiI6Y7--hZTd_RJEAjAUy/view?usp=sharing" target="_blank" rel="noreferrer noopener">Xojo Binary Project</a> file and start enhancing your logging workflow.</p>



<p>We look forward to hearing how you’re using Log4Xojo in your projects!</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
