|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic
List API BitBlt: Present a Non-Selectable 'No Data' Picture in a ListBox |
||
Posted: | Saturday November 29, 2003 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB6, Windows XP | |
OS restrictions: | None | |
Author: | VBnet - Randy Birch | |
Related: |
VBnet CoolTabs GetTextExtentPoint32: Right-Align List Box Data SetWindowLong: Right-Align List Box Data and/or the Scrollbar SetWindowLong: Right-Align List Contents in a Combo SendMessage: Align Text Box Contents Using Tabstops SendMessage: Align List Box Contents Using Tabstops WM_LBUTTONDOWN: Substitute a Tabbed List for a Combo's Dropdown List WM_LBUTTONDOWN: Substitute a ListView for a Combo's Dropdown List |
|
Prerequisites |
None. |
|
The
VBnet page
SendMessage: Add a Background Image to a ListView showed how to use
SendMessage with the LVBKIMAGE structure to display images in the data
window of a listview control. Although Windows' normal list box does
not support such functionality, we can still fake this functionality using the BitBlt API
to impress an
image on the hDC of a normal VB list box data window.
While this method will allow the presentation of an image along with selectable list data, unlike the listview control there is no mechanism provided by which the image will scroll or act as a watermark as the user navigates the list. However, this technique could be useful for displaying a corporate logo on start-up when the list is empty, or - as shown here - to add a message to the list indicating the list was not ready to use. The traditional way to do this is to utilize the list's AddItem method to add a single list item to an empty list (i.e. "(no data)") and then perform a check in the list's click event to determine if the list contains data and if the string selected was the 'no data' entry. The method shown here actually uses BitBlt to apply a bitmap image to the list's hDc (as shown), which means the data displayed is no longer limited strictly to strings. Furthermore, unlike the aforementioned method to determine the selection, clicking an empty list with only the image applied (as shown) will not generate a click. A further bonus is the list will not display a focus rect when the Blt'ted image is displayed. The three buttons on the form perform slightly different functions to demo the options available. 'Fill List' is straightforward - 20 numbers are added to the list at each press. The 'No data' button executes the routine to display the no data message only when the list does not contain data (the bForceClear flag in the call is False). The 'Clear list' button calls the same routine as the 'No data' button, but passes True when the list contains data, forcing a List1.Clear and subsequent display of the 'no data' message. Note that, at a given point, the control can only display either the Blt'ted image or the list items - in other words, if you modify the code to apply an image or text via BitBlt to a list containing data, the data will be erased when the image is applied. Selecting a list item will destroy the image at that line. To see this in effect, comment out the 'If List1.ListCount = 0 Then' line in Command1. The code below could be applied to other controls through appropriate modification. |
BAS Module Code |
None. |
|
Form Code |
Add a listbox (List1), three command buttons (Command1, Command2, Command3), and a picture box (Picture1) to the form. The code takes care of setting the captions and sizing/setting up the picture box. Add the following code: |
|
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. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const SRCCOPY = &HCC0020 Private Declare Function GetDC Lib "user32" _ (ByVal hwnd As Long) As Long Private Declare Function BitBlt Lib "gdi32" _ (ByVal hDestDC As Long, _ ByVal x As Long, _ ByVal y As Long, _ ByVal nWidth As Long, _ ByVal nHeight As Long, _ ByVal hSrcDC As Long, _ ByVal xSrc As Long, _ ByVal ySrc As Long, _ ByVal dwRop As Long) As Long Private Declare Function ReleaseDC Lib "user32" _ (ByVal hwnd As Long, _ ByVal hdc As Long) As Long Private Const HORZRES = 8 Private Const VERTRES = 10 Private Declare Function GetDeviceCaps Lib "gdi32" _ (ByVal hdc As Long, _ ByVal nIndex As Long) As Long Private Sub Form_Load() 'set up controls Command1.Caption = "No data" Command2.Caption = "Fill list" Command3.Caption = "Clear list" 'Optional - force the form on-screen 'then execute the 'no data' routine 'so the message appears at startup. 'A doevents is required here. Me.Show DoEvents Command1.Value = True End Sub Private Sub Command1_Click() If List1.ListCount = 0 Then BoxShot Picture1, List1, "No data - a category must be selected first.", False Else MsgBox "Nope ... the list contains data!" End If End Sub Private Sub Command2_Click() 'demo - add dummy data Dim x As Long For x = 1 To 20 List1.AddItem x Next End Sub Private Sub Command3_Click() BoxShot Picture1, List1, "No data - a category must be selected first.", (List1.ListCount > 0) End Sub Private Sub BoxShot(ctlMsgSource As PictureBox, _ ctlTarget As ListBox, _ msg As String, _ bForceClear As Boolean) Dim hDcTarget As Long Dim hDcSource As Long Dim w As Long Dim h As Long If bForceClear Then If TypeOf ctlTarget Is ListBox Then ctlTarget.Clear ctlTarget.Refresh End If 'If TypeOf End If 'If bForceClear 'set up and create message to display 'in the listbox If TypeOf ctlMsgSource Is PictureBox Then With ctlMsgSource .Visible = False .Cls .BorderStyle = 0 .Appearance = 0 .AutoRedraw = True .BackColor = ctlTarget.BackColor .Width = ctlTarget.Width .Height = .TextHeight("A") .Font.Name = ctlTarget.Font.Name .Font.Size = ctlTarget.Font.Size 'the print command can not be 'used with a 'With' block! (try 'deleting the 'ctlMsgSource' below - 'an error occurs. ctlMsgSource.Print msg End With 'need the hDcs for the controls hDcTarget = GetDC(ctlTarget.hwnd) hDcSource = ctlMsgSource.hdc If hDcTarget Then If hDcSource Then 'get the size of the pixbox, in pixels w = ctlMsgSource.Width \ Screen.TwipsPerPixelX h = ctlMsgSource.Height \ Screen.TwipsPerPixelY 'blt the message onto the list hDc BitBlt hDcTarget, 0, 0, w, h, hDcSource, 0, 0, SRCCOPY End If 'If hdcSource ReleaseDC 0, hDcTarget End If 'If hdcTarget End If 'If TypeOf End Sub |
Comments |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |