|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Subclassing Routines WM_LBUTTONDOWN: Using a Combo in a MSFlexGrid to Select Data |
||
Posted: | Monday February 8, 1999 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB5, VB6 | |
Developed with: | VB6, Windows 98 | |
OS restrictions: | None | |
Author: | VBnet - Randy Birch | |
Prerequisites |
VB5 or VB6. |
|
When
working with a MSFlexGrid control, the developer may want to display a combo box to provide a list of cell data available for
selection. While the actual code to reposition a combo in relation to a cell is trivial, should the combo be in its visible state when
the user resizes the column, the combo would remain at its initial position and size until the cell is clicked again.
By utilizing subclassing techniques, we can trap the Windows' WM_MOVE and WM_PAINT messages, and in response to these, assure that the displayed combo is realigned to the cell's new width or position. This example was inspired from source provided via the Microsoft Knowledge Base. |
BAS Module Code |
Place the following code into the general declarations area of a bas module: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Const GWL_WNDPROC As Long = (-4) Public Const WM_SIZE As Long = &H5 Public Const WM_PAINT As Long = &HF Public Const CB_DELETESTRING As Long = &H144 Public Const CB_RESETCONTENT As Long = &H14B Public Const WM_LBUTTONDOWN As Long = &H201 Public Const WM_LBUTTONUP As Long = &H202 Public defWinProc As Long Public hWndFlex As Long Declare Function CallWindowProc Lib "user32" _ Alias "CallWindowProcA" _ (ByVal lpPrevWndFunc As Long, _ ByVal hwnd As Long, ByVal Msg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" _ (ByVal hwnd As Long, ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Public Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" _ (ByVal hwnd As Long, ByVal wMsg As Long, _ ByVal wParam As Long, lParam As Any) As Long Public Sub Hook() If defWinProc = 0 Then defWinProc = SetWindowLong(hWndFlex, _ GWL_WNDPROC, _ AddressOf WindowProc) End If End Sub Public Sub Unhook() If defWinProc <> 0 Then Call SetWindowLong(hWndFlex, _ GWL_WNDPROC, _ defWinProc) defWinProc = 0 End If End Sub Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long WindowProc = CallWindowProc(defWinProc, hwnd, uMsg, wParam, lParam) Select Case uMsg Case WM_SIZE, WM_PAINT With Form1 .Combo1.Width = .MSFlexGrid1.CellWidth .Combo1.Left = .MSFlexGrid1.CellLeft + .MSFlexGrid1.Left .Combo1.Top = .MSFlexGrid1.CellTop + .MSFlexGrid1.Top End With Case WM_LBUTTONDOWN With Form1 .Combo1.Width = .MSFlexGrid1.CellWidth .Combo1.Left = .MSFlexGrid1.CellLeft + .MSFlexGrid1.Left .Combo1.Top = .MSFlexGrid1.CellTop + .MSFlexGrid1.Top End With With Form1.MSFlexGrid1 If .Col > 0 Then Form1.Combo1.Visible = False Form1.Combo1.Text = "" Form1.FillComboData .Col Form1.Combo1.Text = .Text Form1.Combo1.Visible = True End If End With Case Else End Select End Function |
Form Code |
To a form, add a command button (Command1), combo (Combo1) and MSFlexGrid control (MSFlexGrid1). Add the following code: |
|
Option Explicit Public Sub FillComboData(currCol As Integer) Static lastColumn As Integer 'Based on the column passed, fill the combo 'with the data for that column If currCol <> lastColumn Then 'erase current combo Call SendMessage(Combo1.hwnd, CB_RESETCONTENT, 0&, ByVal 0&) Select Case currCol Case 1: 'Load the ComboBox's list With Combo1 .AddItem "Some text" .AddItem "Some more text" .AddItem "Still more text" .AddItem "Yet even more text" .AddItem "Way more text than that" End With Case 2: 'Load the ComboBox's list With Combo1 .AddItem "125.00" .AddItem "133.00" .AddItem "229.00" .AddItem "345.00" .AddItem "385.00" End With Case 3: 'Load the ComboBox's list With Combo1 .AddItem "box" .AddItem "carton" .AddItem "case" .AddItem "each" .AddItem "package" End With Case Else End Select End If lastColumn = currCol End Sub Private Sub Command1_Click() Unload Me End Sub Private Sub Form_Unload(Cancel As Integer) If defWinProc <> 0 Then Unhook 'Stop checking messages End If End Sub Private Sub MSFlexGrid1_MouseMove(Button As Integer, Shift As Integer, _ X As Single, Y As Single) Static CurrentWidth As Single 'Check to see if the Cell's width has changed With MSFlexGrid1 If .CellWidth <> CurrentWidth Then Combo1.Width = .CellWidth CurrentWidth = .CellWidth End If End With End Sub Private Sub Form_Load() With MSFlexGrid1 hWndFlex = .hwnd Hook 'Start checking messages .AllowUserResizing = flexResizeColumns .Cols = 4 .Rows = 6 .RowHeightMin = Combo1.Height End With With Combo1 .Visible = False .ZOrder 0 .Width = MSFlexGrid1.CellWidth End With End Sub Private Sub Combo1_Click() 'Place the selected item into the 'Cell and hide the ComboBox MSFlexGrid1.Text = Combo1.Text Combo1.Visible = False End Sub |
Comments |
Save the project before running, and use Start with Full
Compile to catch any errors that might crash the subclassing. Clicking anywhere within the working area will display the combo box for that
column. While the combo is displayed, resize the column. When you release the resize bar, the combo will resize to take up the entire cell.
To compare to the non-subclassed method, comment out the Hook statement in the form load and run again. |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |