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!



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 >

Ensure Mission Success With the Deployable Tactical Analytics Kit (DTAK)

Ensure Mission Success With the Deployable Tactical Analytics Kit (DTAK)

2/11/2025

In today’s fast-evolving world, operational success hinges on real-time geospatial intelligence and data-driven decisions. Whether it’s responding to natural disasters, securing borders, or executing military operations, having the right tools to integrate and analyze data can mean the difference between success and failure.... Read More >

How the COVID-19 Lockdown Improved Air Quality in Ecuador: A Deep Dive Using Satellite Data and ENVI® Software

How the COVID-19 Lockdown Improved Air Quality in Ecuador: A Deep Dive Using Satellite Data and ENVI® Software

1/21/2025

The COVID-19 pandemic drastically altered daily life, leading to unexpected environmental changes, particularly in air quality. Ecuador, like many other countries, experienced significant shifts in pollutant concentrations due to lockdown measures. In collaboration with Geospace Solutions and Universidad de las Fuerzas Armadas ESPE,... Read More >

Rapid Wildfire Mapping in Los Angeles County

Rapid Wildfire Mapping in Los Angeles County

1/14/2025

On January 8, WorldView-3 shortwave infrared (SWIR) imagery captured the ongoing devastation of the wildfires in Los Angeles County. The data revealed the extent of the burned areas at the time of the capture, offering critical insights for rapid response and recovery. To analyze the affected region, we utilized a random forest... Read More >

1345678910Last
«May 2025»
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
23404 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.