georeference.org
Subscribe to this thread
Home - General / All posts - Tool to search any field and zoom to selection
Mike Pelletier

529 post(s)
#30-Jun-08 11:46

In my line of work, most novice users trying to find a map object (ie, a certain road or parcel) just want to be able to select a deisred layer, then type in some characters, and have the software return records containing those characters in any of the existing fields. The user can then choose one or more of selected objects displayed in a table and zoom to the selected object(s). This could be a good addition to the GoTo dialogue box or maybe the SQL query builder (promised in the next release) could include an "all fields" option.

In the meantime, I've been trying to script it and was hoping to get some help. In the attached map file, I've created a form that allows the user to select the drawing layer, type in some search characters, and zoom to the selected object. The zoom_to function works fine but I'm struggling on the search button.

Is there a scripting way to search all fields without actually listing them all in a query? It would be great to create this tool so that it can be quickly used in any map project without a lot of setup hassle.

Attachments:
form - wild card query.map

Ny-Mapper115 post(s)
#30-Jun-08 12:55

I would really like that.

Mike Pelletier

529 post(s)
#30-Jun-08 16:26

I haven't figured out the question above, but please use the attached map file instead. It runs except it uses a simple query on one field instead of all fields. Also, I can't seem to make it delete the "temp" query.

Attachments:
form - wild card query.map

tjhb

2,231 post(s)
#30-Jun-08 16:30

Mike,

