X

NV5 Geospatial Blog

Each month, NV5 Geospatial posts new blog content across a variety of categories. Browse our latest posts below to learn about important geospatial information or use the search bar to find a specific topic or author. Stay informed of the latest blog posts, events, and technologies by joining our email list!



Not All Supernovae Are Created Equal: Rethinking the Universe’s Measuring Tools

Not All Supernovae Are Created Equal: Rethinking the Universe’s Measuring Tools

6/3/2025

Rethinking the Reliability of Type 1a Supernovae   How do astronomers measure the universe? It all starts with distance. From gauging the size of a galaxy to calculating how fast the universe is expanding, measuring cosmic distances is essential to understanding everything in the sky. For nearby stars, astronomers use... Read More >

Using LLMs To Research Remote Sensing Software: Helpful, but Incomplete

Using LLMs To Research Remote Sensing Software: Helpful, but Incomplete

5/26/2025

Whether you’re new to remote sensing or a seasoned expert, there is no doubt that large language models (LLMs) like OpenAI’s ChatGPT or Google’s Gemini can be incredibly useful in many aspects of research. From exploring the electromagnetic spectrum to creating object detection models using the latest deep learning... Read More >

From Image to Insight: How GEOINT Automation Is Changing the Speed of Decision-Making

From Image to Insight: How GEOINT Automation Is Changing the Speed of Decision-Making

4/28/2025

When every second counts, the ability to process geospatial data rapidly and accurately isn’t just helpful, it’s critical. Geospatial Intelligence (GEOINT) has always played a pivotal role in defense, security, and disaster response. But in high-tempo operations, traditional workflows are no longer fast enough. Analysts are... Read More >

Thermal Infrared Echoes: Illuminating the Last Gasp of a Dying Star

Thermal Infrared Echoes: Illuminating the Last Gasp of a Dying Star

4/24/2025

This blog was written by Eli Dwek, Emeritus, NASA Goddard Space Flight Center, Greenbelt, MD and Research Fellow, Center for Astrophysics, Harvard & Smithsonian, Cambridge, MA. It is the fifth blog in a series showcasing our IDL® Fellows program which supports passionate retired IDL users who may need support to continue their work... Read More >

A New Era of Hyperspectral Imaging with ENVI® and Wyvern’s Open Data Program

A New Era of Hyperspectral Imaging with ENVI® and Wyvern’s Open Data Program

2/25/2025

This blog was written in collaboration with Adam O’Connor from Wyvern.   As hyperspectral imaging (HSI) continues to grow in importance, access to high-quality satellite data is key to unlocking new insights in environmental monitoring, agriculture, forestry, mining, security, energy infrastructure management, and more.... Read More >

1345678910Last
23506 Rate this article:
No rating

Resizable Widgets

Anonym

When developing widgets, it can often be tricky to position them correctly and make them the right size. Even for an experienced programmer, it takes quite a bit of trial-and-error. Code can quickly become messy and difficult to read when sizing code is mixed in with widget creation; this is especially true when developing a cross-platform widget, which may need different sizes depending on the platform.

Here is an example of widget code that does not contain any size definitions:

  base = WIDGET_BASE(/COLUMN, TITLE='Please make some selections', $
    /BASE_ALIGN_LEFT, /TLB_SIZE_EVENTS)
  features_label = WIDGET_LABEL(base, VALUE='Check all that apply:')
  features_base = WIDGET_BASE(base, /ROW, /NONEXCLUSIVE, UNAME='features_base')
  glasses = WIDGET_BUTTON(features_base, VALUE='Wears glasses', UNAME='glasses')
  moustache = WIDGET_BUTTON(features_base, VALUE='Moustache', UNAME='moustache')
  over6ft = WIDGET_BUTTON(features_base, VALUE='Taller than 6ft', UNAME='over6ft')

  haircolor_label = WIDGET_LABEL(base, VALUE='Select Hair Color:')
  haircolor_base = WIDGET_BASE(base, /ROW, /EXCLUSIVE, UNAME='haircolor_base')
  black = WIDGET_BUTTON(haircolor_base, VALUE='Black', UNAME='black')
  brown = WIDGET_BUTTON(haircolor_base, VALUE='Brown', UNAME='brown')
  blond = WIDGET_BUTTON(haircolor_base, VALUE='Blond', UNAME='blond')
  red = WIDGET_BUTTON(haircolor_base, VALUE='Red', UNAME='red')

  descrip_label = WIDGET_LABEL(base, VALUE='Describe yourself:')
  descrip = WIDGET_TEXT(base, /EDITABLE, UNAME='descrip')

  bottom_base = WIDGET_BASE(base, /ROW, UNAME='bottom_base')
  help_base = WIDGET_BASE(bottom_base, /ROW, UNAME='help_base')
  help = WIDGET_BUTTON(help_base, VALUE='Help', UNAME='help')
  space = WIDGET_BASE(bottom_base, UNAME='space')
  commit_base = WIDGET_BASE(bottom_base, /ROW, UNAME='commit_base', /GRID_LAYOUT)
  ok = WIDGET_BUTTON(commit_base, VALUE='OK', UNAME='ok')
  cancel = WIDGET_BUTTON(commit_base, VALUE='Cancel', UNAME='cancel')

