I Got Rendered Where? Part II Doug Hennig

Similar documents
Cool Uses for ReportListeners

Taking Control Doug Hennig

IntelliSense at Runtime Doug Hennig

A Generic Import Utility, Part 2

The Mother of All TreeViews, Part 2 Doug Hennig

A New IDE Add-on: FoxTabs Doug Hennig

Extending the VFP 9 IDE Doug Hennig

Splitting Up is Hard to Do Doug Hennig

Role-Based Security, Part III Doug Hennig

Cool Tools by Craig Boyd, Part II Doug Hennig

Windows Event Binding Made Easy Doug Hennig

More Flexible Reporting With XFRX Doug Hennig

CATCH Me if You Can Doug Hennig

Custom UI Controls: Splitter

Data-Drive Your Applications Doug Hennig

Base Classes Revisited Doug Hennig

Web Page Components Doug Hennig

Manage Your Applications Doug Hennig

Session V-STON Stonefield Query: The Next Generation of Reporting

uilding Your Own Builders with BuilderB Doug Hennig and Yuanitta Morhart

May I See Your License? Doug Hennig

Advanced Uses for Dynamic Form

Zip it, Zip it Good Doug Hennig

Speed in Object Creation and. Destruction. March 2016 Number 49. Tamar E. Granor, Ph.D.

Much ADO About Something Doug Hennig

Data Handling Issues, Part I Doug Hennig

Give Thor Tools Options

A New Beginning Doug Hennig

pdating an Application over the Internet, Part II Doug Hennig

## Version: FoxPro 7.0 ## Figures: ## File for Subscriber Downloads: Publishing Your First Web Service Whil Hentzen

Report Objects Doug Hennig

A File Open Dialog Doug Hennig

Extending the VFP 9 Reporting System, Part I: Design-Time

Christmas Stocking Stuffers Doug Hennig

anguage Enhancements in VFP 7, Part V Doug Hennig

Access and Assign Methods in VFP

Word 2003: Flowcharts Learning guide

The Best of Both Worlds

Handling crosstabs and other wide data in VFP reports

Making the Most of the Toolbox

Understanding Business Objects, Part 1

Advisor Discovery. Use BindEvent() to keep things in synch. BindEvent() Refresher. June, By Tamar E. Granor, technical editor

SlickEdit Gadgets. SlickEdit Gadgets

FoxTalk. GOING through the classes provided in the FoxPro. More Gems in the FFC. Doug Hennig 6.0

Putting Parameters in Perspective Doug Hennig

Tabbing Between Fields and Control Elements

Class 3 Page 1. Using DW tools to learn CSS. Intro to Web Design using Dreamweaver (VBUS 010) Instructor: Robert Lee

Working with the Registry. The Registry class makes it easy. The Registry Structure. January, By Tamar E. Granor

FrontPage 98 Quick Guide. Copyright 2000 Peter Pappas. edteck press All rights reserved.

Using Tab Stops in Microsoft Word

anguage Enhancements in VFP 7, Part I Doug Hennig

HOUR 4 Understanding Events

Part II: Creating Visio Drawings

Acrobat X Professional

Authoring World Wide Web Pages with Dreamweaver

textures not patterns

Using Windows 7 Explorer By Len Nasman, Bristol Village Computer Club

In this lesson, you ll learn how to:

Access Forms Masterclass 5 Create Dynamic Titles for Your Forms

Drilling Down Into Your Data Doug Hennig

All About Me in HyperStudio

Rev. C 11/09/2010 Downers Grove Public Library Page 1 of 41

Extending the VFP 9 Reporting System, Part II: Run-Time

Generating crosstabs in VFP

Consolidate data from a field into a list

HYPERSTUDIO TOOLS. THE GRAPHIC TOOL Use this tool to select graphics to edit. SPRAY PAINT CAN Scatter lots of tiny dots with this tool.

Graphing crosstabs. Tamar E. Granor, Ph.D.

Karlen Communications Add Accessible PowerPoint Placeholders. Karen McCall, M.Ed.

COMP : Practical 8 ActionScript II: The If statement and Variables

Try Thor s Terrific Tools, Part 2

How to create interactive documents

Create a Scrolling Effect in PowerPoint 2007

SNOWFLAKES PHOTO BORDER - PHOTOSHOP CS6 / CC

Hello World! Computer Programming for Kids and Other Beginners. Chapter 1. by Warren Sande and Carter Sande. Copyright 2009 Manning Publications

