home *** CD-ROM | disk | FTP | other *** search
/ Programming Tool Box / SIMS_2.iso / vb_code1 / listdemo / list_utl.bas next >
BASIC Source File  |  1994-01-10  |  12KB  |  397 lines

  1. 'These Visual Basic functions were written by Brad Kaenel
  2. 'of PC HELP-LINE, and are considered to be a "work-in-progress".
  3. 'If you have a comment or suggestion for improvement, contact
  4. 'Brad through Compuserve (72357,3523) or Internet (72357.3523@compuserve.com)
  5.  
  6. Option Explicit
  7.  
  8. Declare Function WinAPI_SetTabstops Lib "User" Alias "SendMessage" (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, lParam As Any) As Long
  9. Declare Function WinAPI_SelectString Lib "User" Alias "SendMessage" (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Long
  10. Declare Function WinAPI_GetTextExtent Lib "GDI" Alias "GetTextExtent" (ByVal hDC As Integer, ByVal lpString As String, ByVal nCount As Integer) As Long
  11. Declare Function WinAPI_GetDialogBaseUnits Lib "User" Alias "GetDialogBaseUnits" () As Long
  12.  
  13. Const WM_USER = 1024
  14. Const LB_SETTABSTOPS = WM_USER + 19
  15. Const EM_SETTABSTOPS = WM_USER + 27
  16. Const CB_SELECTSTRING = WM_USER + 13
  17. Const LB_SELECTSTRING = WM_USER + 13
  18.  
  19. Const SEARCH_FROM_TOP = -1
  20.  
  21. Function SelectListItem (ListControl As Control, SelectString As String) As Integer
  22.  
  23. Dim MsgID As Integer
  24. Dim RC As Long
  25.  
  26.  
  27. '===================
  28. SelectListItem_Main:
  29. '===================
  30. SelectListItem = True
  31.  
  32. GoSub SelectListItem_VerifyControls
  33. GoSub SelectListItem_UpdateControls
  34.  
  35. Exit Function
  36.  
  37.  
  38. '=============================
  39. SelectListItem_VerifyControls:
  40. '=============================
  41. If TypeOf ListControl Is ListBox Then
  42.    MsgID = LB_SELECTSTRING
  43. Else
  44.    If TypeOf ListControl Is ComboBox Then
  45.       MsgID = CB_SELECTSTRING
  46.    Else
  47.       SelectListItem = False
  48.       Exit Function
  49.    End If
  50. End If
  51.  
  52. If Len(SelectString) = 0 Then
  53.    SelectListItem = False
  54.    Exit Function
  55. End If
  56.  
  57. Return
  58.  
  59. '=============================
  60. SelectListItem_UpdateControls:
  61. '=============================
  62. RC = WinAPI_SelectString(ListControl.hWnd, MsgID, SEARCH_FROM_TOP, SelectString)
  63.  
  64. Return
  65.  
  66. End Function
  67.  
  68. Function SetListCols (ListControl As Control, TextControl As Control, UseHeadingWidthsOnly As Integer, SetDefaultTabstops As Integer) As Integer
  69.  
  70. 'This function automatically calculates and sets appropriate
  71. 'tabstops for a multi-column listbox, based on the actual data
  72. 'in the listbox.  You do not have to tell the function how many
  73. 'columns you want, nor figure out how wide each column should be;
  74. 'the actual data placed into the listbox determines that.
  75.  
  76. 'In addition to the listbox, the function also sets identical
  77. 'tabstops in an accompanying, multi-line textbox.  This textbox
  78. 'provides the data for the column headings.
  79.  
  80. 'UseHeadingWidthsOnly:
  81. '  True -  Tabstops are calculated based only on the
  82. '          widths of the column headings. This option
  83. '          is must faster, but you're gambling that the
  84. '          actual data will always be narrower than the
  85. '          headings.
  86. '
  87. '  False - Tabstops are calculated based on the widest
  88. '          entry in each column; both the headings and
  89. '          the data are examined.  This option is slower
  90. '          because each entry in the listbox must be
  91. '          parsed, but it eliminates the guesswork.
  92.  
  93. 'SetDefaultTabstops:
  94. '  True -  Tabstops are reset to Windows' default intervals
  95. '          of 8 dialog units.
  96. '
  97. '  False - Tabstops are calculated based on the actual
  98. '          data in the listbox/textbox.
  99. '
  100. '
  101. 'The function itself return FALSE if any of the control
  102. 'verification tests fail; otherwise it returns TRUE.
  103.  
  104.  
  105. Dim ColHeadings As String, ColData As String, ColString As String
  106. Dim ParentFontName As String, ParentFontSize As Single
  107. Dim ParentFontBold As Integer, ParentFontItalic As Integer
  108. Dim ColCount As Integer, DataWidth As Integer, SpaceBetweenCols As Integer
  109. Dim MaxListboxCols As Integer, NbrListboxCols As Integer, NbrTabstops As Integer
  110. Dim InStart As Integer, TabPos As Integer
  111. Dim ListSub As Integer, TabSub As Integer
  112. Dim RC As Long
  113. Dim ListFontAvgWidth As Integer, SystemFontAvgWidth As Integer
  114. Dim ListFontPixelsPerDlgUnit As Single, FontRatio As Single
  115.  
  116. Dim ColWidth() As Integer  'measured column widths
  117. Dim Tabstop() As Integer   'calculated WinAPI tabstops
  118.  
  119. '================
  120. SetListCols_Main:
  121. '================
  122. SetListCols = True
  123.  
  124. GoSub SetListCols_VerifyControls
  125. GoSub SetListCols_Initialize
  126.  
  127. If SetDefaultTabstops Then
  128.    NbrTabstops = 0
  129.    GoSub SetListCols_UpdateControls
  130. Else
  131.    'Since VB provides an hDC property only for forms,
  132.    'not for controls, we must temporarily set the parent
  133.    'form's font characteristics equal to the listbox's
  134.    'font characteristics.  Doing this ensures that all
  135.    'text measurements made using the form's DC will be
  136.    'accurate for the listbox.
  137.  
  138.    ParentFontName = ListControl.Parent.FontName
  139.    ParentFontSize = ListControl.Parent.FontSize
  140.    ParentFontBold = ListControl.Parent.FontBold
  141.    ParentFontItalic = ListControl.Parent.FontItalic
  142.    ListControl.Parent.FontName = ListControl.FontName
  143.    ListControl.Parent.FontSize = ListControl.FontSize
  144.    ListControl.Parent.FontBold = ListControl.FontBold
  145.    ListControl.Parent.FontItalic = ListControl.FontItalic
  146.  
  147.    'Identify and measure the width of the column headings
  148.    'present in the textbox.
  149.  
  150.    GoSub SetListCols_MeasureColHeadingWidths
  151.  
  152.    'Measure the width of the column data values present
  153.    'in the listbox.
  154.  
  155.    If Not UseHeadingWidthsOnly Then
  156.       GoSub SetListCols_MeasureColDataWidths
  157.    End If
  158.  
  159.    'Calculate and set the necessary tabstop values, based
  160.    'on the maximum width of each column.
  161.  
  162.    GoSub SetListCols_UpdateControls
  163.  
  164.    'Reset the parent form's font characteristics to their
  165.    'original values.
  166.  
  167.    ListControl.Parent.FontName = ParentFontName
  168.    ListControl.Parent.FontSize = ParentFontSize
  169.    ListControl.Parent.FontBold = ParentFontBold
  170.    ListControl.Parent.FontItalic = ParentFontItalic
  171. End If
  172.  
  173. Exit Function
  174.  
  175.  
  176. '==========================
  177. SetListCols_VerifyControls:
  178. '==========================
  179. 'Make sure both controls are the proper type,
  180. 'and that the necessary property values are set.
  181.  
  182. If TypeOf ListControl Is ListBox Then
  183. Else
  184.    SetListCols = False
  185.    Exit Function
  186. End If
  187.  
  188. If TypeOf TextControl Is TextBox Then
  189. Else
  190.    SetListCols = False
  191.    Exit Function
  192. End If
  193.  
  194. If ListControl.Columns <> 0 Then
  195.    SetListCols = False
  196.    Exit Function
  197. End If
  198.  
  199. If TextControl.MultiLine = False Then
  200.    SetListCols = False
  201.    Exit Function
  202. End If
  203.  
  204. If TextControl.BorderStyle <> 0 Then
  205.    SetListCols = False
  206.    Exit Function
  207. End If
  208.  
  209. If Len(TextControl.Text) = 0 Then
  210.    SetListCols = False
  211.    Exit Function
  212. End If
  213.  
  214. Return
  215.            
  216. '======================
  217. SetListCols_Initialize:
  218. '======================
  219. 'A little extra space between columns helps
  220. 'to mitigate the inevitable rounding errors
  221. 'that will occur in the tabstop calculations.
  222.  
  223. SpaceBetweenCols = 2
  224.  
  225. MaxListboxCols = 10
  226. ReDim ColWidth(MaxListboxCols)
  227.  
  228. Return
  229.  
  230. '===================================
  231. SetListCols_MeasureColHeadingWidths:
  232. '===================================
  233. 'Search for TAB characters in the column heading
  234. 'text.  For each column found, measure the width
  235. 'of the heading text.
  236.  
  237. ColHeadings = TextControl.Text
  238. NbrListboxCols = 1
  239.  
  240. InStart = 1
  241. Do
  242.    TabPos = InStr(InStart, ColHeadings, Chr$(9))
  243.  
  244.    If TabPos > 0 Then
  245.       ColString = Mid$(ColHeadings, InStart, TabPos - InStart)
  246.    Else
  247.       ColString = Mid$(ColHeadings, InStart, Len(ColHeadings) - InStart + 1)
  248.    End If
  249.  
  250.    'Measure the length of the string, in pixels;
  251.    'this value is the current "column width".
  252.    
  253.    ColString = ColString + Space$(SpaceBetweenCols)
  254.    ColWidth(NbrListboxCols) = WinAPI_GetTextExtent(ListControl.Parent.hDC, ColString, Len(ColString)) Mod 65536
  255.  
  256.    If TabPos > 0 Then
  257.       NbrListboxCols = NbrListboxCols + 1
  258.  
  259.       'Allocate more space for more columns, if necessary
  260.  
  261.       If NbrListboxCols > MaxListboxCols Then
  262.          MaxListboxCols = NbrListboxCols
  263.          ReDim Preserve ColWidth(MaxListboxCols)
  264.       End If
  265.  
  266.       If TabPos < Len(ColHeadings) Then
  267.          InStart = TabPos + 1
  268.       End If
  269.    End If
  270. Loop Until TabPos = 0
  271.  
  272. NbrTabstops = NbrListboxCols - 1
  273.  
  274. Return
  275.  
  276. '================================
  277. SetListCols_MeasureColDataWidths:
  278. '================================
  279. 'Search for TAB characters in the listbox data.
  280. 'For each column found, measure the width of
  281. 'the data.
  282.  
  283. For ListSub = 0 To ListControl.ListCount - 1
  284.    If Len(ListControl.List(ListSub)) > 0 Then
  285.       ColData = ListControl.List(ListSub)
  286.       ColCount = 1
  287.  
  288.       InStart = 1
  289.       Do
  290.          TabPos = InStr(InStart, ColData, Chr$(9))
  291.  
  292.          If TabPos > 0 Then
  293.             ColString = Mid$(ColData, InStart, TabPos - InStart)
  294.          Else
  295.             ColString = Mid$(ColData, InStart, Len(ColData) - InStart + 1)
  296.          End If
  297.  
  298.          'Measure the length of the string, in pixels
  299.    
  300.          ColString = ColString + Space$(SpaceBetweenCols)
  301.          DataWidth = WinAPI_GetTextExtent(ListControl.Parent.hDC, ColString, Len(ColString)) Mod 65536
  302.  
  303.          'Ignore data columns for which there is no heading.
  304.  
  305.          If ColCount <= NbrListboxCols Then
  306.             'If any data value is wider than the current column width,
  307.             'it becomes the new column width.
  308.  
  309.             If DataWidth > ColWidth(ColCount) Then
  310.                ColWidth(ColCount) = DataWidth
  311.             End If
  312.          End If
  313.  
  314.          If TabPos > 0 Then
  315.             ColCount = ColCount + 1
  316.  
  317.             If TabPos < Len(ColData) Then
  318.                InStart = TabPos + 1
  319.             End If
  320.          End If
  321.       Loop Until TabPos = 0
  322.    End If
  323. Next
  324.  
  325. Return
  326.  
  327. '==========================
  328. SetListCols_UpdateControls:
  329. '==========================
  330. 'Set the textbox font characteristics equal
  331. 'to the listbox font characteristics.
  332.  
  333. TextControl.Enabled = False
  334. TextControl.FontName = ListControl.FontName
  335. TextControl.FontSize = ListControl.FontSize
  336. TextControl.FontBold = ListControl.FontBold
  337. TextControl.FontItalic = ListControl.FontItalic
  338. TextControl.Move ListControl.Left, ListControl.Top - TextControl.Height, ListControl.Width, TextControl.Height
  339.  
  340. ReDim Tabstop(NbrTabstops)
  341.  
  342. 'Calculate tabstop values for each column, in "dialog units"
  343.  
  344. If NbrTabstops > 0 Then
  345.    'Get the average character widths, in pixels, of the
  346.    'listbox font and the system font.
  347.  
  348.    ListFontAvgWidth = (WinAPI_GetTextExtent(ListControl.Parent.hDC, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52) Mod 65536) / 52
  349.    SystemFontAvgWidth = WinAPI_GetDialogBaseUnits() Mod 65536
  350.  
  351.    'A "dialog unit" is defined as 1/4 of the average
  352.    'character width of the system font, in pixels.
  353.    'We've already measured the width of each column,
  354.    'in pixels, but it's not accurate enough to simply
  355.    'divide one value into the other.
  356.  
  357.    'Note that errors in precision will start to creep in
  358.    'at this point, due to integer rounding and intermediate
  359.    'calculation results.  Experience shows that a little
  360.    'extra white space between the data columns helps to
  361.    'compensate (see "SpaceBetweenCols").
  362.  
  363.    'Since a dialog unit is based on the system font,
  364.    'not the font we're actually using in the listbox,
  365.    'we must factor in the difference between the two
  366.    'average character widths.  Thus, a more accurate
  367.    'divisor is calculated as follows.
  368.  
  369.    FontRatio = ListFontAvgWidth / SystemFontAvgWidth
  370.    ListFontPixelsPerDlgUnit = (SystemFontAvgWidth * FontRatio) / 4
  371.  
  372.    'Set a tabstop at the dialog unit closest to the
  373.    'right-hand boundary (width) of each column.
  374.  
  375.    Tabstop(0) = ColWidth(1) / ListFontPixelsPerDlgUnit
  376.    For TabSub = 2 To NbrTabstops
  377.       Tabstop(TabSub - 1) = Tabstop(TabSub - 2) + ColWidth(TabSub) / ListFontPixelsPerDlgUnit
  378.    Next
  379. Else
  380.    Tabstop(0) = 0
  381. End If
  382.  
  383. 'Activate the tabstops.
  384.  
  385. RC = WinAPI_SetTabstops(TextControl.hWnd, EM_SETTABSTOPS, NbrTabstops, Tabstop(0))
  386. RC = WinAPI_SetTabstops(ListControl.hWnd, LB_SETTABSTOPS, NbrTabstops, Tabstop(0))
  387.  
  388. 'Redraw the controls.
  389.  
  390. TextControl.Refresh
  391. ListControl.Refresh
  392.  
  393. Return
  394.  
  395. End Function
  396.  
  397.