This is what the widget looks like after calling WIDGET_CONTROL, base, /REALIZE on the widget (on Windows 7):


This doesn't look bad. However, the OK and Cancel buttons are not in their usual spot, the bottom-right corner, and the text box is rather small.

One trick to creating a widget that has the desired size and layout is to write a separate routine instead of modifying the code above. Once the above code is run, simply call the new routine with the desired size before realizing the base.

Why do this in a separate routine? This routine will not only set the original size, but it can also be used to resize the widget and all of its components when the user drags the edges or corners. Allowing the user to resize the widget will provide an enhanced user-experience. In this example, the user may enter text that is longer than the width of the text box, and the ability to widen it would allow the user to view all of the text at once rather than using the arrow keys to navigate through it.

Here is an example of a routine that can be used to adjust the size of this example widget:


PRO example_widget_adjust_size, base, new_size
  COMPILE_OPT IDL2

  ; Do not allow the widget to be made any smaller than the original size.
  WIDGET_CONTROL, base, GET_UVALUE=orig_size
  IF new_size[0] LT orig_size[0] THEN new_size[0] = orig_size[0]
  IF new_size[1] LT orig_size[1] THEN new_size[1] = orig_size[1]

  ; Determine the padding, which needs to be subtracted.
  base_geom = WIDGET_INFO(base, /GEOMETRY)
  xpad = base_geom.xpad
  ypad = base_geom.ypad

  ; There is padding on both sides of the textbox, so subtract twice the xpad.
  descrip_width = new_size[0] - 2*xpad
  descrip = WIDGET_INFO(base, FIND_BY_UNAME='descrip')
  WIDGET_CONTROL, descrip, SCR_XSIZE=descrip_width

  ; Determine the size of the Help, OK and Cancel buttons. There are
  ; three bases within the bottom base, so subtract 4 times xpad.

  commit_base = WIDGET_INFO(base, FIND_BY_UNAME='commit_base')
  commit_geom = WIDGET_INFO(commit_base, /GEOMETRY)
  help_base = WIDGET_INFO(base, FIND_BY_UNAME='help_base')
  help_geom = WIDGET_INFO(help_base, /GEOMETRY)
  space_width = new_size[0] - commit_geom.xsize - help_geom.xsize - 4*xpad
  space = WIDGET_INFO(base, FIND_BY_UNAME='space')
  WIDGET_CONTROL, space, XSIZE=space_width

END

The main routine now needs to define a size and pass it, along with the base, into this routine. There are two options for choosing the original size: A fixed original size can be chosen, based on what the developer thinks is suitable, or the original size can be calculated by calling WIDGET_INFO with /GEOMETRY on each of the component items and totaling the x and y sizes. For example purposes, a fixed size will be used. When using a fixed original size, it may be a good idea to make the size slightly larger on motif widgets than on Windows because motif widgets use bigger text. 

Here is the code needed to set the original size, which should be added right above the REALIZE call:

  IF !VERSION.OS_FAMILY EQ 'Windows' THEN BEGIN
    orig_size = [300, 180]
  ENDIF ELSE BEGIN
    orig_size = [350, 200]
  ENDELSE

  ; Set the original size in the UVALE to keep track of it.
  WIDGET_CONTROL, base, SET_UVALUE=orig_size
  
  example_widget_adjust_size, base, orig_size

If the developer decides to change the original size, this is the only place that will need to be updated. Here is the new look:

Allowing the user to resize the widget now falls into place. The widget's event handler can catch the size event, which uses the WIDGET_BASE structure, and pass the new size into the resize routine.

  IF TAG_NAMES(event, /STRUCTURE_NAME) EQ 'WIDGET_BASE' THEN BEGIN
    example_widget_adjust_size, event.top, [event.x, event.y]
  ENDIF

Now the user can expand the widget, and the text box and buttons automatically adjust:

In this example, the labels, checkboxes, and radio buttons aren't changed when the widget is resized, but this technique can be applied to any widget, no matter how big or small, in order to provide a resizable widget.

Please login or register to post comments.