One way of doing it (maybe not what you'd like) would be to create a query (ad hoc, within the script) that aggregated all the user columns into a single field, against IDs. Then run a second query like the one in your current script, to search on that aggregated field.

Mike Pelletier

529 post(s)
#30-Jun-08 18:21

That would definitely work Tim, but I"m thinking it would require writing all the fields out in the aggregating query, which might be a similar amount of work as writing them into the original query. Maybe your idea could be made to work by aggregating the fields within the script such that it happens after the user selects the desired layer. Then the query references the newly created field.

I recall an ArcIMS site that had a query that hit any field in the table. I was just a user so couldn't see the code behind it though. It made me think it was doable, although it may have been just a long query statement containing all the fields.

tjhb

2,231 post(s)
#30-Jun-08 19:01

Maybe your idea could be made to work by aggregating the fields within the script such that it happens after the user selects the desired layer. Then the query references the newly created field.

Yes that's it. The script would list all the field names into one string, use that string to write a query aggregating all their values into one field, then run a second query to search on the result. I could have a go later.

tjhb

2,231 post(s)
#01-Jul-08 02:03

I've changed as little as possible Mike. It works but needs a lot of refinement.

Attachments:
Form Script.txt

Mike Pelletier

529 post(s)
#01-Jul-08 10:13

Tim,

That's absolutely fantastic! It seems to work flawlessly on a variety of column types and it laughs at it being lower or upper case. It even works within just several seconds on our relatively large parcel layer (18600 rec, 55 cols). Thank you very much.

Attached is a cleaned up working version. There is one issue unless you adjust the form screen location, either manually or by adjusting its initial location (main form object - properties). When you click on a message box to close it, the click will hit one of the underlying command buttons on the form.

A very handy tool for when running in 32-bit.

Attachments:
All Query.map

tjhb

2,231 post(s)
#01-Jul-08 10:58

Yes this project was a really good idea Mike.

danb

555 post(s)
#01-Jul-08 13:47

Great tool, except that you have hardcoded the layers in the dropdown. This stumped me for a while.

BTW thanks Mike for your forms posts recently. Inspired by your work, I had a go at modifying some existing tools to use a form as a front end and I am really glad that I did ... much more flexible thanks for that

jnorman

153 post(s)
#01-Jul-08 13:48

Very nice tool. I took the liberty of changing the first bit of code to allow for the tool to build a list of all Drawing components. Dropped it into one of my projects and it worked like a charm. The next idea I have is to perhaps build a Map component with the selected drawing (to allow the Zoom to work even if there isn't a Map called "Map".

FWIW

John

Attachments:
All Query with built list.map

Mike Pelletier

529 post(s)
#01-Jul-08 16:54

Thanks for that improvement John. I was hoping folks would want make it better, especially since programming takes me a long time.

Some other thoughts for improvements are:

1. Have the table just display the selected records. That would save a click on the selection filter.

2. Have it zoom to a size a bit larger than the object and a minimum size for points.

This forum is sooo great!

rfriedman
138 post(s)
#03-Jul-08 09:08

Mike, Tim, and John,

Thanks for all your work on this!

Great little tool to implement for the user who needs things as simple as possible.

jnorman

153 post(s)
#03-Jul-08 09:25

Ok,

I've played around a bit more and have been able to do a couple of things. I have to admit that I'm always humbled to see what Tim can do with SQL. Mike what a great idea!

I changed the code (hopefully didn't break it) to...

1) Allow for the selection of any map as a starting point. The layers are then populated from that map.

Note -- as part of this, I edited the code section where Q1 is being built such that it doesn't eliminate columns that are not native. See below. This allows linked drawings to work as well.

code //VBScript

    For Each col In table.ColumnSet

        ' Commented out the col.IsNative and this seems to work with linked drawings 

        If Not col.IsIntrinsic and Not col.Identity then 'And col.IsNative Then

            If cols <> "" Then cols = cols & " & " & Chr(34) & " " & Chr(34) & " & "

            cols = cols & "CStr([" & col.Name & "])"

        End If

    Next ' col

2) I added a zoom to multiplier which defaults to 1.2 x the normal zoomed to scale.

I couldn't figure out how to script the display of only the selected records. I imagine UI scripting could take care of this...maybe over the weekend :)

Because I use Themes A LOT, I would love to be able to make this work with themes as well. At this point, it only works with actual Drawing components.

Anyway -- this has been a fun exercise!

Cheers and have a great 4th! if you celebrate it.

John

Attachments:
All Query Any Map.map

Mike Pelletier

529 post(s)
#03-Jul-08 09:56

Very nice John for making it ever more useful. At some point, I'm thinking this might be a good project for converting to VB.Net so that it will work in 64-bit and as a way to gain an understanding of how to use Visual Studio with Manifold. This might be asking to broad a question but does anyone have pointers or basic concept on how to do convert this to VB.Net in Visual Studio?

jnorman

153 post(s)
#03-Jul-08 10:01

I just saw your other thread on the subject of converting to VB.Net. I'm going to need to make this leap as well, and would love those pointers on using Visual Studio. I like your idea of converting this simple project as a good way to get started.

jkelly

489 post(s)
#03-Jul-08 15:52

The only suggestion I have is to have a look at the examples that Lorne has built. Most of the threads that contain the source are referenced on http://www.manipedia.eu/ under Add-ins. I used one of these with the first add-in I built, it was a God send to see how the events behaved.

As for the code, I have not found an easy way to convert vbscript into vb.net, so you probably have to recode it.

James K.

Lorne

560 post(s)
online
#04-Jul-08 06:14

Here's a stab at converting this useful utility to a VB.NET Windows Forms application. I'm not sure if I am merging VS code in an efficient way but it does seem to work. Since people are still brain-storming features, I have just moved the code to a GUI .Net script. However, at some point, a utility like this should get moved to an add-in pane since it would then be available in any project. Very little testing done so I probably introduced errors

Attachments:
vbNET_Script.txt

tjhb

2,231 post(s)
#04-Jul-08 07:02

Gosh, this is a learning experience. (The external version looks even more daunting than I'd've thunk, no fault on Lorne's part of course just my ignorance.)

It's a while since we had so many hands collaborate on one bit of code. It gets better and better. What a nice bunch of people.

Lorne

560 post(s)
online
#04-Jul-08 07:31

I just write amateur code Tim and I would really like others to clean it up. Mostly, I approach this stuff by banging away until it works.

It is the Form/Controls definitions that makes it all look hard - Public Sub New(). You don't see that in an add-in DLL although it is there, hidden in the background. On the up-side, you do not have to create that code by hand. Just design the Form in VS then open "Form1.Designer.vb" and copy the applicable code. The actual application code can be done in VS as well which makes it easier - IntelliSense is great when working with multi-level object properties! The application code is very similar to vbScript versions. Option Explicit is turned on and all variables have to be fully dimensioned which adds a bit of length but, otherwise, much the same.

tjhb

2,231 post(s)
#04-Jul-08 08:17

(Me too.) Yes the definitions subroutine was a major part of it Lorne and it seems less daunting after your explanation thank you.

But similarly e.g. the fourth line below:

If Context.Document.ComponentSet.ItemByName("Q1") < 0 Then

    Qry1 = Context.Document.NewQuery("Q1")

Else

    Qry1 = CType(Context.Document.ComponentSet.Item("Q1"), Manifold.Interop.Query)

End If

Why can't the engine just see what type the item is, and what type Qry1 is (from its declaration), and tacitly assent to the match? I suppose because fussiness like this snags some errors at compile time, that would otherwise be revealed only at runtime. Programming for grownups.

KlausDE

3,028 post(s)
#04-Jul-08 08:38

Why can't the engine just see what type the item is

Well, it sees a type on the left side. It's "Manifold.Interop.Component", a super type (probably not the correct term) that allows to access all those properties common to all component types like Name or Type. The expicit cast to query in line 4 is only to help the compiler and make intellisense show all properties and not only the superset. If there is a component "Q1" of an other type you'll get a runtime error. You could (and probably should) check the component.Type before you cast and try to call a method Drawing.RunEx()

adamw


4,660 post(s)
#04-Jul-08 08:53

The correct term is "base type". Component is a base type of Query. Query is a derived type of Component.

If the right part of the assignment to a variable of type Query is not a Query, the assignment will generate an error by throwing an exception. You could catch and handle that exception, but generally it is better to make sure that the component at hand is a Query by checking its Type or TypeName property.

Lorne

560 post(s)
online
#04-Jul-08 13:02

Thanks all

I think this is just an example of carrying old ideas forward by copy/paste I began using that code construct in my early days of vbScript. I was always experimenting with forum code snippets that created temporary queries but did not delete them (exactName=False). Queries kept building up in the project as you ran the script. Another situation where deletion does not occur is with run-time errors (oops, I get lots of those) that prevent the code from completing and never gets to the query deletion code. This is mostly in the developing stage but, again, the query is left in the project. Using an obscure name like "__Query__1" would minimize the risk of having a non-query component with such a name.

So maybe something like:

'VB .NET

Dim Qry1 As Manifold.Interop.Query

If Context.Document.ComponentSet.ItemByName("__Query__1") < 0 Then

      ' Create a new query

    Qry1 = Context.Document.NewQuery("__Query__1")

ElseIf Context.Document.ComponentSet.Item("__Query__1").Type = _

 Manifold.Interop.ComponentType.ComponentQuery Then

      ' Use the old Query

    Qry1 = Context.Document.ComponentSet.Item("__Query__1")

Else

      ' Flag an error

    MessageBox.Show( _

       text:="__Query__1 exists in the project but is not a Query Component.", _

       caption:="Error", _

       buttons:=System.Windows.Forms.MessageBoxButtons.OK, _

       icon:=System.Windows.Forms.MessageBoxIcon.Information)

    Exit Sub

End If

Perhaps the simplest way of handling this in a .NET application would be to use exactName=False when creating a Query which would always create a new Query but allow Manifold to change the name to prevent conflicts. Use a Finally statement in the error routines to delete the temporary query. This would get rid of it even if a run-time error prevented completion of the main subroutine/function code.

'VB .NET

Dim Qry1 As Manifold.Interop.Query

Try

    ' ...

    Qry1 = Context.Document.NewQuery("Q1"False)

Catch ex As Exception

    ' Error message

Finally

    If Context.Document.ComponentSet.ItemByName(Qry1.Name) >= 0 Then

        Context.Document.ComponentSet.Remove(Qry1)

    End If

End Try

Better ideas very much welcomed!

jnorman

153 post(s)
#04-Jul-08 16:02

Wow -- just stole away from the 4th of July festivities at home. Looks like I'll have some catching up to do when I get some more time .

This is really cool to see the collaboration. Neat little tool and a learning experience to boot. I am certainly a trial and error programmer, but these exercises make it worth the effort. Now that it's in the .NET realm, I think I'll be spending time learning before contributing much more -- looking forward to it.

I like what I see --

adamw


4,660 post(s)
#05-Jul-08 03:23

There is an issue with the Try ... Finally code above. If the call to NewQuery(...) throws an exception the code in Finally tries to access Qry1.Name. This will throw another exception since Qry1 has not been initialized.

It would be better to use:

'VB.NET

Try

  '...

  Dim Qry1 As Manifold.Interop.Query ' no use to have Qry1 visible outside Try

  Qry1 = Context.Document.NewQuery("Q1"False)

  Try

    '...

  Finally

    Context.Document.ComponentSet.Remove(Qry1) ' no need to search by name

  End Try

Catch ex As Exception

  ' ... couldn't create Q1

End Try

Lorne

560 post(s)
online
#05-Jul-08 04:00

Thank you Adam!

Juanito3 post(s)
#14-Jul-08 00:01

Thanks for this wonderful tool because this what I need for my project . Apparently, when I open it to Manifold v. 6 an error occurs. It says that the file version is not supported. What Manifold version did you use?

lionel_

519 post(s)
#14-Jul-08 02:16

new map format is not compatible with all last new manifold system version. this force you to have the last version to better debug, feedback , feature (wish) of manifold Team and avoid waste time (manage old version). The only way to do that is export using last version manifold system each file inside the map then re import all file one by one .Which versionS numberS have you got ? A script could be implemented to do that easely instead using mouse/gui .

Attachments:
all_any_map.zip
all_any_map1.zip

Juanito3 post(s)
#14-Jul-08 17:30

Thanks lionel for a quick response. Currently, we are using Manifold System 6.50 Enterprise Edition.

Juanito3 post(s)
#14-Jul-08 18:27

I already downloaded and imported the files that you uploaded. What is the name of Choose Map textbox, Choose Layer textbox, Search for textbox and ZoomTo Multiplier textbox. Sorry coz I am a newbie in using a script. :-)

Lorne

560 post(s)
online
#18-Jul-08 09:21

I have been playing around with an add-in pane for this project. Lots of little problems but I discovered a few things as well. The code (SearchAllColumns.vb) is full of comments. It would be great if others would enhance the code. Sure to be lots of errors.

Attachments:
SearchAllColumns_DLL_XML.Zip
SearchAllColumns_VSproject.zip

Mike Pelletier

529 post(s)
#08-Aug-08 11:01

Lorne, just found your addition to this thread. The add-in is a wonderful improvement with very nice look and feel. It works great in both 32 and 64 bit. The ability to dock it like other panes is just great.

Hope to find some time to check it out in Visual Studio as well. Thanks for taking this so far

Converting the form to a dll also would seem to be great for data entry forms since the docking option is very nice.

Lorne

560 post(s)
online
#08-Aug-08 15:44

Thanks Mike. Appreciate the comments.

10 msec Copyright (C) 2007-2008 Manifold.net. All rights reserved.