<?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>Beyond Excel: VBA and Database Manipulation &#187; ms query</title>
	<atom:link href="http://itknowledgeexchange.techtarget.com/beyond-excel/tag/ms-query/feed/" rel="self" type="application/rss+xml" />
	<link>http://itknowledgeexchange.techtarget.com/beyond-excel</link>
	<description>Everyone knows Excel is a powerful data manipulation engine – but data lives in databases.  Explore ways to exploit this natural synergy.</description>
	<lastBuildDate>Tue, 28 May 2013 18:23:13 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Getting User Names from Outlook Into Excel</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/getting-names-from-outlook-into-excel/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/getting-names-from-outlook-into-excel/#comments</comments>
		<pubDate>Thu, 07 Apr 2011 20:41:21 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[dynamic ranges]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[ListObjects]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[Outlook]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[Tables]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=991</guid>
		<description><![CDATA[The company president&#8217;s mother died.   The staff wanted to express their sympathy.  Cards were purchased and now we needed to make sure everyone got a chance to sign them.  We needed names on a check list to circulate with the cards so when someone signed, they could check their name and hand the card to someone whose name remained unchecked.  [...]]]></description>
				<content:encoded><![CDATA[<p><span style="font-family: 'Lucida Sans Unicode','sans-serif';color: black;font-size: 10pt">The company president&#8217;s mother died.   The staff wanted to express their sympathy.  Cards were purchased and now we needed to make sure everyone got a chance to sign them.  We needed names on a check list to circulate with the cards so when someone signed, they could check their name and hand the card to someone whose name remained unchecked.  So how do we make a list with everyone&#8217;s name and make sure no one is left off?</span></p>
<p><span style="font-family: 'Lucida Sans Unicode','sans-serif';color: black;font-size: 10pt">Everyone in our office has a computer.  Everyone <strong>uses</strong> Outlook.  All we needed was a quick way to get all <strong>user names</strong> into Excel to edit, format and print.  This is different from the contact list.  The contact list may, or may not have all users in it and it definitely has far more names than users. </span></p>
<p class="MsoNormal"><span style="font-family: Calibri"><span style="font-size: small">NOTE! Requires Excel 2003 or later because of ListObject</span></span></p>
<ol>
<li>
<div class="MsoNormal"><span style="font-family: Calibri"><span style="font-size: small">Open Excel and get to the VBE (<strong>Alt-F11</strong>)</span></span></div>
</li>
<li><span style="font-family: Calibri"><span style="font-size: small">Use <strong>Ctrl-R</strong> to bring up the <strong>Project Explorer</strong></span></span></li>
<li>
<div class="MsoNormal"><span style="font-family: Calibri"><span style="font-size: small">Double click <strong>ThisWorkbook</strong> to bring up its <strong>code window</strong></span></span></div>
</li>
<li>
<div class="MsoNormal"><span style="font-family: Calibri"><span style="font-size: small">Enter this code then run it.</span></span><span style="font-family: Consolas;color: green"><span style="font-size: small"><span style="font-family: Consolas"><span><span style="color: #000000"><span style="font-family: Consolas;color: green"><span style="font-size: small"><span style="font-family: Consolas"><span><span style="color: #000000"> </span></span></span></span></span></span></span></span></span></span></div>
</li>
</ol>
<p> </p>
<p><span style="font-family: Consolas;color: blue;font-size: 10pt">Sub</span><span style="font-family: Consolas;color: #0070c0;font-size: 10pt"> </span><span style="font-family: Consolas;font-size: 10pt">Network_Users()</span></p>
<p><span style="font-family: Consolas;color: green;font-size: 10pt">&#8216;<span>     </span>Date<span>   </span>Ini Modification</span><br />
<span style="font-family: Consolas;color: green;font-size: 10pt">&#8216;<span>   </span>04/10/11 CWH Initial Programming</span></p>
<p><span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">On Err GoTo </span>ErrHandler</span> </p>
<p><span style="font-family: Consolas;color: green;font-size: 10pt"><span>   </span>&#8216;To remove dependency on &#8220;Microsoft Outlook 14.0 Object Library&#8221; reference&#8230;</span><br />
<span style="font-family: Consolas;color: green;font-size: 10pt"><span>   </span>&#8216;<span>               </span>LateBinding<span>   </span>EarlyBinding<span>           </span>Purpose</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">Dim </span>olA<span>     </span><span style="color: blue">As</span> Object<span>       </span><span style="color: green">&#8216;Outlook.Application<span>    </span>Start Outlook (OL)</span></span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">Dim </span>olNS<span>    </span><span style="color: blue">As</span> Object<span>       </span><span style="color: green">&#8216;Namespace<span>              </span>OL identifiers context<br />
</span></span><span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">Dim </span>olAL<span>    </span><span style="color: blue">As</span> Object<span>       </span><span style="color: green">&#8216;AddressList<span>            </span>An OL address list</span></span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">Dim </span>olAE<span>    </span><span style="color: blue">As</span> Object<span>       </span><span style="color: green">&#8216;AddressEntry<span>           </span>An Address List entry</span></span></p>
<p><span style="font-family: Consolas;font-size: 10pt"><span> </span></span><span style="font-family: Consolas;font-size: 10pt"><span>   </span><span style="color: blue">Dim </span>lo<span>      </span><span style="color: blue">As </span>ListObject<span>   </span><span style="color: green">&#8216;An Excel Table</span></span></p>
<p><span style="font-family: Consolas;color: green;font-size: 10pt"><span>   </span>&#8216;Create a ListObject/Table in the spreadsheet<br />
</span><span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">With </span>ActiveSheet</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>        </span>.Cells.ClearContents<span>                    </span><span style="color: green">&#8216;Clear worksheet completely</span></span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>        </span>.Cells.ClearFormats<span>                     </span><span style="color: green">&#8216;Clear formats as well</span></span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>        </span>.Cells(4, 1) = &#8220;Names&#8221;<span>                  </span><span style="color: green">&#8216;Add a column heading</span></span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>        </span>.ListObjects.Add(1, .Cells(4, 1), , xlYes).Name = &#8220;Names&#8221;</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>        </span>Set lo = .ListObjects(&#8220;Names&#8221;)</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">End With</span></span><span style="font-family: Consolas;font-size: 10pt"> </span></p>
<p><span style="font-family: Consolas;color: green;font-size: 10pt"><span>   </span>&#8216;Open Outlook, set context, open &#8220;All Users&#8221; address list</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">Set</span> olA = CreateObject(&#8220;Outlook.Application&#8221;)</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">Set</span> olNS = olA.GetNamespace(&#8220;MAPI&#8221;)</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">Set</span> olAL = olNS.AddressLists(&#8220;All Users&#8221;)</span><span style="font-family: Consolas;font-size: 10pt"> </span></p>
<p><span style="font-family: Consolas;color: green;font-size: 10pt"><span>   </span>&#8216;Add each address entry name to the Excel Table</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">For Each </span>olAE <span style="color: blue">In </span>olAL.AddressEntries</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>        </span>lo.ListRows.Add.Range(1, 1) = olAE.Name</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">Next</span></span><span style="font-family: Consolas;font-size: 10pt"><span>    </span></span></p>
<p><span style="font-family: Consolas;color: green;font-size: 10pt"><span>   </span>&#8216;Format Results</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span>lo.HeaderRowRange.Style = ActiveWorkbook.Styles(&#8220;Heading 1&#8243;)</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span>lo.DataBodyRange.Style = ActiveWorkbook.Styles(&#8220;Output&#8221;)</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span>Range(&#8220;A5&#8243;).Select</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span>ActiveWindow.FreezePanes = <span style="color: blue">True</span></span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span>Cells.</span><span style="font-family: Consolas;font-size: 10pt">EntireColumn.AutoFit</span><span style="font-family: Consolas;font-size: 10pt"><span>    </span></span></p>
<p><span style="font-family: Consolas;color: green;font-size: 10pt"><span>   </span>&#8216;Do this ONLY if you want to close Outlook</span><br />
<span style="font-family: Consolas;color: green;font-size: 10pt"><span>   </span>&#8216;olA.Quit</span><span style="font-family: Consolas;font-size: 10pt"><span>    </span></span></p>
<p><span style="font-family: Consolas;font-size: 10pt">ErrHandler:</span><span style="font-family: Consolas;font-size: 10pt"><span>    </span></span></p>
<p><span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">If </span>Err.Number &lt;&gt; 0 <span style="color: blue">Then </span>MsgBox _</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>        </span>“ Network_Users &#8211; Error#&#8221; &amp; Err.Number &amp; vbCrLf &amp; _</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>        </span>Err.Description, vbCritical, &#8220;Error&#8221;, Err.HelpFile, Err.HelpContext</span><br />
<span style="font-family: Consolas;font-size: 10pt"><span>    </span><span style="color: blue">On Error GoTo </span>0</span><span style="font-family: Consolas;font-size: 10pt"><span>    </span></span></p>
<p><span style="font-family: Consolas;color: blue;font-size: 10pt">End Sub</span></p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/getting-names-from-outlook-into-excel/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Solving Dynamic Ranges with Tables/ListObjects</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/solving-dynamic-ranges-with-tableslistobjects/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/solving-dynamic-ranges-with-tableslistobjects/#comments</comments>
		<pubDate>Thu, 24 Feb 2011 23:53:44 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[dynamic ranges]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[ListObjects]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[Tables]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=976</guid>
		<description><![CDATA[Dynamic named ranges have been a subject of interest on Excel boards for sometime.  Lots of people want to know what&#8217;s the best way to create a named range that expands (or shrinks) according to the data entered, and can be used in formulas like VLOOKUP without change.  For some background on this subject see: Dynamic Ranges &#8211; Overcoming Shortcomings.  [...]]]></description>
				<content:encoded><![CDATA[<p>Dynamic named ranges have been a subject of interest on Excel boards for sometime.  Lots of people want to know what&#8217;s the best way to create a named range that expands (or shrinks) according to the data entered, and can be used in formulas like VLOOKUP without change.  For some background on this subject see: <a href="http://itknowledgeexchange.techtarget.com/beyond-excel/dynamic-named-ranges-in-excel-overcoming-shortcomings/">Dynamic Ranges &#8211; Overcoming Shortcomings</a>.  In that post I promised to talk about what I believe is truly, the one best way to handle this kind of thing, <a href="http://office.microsoft.com/en-us/excel-help/overview-of-excel-tables-HA010048546.aspx">Excel&#8217;s Tables</a>.</p>
<h3>Tables!</h3>
<p>In 2003, Excel introduced something called a &#8220;<a href="http://msdn.microsoft.com/en-us/library/aa174247(v=office.11).aspx">ListObject</a>&#8221; also known as a &#8221;Table&#8221;.  There are several features packed into Tables, but the main feature of importance in this discussion is their ability to grow or shrink dynamically.  Out of the box, a table is a dynamic named range.  So why agonize over what formula best creates one?</p>
<p>Creating tables is easy, simply select any cell within the desired range of data and press Ctrl-L (in Excel 2007 or 2010 you can also use Ctrl-T).  Excel will probably guess correctly what range you meant but gives you the opportunity to specify exactly what you want.  Whenever your selected cell is in a table Excel adds the <strong>Table Tools</strong> tab to its ribbon. There you can change the table&#8217;s name using the convenient &#8220;Table Name:&#8221; box in the upper left corner.</p>
<p>Unlike formula approaches, tables don&#8217;t mind other tables on a worksheet.  And Tables come with right click menu functions for adding/inserting/deleting rows/columns.  As you add rows or columns, the table automatically encompasses the new data, extends formats and formulas, and when rows are inserted, moves tables below to make room. </p>
<p>Tables are superior to named ranges in every way except one: they can&#8217;t be used as datasources.   That&#8217;s easily overcome.  Simply select the range you want to use as a datasource (that can be the entire table, just the data, a column&#8230;) and give it a name using the name box in the upper left corner of each worksheet, or using the name manager.  The new name is every bit as dynamic as the best dynamic range formula &#8211; without the formula.</p>
<h3>It&#8217;s Time to Move Ahead</h3>
<p>At the time of this blog post, I still meet Excel fans enthusiastic over dynamic ranges.  When asked &#8220;why not tables?&#8221; I usually get a blank stare.  Some point out tables don&#8217;t work with all versions of Excel.  True enough.  But it&#8217;s been almost a decade now since XL 2003 came out.  I&#8217;ve long since upgraded every user in the company I work for to Office 2003 or higher.  I&#8217;ll bet your company has too.  So put your favorite dynamic named range formula in a frame and hang it on the wall with other momentous from your past.  It&#8217;s time to move ahead with tables.</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/solving-dynamic-ranges-with-tableslistobjects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Animating Your Company&#8217;s Logo in Excel</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/animating-your-companys-logo-in-excel/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/animating-your-companys-logo-in-excel/#comments</comments>
		<pubDate>Thu, 27 Jan 2011 14:50:06 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=939</guid>
		<description><![CDATA[This post shows how to animate a logo in Excel using VBA.  (Click here to download code) Preview: [kml_flashembed movie="http://www.youtube.com/v/97tZL3TJhWs" width="480" height="292" wmode="transparent" /] Logos are an easy way to add a sense of professionalism to your work. Splash screens and logos are part of every software product purchased and should be part of every [...]]]></description>
				<content:encoded><![CDATA[<p>This post shows how to animate a logo in Excel using VBA.  <a title="Download Code Here" href="http://dl.dropbox.com/u/13737137/Animated_Logo.xls" target="_blank">(Click here to download code)</a></p>
<div style="text-align: center"><strong>Preview</strong>:</div>
<div style="text-align: center"><code>[kml_flashembed movie="http://www.youtube.com/v/97tZL3TJhWs" width="480" height="292" wmode="transparent" /]</code></div>
<p>Logos are an easy way to add a sense of professionalism to your work. Splash screens and logos are part of every software product purchased and should be part of every application you provide you customers. Besides, animating logos is fun. It entertains users and sets your work apart from the average Excel programmer.  I use them when the workbook first opens.  Here&#8217;s how it&#8217;s done.</p>
<p>Open a blank workbook. Rename the first tab “Data”. This will be the worksheet displayed when our workbook opens.  Now get a copy of your company’s logo. Your company’s website probably has one about the right size. Paste it onto the Data worksheet.  We need to name it “Logo”. To do that, select it, then use Alt-F11 to get to the Visual Basic Editor. Use Ctrl-G to display the Immediate Window. Type “Selection.Name = “Logo” and hit enter. Now we’re ready to code.</p>
<p>Use Ctrl-R to bring up the Project Explorer. Double click “ThisWorkBook.” That brings up the workbook’s code window.  Our first routine must run when the workbook opens so we will code it in the Workbook_Open event. This routine activates the worksheet we renamed “Data”, and passes our “Logo” shape to two routines. The first “Grows” the logo into view. The second spins it once.</p>
<pre><span style="color: #0000ff">Private Sub </span>Workbook_Open()
 
    Worksheets("Data").Activate
    ActiveSheet.Shapes("Logo").LockAspectRatio = False
    GrowShape ActiveSheet.Shapes("Logo"), 10
    SpinShape ActiveSheet.Shapes("Logo"), 10
           
<span style="color: #0000ff">End Sub</span></pre>
<p>The &#8220;Grow&#8221; routine expands any shape into view. It first turns off screen updating. This allows us to make changes behind the scenes and display the results when we’re ready. Next, the routine remembers the shape’s dimensions. Then the routine changes the shape’s size, displays it, freezes the screen, and loops back until finished. Before returning, the Grow routine makes sure the shape is exactly as we found it.</p>
<p>The Spin routine is nearly identical. It freezes the screen, remembers the shape’s original dimensions, then alters the shapes size in a loop that simulates the shape spinning around its Y axis. When finished, the routine restores the shape to its original size.</p>
<p>That’s all there is to animating a logo. </p>
<pre><span style="color: #0000ff">Function </span>GrowShape(<span style="color: #0000ff">ByRef</span> Shape <span style="color: #0000ff">As</span> Shape, Step <span style="color: #0000ff">As</span> Integer) <span style="color: #0000ff">As Boolean</span></pre>
<pre><span style="color: #008000">'   Description:Expands a shape into view</span></pre>
<pre><span style="color: #008000">'   Parameters: Shape       The shape to animate
'               Step        Larger #s animate faster</span></pre>
<pre><span style="color: #008000">'   Example:    GrowShape ActiveSheet.Shapes("Logo"), 10</span></pre>
<pre><span style="color: #008000">'   Note:       For best results, shape should be hidden before calling
'               this routine</span></pre>
<pre><span style="color: #008000">'     Date   Init Modification
'   01/10/11 CWH  Initial Programming</span></pre>
<pre>    <span style="color: #0000ff">Dim</span> lCenterX <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Shape's center X coordinate</span>
    <span style="color: #0000ff">Dim</span> lCenterY <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Shape's center Y coordiante</span>
    <span style="color: #0000ff">Dim</span> lWidth   <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Shape's width</span>
    <span style="color: #0000ff">Dim</span> lHeight  <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Shape's height</span>
    <span style="color: #0000ff">Dim</span> l        <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Generic Counter for the loop</span>
   
    Application.ScreenUpdating = <span style="color: #0000ff">False</span>
   
    With Shape
       <span style="color: #008000">'Remember shape's original dimensions</span>
        lCenterX = .Width / 2 + .Left
        lCenterY = .Height / 2 + .Top
        lWidth = .Width
        lHeight = .Height
       <span style="color: #008000">'Animation Loop</span>
        <span style="color: #0000ff">For</span> l = 0 <span style="color: #0000ff">To</span> lWidth <span style="color: #0000ff">Step</span> Step
            .Width = l
            .Height = l * lHeight / lWidth
            .Left = lCenterX - .Width / 2
            .Top = lCenterY - .Height / 2
            Shape.Visible = <span style="color: #0000ff">True</span>
            Application.ScreenUpdating = <span style="color: #0000ff">True</span>
            Application.ScreenUpdating = <span style="color: #0000ff">False</span>
        <span style="color: #0000ff">Next</span> l
       <span style="color: #008000">'Restore shape's original dimensions</span>
        .Width = lWidth
        .Height = lHeight
        .Left = lCenterX - .Width / 2
        .Top = lCenterY - .Height / 2
    <span style="color: #0000ff">End With</span>
   
    Application.ScreenUpdating = <span style="color: #0000ff">True</span></pre>
<pre><span style="color: #0000ff">End Function</span></pre>
<pre><span style="color: #0000ff"> </span></pre>
<pre><span style="color: #0000ff">Function </span>SpinShape(<span style="color: #0000ff">ByRef</span> Shape <span style="color: #0000ff">As</span> Shape, Step <span style="color: #0000ff">As</span> <span style="color: #0000ff">Integer</span>) <span style="color: #0000ff">As Boolean</span></pre>
<pre><span style="color: #008000">'   Description:Expands a shape into view</span></pre>
<pre><span style="color: #008000">'   Parameters: Shape       The shape to animate
'               Step        Larger #s animate faster
'                           Steps should divide 90 evenly</span></pre>
<pre><span style="color: #008000">'   Example:    SpinShape ActiveSheet.Shapes("Logo"), 10</span></pre>
<pre><span style="color: #008000">'     Date   Init Modification
'   01/10/11 CWH  Initial Programming
</span>   
    <span style="color: #0000ff">Const </span>Pi = 3.14159265358979
    Dim sng01 <span style="color: #0000ff">As Single</span>     '1 Degree in Radians
        sng01 = Pi / 180
       
    <span style="color: #0000ff">Dim</span> lCenterX <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Shape's center X coordinate</span>
    <span style="color: #0000ff">Dim</span> lCenterY <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Shape's center Y coordiante</span>
    <span style="color: #0000ff">Dim</span> lWidth   <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Shape's width</span>
    <span style="color: #0000ff">Dim</span> lHeight  <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Shape's height</span>
    <span style="color: #0000ff">Dim</span> l        <span style="color: #0000ff">As Long</span>    <span style="color: #008000">'Generic Counter for the loop</span>
   
    Application.ScreenUpdating = <span style="color: #0000ff">False</span>
   
    <span style="color: #0000ff">With</span> Shape
        .LockAspectRatio = <span style="color: #0000ff">False</span>
       <span style="color: #008000">'Remember shape's original dimensions</span>
        lCenterX = .Width / 2 + .Left
        lCenterY = .Height / 2 + .Top
        lWidth = .Width
        lHeight = .Height
       <span style="color: #008000">'Animation Loop</span>
        <span style="color: #0000ff">For</span> l = 0 <span style="color: #0000ff">To</span> 360 <span style="color: #0000ff">Step</span> Step
            .Width = lWidth * Abs(Cos(l * sng01))
            .Left = lCenterX - .Width / 2
            If l = 90 Or l = 270 Then .Flip msoFlipHorizontal
            Shape.Visible = <span style="color: #0000ff">True</span>
            Application.ScreenUpdating = True
            Application.ScreenUpdating = <span style="color: #0000ff">False</span>
        <span style="color: #0000ff">Next</span> l
       <span style="color: #008000">'Restore shape's original dimensions</span>
        .Width = lWidth
        .Height = lHeight
        .Left = lCenterX - .Width / 2
        .Top = lCenterY - .Height / 2
    <span style="color: #0000ff">End With</span>
   
    Application.ScreenUpdating = <span style="color: #0000ff">True</span></pre>
<pre><span style="color: #0000ff">End Function</span></pre>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/animating-your-companys-logo-in-excel/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Debug Your Data with Conditional Formatting</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/debug-your-data-with-conditional-formatting/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/debug-your-data-with-conditional-formatting/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 22:28:15 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=914</guid>
		<description><![CDATA[(By Guest blogger Yoav Ezer) Many times when a workbook is crammed full of numbers, your data can be difficult to read. This is bad enough when you are sure the data is correct, but If you are supplied a spreadsheet that contains potential errors you really want to be able to detect them so [...]]]></description>
				<content:encoded><![CDATA[<p>(By Guest blogger Yoav Ezer)</p>
<p>Many times when a workbook is crammed full of numbers, your data can be difficult to read. This is bad enough when you are sure the data is correct, but If you are supplied a spreadsheet that contains potential errors you really want to be able to detect them so they can be fixed.</p>
<p>A common error in inputting is where your work contains duplicate records. There are a couple of ways we can delete duplicates, but what if you only want to see them rather than delete them? Here is when conditional formatting can help. With this little technique you can make the duplicates jump out at you!</p>
<p>Check out this screen grab below.</p>
<p><a href="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/139/files/2011/01/duplicate-invoices.png"><img class="aligncenter size-medium wp-image-928" src="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/139/files/2011/01/duplicate-invoices.png" alt="" width="332" height="345" /></a></p>
<p>See how the duplicate rows are highlighted? In this <a href="http://dl.dropbox.com/u/13737137/highlight-duplicate.xlsx" target="_blank">sheet</a>, the highlighting helps us indentify duplicate invoices.</p>
<h2>The Solution</h2>
<p>Here is how it was done.<a href="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/139/files/2011/01/normally-would.gif"><img class="size-full wp-image-930 alignright" src="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/139/files/2011/01/normally-would.gif" alt="" width="97" height="83" /></a></p>
<p>First you need to go to the conditional formatting dialog as you normally would.</p>
<p>Then in the &#8220;Edit the Rule Description&#8221; box:</p>
<p><a href="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/139/files/2011/01/supply-in-a-moment.jpg"><img class="aligncenter size-medium wp-image-929" src="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/139/files/2011/01/supply-in-a-moment.jpg" alt="" width="847" height="489" /></a></p>
<p>Enter this formula:</p>
<pre>=SUMPRODUCT(($B2=$B$2:$B$16)*($A2=$A$2:$A$16)*($C2=$C$2:$C$16))&gt;1</pre>
<p>The formula might look complicated, and it kind of is. It relies on a function you might not have seen much called SUMPRODUCT. If you are curious about the function, <a href="http://www.excelhero.com/blog/2010/01/the-venerable-sumproduct.html">this article</a> is a great introduction to the topic.</p>
<p>In this formula, SUMPRODUCT will return the sum of rows from rows 2 through 16 where columns A,B and C are equal to the current row. If the result is greater than 1 then the format is implemented on that row.</p>
<h2>Summary</h2>
<p>As you can see, when you are given a spreadsheet containing problems, you don&#8217;t always want to nuke error rows, some times you need to know about them so you can deal with the issues at source. Conditional formatting can raise your awareness without changing the content of your spreadsheet. Give it a try!</p>
<h2>About the author</h2>
<p>Yoav Ezer co-authors the technology and productivity blog Codswallop. He is also the CEO of a company that produces <a href="http://www.cogniview.com/pdf2xl.php">PDF to Excel</a> conversion software.</p>
<p>For more Excel tips from Yoav, join him on <a href="http://www.facebook.com/Cogniview.Codswallop">Facebook</a> or <a href="http://twitter.com/cogniview">Twitter</a></p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/debug-your-data-with-conditional-formatting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dynamic Named Ranges in Excel &#8211; Overcoming Shortcomings</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/dynamic-named-ranges-in-excel-overcoming-shortcomings/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/dynamic-named-ranges-in-excel-overcoming-shortcomings/#comments</comments>
		<pubDate>Thu, 13 Jan 2011 19:00:57 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[dynamic named ranges]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=916</guid>
		<description><![CDATA[A couple of months ago, Guest blogger Yoav Ezer posted a piece including the concept of Dynamic Named Ranges (see Strategies for Speeding Spreadsheets).  Dynamic Named Ranges are ranges within Excel that have been named using &#8220;Name Manager&#8221; or &#8220;Define Name&#8221; and that can be expanded or contracted without having to change what the name refers [...]]]></description>
				<content:encoded><![CDATA[<p>A couple of months ago, Guest blogger Yoav Ezer posted a piece including the concept of Dynamic Named Ranges (see <a href="http://itknowledgeexchange.techtarget.com/beyond-excel/strategies-for-speeding-spreadsheets/" target="_blank">Strategies for Speeding Spreadsheets</a>).  Dynamic Named Ranges are ranges within Excel that have been named using &#8220;Name Manager&#8221; or &#8220;Define Name&#8221; and that can be expanded or contracted without having to change what the name refers to.  Once named, you can use the range&#8217;s name in formulas and data validation instead of the common &#8220;$A$1:$D$50&#8243; cell references.  This makes your formulas simpler to read.  And with the dynamic nature of Dynamic Named Ranges, you don&#8217;t have to change the formula when rows of data are added. </p>
<p>Here is a typical formula that could be added in Name Manger for a named range that starts in cell $A$1, has two columns, and can grow to as many rows as entries:</p>
<pre>=OFFSET($A$1,0,0,COUNTA($A:$A),2)</pre>
<p>Translating this formula for us humans, it says:</p>
<ul>
<li>From $A$1</li>
<li>Go down 0 rows</li>
<li>Go right 0 columns</li>
<li>Expand to down by the number of cells in column A that contain characters</li>
<li>Expand to the right 2 columns </li>
</ul>
<h3>Shortcommings</h3>
<p>I &#8221;Googled&#8221; the subject and found many articles on Dynamic Named Ranges.  Obviously there is a lot of interest and many examples of their use; however, in every article I read, including those in Microsoft&#8217;s MSDN, I kept coming across the same shortcomings:</p>
<ul>
<li>If your range contains empty cells, especially in the first column, you&#8217;re likely to get bad results</li>
<li>If your range contains spaces after the last row, you&#8217;re likely to get bad results.</li>
<li>If your range contains columns of different lengths, the suggested approaches are very cumbersome.</li>
<li>If your range starts somewhere other than row 1, the formula gets more complex.</li>
<li>If another range exists below or to the right of the first named range, you&#8217;re likely to get bad results.</li>
</ul>
<p>Most of these limitations are because almost everyone seems to want to use COUNT or COUNTA to determine how many rows should be contained in the range.  I found <a href="http://www.ozgrid.com/Excel/advanced-dynamic-ranges.htm" target="_blank">one blogger</a> who used MATCH instead of COUNT.  This had the advantage of skipping over empty cells, but still worked only for numbers, or for characters, but not for both (unless you double the formula and the MAX function). </p>
<pre>=OFFSET($A$1,0,0,MATCH("",$A:$A,-1),2)		'Finds last character cell</pre>
<pre>=OFFSET($A$1,0,0,MATCH(1E+306,$A:$A,1),2)	'Finds last numeric cell</pre>
<h3>Seeking A Better Approach</h3>
<p>The above approaches all work.  But no one of them works for all circumstances by itself.  And none of the approaches dealt with the stray space after the table&#8217;s last row.  That&#8217;s not good enough.  I want one compact formula that requires as little thought as possble that works for as many situations as possible.  In researching and experimenting, I accidently stumbled on a quirk regarding formulas stored in names that makes overcoming these problems much simpler.  Chip explains this quirk very well.</p>
<blockquote>
<p class="sectionheader"><a href="http://www.cpearson.com/excel/DefinedNames.aspx" target="_blank">Defined Name Formulas And Array Formulas</a> by Charles H. Pearson</p>
<p class="main"><em>If you use a formula in a Defined Name, that formula is evaluated as if it were an array formula. There is no way to force a formula in a Defined Name to be evaluated as a non-array formula.</em></p>
</blockquote>
<p>Brilliant!  With this bit of knowledge, we can use logical functions that are insensitive to the type of data used (Numbers vs Characters).  Here is an array formula that finds the last row in column A containing anything at all (NOTE! The curly brackets are the result of Shift-Ctrl-Enter.  For more information on how to enter array formulas see <a href="http://www.cpearson.com/excel/ArrayFormulas.aspx" target="_blank">Array Formulas</a> by Charles H. Pearson).</p>
<pre>{=MAX(IF($A:$A&lt;&gt;"", ROW($A:$A),0))}</pre>
<p>Building on this, we can find the last row within the first four columns that contains anything at all, regardless of which column is longest.</p>
<pre>{=MAX(IF($A:$D&lt;&gt;"", ROW($A:$A),0))}</pre>
<p>Because logical operators in Excel return 0 for FALSE and 1 for TRUE, we can shorten the formula up a bit, if that&#8217;s your preference.</p>
<pre>{=MAX(($A:$D&lt;&gt;"")*ROW($A:$A))}</pre>
<p>But one problem remains.  In my opinion, entries containing only spaces are the same as totally empty cells and as I said before, the above formula finds cells that contain anything at all, including those with just spaces.  No worries, this is simple enough to overcome by trimming cells.</p>
<pre>{=MAX((TRIM($A:$D)&lt;&gt;"")*ROW($A:$A))}</pre>
<p>This formula finds the last cell that contains anything other than just spaces.  It doesn&#8217;t matter if any of the cells in between are empty.  It doesn&#8217;t matter if any of the cells are numbers or characters.  It doesn&#8217;t matter which column is longest. To put it all together, you need to adjust for one more thing, the starting row.  I often want my ranges to start in row 4 with totals in row 2.  So if you want your range to start somewhere other than row 1, you need to subtract the starting row number and add 1 back for good measure.   Here is the final formula that you would enter into Name Manager for a range that starts in $A:$4 and has 5 columns (NOTE! Name Manager does not need the curly brackets since it treats ALL formulas as array formulas no matter what).</p>
<pre>=OFFSET($A$4,0,0,MAX((TRIM($A:$E)&lt;&gt;"")*(ROW($A:$A)))-3, 5) </pre>
<p>This works.  It&#8217;s also slow.  It&#8217;s cumbersome.   </p>
<h3>Solving with VBA</h3>
<p>Formula approaches just don&#8217;t work well. There are just too many ways they can fail and too many limitations.  So I looked to VBA.  VBA has always had a very simple and elegant way of dealing with dynamic ranges:</p>
<pre>Set DynamicRange = Range("A4").CurrentRegion</pre>
<p><strong>CurrentRegion</strong> finds all adjacent non-empty cells.  So if &#8220;A4&#8243; is anywhere inside a table, <strong>CurrentRegion</strong> will identify the entire table.  One minor problem is it will also pick up any adjacent cells with stray spaces.  But a bigger problem is that when used in a UDF (User Defined Function intended to be used within an Excel formula), <strong>CurrentRegion</strong> returns only one cell. </p>
<p>A different approach (copied from Andy Pope) can be encapsulated into a VBA routine and used in a UDF context:</p>
<pre>Set DynamicRange = Range("A4").Resize(Range("A4").End(xlDown).Row - 1, _
                   Range("A4").End(xlToRight).column - 1)</pre>
<p><strong>End() </strong>works as long as there is more than one row and column in the range.  If, for example, only one row is in the table, the <strong>End()</strong> method will find the last cell in the worksheet or the next list.</p>
<h3>The &#8220;One Best Way&#8221;</h3>
<p>Going through this exercise was interesting, but utlimately, neither VBA, nor complex formulas are required to create dynamic ranges without ANY of the shortcommings of either.  We&#8217;ll discuss that after another great Excel tip from Yoav Ezer.</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/dynamic-named-ranges-in-excel-overcoming-shortcomings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Chart Drill Down</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/chart-drill-down/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/chart-drill-down/#comments</comments>
		<pubDate>Mon, 04 Oct 2010 17:58:58 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=897</guid>
		<description><![CDATA[PivotChart Drill DownThis seems so basic to me that I was not surprised Googling &#8220;Drilldown Excel Chart&#8221; shows lots of interest out there.  But the implementation is so simple that I was very surprised Googling &#8220;Drill Down Excel Chart&#8221; yielded almost no good suggestions.  That ends today. Preview: [kml_flashembed movie="http://www.youtube.com/v/-Uu2WqDxLdk" width="480" height="292" wmode="transparent" /] For beginners: What is &#8221;Drilldown?&#8221;  Drilldown is displaying [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.youtube.com/watch?v=fngdFJAJAnc">PivotChart Drill Down</a>This seems so basic to me that I was not surprised Googling &#8220;Drilldown Excel Chart&#8221; shows lots of interest out there.  But the implementation is so simple that I was very surprised Googling &#8220;Drill Down Excel Chart&#8221; yielded almost no good suggestions.  That ends today.</p>
<div style="text-align: center"><strong>Preview</strong>:</div>
<div style="text-align: center"><code>[kml_flashembed movie="http://www.youtube.com/v/-Uu2WqDxLdk" width="480" height="292" wmode="transparent" /]</code></div>
<p><strong>For beginners: What is &#8221;Drilldown?&#8221; <br />
</strong>Drilldown is displaying underlying details for a total.  This is important because we hope charts and summaries show something we didn&#8217;t know and/or expect.  When that happens, we want to know why.  Displaying what makes up a total helps answer that question.</p>
<p><strong>Doesn&#8217;t Excel Support Drilldown Automatically?<br />
</strong>In PivotTables and Outline Reports &#8211; yes.  You can double click any calculated number in these Excel objects and Excel displays the associated rows from their source data range.  But if you double click on a Chart/Graph element, the &#8220;Format Data Point&#8221; dialog box appears.  That&#8217;s not what my users want.  The good news, though, is the very same mechanism that reveals detail beneath PivotTables makes coding drilldown for PivotCharts a snap.</p>
<p><strong>What are PivotCharts?</strong><br />
A PivotChart is a chart over a PivotTable.  In the templates provided in this blog, we use PivotTables to summarize data in our extracted rows.  PivotTables are extremely flexible and allow the user to slice and dice data in many, many useful ways.  The only draw back to PivotTables is they show numbers, not graphs.  This is easily overcome by simply creating a chart over the PivotTable.  Charts made from PivotTable data, as opposed to simple rows of data, also allow users to slice and dice the underlying data just like the user can with a PivotTable.  The only drawback to the PivotChart is that it lacks Drill Down. </p>
<p><strong>Adding Drilldown to PivotTable Charts</strong><br />
This &#8220;trick&#8221; only works with PivotCharts because it relies on the PivotTable&#8217;s <strong>ShowDetail</strong> property.  As mentioned before, you can double click on any calculated result in a PivotTable and it will automatically show the associated detail rows.  If you start the Macro Recorder, double click on a PivotTable cell, stop the recorder, and then view the recorded code, you&#8217;ll see something like this:</p>
<pre>Range("B9").Select
Selection.ShowDetail = <span style="color: #0000ff">True</span></pre>
<p>&#8230;where &#8220;B9&#8243; is the cell you double clicked.  The <strong>Selection.ShowDetail = True</strong> is what causes the detail to display.  Now when you create a PivotChart from a PivotTable, each PivotTable cell becomes a chart element.  So what we have to do is figure out which chart element the user double clicked and which PivotTable cell that represents.  Then all that&#8217;s left to do is use that cell&#8217;s <strong>ShowDetail</strong> property to display the data.  As it turns out, this is almost easier done than said.</p>
<p><strong>Determining Which Chart Element was Clicked</strong><br />
Excel provides a simple routine that makes this easy - <strong>ActiveChart.GetChartElement</strong>.  <strong>ActiveChart.GetChartElement</strong> is a method attached to every chart in Excel.  You pass to it the mouse pointer&#8217;s X and Y coordinates and it returns the Chart Element Type and two of that Chart Element Type&#8217;s properties.  Chart Element Types can be the chart&#8217;s Title, Legend, Axis, &#8230; or a Graph Element.  We are only interested in Graph Elements such as a slice in a Pie Chart, a line in a Line Chart, a bar in a Bar Chart, etc.  So if <strong>ActiveChart.GetChartElement</strong> returns anything other than a Chart Element Type of 3 (Graph Element), we know to ignore things and move on.  On the other hand, if the user clicked a Graph Element, we want to show the detail.  When Chart Element Type is 3, Arg1 is the associated PivotTable row and Arg2 is the column.  So to show the detail beneath we use:</p>
<pre>ActiveChart.PivotLayout.PivotTable.DataBodyRange. _
            Cells(Arg2, Arg1).ShowDetail = <span style="color: #0000ff">True </span></pre>
<p><strong>Capturing Chart Double Click and Mouse Pointer&#8217;s X and Y</strong><br />
Every Chart also has a <strong>Chart_MouseUp</strong> event.  <strong>Chart_MouseUp</strong> fires whenever the user clicks (and releases) the mouse on a chart.  Excel also passes a few properties to this event.  Two are important to us: X and Y.</p>
<p>We now have all of the pieces to the puzzle.  All that&#8217;s left to do is put it together.  Place this code in the Chart Sheet object:</p>
<p> </p>
<pre><span style="color: #0000ff">Private Sub </span>Chart_MouseUp(<span style="color: #0000ff">ByVal</span> Button <span style="color: #0000ff">As Long</span>, <span style="color: #0000ff">ByVal</span> Shift <span style="color: #0000ff">As Long</span>, _
                          <span style="color: #0000ff">ByVal</span> x <span style="color: #0000ff">As Long</span>, <span style="color: #0000ff">ByVal</span> y <span style="color: #0000ff">As Long</span>)</pre>
<pre><span style="color: #009900">'   Description:Drill Down into Pivot Chart's data</span></pre>
<pre><span style="color: #009900">'   Parameters: Button  Mouse botton that was released
'               Shift   State of SHIFT, CTRL, and ALT keys
'               x       Mouse pointer X coordinate within Chart
'               y       Mouse pointer Y coordinate within Chart</span></pre>
<pre><span style="color: #009900">'   Example:    *none - This is an event handler</span></pre>
<pre><span style="color: #009900">'     Date   Init Modification
'   10/04/10 CWH  Initial Programming </span></pre>
<pre>    <span style="color: #0000ff">On Error GoTo</span> ErrHandler
   
    <span style="color: #0000ff">Dim</span> ElementID <span style="color: #0000ff">As Long
</span>    <span style="color: #0000ff">Dim</span> Arg1 <span style="color: #0000ff">As Long
</span>    <span style="color: #0000ff">Dim</span> Arg2 <span style="color: #0000ff">As Long</span>
       
<span style="color: #009900">'   Pass: x, y. Receive: ElementID, Arg1, Arg2
</span>    ActiveChart.GetChartElement x, y, ElementID, Arg1, Arg2
   
<span style="color: #009900">'   If data element clicked, show detail
</span>    <span style="color: #0000ff">If</span> ElementID = 3 <span style="color: #0000ff">Then</span>
        ActiveChart.PivotLayout.PivotTable.DataBodyRange. _
            Cells(Arg2, Arg1).ShowDetail = <span style="color: #0000ff">True</span>
        ActiveSheet.Cells(2, 2).Select
        ActiveWindow.FreezePanes = <span style="color: #0000ff">True</span>
    <span style="color: #0000ff">End If</span></pre>
<pre>ErrHandler:
   
    <span style="color: #0000ff">If</span> Err.Number &lt;&gt; 0 <span style="color: #0000ff">Then</span> MsgBox _
        "Chart_MouseUp - Error#" &amp; Err.Number &amp; vbCrLf &amp; _
        Err.Description, vbCritical, "Error", Err.HelpFile, Err.HelpContext
    <span style="color: #0000ff">On Error Resume Next</span>
    <span style="color: #0000ff">On Error GoTo 0
</span>   
<span style="color: #0000ff">End Sub</span></pre>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/chart-drill-down/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Controlling the Cursor: Find_Unlocked_Cell</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/controlling-the-cursor-find_unlocked_cell/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/controlling-the-cursor-find_unlocked_cell/#comments</comments>
		<pubDate>Fri, 24 Sep 2010 00:45:58 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=893</guid>
		<description><![CDATA[Today&#8217;s little routine was repeated all throughout Position_Cursor_In_Data (See previous post).  It&#8217;s a simple little routine with not much to talk about except one little trick: v = Intersect(ActiveWindow.VisibleRange, Selection) If you look closely at this routine, the variable &#8220;v&#8221; is never used.  So why is it there?  Answer: To cause an error.  Purposefully causing an [...]]]></description>
				<content:encoded><![CDATA[<p>Today&#8217;s little routine was repeated all throughout <strong>Position_Cursor_In_Data</strong> (See previous post).  It&#8217;s a simple little routine with not much to talk about except one little trick:</p>
<pre style="padding-left: 30px">v = Intersect(ActiveWindow.VisibleRange, Selection)</pre>
<p>If you look closely at this routine, the variable &#8220;v&#8221; is never used.  So why is it there?  Answer: To cause an error.  Purposefully causing an error may sound crazy.  Well, there may be a better way, but it&#8217;s not crazy.  If the newly selected cell happens to be outside the visible window, attempting to intersect the selection with the visible window will fail causing error #91.  If that happens, we want to shift the window to display the selection with a call to <strong>Position_Window_to_Cursor</strong>.</p>
<p>Here is the code.</p>
<p> </p>
<pre><span style="color: #0000ff">Function</span> Find_UnLocked_Cell(lRowFrom <span style="color: #0000ff">As Long</span>, lRowTo <span style="color: #0000ff">As Long</span>, _
                            lColFrom <span style="color: #0000ff">As Long</span>, lColTo <span style="color: #0000ff">As Long</span>, _
                            lStep <span style="color: #0000ff">As Long</span>) <span style="color: #0000ff">As Boolean</span></pre>
<pre><span style="color: #32cd32">'   Description:Find the next unlocked cell</span></pre>
<pre><span style="color: #32cd32">'   Parameters: lRowFrom        Starting Row
'               lRowTo          Ending Row
'               lColFrom        Starting Column
'               lColTo          Ending Column
'               lStep           Direction (-1=backward)</span></pre>
<pre><span style="color: #32cd32">'   Example:    bFound = Find_UnLocked_Cell(Selection.Row, Selection.Row, _
'                                           Selection.Column + 1, _
                                            Range("Data").Columns.Count, 1)</span></pre>
<pre><span style="color: #32cd32">'     Date   Init Modification
'   01/12/06 CWH  Initial Programming</span></pre>
<pre>    <span style="color: #0000ff">On Error GoTo </span>ErrHandler    <span style="color: #32cd32">'
</span>    Find_UnLocked_Cell <span style="color: #0000ff">=</span> <span style="color: #0000ff">False</span>  <span style="color: #339966"><span style="color: #32cd32">'Assume the Worst</span>
</span>   
    <span style="color: #0000ff">Dim</span> lRow <span style="color: #0000ff">As Long</span>
    <span style="color: #0000ff">Dim</span> lCol <span style="color: #0000ff">As Long</span>
    <span style="color: #0000ff">Dim</span> v <span style="color: #0000ff">As Variant</span>
   
    <span style="color: #0000ff">For</span> lRow = lRowFrom <span style="color: #0000ff">To</span> lRowTo <span style="color: #0000ff">Step</span> lStep
        <span style="color: #0000ff">For</span> lCol = lColFrom <span style="color: #0000ff">To</span> lColTo <span style="color: #0000ff">Step</span> lStep
            <span style="color: #0000ff">If</span> Cells(lRow, lCol).Interior.Color &lt;&gt; CellLocked <span style="color: #0000ff">Then</span>
                Cells(lRow, lCol).Select
                Find_UnLocked_Cell = <span style="color: #0000ff">True</span>
                v = Intersect(ActiveWindow.VisibleRange, Selection)
                <span style="color: #0000ff">Exit Function</span>
            <span style="color: #0000ff">End If</span>
        <span style="color: #0000ff">Next</span> lCol
    <span style="color: #0000ff">Next</span> lRow</pre>
<pre>ErrHandler:
   
    <span style="color: #0000ff">If</span> Err.Number = 91 <span style="color: #0000ff">Then</span>
        Position_Window_to_Cursor Selection
    <span style="color: #0000ff">ElseIf</span> Err.Number &lt;&gt; 0 <span style="color: #0000ff">Then</span> _
        MsgBox _
        "Find_UnLocked_Cell - Error#" &amp; Err.Number &amp; vbCrLf &amp; Err.Description, _
        vbCritical, "Error", Err.HelpFile, Err.HelpContext
    <span style="color: #0000ff">End If</span>
    <span style="color: #0000ff">On Error GoTo</span> 0</pre>
<pre><span style="color: #0000ff">End Function</span></pre>
<pre> </pre>
<pre> </pre>
<pre><span style="color: #0000ff">Function</span> Position_Window_to_Cursor(rngCursor <span style="color: #0000ff">As Range</span>) <span style="color: #0000ff">As Boolean</span></pre>
<pre><span style="color: #32cd32">'   Description:Positions the window/pane so the cursor is visible</span></pre>
<pre><span style="color: #32cd32">'   Parameters: rngCursor   The cursor's cell/range</span></pre>
<pre><span style="color: #32cd32">'   Example:    bResult = Position_Window_to_Cursor(Selection)</span></pre>
<pre><span style="color: #32cd32">'     Date   Init Modification
'   12/14/09 CWH  Initial Programming</span></pre>
<pre>   <span style="color: #0000ff"> On Error GoTo</span> ErrHandler
    Position_Window_to_Cursor = Failure  <span style="color: #32cd32">'Assume the Worst</span>
   
    <span style="color: #0000ff">Dim</span> iPaneRow <span style="color: #0000ff">As Integer</span>
    <span style="color: #0000ff">Dim</span> iPaneCol <span style="color: #0000ff">As Integer</span>
    <span style="color: #0000ff">Dim</span> lRow <span style="color: #0000ff">As Long</span>
    <span style="color: #0000ff">Dim</span> lCol <span style="color: #0000ff">As Long</span>
       
    lRow = rngCursor.Row
    lCol = rngCursor.Column
   
    <span style="color: #0000ff">With</span> ActiveWindow
   
        <span style="color: #0000ff">If</span> lRow &gt; .SplitRow + 1 <span style="color: #0000ff">Then</span>
            iPaneRow = .Panes.Count
        <span style="color: #0000ff">Else</span>
            iPaneRow = 1
        <span style="color: #0000ff">End If</span>
        <span style="color: #0000ff">If</span> lCol &gt; .SplitColumn + 1 <span style="color: #0000ff">Then</span>
            iPaneCol = .Panes.Count
        <span style="color: #0000ff">Else</span>
            iPaneCol = 1
        <span style="color: #0000ff">End If
</span>       
        lRow = rngCursor.Row - _
               .Panes(iPaneRow).VisibleRange.Rows.Count + 2
        <span style="color: #0000ff">If</span> lRow &lt;= .SplitRow <span style="color: #0000ff">Then</span> lRow = .SplitRow + 1
        .Panes(iPaneRow).ScrollRow = lRow
       
        lCol = rngCursor.Column - _
               .Panes(iPaneCol).VisibleRange.Columns.Count + 2
        <span style="color: #0000ff">If</span> lCol &lt;= .SplitColumn <span style="color: #0000ff">Then</span> _
            lCol = .SplitColumn + 1
        .Panes(iPaneCol).ScrollColumn = lCol
   
    <span style="color: #0000ff">End With</span>
   
    Position_Window_to_Cursor = Success
   </pre>
<pre>ErrHandler:
   
    <span style="color: #0000ff">If</span> Err.Number &lt;&gt; 0 <span style="color: #0000ff">Then</span> MsgBox _
        "Position_Window_to_Cursor - Error#" &amp; Err.Number &amp; vbCrLf &amp; _
        Err.Description, vbCritical, "Error", Err.HelpFile, Err.HelpContext
    <span style="color: #0000ff">On Error GoTo</span> 0</pre>
<pre><span style="color: #0000ff">End Function</span></pre>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/controlling-the-cursor-find_unlocked_cell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Controlling the Cursor: Position_Curosr_In_Data</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/controlling-the-cursor-position_curosr_in_data/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/controlling-the-cursor-position_curosr_in_data/#comments</comments>
		<pubDate>Wed, 15 Sep 2010 01:02:28 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=888</guid>
		<description><![CDATA[The last few posts covered Worksheet_Change and Worksheet_SelectionChange events.  Both rely on a function called Position_Cursor_In_Data.  Position_Cursor_In_Data&#8216;s Job is to jump over &#8216;locked&#8217; cells and place the cursor in the next &#8216;unlocked&#8217; cell.  This prevents the user from inadvertently changing things that won&#8217;t get updated, or in other words, wasting their time.  Since the purpose [...]]]></description>
				<content:encoded><![CDATA[<p>The last few posts covered <strong>Worksheet_Change</strong> and <strong><span style="font-size: x-small">Worksheet_SelectionChange</span></strong> events.  Both rely on a function called <strong>Position_Cursor_In_Data</strong>.  <strong>Position_Cursor_In_Data</strong>&#8216;s<strong> </strong>Job is to jump over &#8216;locked&#8217; cells and place the cursor in the next &#8216;unlocked&#8217; cell.  This prevents the user from inadvertently changing things that won&#8217;t get updated, or in other words, wasting their time. </p>
<p>Since the purpose of the routine is to jump over &#8216;locked&#8217; cells, the routine first checks to see if the cursor has moved into a &#8216;locked&#8217; cell.  If the cursor is in an &#8216;unlocked&#8217; cell there is nothing for the routine to do and so, it ends (exits).</p>
<p>Another excuse for the routine to end is if the user has selected a group of cells.  This may be a prelude to a copy or paste command.  I want to facilitate copy/paste commands so if more than one cell is selected, this routine doesn&#8217;t interfere.</p>
<p>There is one last excuse for this routine to end itself and that is if the user used the mouse to navigate to a &#8216;locked&#8217; cell.  If the user really wants to position the cursor in a single &#8216;locked&#8217; cell, it may also be for the purpose of copy/paste.  It could also be because the user really doesn&#8217;t know what they&#8217;re doing.  That&#8217;s okay.  Remember that If the user tries to change &#8216;locked&#8217; cells <strong>Worksheet_Change</strong> will &#8216;undo&#8217; their change and restore &#8217;locked&#8217; cell values.  Neat huh?</p>
<p>So the user has pressed a key and ended up in a &#8216;locked&#8217; cell.  The key to knowing where to jump to is in knowing which key the user pressed.  If they pressed RIGHT, TAB, ENTER, DOWN, or PAGEDOWN the system assumes they want the next &#8216;unlocked&#8217; cell.  If there is no &#8216;unlocked&#8217; cell to the right, the routine searches below starting in the left most position and looking right for the next &#8216;unlocked&#8217; cell.  If the pressed LEFT, SHIFT TAB, UP, or PAGEUP the system assumes they want the previous &#8216;unlocked&#8217; cell.  In that case, the search moves left, and if need be, up starting in the last cell of the previous line and looking left.</p>
<p>Below is the code for <strong>Position_Cursor_In_Data</strong>.  It relies on <strong>Find_UnLocked_Cell</strong>.  That will be the topic of our next post.</p>
<p>  </p>
<pre><span style="color: #0000ff">Function</span> Position_Cursor_In_Data(Cell <span style="color: #0000ff">As Range</span>, _
                                 Entries <span style="color: #0000ff">As Range</span>, _
                                 KeyPressed <span style="color: #0000ff">As String</span>)<span style="color: #0000ff"> As Boolean</span></pre>
<pre><span style="color: #339966">'   Description:Call this from Worksheet_SelectionChange to force _
                cursor positions inside the entry area</span></pre>
<pre><span style="color: #339966">'   Parameters: Cell       Current cell or range selected by user
'               Entries    Range to restrict the cursor to
'               KeyPressed Last key the user pressed</span></pre>
<pre><span style="color: #339966">'   Example:    bResult = Position_Cursor_In_Data( _
                            Target, Range("Data"), KeyPressed)</span></pre>
<pre><span style="color: #339966">'   Abstract:   If the cursor is moved to a locked cell via
'               keyboard, move the cursor to the next unlocked cell.</span></pre>
<pre><span style="color: #339966">'     Date   Init Modification
'   01/12/06 CWH  Initial Programming</span></pre>
<pre>    <span style="color: #0000ff">On Error GoTo </span>ErrHandler            '
    Position_Cursor_In_Data = Success   <span style="color: #339966">'Assume the Best</span></pre>
<pre><span style="color: #339966">'   If more than 1 cell is selected, don't do anything</span>
    <span style="color: #0000ff">If</span> Cell.Rows.Count &gt; 1 <span style="color: #0000ff">Or</span> Cell.Columns.Count &gt; 1 <span style="color: #0000ff">Then</span> _
        <span style="color: #0000ff">Exit Function</span>
<span style="color: #339966">'   If the Cell is unlocked, we're done</span>
    <span style="color: #0000ff">If</span> Cell.Interior.Color &lt;&gt; CellLocked <span style="color: #0000ff">Then Exit Function</span>
   
<span style="color: #339966">   'From last key pressed, determine direction to _
    search for an unlocked cell</span>
    <span style="color: #0000ff">Dim</span> sLocateMethod<span style="color: #0000ff"> As String</span>
    <span style="color: #0000ff">Select Case</span> KeyPressed
        <span style="color: #0000ff">Case Is =</span> "Up", "PageUp", "Left", "ShiftTab"
            sLocateMethod = "Previous"
        <span style="color: #0000ff">Case Is =</span> "Down", "PageDown", "Right", "Tab", "Return"
            sLocateMethod = "Next"
        <span style="color: #0000ff">Case Else
            Exit Function
    End Select</span>
   
<span style="color: #339966">'   End looking for an excuse to leave early</span>
               
    Settings "Save"        <span style="color: #339966"> 'Save current application settings</span>
    Settings "Disable"      <span style="color: #339966">'Disable events, screen updates &amp; calc.s</span>
   
    <span style="color: #0000ff">Dim</span> lRow <span style="color: #0000ff">As Long</span>
    <span style="color: #0000ff">Dim</span> lCol <span style="color: #0000ff">As Long</span>
    <span style="color: #0000ff">Dim</span> bfound <span style="color: #0000ff">As Boolean</span>
                       
    <span style="color: #0000ff">Dim</span> lRight <span style="color: #0000ff">As Long</span>      <span style="color: #339966">'Last allowable column</span>
    <span style="color: #0000ff">Dim</span> lBottom <span style="color: #0000ff">As Long</span>     <span style="color: #339966">'Last allowable row</span>
   
    lRight = Entries.Column + Entries.Columns.Count - 1
    lBottom = Entries.Row + Entries.Rows.Count
                
    <span style="color: #0000ff">If</span> sLocateMethod = "Next" <span style="color: #0000ff">Then</span>
       <span style="color: #339966">'Search to the right on same row</span>
        bfound = Find_UnLocked_Cell(Cell.Row, Cell.Row, _
                                    Cell.Column + 1, lRight, 1)
      <span style="color: #339966"> 'Search rows below</span>
        <span style="color: #0000ff">If Not</span> bfound <span style="color: #0000ff">Then</span> _
            bfound = Find_UnLocked_Cell(Cell.Row + 1, lBottom, _
                                        1, lRight, 1)
    <span style="color: #0000ff">End If</span>
   
  <span style="color: #339966"> 'We're here, either because there's nothing below, _
    or we want to check previous
   'Search to the left on same row</span>
    <span style="color: #0000ff">If Not</span> bfound <span style="color: #0000ff">Then</span>
        <span style="color: #0000ff">If</span> Cell.Column &gt; 1 <span style="color: #0000ff">Then</span> _
            bfound = Find_UnLocked_Cell(Cell.Row, Cell.Row, _
                                        Cell.Column - 1, 1, -1)
    <span style="color: #0000ff">End If</span>
    <span style="color: #339966">'Search rows above</span>
    <span style="color: #0000ff">If Not</span> bfound <span style="color: #0000ff">Then</span>
        <span style="color: #0000ff">If</span> Cell.Row &gt; 1 <span style="color: #0000ff">Then</span> _
            bfound = Find_UnLocked_Cell(Cell.Row - 1, 1, _
                                        lRight, 1, -1)
    <span style="color: #0000ff">End If</span>
   
   <span style="color: #339966">'We're here because we looked previous &amp; found nothing or _
    there's just nothing here
   'Search to the right on same row</span>
    <span style="color: #0000ff">If Not</span> bfound <span style="color: #0000ff">Then</span> _
        bfound = Find_UnLocked_Cell(Cell.Row, Cell.Row, _
                                    Cell.Column + 1, lRight, 1)
  <span style="color: #339966"> 'Search rows below</span>
    <span style="color: #0000ff">If Not</span> bfound <span style="color: #0000ff">Then</span> _
        bfound = Find_UnLocked_Cell(Cell.Row + 1, lBottom, _
                                    1, lRight, 1)</pre>
<pre>    <span style="color: #0000ff">If Not</span> bfound <span style="color: #0000ff">Then</span> Position_Cursor_In_Data = Failure
   
ErrHandler:
   
    <span style="color: #0000ff">If</span> Err.Number &lt;&gt; 0 <span style="color: #0000ff">Then</span> MsgBox _
        "Position_Cursor_In_Data - Error#" &amp; Err.Number &amp; vbCrLf &amp; _
        Err.Description, vbCritical, "Error", Err.HelpFile, _
        Err.HelpContext
    Settings "Restore"     <span style="color: #339966"> 'Restore application settings</span>
    <span style="color: #0000ff">On Error GoTo</span> 0</pre>
<pre><span style="color: #0000ff">End Function</span></pre>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/controlling-the-cursor-position_curosr_in_data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Back to Controlling the Cursor</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/back-to-controlling-the-cursor/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/back-to-controlling-the-cursor/#comments</comments>
		<pubDate>Wed, 08 Sep 2010 22:49:11 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=883</guid>
		<description><![CDATA[This post returns to controlling the cursor in update spreadsheets. As the user positions the cursor on the spreadsheet, we want to have it jump over &#8216;locked&#8217; cells to the next &#8216;unlocked&#8217; cell.  The words &#8216;locked&#8217; and &#8216;unlocked&#8217; are quoted because we aren&#8217;t exactly using Excel&#8217;s notion of &#8216;locked&#8217; and &#8216;unlocked&#8217; cells. Excel provides the [...]]]></description>
				<content:encoded><![CDATA[<p>This post returns to controlling the cursor in update spreadsheets.</p>
<p>As the user positions the cursor on the spreadsheet, we want to have it jump over &#8216;locked&#8217; cells to the next &#8216;unlocked&#8217; cell.  The words &#8216;locked&#8217; and &#8216;unlocked&#8217; are quoted because we aren&#8217;t exactly using Excel&#8217;s notion of &#8216;locked&#8217; and &#8216;unlocked&#8217; cells. Excel provides the ability to prevent the cursor from entering locked cells when you protect the worksheet. Unfortunately, protecting the worksheet also prevents other things such as copy/paste if the paste range touches locked cells. Excel&#8217;s documentation says you can selectively allow some things within a protected worksheet, but my experiments with this have frustrated me and I&#8217;ve never gotten it to work satisfactorily (Maybe smarter minds than mine will contribute to the discussion and show us the way). </p>
<p>Without worksheet protection, Excel has no problem letting users do whatever they want to &#8216;locked&#8217; cells.  To work around this, we use the <strong>Worksheet_SelectionChange</strong> event to monitor cursor movements and call our <strong>Position_Curosr_In_Data </strong>function to help the user stay in &#8216;unlocked&#8217;/'open for entry&#8217; cells.  <strong>Position_Curosr_In_Data </strong>is also called from the <strong>Worksheet_Change</strong> event and we will cover it shortly.  But for now, let&#8217;s look at the <strong>Worksheet_SelectionChange</strong> event.</p>
<p>Below is the code for the <strong>Worksheet_SelectionChange </strong>event.   Almost all of it is consumed with figuring out which key the user pressed.  This is important because we need to know which way to &#8216;jump&#8217;.  If the user pressed the right arrow, we want to jump the the first unlocked cell to the right.  This same code is in the <strong>Worksheet_Change</strong> event so I suppose it&#8217;s time I explained it. </p>
<p>At the heart of the code is an API called <strong>GetAsyncKeyState.  </strong> <strong>GetAsyncKeyState </strong>is included in <strong>user32.dll</strong>.  This Windows API tells us what the last key pressed was.  Actually, it doesn&#8217;t do that.  I wish it were that simple.   But since groups of keys can be pressed simultaneously, such as the familiar <strong><em>Ctrl</em></strong>-<strong><em>Alt</em></strong>-<strong><em>Delete</em></strong>, the good folks at Microsoft created this API to tell you if a certain key is pressed or not.  So if you want to determine if <strong><em>Ctrl</em></strong>, <strong><em>Alt</em></strong>, and <strong><em>Delete</em></strong> were pressed, you have to ask: &#8220;Is <strong><em>Ctrl</em></strong> pressed?  And if so, is <strong><em>Alt</em></strong> pressed?  And if so is <strong><em>Delete</em></strong> also pressed?&#8221;  If you want more detail on this API, here are some good resources:</p>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx">Microsoft Developer&#8217;s Network Documentation: GetAsyncKeyState Function</a></li>
<li><a href="http://www.cpearson.com/excel/keytest.aspx">Chip Person&#8217;s: Testing Key States</a></li>
<li><a href="http://www.answers.com/topic/getasynckeystate">Answers.Com: GetAsyncKeyState</a></li>
</ul>
<p>To use the API, we have to first declare it.  I put this code at the top of modGeneral so it is available to all functions in my project.</p>
<pre><span style="color: #008000">'API Classes</span>
<span style="color: #008000">'   Get Key state</span>
    <span style="color: #0000ff">Public Declare Function </span>GetAsyncKeyState <span style="color: #0000ff">Lib</span> "user32" _
        (<span style="color: #0000ff">ByVal</span> vKey <span style="color: #0000ff">As Long</span>) <span style="color: #0000ff">As Integer</span></pre>
<p>Once declared we can use it as shown in the code below.  As you can see, we have to ask <strong>GetAsyncKeyState</strong> if a certain key was pressed.  We pass it the key we want to know about, and it returns a 16 bit number.  If the most significant bit is turned on, the key was pressed.  &amp;H8000 is the bit mask we use to determine if the most significant bit is on.  &amp;H8000 in binary form is 1000000000000000.  If you &#8220;AND&#8221; it with <strong>GetAsyncKeyState</strong>&#8216;s 16 bit number and the result is <strong><em>TRUE</em></strong>, the most significant bit is on and the key is pressed.  Based on which key is pressed, we can determine which way to jump. </p>
<p>Here is the code for the <strong>Worksheet_SelectionChange </strong>event.  It must be placed in the worksheet class.  Next post will be on the <strong>Position_Curosr_In_Data </strong>function.</p>
<p>  </p>
<pre><span style="color: #0000ff">Private Sub</span> Worksheet_SelectionChange(<span style="color: #0000ff">ByVal</span> Target <span style="color: #0000ff">As</span> Range)</pre>
<pre><span style="color: #008000">'   Purpose:    Restrict the user to areas open for update</span></pre>
<pre><span style="color: #008000">'   Determine the last key pressed</span>
    <span style="color: #0000ff">Dim</span> sKey <span style="color: #0000ff">As String</span>
    <span style="color: #0000ff">If</span> GetAsyncKeyState(vbKeyTab) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
        <span style="color: #0000ff">If</span> GetAsyncKeyState(vbKeyShift) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
            sKey = "ShiftTab"
        <span style="color: #0000ff">Else</span>
            sKey = "Tab"
        <span style="color: #0000ff">End</span> <span style="color: #0000ff">If</span>
    <span style="color: #0000ff">ElseIf</span> GetAsyncKeyState(vbKeyRight) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
        sKey = "Right"
    <span style="color: #0000ff">ElseIf</span> GetAsyncKeyState(vbKeyLeft) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
        sKey = "Left"
    <span style="color: #0000ff">ElseIf</span> GetAsyncKeyState(vbKeyPageUp) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
        sKey = "PageUp"
    <span style="color: #0000ff">ElseIf</span> GetAsyncKeyState(vbKeyUp) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
        sKey = "Up"
    <span style="color: #0000ff">ElseIf</span> GetAsyncKeyState(vbKeyDown) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
        sKey = "Down"
    <span style="color: #0000ff">ElseIf</span> GetAsyncKeyState(vbKeyPageDown) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
        sKey = "PageDown"
    <span style="color: #0000ff">ElseIf</span> GetAsyncKeyState(vbKeyReturn) <span style="color: #0000ff">And</span> &amp;H8000 <span style="color: #0000ff">Then</span>
        sKey = "Return"
    <span style="color: #0000ff">Else</span>
        sKey = "Mouse"
    <span style="color: #0000ff">End</span> <span style="color: #0000ff">If</span>
   
    Position_Cursor_In_Data Target, Range(sData), sKey</pre>
<pre><span style="color: #0000ff">End Sub</span></pre>
<pre> </pre>
<pre> </pre>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/back-to-controlling-the-cursor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Strategies for Speeding Spreadsheets</title>
		<link>http://itknowledgeexchange.techtarget.com/beyond-excel/strategies-for-speeding-spreadsheets/</link>
		<comments>http://itknowledgeexchange.techtarget.com/beyond-excel/strategies-for-speeding-spreadsheets/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 15:16:23 +0000</pubDate>
		<dc:creator>Craig Hatmaker</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[Microsoft Excel]]></category>
		<category><![CDATA[ms query]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vba]]></category>

		<guid isPermaLink="false">http://itknowledgeexchange.techtarget.com/beyond-excel/?p=871</guid>
		<description><![CDATA[By guest contributor: Yoav Ezer NOTE: This post provides an example spreadsheet: accelerating-excel.xlsm.  Due to concern for your system&#8217;s security, macro enabled spreadsheets cannot be stored in this blog.  So to accomodate security and free exchange of ideas, we loaded the spreadsheet as a text file with a &#8220;txt&#8221; extension.  To use this example, right click the [...]]]></description>
				<content:encoded><![CDATA[<p>By guest contributor: Yoav Ezer</p>
<blockquote><p><strong>NOTE</strong>: This post provides an example spreadsheet: <a href="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/139/files/2010/08/accelerating-excel.txt">accelerating-excel.xlsm</a>.  Due to concern for your system&#8217;s security, macro enabled spreadsheets cannot be stored in this blog.  So to accomodate security and free exchange of ideas, we loaded the spreadsheet as a text file with a &#8220;txt&#8221; extension.  To use this example, right click the link, select &#8220;Save Target As&#8221;, change the extension on the file name from .zip (it&#8217;s a text file that ITKnowledgeExchange has compressed for you) to .xlsm, click &#8220;Save&#8221;, scan your local copy for viruses, then open it.</p></blockquote>
<p>Do your Excel spreadsheets sometimes take too long to calculate? It may be due to formulas that crunch large sets of data (for example, data that comes from large databases – the focus of this blog). This is because Excel recalculates all formulas that depend on a specific cell every time you change that cell. And if those formulas have dependents, Excel will recalculate them, and their dependents, and so on, and so on.</p>
<p>Consider the formula =SUM(A:A). This adds all cells in column A. It recalculates each time you update any cell in column A. Fortunately, the SUM function is very fast and may not cause significant delay even if used a 1,000 times in your workbook. But more advanced functions, like SUMPRODUCT() and array formulas, are not so efficient.</p>
<p>For instance, the following array formula is pretty simple: =SUM(IF(MOD(A:A,2)=1,A:A,0)). It sums all odd numbers in column A. It is much slower than the SUM function. I&#8217;ve used this formula only 12 times on sheet1 (See <a href="http://cdn.ttgtmedia.com/ITKE/uploads/blogs.dir/139/files/2010/08/accelerating-excel.txt">accelerating-excel.xlsm</a> above) in this workbook and on my machine it takes 5 seconds to add a value to column A, which makes this workbook too slow to use.  Fortunately for us, there are ways to make Excel work faster even with advanced formulas.</p>
<p><strong>Strategy #1: Use Limited Ranges<br />
</strong>The reason the array formula evaluates so slowly is that it calculates for every cell in column A (that&#8217;s more than 1 million cells). One way to make this formula work faster is to limit the range. So instead of using this formula:</p>
<pre style="padding-left: 30px">{=SUM(IF(MOD(A:A,2)=1,A:A,0))}</pre>
<p>We can use this formula specifying only the rows needed:</p>
<pre style="padding-left: 30px">{=SUM(IF(MOD(A1:A10000,2)=1,A1:A10000,0))}</pre>
<blockquote><p><strong>NOTE</strong>: Excel adds curly brackets when you enter a formula using CTRL+SHIFT+ENTER. CTRL+SHIFT+ENTER tells Excel your formula is an array formula. For more information on array formulas and their power, see: <a href="//office.microsoft.com/en-us/excel-help/introducing-array-formulas-in-excel-HA001087290.aspx">Introducing Array Formulas in Excel</a> by Colin Wilcox and John Walkenbach</p></blockquote>
<p>Because the revised formula is limited to 10,000 rows it works 100x times faster!</p>
<p><strong>Strategy #2: Use Dynamic Ranges<br />
</strong>Strategy #1 works as long as you know how many cells contain data. When you don’t know, you can still limit your ranges using a Dynamic Range. Dynamic Ranges expand automatically to include only cells that contain data.  You can define a dynamic range called &#8216;ColumnA&#8217; like this:</p>
<pre style="padding-left: 30px">=OFFSET(Sheet2!$A$1,0,0,COUNT(Sheet2!$A:$A),1)</pre>
<p>And then use it in the original formula in the following manner:</p>
<pre style="padding-left: 30px">{=SUM(IF(MOD(ColumnA,2)=1,ColumnA,0))}</pre>
<blockquote><p><strong>NOTE</strong>: See <a href="//www.homeandlearn.co.uk/me/mes9p2.html">How to Set up a Named Range in Microsoft Excel</a> if you need help with this.</p></blockquote>
<p>This formula calculates only rows in column A that contain data. That’s good for two reasons: It reduces the number of cells calculated if your range contains fewer cells than anticipated; AND, it calculates cells that might otherwise be overlooked if your range contains more cells than anticipated. For more information on Dynamic Ranges see: <a href="//www.automateexcel.com/2008/08/23/introduction-to-dynamic-ranges/">Introduction to Dynamic Ranges</a>.</p>
<p>To experience the performance difference between these two methods, open the sample file and update data on the first and second sheet. You&#8217;ll see a very palpable difference.</p>
<p><strong>Strategy #3: Stopping/Starting Calculation<br />
</strong>At times, even limiting the range used in the formula isn&#8217;t enough. One of our clients had a workbook with over 12,000 array formulas and although we used dynamic ranges to limit the range size in each of those formulas, the workbook took over a minute to update with 1,000 data rows. For that client we used the following technique.</p>
<p>The workbook was divided into a data entry sheet and &#8216;data analysis&#8217; sheets which contained the array formulas. We employed a simple macro to stop the formulas on the workbook from automatically updating every time the user entered the &#8216;data entry&#8217; sheet and a second macro to calculate all the formulas on the workbook when the user left the &#8216;data entry&#8217; sheet. This way the user was able to update data very quickly and wait only once (when leaving the sheet).  Here is the macro we used whenever the user entered the &#8216;data entry&#8217; sheet:</p>
<pre style="padding-left: 30px"><span style="color: #0000ff">Private Sub </span>Worksheet_Activate()</pre>
<pre style="padding-left: 60px">Application.Calculation = xlCalculationManual</pre>
<pre style="padding-left: 30px"><span style="color: #0000ff">End Sub</span></pre>
<p>And this is the macro we used when the user left the sheet:</p>
<pre style="padding-left: 30px"><span style="color: #0000ff">Private Sub</span> Worksheet_Deactivate()</pre>
<pre style="padding-left: 60px">Application.Calculate
Application.Calculation = xlCalculationAutomatic</pre>
<pre style="padding-left: 30px"><span style="color: #0000ff">End Sub</span></pre>
<p>You can see how stopping and starting the automatic calculations effects performance in the sample file.</p>
<p><strong>Summary</strong><br />
We use Microsoft Excel to improve productivity. We can improve productivity even more by removing unnecessary waits through writing efficient formulas and controlling when Excel does its magic! Look for opportunities to use these techniques to speed results and improve the user experience.</p>
<p>Do you have Excel optimization tips? Please share with us in the comments.</p>
<p><strong>About the author</strong><br />
Yoav Ezer co-authors the technology and productivity blog Codswallop. He is CEO of <a href="//www.cogniview.com">Cogniview</a>, producer of <a href="//www.cogniview.com/articles/pdf-to-xls-converter.php">PDF2XL</a>, a Native PDF to Excel Converter, <a href="//www.cogniview.com/pdf2xl-ocr.php">PDF2XL OCR</a>, a scanned PDF to Excel converter, and <a href="//www.cogniview.com/pdf2xl-enterprise.php">PDF2XL Enterprise</a>, a universal format converter to Excel.  For more Excel tips from Yoav, join him on: <a href="//www.facebook.com/Cogniview.Codswallop">Facebook</a>; or <a href="“">Twitter</a></p>
<p>Thanks Yoav for those great tips!</p>
<!-- wpms-network-global-inserts -->]]></content:encoded>
			<wfw:commentRss>http://itknowledgeexchange.techtarget.com/beyond-excel/strategies-for-speeding-spreadsheets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