Would you like to put an image on your index page? There are several ways to do this and I will start with the easy way.

Christmas Card Final Image Preview Coach Christian s Example Ctrl+N 1920px 1200px RGB 72 pixels/inch Rectangle Tool (U)

ORGANIZING YOUR ARTWORK WITH LAYERS

How To Upload Your Newsletter

One of the fundamental kinds of websites that SharePoint 2010 allows

FROM 4D WRITE TO 4D WRITE PRO INTRODUCTION. Presented by: Achim W. Peschke

GOOGLE APPS. If you have difficulty using this program, please contact IT Personnel by phone at

Q: I've been playing with the Microsoft Internet Transfer Control (inetctls.inet.1) and it would be great if only it worked.

Cadence Virtuoso Layout Connectivity Mark- Net Tutorial

Creating/Updating Finding Aids in ArchivesSpace

Using Microsoft Word. Working With Objects

Introduction to MS Word XP 2002: An Overview

Learning to use the drawing tools

In the Map Background menu, you can go to Manage Background Maps and modify how your background maps look.

The first thing we ll need is some numbers. I m going to use the set of times and drug concentration levels in a patient s bloodstream given below.

Smoother Graphics Taking Control of Painting the Screen

Page design and working with frames

Chapter 1. Getting to Know Illustrator

A Step-by-Step Guide to getting started with Hot Potatoes

Industrial Strength Add-Ins: Creating Commands in Autodesk Inventor

Chapter 10 Working with Graphs and Charts

Project 1 Balanced binary

GGR 375 QGIS Tutorial

TRAINING SESSION Q3 2016

Adobe Dreamweaver CS5 Tutorial

Product Interface Design using Axure RP Pro 7.0

Transcription:

I Got Rendered Where? Part II Doug Hennig Thanks to the new ReportListener in VFP 9, we have a lot more control over where reports are rendered. Last month, Doug Hennig showed a listener that collaborates with a custom preview window to provide a live preview surface. This month, he takes it a step further and adds support for finding and highlighting text. Last month, I showed a ReportListener subclass called DBFListener that renders a report to a cursor. The cursor contains information about each object in the report: the type of object (field, label, rectangle, etc.), its content (in the case of fields and labels), page number, horizontal and vertical position, and size. I also showed a custom preview window that uses the cursor to provide a live preview surface, one in which the user could click on a specific report object and fire an event in the form. This month, I m going to extend the behavior of the preview form to support finding and highlighting text. Finding text Clicking on the Find button in the preview form s toolbar calls the FindText method of the preview form (the SFPreviewForm class in SFPreview.VCX). That method prompts the user for some text to find, calls ClearFind to clear any existing find settings, tries to find the specified text in the output cursor created by DBFListener, and calls the HandleFind method to deal with the results. local lctext, ; lcobject lctext = inputbox('find:', 'Find Text') if not empty(lctext).clearfind() select (.coutputalias).ctexttofind = lctext locate for ; upper(this.ctexttofind) $ upper(contents).handlefind(found()) endif not empty(lctext) FindNext, called from the Find Next button in the toolbar, simply uses CONTINUE to find the next instance and also calls HandleFind to handle the results. HandleFind deals with the results of the search. If a record was found containing the desired text, HandleFind calls the AddHighlightedItem method to add the record number and page number of the record to the ohighlighteditems collection of items to highlight (we won t look at this method). One complication of highlighting the found text is that if the preview form is sized smaller than page size, the highlighted text may be outside the visible area of the page. So, HandleFind calls the ScrollToObject method to scroll the form so the highlighted text is within the visible area. It then either calls DrawPage or DisplayPage, both of which I discussed last month, depending on whether the first instance of the found text appears on the currently displayed page or on a different page. (In case you re wondering, ScrollToObject must be called before DrawPage or DisplayPage because the highlighting process, which we ll look at later, needs to have the highlighted area within the current viewable area.) If no matching record could be found, HandleFind beeps (using the Windows API MessageBeep function, declared in Init), clears the existing find information, and redraws the current page, thus clearing any previously highlighted text. lparameters tlfound local lcobject, ; loobject * If we found the object, add it to the collection * of highlighted objects and flag that the Find Next * function can be used.

