<?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>ComboBox &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/combobox/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Fri, 16 Jul 2021 16:56:40 +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>Creating your own ComboBox Subclass with Sorted Menu Items</title>
		<link>https://blog.xojo.com/2021/03/25/creating-your-own-combobox-subclass-with-sorted-menu-items/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 25 Mar 2021 10:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[ComboBox]]></category>
		<category><![CDATA[Object-Oriented]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=8206</guid>

					<description><![CDATA[The Xojo ComboBox desktop control is a powerful one. It combines the capabilities of a TextField with the PopupMenu. That means that you can choose from the available options in the associated menu or you can type another value in the ComboBox text field. What about getting the ComboBox to do things not included in the class?]]></description>
										<content:encoded><![CDATA[
<p>The Xojo <a href="https://documentation.xojo.com/api/deprecated/combobox.html"><strong>ComboBox</strong></a> desktop control is a powerful one. It combines the capabilities of a <a href="https://documentation.xojo.com/api/deprecated/textfield.html"><strong>TextField</strong></a> with the <a href="https://documentation.xojo.com/api/deprecated/popupmenu.html"><strong>PopupMenu</strong></a>. That means that you can choose any of the available options from the associated menu (for example those assigned using the <strong>Appearance &gt; Initial value</strong> option in the Inspector Panel) or simply type another value in the ComboBox text field.</p>



<p>What about getting the ComboBox to do things not included in the class? In this tutorial you will learn how to add the text typed by the user as an option in the associated ComboBox menu. We&#8217;ll make sure entries are not duplicated and that they are sorted alphabetically. We&#8217;ll use the <code>AddAllRows</code> method to add a strings array to those already available in the ComboBox menu. In addition, we will add a new method to the ComboBox so you can retrieve all the menu entries as an Array of Strings.</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="505" class="wp-image-8212 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2021/03/SortedComboBox-1024x505.png" alt="" srcset="https://blog.xojo.com/wp-content/uploads/2021/03/SortedComboBox-1024x505.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/03/SortedComboBox-300x148.png 300w, https://blog.xojo.com/wp-content/uploads/2021/03/SortedComboBox-768x378.png 768w, https://blog.xojo.com/wp-content/uploads/2021/03/SortedComboBox-1536x757.png 1536w, https://blog.xojo.com/wp-content/uploads/2021/03/SortedComboBox.png 1648w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>


<p>You&#8217;ll find it very convenient that Xojo is an&nbsp;Object-Oriented Programming language as you create any subclass from any existing one. Creating your own specialized subclasses adds tons of extra functionality to <em>any</em> of your projects since they can be used in your other desktop projects. Keep reading to create your own subclasses! <a href="https://bit.ly/2OS99hO">Download this Xojo project</a></p>
<h2>1. Adding a Class to the Project</h2>
<p>Start a new Xojo Desktop project and select the <strong>Insert &gt; class</strong> option from the menu in order to add a new class to the Navigator.</p>
<p>With the new <code>Class1</code> item selected in the Navigator, change the following values in the associated Inspector Panel:</p>
<ul>
<li><strong>Name:</strong> MyComboBox (you may use any other class name you want).</li>
<li><strong>Super:</strong> ComboBox</li>
</ul>
<p>Confirm the changes.&nbsp;You&#8217;ll see how the new class item is now named&nbsp;<code>MyComboBox</code> in the Navigator, while its icon has changed to the one for the ComboBox control.</p>
<h2>2. Adding Event Handlers to the Class</h2>
<p>Keep <code>MyComboBox</code> selected in the Navigator and then select the <strong>Insert &gt; Event Handler</strong> option from the menu. That action will open a new window listing all the available Event Handlers for the ComboBox class and, thus, also for all the subclasses created from it &#8211; like our new class.</p>
<p>Select the <code>Change</code>, <code>KeyDown</code>, <code>Open</code> and <code>LostFocus</code> entries from the list and confirm the changes by clicking on the &#8220;OK&#8221; button. The &#8220;Add Event Handler&#8221; window will close and the selected entries will be added to the <code>MyComboBox</code> item in the Navigator.</p>
<p>Use the <code>KeyDown</code> and <code>LostFocus</code> event handlers to add the text typed by the user as new entries in the ComboBox menu.</p>
<p>Select the <code>KeyDown</code> event under the <code>MyComboBox</code> item in the Navigator and type the following code in the associated Code Editor:</p>
<pre>AddNewEntry(key)
Return RaiseEvent KeyDown(Key)</pre>
<p>The <code>AddNewEntry</code> method will add the new entry to our ComboBox menu.&nbsp;Notice the <code>RaiseEvent KeyDown(Key)</code> line of code. Because our subclass makes use of this event handler, that means that it will not be available to any instances (objects) created from the class, as for example those created when adding the class to a Window in the Layout Editor.</p>
<h2>3. Adding Event Definitions</h2>
<p>With <code>MyComboBox</code> still selected in the Navigator, choose the <strong>Insert &gt; Event Definition</strong> menu option and add the following values in the associated Inspector Panel:</p>
<ul>
<li><strong>Event Name:</strong> KeyDown</li>
<li><strong>Parameters:</strong> Key As String</li>
<li><strong>Return Type:</strong> Boolean</li>
</ul>
<p>This creates the same Event Handler for the class so it can be implemented by any of the instances created from the class, while the <code>RaiseEvent KeyDown(Key)</code> line of code will make sure that this event will also be called for its instances.</p>
<p>Now select the <code>LostFocus</code> event handler from the <code>MyComboBox</code> item in the Navigator and type the following code in the associated Code Editor:</p>
<pre>Me.AddRow(Me.Text)
RaiseEvent LostFocus</pre>
<p>Once again, because we are implementing this event handler, we need to make it available for our class instances. With <code>MyComboBox</code> selected, choose the <strong>Insert &gt; Event Definition</strong> menu option adding the following value in the associated Inspector Panel:</p>
<ul>
<li><strong>Event Name:</strong> LostFocus</li>
</ul>
<p>Now select the <code>Open</code> event handler under <code>MyComboBox</code>, typing the following code in the associated Code Editor:</p>
<pre>Var selectedIndex As Integer = Me.mSelectedRowIndex

Var s() As String = Me.Rows
s.Sort
Me.RemoveAllRows
Me.AddAllRows(s)

If selectedIndex = -1 Then
  Me.mSelectedRowIndex = -1
  Me.Text = ""
End If

RaiseEvent Open</pre>
<p>Once again, we need to create a new Event Definition for the class using the values:</p>
<ul>
<li><strong>Event Name:</strong> Open</li>
</ul>
<p>And repeat the last operation to add the last Event Definition with the following:</p>
<ul>
<li><strong>Event Name:</strong> Change</li>
</ul>
<p>Type this snippet of code in the associated Code Editor for the <code>Change</code> Event Handler:</p>
<pre>Var s() As String = Me.rows
Var n As Integer = s.LastRowIndex

For i As Integer = 0 To n
  If s(i) = Me.Text Then
    Me.mSelectedRowIndex = i
    Exit For
  End If
Next

RaiseEvent Change</pre>
<h2>4. Adding Methods to the Class</h2>
<p>While <code>MyComboBox</code> is still selected in the Navigator, select the <strong>Insert &gt; Method</strong> option from the menu, using the following values in the associated Inspector Panel:</p>
<ul>
<li><strong>Method Name:</strong> AddNewEntry</li>
<li><strong>Parameters:</strong> Key As String</li>
<li><strong>Scope:</strong> Protected</li>
</ul>
<p>And type the following snippet of code in the Code Editor associated with the new method:</p>
<pre>// If return key or tab key is pressed then we add the current text to the menu options

If (key.Asc = 13 Or key.Asc = 9) And Me.Text &lt;&gt; "" Then

  Me.AddRow(Me.Text)

End If</pre>
<p>Now add a second method to the class, using the following values:</p>
<ul>
<li><strong>Method Name:</strong> Rows</li>
<li><strong>Return Type:</strong> String()</li>
<li><strong>Scope:</strong> Public</li>
</ul>
<p>And type the following code in the method&#8217;s Code Editor:</p>
<pre>Var r() As String
Var i As Integer = Me.RowCount - 1

For n As Integer = 0 To i
  r.Add(Me.RowValueAt(n))
Next

Return r</pre>
<h2>&nbsp;</h2>
<h2>5. Overriding existing Methods</h2>
<p>You always want your ComboBox menu items to be sorted alphabetically. And that means taking care of the default functionality of the <code>AddRow</code> and <code>AddAllRows</code> methods. At the same time, we don&#8217;t want the <code>AddRowAt</code> ComboBox method to be available for our subclass (it wouldn&#8217;t make much sense to add a new entry at a particular spot in the menu if it wouldn&#8217;t stay at that position afterwards).</p>
<p>Add a couple of new methods to <code>MyComboBox</code> using the following values:</p>
<ul>
<li><strong>Method Name:</strong> AddAllRows</li>
<li><strong>Parameters:</strong> Items() As String</li>
<li><strong>Scope:</strong> Public</li>
</ul>
<ul>
<li><strong>Method Name:</strong> AddRow</li>
<li><strong>Parameters:</strong> Item As String</li>
<li><strong>Scope:</strong> Public</li>
</ul>
<p>Select the <code>AddAllRows</code> method and type the following code in the associated Code Editor:</p>
<pre>Var selectedItem As String = Me.SelectedRow
Var lastAddedItem As String = items(items.LastIndex).Trim.Titlecase

Var d As New Dictionary

Var s() As String = Me.Rows

For n As Integer = 0 To s.LastIndex

  d.Value(s(n)) = Me.RowTagAt(n)

Next

For Each item As String In items
  If Not d.HasKey(item) And item &lt;&gt; "" Then s.Add(item.Trim.Titlecase)
Next

s.Sort
Me.RemoveAllRows

// Calling the overridden superclass method.
Super.AddAllRows(s)

For n As Integer = 0 To s.LastIndex

  If d.HasKey(s(n)) Then
    Me.RowTagAt(n) = d.Value(s(n))
  End If

  If s(n) = selectedItem Then
    Me.mSelectedRowIndex = n
  End If

  If s(n) = lastAddedItem Then
    Me.mLastAddedRowIndex = n
  End If

Next</pre>
<p>Select next the <code>AddRow</code> method and type the following code in the associated Code Editor:</p>
<pre>If item = "" Then Return

item = item.Trim.Titlecase

If Not Me.HasMember(item) Then

  Var selectedItem As String = Me.SelectedRow

  Var d As New Dictionary

  Var s() As String = Me.rows

  For n As Integer = 0 To s.LastIndex

    d.Value(s(n)) = Me.RowTagAt(n)

  Next

  s.Add(item)
  s.Sort

  Me.RemoveAllRows
  Super.AddAllRows(s)

  // Let's restore the original rowtags to their new spot in the menu

  For n As Integer = 0 To s.LastIndex

    If d.HasKey(s(n)) Then
      Me.RowTagAt(n) = d.Value(s(n))
    End If

    If s(n) = selectedItem Then
      Me.mSelectedRowIndex = n
    End If

    If s(n) = item Then
      Me.mLastAddedRowIndex = n
    End If

  Next
End If</pre>
<p>We still need a last method to our class that will check if an item is already among the current entries for the menu. So, add it using the following values:</p>
<ul>
<li><strong>Method Name:</strong> HasMember</li>
<li><strong>Parameters:</strong> Item As String</li>
<li><strong>Return Type:</strong> Boolean</li>
<li><strong>Scope:</strong> Protected</li>
</ul>
<p>Type the following code in the associated Code Editor:</p>
<pre>Var b As Boolean

For Each s As String In Me.Rows
  If s = item Then
    b = True
    Exit For
  End If
Next

Return b</pre>
<h2>&nbsp;</h2>
<h2>6. Overriding Existing Properties</h2>
<p>Because we are sorting the entries in the menu, we also need to make sure that the <code>LastAddedRowIndex</code> and <code>SelectedRowIndex</code> properties are pointing to the right item and selected row index. That means that we need to override the current functionality of the base class.</p>
<p>In order to do that, select the <strong>Insert &gt; Property</strong> option from the menu with the following values in the associated Inspector Panel:</p>
<ul>
<li><strong>Name:</strong> LastAddedRowIndex</li>
<li><strong>Type:</strong> Integer</li>
<li><strong>Scope:</strong> Public</li>
</ul>
<p>With the new property still selected in the <code>MyComboBox</code> class, access the contextual menu and choose the <code>Convert to Computed Property</code> option. That action will add a <code>Get</code> and <code>Set</code> method under the property item, in addition of adding a new <code>mLastAddedRowIndex</code> property whose scope will be Private.</p>
<p>Let&#8217;s add the second Property using these values:</p>
<ul>
<li><strong>Name:</strong> SelectedRowIndex</li>
<li><strong>Type:</strong> Integer</li>
<li><strong>Scope:</strong> Public</li>
</ul>
<p>Once again, with the just added property still selected under the <code>MyComboBox</code> class in the Navigator, select the <code>Convert to Computed Property</code> option from the contextual menu. Then select the <code>Set</code> method under <code>SelectedRowIndex</code> and type the following code in the associated Code Editor:</p>
<pre>Var r() As String = Me.Rows

If value &gt; r.LastIndex Then Raise New OutOfBoundsException

If value &gt; 0 Then
  Me.Text = r(value)
Else
  value = -1
  Me.Text = ""
End If

mSelectedRowIndex = value
RaiseEvent Change</pre>
<p>This is the code that will be executed every time our code sets a new value to the property, so we need to make sure it is between the allowed range, raising a new <code>OutBoundsException</code> exception if it is beyond the limits of the available entries in the menu.</p>
<p>At the same time, if it is not a positive number that would mean that the we don&#8217;t want to select any entry, so we can set the text property of the ComboBox to an empty string and the inner <code>mSelectedRowIndex</code> value to -1.</p>
<h2>7. Putting it to Work</h2>
<p>Now that you have the ComboBox subclass ready to work, choose the <code>Window1</code> item in the Navigator in order to access its Layout Editor. Next, drag the <code>MyComboBox</code> item from the Navigator and drop it over the <code>Window1</code> in the Layout Editor. You can use the layout guides in order to keep it aligned with the window margins.</p>
<p>With the <code>MyCombobox1</code> item still selected in the Layout Editor, access its Panel Inspector in order to assign some initial values for its menu from the <strong>Appearance &gt; Initial Value</strong> section. For our example, you could enter <code>"One"</code>, <code>"Two"</code> and <code>"Three"</code> as the values in the associated editor. And you can&nbsp;also enable the autocomplete option for the control under <strong>Behavior &gt; Allow <a href="https://documentation.xojo.com/api/deprecated/combobox.html#combobox-allowautocomplete">Auto Complete</a></strong>.</p>
<p>Run the example app and observe how every new entry made by the user is added to those already available in the ComboBox menu, while keeping them sorted.</p>
<p>You can add more UI controls to Window1 in order to use the other methods and properties, or just <a href="https://bit.ly/2OS99hO">download the example project</a> and run it from the Xojo IDE. I hope you have found this tutorial helpful and that you can learn from it and adapt it to your needs. If you have questions about this post or the Xojo programming language you can find me at the <a href="https://forum.xojo.com/u/javier_menendez/summary">Xojo Forums</a> and on Twitter <a href="https://twitter.com/xojoes">@xojoES</a>.</p>


<p></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