if tlfound lcobject = transform(recno()).addhighlighteditem(lcobject, PAGE).lCanFindNext =.T. * Scroll the form if the found object isn't currently * visible. If the object is on the current page, * redraw it. Otherwise, display the proper page. scatter name loobject.scrolltoobject(loobject.top/10, ; loobject.height/10, loobject.left/10, ; loobject.width/10) if PAGE =.ncurrentpage.drawpage().refreshtoolbar() else.displaypage(page) endif PAGE =.ncurrentpage * We didn't find the text, so clear the find * settings. else MessageBeep(16).ClearFind().DrawPage().RefreshToolbar() endif tlfound The ScrollToObject method does what its name suggests (I find that s usually the best way to name a method <g>) it scrolls the form as necessary so the specified location is visible. This involves checking the various ViewPort* properties to see what part of the total image is currently displayed in the viewable area and calling SetViewPort to change the viewable area if necessary. lparameters tntop, ; tnheight, ; tnleft, ; tnwidth local lnnewtop, ; lnnewleft, ; lnvpos, ; lnhpos lnnewtop =.ViewPortTop lnnewleft =.ViewPortLeft lnvpos = tntop + tnheight lnhpos = tnleft + tnwidth if not between(lnvpos,.viewporttop, ;.ViewPortTop +.ViewPortHeight) lnnewtop = lnvpos -.ViewPortHeight/2 endif not between(lnvpos... if not between(lnhpos,.viewportleft, ;.ViewPortLeft +.ViewPortWidth) lnnewleft = lnhpos -.ViewPortWidth/2 endif not between(lnhpos... if lnnewtop <>.ViewPortTop or ; lnnewleft <>.ViewPortLeft.SetViewPort(lnNewLeft, lnnewtop) endif lnnewtop <>.ViewPortTop... Highlighting text

How is the found text highlighted? The DrawPage method, which I discussed last month, calls the HighlightObjects method to ensure any objects on the current page that exist in the collection of items to highlight are drawn in a manner that makes them stand out. local lcobject, ; lcrepobject, ; lorepobject for each loobject in.ohighlighteditems if loobject.page =.ncurrentpage lcrepobject = loobject.name lorepobject = evaluate('.ocontainer.object' + ; lcrepobject).highlightobject(lorepobject) endif loobject.page =.ncurrentpage next loobject The actual work of highlighting a specific object is done in HighlightObject. Remember that the page displayed in the preview window is really a GDI+ image, so we can t do much with it. As we saw last month, SFPreviewForm creates invisible shape objects (not really invisible, but without a border so they don t appear on the preview surface) for each rendered item in the current page of the report. So, to make the found text stand out, we simply have to make the object representing the text visible. You might think the code could simply do something like this: Object.BorderWidth = 2 Object.BorderStyle = 1 Object.BorderColor = rgb(255, 0, 0) However, that doesn t work for two reasons. First, even though it s transparent, the shape overlays the report image, blocking off the text the user wants to see. Second, the form continually flashes. It turns out that if something is changed when Paint fires (in SFPreviewForm, Paint calls DrawPage, which calls HighlightObjects, which calls HighlightObject, which would change the border of the shape if we used this code), it starts a vicious cycle: Paint fires, which changes the drawing surface, which causes Paint to fire, which changes the drawing surface, and so on. So, instead, we ll use GDI+ to draw a box around the shape. The Init method of the form instantiates a GpGraphics object from _GDIPlus.VCX in the FFC subdirectory of the VFP home directory. This class library, which provides an easy-to-use wrapper for GDI+ functions, was created by Walter Nicholls, and he discussed some of its classes in the August and September 2004 issues of FoxTalk. GDI+ needs a handle to the surface it draws on, so you normally call the CreateFromHWnd method of GpGraphics, passing it the HWnd property of the form. However, I ran into a snag using it with SFPreviewForm: when the ScrollBars property is set to anything but 0-None, none of the GDI+ drawing I did showed up on the form. Fortunately, Walter generously pointed out to me that drawing should actually occur on the child window of the form (the part inside the form that scrolls is actually another window), and that I could get a handle to the child window using the GetHandle Windows API function. HighlightObject uses the GpGraphics object to draw a rectangle of the appropriate size and position for the shape object being highlighted. Set the custom nhighlightcolor and nhighlightwidth properties of the form to the RGB value for the desired color and width of the box; they re set by default to 255 (Red) and 2. Note that the RGB values used by VFP are somewhat different than those used by GDI+, so the code in HighlightObject rearranges the color value so it works with GDI+. lparameters toobject local lnx1, ; lny1, ; lnx2, ; lnred, ; lngreen, ; lnblue, ; lnargb, ; lnhwnd, ;

locolor, ; lopen * Figure out the upper left corner of the box. lnx1 = toobject.left +.ocontainer.left lny1 = toobject.top +.ocontainer.top * Figure out the ARGB color to use from the RGB * value. lnred = bitand(.nhighlightcolor, 255) lngreen = bitrshift(bitand(.nhighlightcolor, ; 0x00FF00), 8) lnblue = bitrshift(bitand(.nhighlightcolor, ; 0xFF0000), 16) lnargb = 0xFF000000 + 0x10000 * lnred + ; 0x100 * lngreen + lnblue * Get the handle of the form to draw on (since we're * a scrollable form, we need to get the child of the * form, not the form itself). Since we may have * scrolled the form, we need to do this each time. #define GW_CHILD 5 lnhwnd = GetWindow(.HWnd, GW_CHILD).oGraphics.CreateFromHWnd(lnHWnd) * Draw the box. locolor = createobject('gpcolor', lnargb) lopen = createobject('gppen') lopen.create(locolor,.nhighlightwidth).ographics.drawrectangle(lopen, lnx1, lny1, ; toobject.width, toobject.height) Check it out Let s see how it works. Run TestSFPreview.PRG to run a report and preview it using SFPreviewForm. Click the Find button in the toolbar and when prompted, enter something that appears multiple times, such as London. You ll see a red box appear around the first instance of that text; see Figure 1 for an example. Click the Find Next button and notice that the box around the first instance disappears and the second instance is now highlighted. As you continue to click Find Next, you may see the preview form automatically scroll or move to another page so the found instance is always visible. Once no more instances are found, you ll hear a beep and no text will be highlighted.

Figure 1. SFPreviewForm highlights found text, adding an important feature to a report preview window. One thing you might be curious about is why I used a collection to hold the highlighted items when only one item is highlighted at a time during a find. That s because I wanted to support the possibility of highlighting multiple items at a time. Perhaps you want the find functionality to find and highlight all instances of the found text rather than one at a time. Perhaps you want to support bookmarks, with each bookmarked item being highlighted. Here s a simple example: TestSFPreview.PRG binds the ObjectClicked and ObjectRightClicked events to the OnClick and OnRightClick methods of a click handler class (I discussed how events are handled in last month s article). When you click an object, that object becomes highlighted. To unhighlight the object, right-click it. Figure 2 shows the results after I clicked on various objects. lohandler = createobject('clickhandler') bindevent(loform, 'ObjectClicked', lohandler, 'OnClick') bindevent(loform, 'ObjectRightClicked', lohandler, 'OnRightClick') * A class to handle object clicks. define class ClickHandler as Custom procedure OnClick(toObject, toform) local lcobject toobject.top = toobject.top/10 toobject.left = toobject.left/10 toobject.width = toobject.width/10 toobject.height = toobject.height/10 lcobject = transform(toobject.recordnumber) toform.addhighlighteditem(lcobject, ; toobject.page) toform.drawpage() endproc procedure OnRightClick(toObject, toform) local lcobject lcobject = transform(toobject.recordnumber) toform.ohighlightitems.remove(lcobject) toform.drawpage() endproc enddefine

Figure 2. Because it uses a collection, SFPreviewForm supports multiple highlighted objects. Summary Over the past several months, I ve discussed the new ReportListener in VFP 9 and some of the ways it can be used to provide features we could only dream of in earlier versions. Among the things I ve looked at are dynamically formatting text, hyperlinking objects within a report, having a live preview surface, and highlighting objects in a report. I m going to move on to another topic next month, but rest assured that we ll find other cool things to explore in this area in the future. Doug Hennig is a partner with Stonefield Systems Group Inc. He is the author of the award-winning Stonefield Database Toolkit (SDT) and Stonefield Query, and the MemberData Editor, Anchor Editor, New Property/Method Dialog, and CursorAdapter and DataEnvironment builders that come with VFP. He is co-author of the What s New in Visual FoxPro series and The Hacker s Guide to Visual FoxPro 7.0, all from Hentzenwerke Publishing. Doug has spoken at every Microsoft FoxPro Developers Conference (DevCon) since 1997 and at user groups and developer conferences all over North America. He is a long-time Microsoft Most Valuable Professional (MVP), having first been honored with this award in 1996. Web: www.stonefield.com and www.stonefieldquery.com Email: dhennig@stonefield.com