VB format syntax
Using the Visual Basic format() function
The Format function converts a value to a text string and gives you control over the string's appearance. For example, you can specify the number of decimal places for a numeric value, leading or trailing zeros, currency formats, and portions of the date. The syntax is:
Syntax
Format(expression [,format [,firstdayofweek [,firstweekofyear]]])
expression
Any valid expression
format
A valid named or user-defined format expression
firstdayofweek
A constant that specifies the first day of the week
firstweekofyear
A constant that specifies the first week of the year The firstdayofweek argument has these settings: Constant Value Description
vbUseSystem 0 Use NLS API setting.
vbSunday 1 Sunday (default)
vbMonday 2 Monday
vbTuesday 3 Tuesday
vbWednesday 4 Wednesday
vbThursday 5 Thursday
vbFriday 6 Friday
vbSaturday 7 Saturday
The firstweekofyear argument has these settings: Constant Value Description
vbUseSystem 0 Use NLS API setting.
vbFirstJan1 1 Start with week in which January 1 occurs (default).
vbFirstFourDays 2 Start with the first week that has at least four days in the year.
vbFirstFullWeek 3 Start with the first full week of the year.
Notes
If you try to format a number without specifying format, Format provides functionality similar to the Str function, although it is internationally aware. However, positive numbers formatted as strings using Format don’t include a leading space reserved for the sign of the value; those converted using Str retain the leading space.
If you are formatting a non-localized numeric string, you should use a user-defined numeric format to ensure that you get the look you want.
If the Calendar property setting is Gregorian and format specifies date formatting, the supplied expression must be Gregorian. If the Visual Basic Calendar property setting is Hijri, the supplied expression must be Hijri.
If the calendar is Gregorian, the meaning of format expression symbols is unchanged. If the calendar is Hijri, all date format symbols (for example, dddd, mmmm, yyyy) have the same meaning but apply to the Hijri calendar. Format symbols remain in English; symbols that result in text display (for example, AM and PM) display the string (English or Arabic) associated with that symbol. The range of certain symbols changes when the calendar is Hijri.
Formatting Symbols
Character Description
None
No formatting Display the number with no formatting.
: Time separator. In some locales, other characters may be used to represent the time separator. The time separator separates hours, minutes, and seconds when time values are formatted. The actual character used as the time separator in formatted output is determined by your system settings.
/ Date separator. In some locales, other characters may be used to represent the date separator. The date separator separates the day, month, and year when date values are formatted. The actual character used as the date separator in formatted output is determined by your system settings.
C Display the date as ddddd and display the time as t t t t t, in that order. Display only date information if there is no fractional part to the date serial number; display only time information if there is no integer portion.
D Display the day as a number without a leading zero (1 - 31).
dd Display the day as a number with a leading zero (01 - 31).
ddd Display the day as an abbreviation (Sun - Sat).
dddd Display the day as a full name (Sunday - Saturday).
ddddd Display the date as a complete date (including day, month, and year), formatted according to your system's short date format setting. The default short date format is m/d/yy.
dddddd Display a date serial number as a complete date (including day, month, and year) formatted according to the long date setting recognized by your system. The default long date format is mmmm dd, yyyy.
w Display the day of the week as a number (1 for Sunday through 7 for Saturday).
ww Display the week of the year as a number (1 - 53).
m Display the month as a number without a leading zero (1 - 12). If m immediately follows h or hh, the minute rather than the month is displayed.
MM Display the month as a number with a leading zero (01 - 12). If m immediately follows h or hh, the minute rather than the month is displayed.
MMM Display the month as an abbreviation (Jan - Dec).
MMMM Display the month as a full month name (January - December).
q Display the quarter of the year as a number (1 - 4).
y Display the day of the year as a number (1 - 366).
yy Display the year as a 2-digit number (00 - 99).
yyyy Display the year as a 4-digit number (100 - 9666).
h Display the hour as a number without leading zeros (0 - 23).
hh Display the hour as a number with leading zeros (00 - 23).
n Display the minute as a number without leading zeros (0 - 59).
nn Display the minute as a number with leading zeros (00 - 59).
s Display the second as a number without leading zeros (0 - 59).
ss Display the second as a number with leading zeros (00 - 59).
t t t t t Display a time as a complete time (including hour, minute, and second), formatted using the time separator defined by the time format recognized by your system. A leading zero is displayed if the leading zero option is selected and the time is before 10:00 A.M. or P.M. The default time format is h:mm:ss.
AM/PM Use the 12-hour clock and display an uppercase AM with any hour before noon; display an uppercase PM with any hour between noon and 11:59 P.M.
am/pm Use the 12-hour clock and display a lowercase AM with any hour before noon; display a lowercase PM with any hour between noon and 11:59 P.M.
A/P Use the 12-hour clock and display an uppercase A with any hour before noon; display an uppercase P with any hour between noon and 11:59 P.M.
a/p Use the 12-hour clock and display a lowercase A with any hour before noon; display a lowercase P with any hour between noon and 11:59 P.M.
AMPM Use the 12-hour clock and display the AM string literal as defined by your system with any hour before noon; display the PM string literal as defined by your system with any hour between noon and 11:59 P.M. AMPM can be either uppercase or lowercase, but the case of the string displayed matches the string as defined by your system settings. The default format is AM/PM.
0
Digit placeholder Display a digit or a zero. If the expression has a digit in the position where the 0 appears in the format string, display it; otherwise, display a zero in that position. If the number has fewer digits than there are zeros (on either side of the decimal) in the format expression, display leading or trailing zeros. If the number has more digits to the right of the decimal separator than there are zeros to the right of the decimal separator in the format expression, round the number to as many decimal places as there are zeros. If the number has more digits to the left of the decimal separator than there are zeros to the left of the decimal separator in the format expression, display the extra digits without modification.
#
Digit placeholder
Display a digit or nothing. If the expression has a digit in the position where the # appears in the format string, display it; otherwise, display nothing in that position. This symbol works like the 0 digit placeholder, except that leading and trailing zeros aren't displayed if the number has the same or fewer digits than there are # characters on either side of the decimal separator in the format expression.
.
Decimal placeholder
In some locales, a comma is used as the decimal separator. The decimal placeholder determines how many digits are displayed to the left and right of the decimal separator. If the format expression contains only number signs to the left of this symbol, numbers smaller than 1 begin with a decimal separator. If you always want a leading zero displayed with fractional numbers, use 0 as the first digit placeholder to the left of the decimal separator instead. The actual character used as a decimal placeholder in the formatted output depends on the Number Format recognized by your system.
%
Percent placeholder The expression is multiplied by 100. The percent character (%) is inserted in the position where it appears in the format string.
,
Thousand separator In some locales, a period is used as a thousand separator. The thousand separator separates thousands from hundreds within a number that has four or more places to the left of the decimal separator. Standard use of the thousand separator is specified if the format contains a thousand separator surrounded by digit placeholders (0 or #). Two adjacent thousand separators or a thousand separator immediately to the left of the decimal separator (whether or not a decimal is specified) means “scale the number by dividing it by 1000, rounding as needed.” You can scale large numbers using this technique. For example, you can use the format string “##0,,” to represent 100 million as 100. Numbers smaller than 1 million are displayed as 0. Two adjacent thousand separators in any position other than immediately to the left of the decimal separator are treated simply as specifying the use of a thousand separator. The actual character used as the thousand separator in the formatted output depends on the Number Format recognized by your system.
:
Time separator In some locales, other characters may be used to represent the time separator. The time separator separates hours, minutes, and seconds when time values are formatted. The actual character used as the time separator in formatted output is determined by your system settings.
/
Date separator In some locales, other characters may be used to represent the date separator. The date separator separates the day, month, and year when date values are formatted. The actual character used as the date separator in formatted output is determined by your system settings.
E- E+ e- e+
Scientific format If the format expression contains at least one digit placeholder (0 or #) to the right of E-, E+, e-, or e+, the number is displayed in scientific format and E or e is inserted between the number and its exponent. The number of digit placeholders to the right determines the number of digits in the exponent. Use E- or e- to place a minus sign next to negative exponents. Use E+ or e+ to place a minus sign next to negative exponents and a plus sign next to positive exponents.
- + $ ( ) space
Display a literal character To display a character other than one of those listed, precede it with a backslash (\) or enclose it in double quotation marks (” “).
\
Display the next character in the format string Many characters in the format expression have a special meaning and can't be displayed as literal characters unless they are preceded by a backslash. The backslash itself isn't displayed. Using a backslash is the same as enclosing the next character in double quotation marks. To display a backslash, use two backslashes (\). Examples of characters that can't be displayed as literal characters are the date- and time-formatting characters (a, c, d, h, m, n, p, q, s, t, w, y, and /:), the numeric-formatting characters (#, 0, %, E, e, comma, and period), and the string-formatting characters (@, &, <, >, and !).
“ABC”
Display the string inside the double quotation marks To include a string in format from within code, you must use Chr(34) to enclose the text (34 is the character code for a double quotation mark).
@
Character placeholder Display a character or a space. If the string has a character in the position where the @ appears in the format string, display it; otherwise, display a space in that position. Placeholders are filled from right to left unless there is an ! character in the format string. See below.
&
Character placeholder Display a character or nothing. If the string has a character in the position where the & appears, display it; otherwise, display nothing. Placeholders are filled from right to left unless there is an ! character in the format string. See below.
<
Force lowercase Display all characters in lowercase format.
>
Force uppercase Display all characters in uppercase format.
!
Force left to right fill of placeholders The default is to fill from right to left.
Named Formats
Visual Basic provides several standard formats to use with the Format function. Instead of using symbols, you specify these formats by name in the format argument of the Format function. Always enclose the format name in double quotation marks (“”). The following table lists the format names you can use. Named format Description
General Number Shows numbers as entered.
Currency Shows negative numbers inside parentheses.
Fixed Shows at least one digit.
Standard Uses a thousands separator.
Percent Multiplies the value by 100 with a percent sign at the end.
Scientific Uses standard scientific notation.
General Date Shows date and time if expression contains both. If expression is only a date or a time, the missing information is not displayed.
Long Date Uses the Long Date format specified in the Regional Settings dialog box of the Microsoft Windows Control Panel.
Medium Date Uses the dd-mmm-yy format (for example, 03-Apr-93)
Short Date Uses the Short Date format specified in the Regional Settings dialog box of the Windows Control Panel.
Long Time Shows the hour, minute, second, and “AM” or “PM” using the h:mm:ss format.
Medium Time Shows the hour, minute, and “AM” or “PM” using the “hh:mm AM/PM” format.
Short Time Shows the hour and minute using the hh:mm format.
Yes/No Any nonzero numeric value (usually - 1) is Yes. Zero is No.
True/False Any nonzero numeric value (usually - 1) is True. Zero is False.
On/Off Any nonzero numeric value (usually - 1) is On. Zero is Off.
Multiple Formats
A user-defined format expression can have from one to four sections separated by semicolons. (If the format argument contains one of the named formats, only one section is allowed.) If you use The result is
One section The format expression applies to all values.
Two sections The first section applies to positive values and zeros, the second to negative values.
Three sections The first section applies to positive values, the second to negative values, and the third to zeros.
Four sections The first section applies to positive values, the second to negative values, the third to zeros, and the fourth to Null values.
The following example has two sections: the first defines the format for positive values and zeros; the second section defines the format for negative values.
$#,##0;($#,##0)
If you include semicolons with nothing between them, the missing section is printed using the format of the positive value. For example, the following format displays positive and negative values using the format in the first section and displays “Zero” if the value is zero.
$#,##0;;\Z\e\r\o
Note If you try to format a number without specifying format, Format provides the same functionality as the Str function. However, positive numbers formatted as strings using Format lack the leading space reserved for displaying the sign of the value; whereas, those converted using Str retain the leading space.
Examples
The following conversions assume that the country in the Windows Control Panel is set to “English (United States).” Format syntax Result
Format(8315.4, “00000.00”) 08315.40
Format(8315.4, “#####.##”) 8315.4
Format(8315.4, “##,##0.00”) 8,315.40
Format(315.4, “$##0.00”) $315.40
Format(7, “0.00%”) 700.00%
Format(“This Is A Test”, “<”) this is a test
Format(“This Is A Test”, “>”) THIS IS A TEST
Format(Now, “m/d/yy”) 1/27/93
Format(Now, “dddd, mmmm dd, yyyy”) Wednesday, January 27, 1993
Format(Now, “d-mmm”) 27-Jan
Format(Now, “mmmm-yy”) January-93
Format(Now, “hh:mm AM/PM”) 07:18 AM
Format(Now, “h:mm:ss a/p”) 7:18:00 a
Format(Now, “d-mmmm h:mm” 27-January 7:18
Format(Now, “d-mmmm-yy”) 27-January-93
Format(Now, “d mmmm”) 27 January
Format(Now, “mmmm yy”) January 93
Format(Now, “hh:mm AM/PM”) 08:50 PM
Format(Now, “h:mm:ss a/p”) 8:50:35 p
Format(Now, “h:mm”) 20:50
Format(Now, “h:mm:ss”) 20:50:35
Format(Now, “m/d/yy h:mm”) 1/27/93 20:50
Format (format) Positive 5 Negative 5 Decimal .5 Null
Zero-length string 5 -5 0.5
0 5 -5 1
0.00 5.00 -5.00 0.50
#,##0 5 -5 1
#,##0.00;;;Nil 5.00 -5.00 0.50 Nil
$#,##0;($#,##0) $5 ($5) $1
$#,##0.00;($#,##0.00) $5.00 ($5.00) $0.50
0% 500% -500% 50%
0.00% 500.00% -500.00% 50.00%
0.00E+00 5.00E+00 -5.00E+00 5.00E-01
0.00E-00 5.00E00 -5.00E00 5.00E-01
Credit
Most of this is a re-hash of the documentation available from Microsoft. But Microsoft has its Format() documentation spread out in a number of loosely related entries, instead of being in one place.
String Formating in VB
Labels: VisualBasic 0 commentsby gini at 4:06 AM
Flat Button in VB
Labels: VisualBasic 0 commentsHow do we implement a Flat Button?
Well, let's describe step by step how we can create a usercontrol that behaves as a flat button. From VB open a new ActiveX project and save it as MyFlatButton.ctl.
Open a new ActiveX control project
Events "MouseDown" and "MouseUp" will help us to draw the edge sunken or raised when the user mouse-clicks the usercontrol. When the MouseDown event is fired we will draw a sunken edge. When the MouseUp event is fired we will draw a raised edge. This is when we should take the first decision: do we draw the edge directly from the mouse event? or should we call the Paint event instead? Is there a difference? The answer is yes, there's a big difference! Always try to have as little code as you can in procedures that are message consumers. The more code we add to the MouseDown message the slower our application will process mouse events. It is a better approach to put all drawing code in the Paint event and let the MouseDown and MouseUp events flow faster.
Let's see this with more detail. If we were drawing the button edge directly from the MouseDown event we would code something like:
Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then
Call pDrawEdgeSunken
End If
End Sub
Where pDrawEdgeRaised would be a procedure that draws the usercontrol edge with a sunken style. On the other hand, if we just call the Paint event our code would be:
Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then
m_MouseDown = True
Call UserControl_Paint
End If
End Sub
Where m_MouseDown is a boolean flag we've created to let the rest of the code know when the mouse is down. The UserControl_Paint event will have all necessary drawing code. What's the difference? well, the first version is calling procedure pDrawEdgeSunken and therefore the MouseDown event will not finish until pDrawEdgeSunken does. On the other hand, the second version calls UserControl_Paint and doesn't wait for this procedure to finish (Paint is an event procedure). It just posts a message WM_PAINT to itself and quits. This second version is more efficient and would not convert the MouseDown procedure in a potential "bottle-neck".
Using this second approach we are now going to create the first version of our flat button. You can paste the following code into your usercontrol:
Option Explicit
Public Event Click()
Private m_MouseDown As Boolean
Private m_MouseOver As Boolean
Private m_ClientRec As RECT
'API declarations:
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Const BDR_RAISEDINNER = &H4
Private Const BDR_SUNKENOUTER = &H2
Private Const BF_RECT = &HF
Private Declare Function DrawEdge Lib "user32" ( _
ByVal hdc As Long, _
qrc As RECT, _
ByVal edge As Long, _
ByVal grfFlags As Long) As Long
Private Declare Function GetWindowRect Lib "user32" ( _
ByVal hwnd As Long, _
lpRect As RECT) As Long
Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then
m_MouseDown = True
Call UserControl_Paint
End If
End Sub
Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Not m_MouseOver Then
m_MouseOver = True
UserControl_Paint
End If
End Sub
Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then
m_MouseDown = False
UserControl_Paint
RaiseEvent Click
End If
End Sub
Private Sub UserControl_Resize()
GetWindowRect UserControl.hwnd, m_ClientRec
'Transform from screen to client coordinates
With m_ClientRec
.Right = .Right - .Left
.Bottom = .Bottom - .Top
.Left = 0
.Top = 0
End With
UserControl_Paint
End Sub
Private Sub UserControl_Paint()
Dim lEdge As Long
If Not UserControl.Ambient.UserMode Then
m_MouseOver = True
End If
UserControl.Cls
lEdge = 0
If m_MouseOver Then
If m_MouseDown Then
lEdge = BDR_SUNKENOUTER
Else
lEdge = BDR_RAISEDINNER
End If
DrawEdge UserControl.hdc, m_ClientRec, lEdge, BF_RECT
End If
'
'Add your code here to draw the picture and caption...
'
End Sub
Let's review this code before we test it. As you can see, MouseUp and MouseDown only check whether the right mouse button has been pressed and they both set the flag m_MouseDown to either True or False depending on the event. MouseMove only takes care of flag m_MouseOver and all three events call Paint to force a re-painting of the object. Resize is responsible for getting the size of the client area - using the API GetWindowRect - and also forces a re-paint. Finally the Paint event clears the usercontrol and draws the appropriate edge based on the values of m_MouseOver and m_MouseDown. Easy, isn't it?
We can now test the usercontrol. If we do so, we can see that the control first shows flat. Then, as soon as the mouse enters its client area, the control shows raised. We can now start clicking the button and the edge turns sunken when we down-click and it turns back to raised when the mouse is released.
Good, it seems to work! There are only two remaining problems:
1. The edge doesn't show flat when the mouse leaves the button.
2. The push-pop effect seems to be wrong if we mouse-click quickly.
In the next section I'm going to discuss how these two problems can be solved.
Trapping messages to solve flat button "issues"
The first question that arises is: how can we know when the mouse leaves the button? In March 1997 Microsoft published the source code of a flat button implemented with Visual Basic. The project was called Visual Basic Soft Button Sample. Since then, many soft buttons have appeared on the net and I would say all share the same technique: they use APIS SetCapture and ReleaseCapture in order to detect when the mouse leaves the button.
How does this solution work and what sort of problems does it have? Basically the solution presented by Microsoft is based on capturing the mouse when the mouse gets into the button client area. Using SetCapture, it holds the mouse until detects that it has moved outside of the button to then release it. Sounds logical? I think it is a very good approach. So what's the problem then? Well, I would say the implementation of this solution has mainly two problems:
1. SetCapture only allows one window to be holding the mouse.
2. MouseMove event will have to release and capture the mouse every time this event is fired.
We'll better understand this if we have a code sample. If we were using SetCapture and ReleaseCapture we would have to modify the MouseMove event with the following code:
Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
ReleaseCapture
If X >= 0 And _
Y >= 0 And _
X <= UserControl.ScaleWidth And _
Y <= UserControl.ScaleHeight Then
SetCapture UserControl.hwnd
m_MouseOver = True
UserControl_Paint
End If
End Sub
After calling the SetCapture API, all mouse messages, no matter where the mouse is, are posted to our window. It would be more logical if we just call SetCapture the first time we detect the mouse has entered the button area and call ReleaseCapture only once too, as soon as we detect that the mouse has left the button. We can't! Why? because only one window can hold the mouse by calling SetCapture. If an external application/code calls SetCapture while the mouse is over the button, we would lose its messages and we would never know when to call ReleaseCapture and draw the edge flat again. Therefore, the solution is based on releasing and capturing the mouse every time the user moves the mouse over the button. Not very efficient and still containing potential problems...
There's a better way to detect when the mouse leaves the button: using API TrackMouseEvent and WM_MOUSELEAVE message. TrackMouseEvent can be used to ask the system to track the mouse for us and post a WM_MOUSELEAVE message as soon as the mouse leaves our window area. It is a cleaner and more efficient approach but, how can we detect the WM_MOUSELEAVE message? We're going to use the SmartSubclass library to trap all messages posted to the usercontrol. You will have to add a reference to SmartSubclass.dll, as described in the article, and you'll be able to create a SmartSubclass variable. You'll find another example on how to use this class in Trap the Mouse!
Add the following code to the usercontrol:
Private WithEvents m_Sniff As SmartSubClass
Private Type TrackMouseEvent
cbSize As Long
dwFlags As Long
hwnd As Long
dwHoverTime As Long
End Type
Private Const WM_MOUSELEAVE = &H2A3
Private Const TME_LEAVE = &H2
Private Declare Function TrackMouseEvent Lib "comctl32.dll" Alias "_TrackMouseEvent" ( _
ByRef lpEventTrack As TrackMouseEvent) As Long
Private Sub UserControl_Initialize()
Set m_Sniff = New SmartSubClass
m_Sniff.SubClassHwnd UserControl.hwnd, True
End Sub
Private Sub UserControl_Terminate()
m_Sniff.SubClassHwnd UserControl.hwnd, False
End Sub
Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim tTrackMouseEvent As TrackMouseEvent
If Not m_MouseOver Then
With tTrackMouseEvent
.cbSize = Len(tTrackMouseEvent)
.dwFlags = TME_LEAVE
.hwnd = UserControl.hwnd
End With
TrackMouseEvent tTrackMouseEvent
m_MouseOver = True
UserControl_Paint
End If
End Sub
Private Sub m_Sniff_NewMessage( _
ByVal hwnd As Long, _
uMsg As Long, _
wParam As Long, _
lParam As Long, _
Cancel As Boolean)
Select Case uMsg
Case WM_MOUSELEAVE
m_MouseOver = False
UserControl_Paint
End Select
End Sub
If you add the code to your usercontrol and you test it again, you will see that the button turns flat again as soon as the mouse leaves its client area. We've had to call TrackMouseEvent just once and when our 'sniffer' gets the WM_MOUSELEAVE message, it sets the m_MouseOver flag to False and forces a control re-painting.
I honestly prefer TrackMouseEvent to SetCapture, basically because we don't get conflicts with other windows, we rely on the system to track the mouse position and we don't need to over-charge the MouseMove event.
Now let's go back to our usercontrol. If you remember there's still a remaining problem: The "push-pop" effect seems to be wrong if we click the button fast. I describe this problem with more details in Trap the mouse!. I will only tell you that this problem is due to receiving DblClick rather than MouseDown. To fix the problem we need to get rid of the DblClick event and get MouseDown instead.
Add the following code to the usercontrol:
Private Const WM_LBUTTONDBLCLK = &H203
Private Const WM_LBUTTONDOWN = &H201
Private Sub m_Sniff_NewMessage( _
ByVal hwnd As Long, _
uMsg As Long, _
wParam As Long, _
lParam As Long, _
Cancel As Boolean)
Select Case uMsg
Case WM_MOUSELEAVE
m_MouseOver = False
UserControl_Paint
Case WM_LBUTTONDBLCLK
uMsg = WM_LBUTTONDOWN
End Select
End Sub
You can now click the flat button as fast as you want. You will always get the right "push-pop" effect. We've used our "sniffer" to get the WM_LBUTTONDBLCLK message and replaced it with a WM_LBUTTONDOWN. It couldn't be easier!
The flat button has now a very solid structure. We can only add enhancements to it. In the next section I will describe how we can make the flat button post click events when we hold the mouse down-clicked.
How can we make the flat button simulate repeated clicks?
When you hold the mouse down-clicked on the button you will get only one MouseDown message. You need to release the mouse and down-click again in order to receive the next MouseDown message. This could be a problem if we would like to use our flat button on the implementation of let's say a viewport control. The user may want to scroll the viewport area by holding the mouse down on the flat button. Makes sense. So how can we do that if Windows sends only one message? We will need to do it ourselves!
We need a timer. Actually we need two timers! We could use the Timer control that comes with Visual Basic, but we're going to use API calls. Why? because it is a good way of learning Windows core functions!
Once the user down-clicks the button we need a timer to control when to start posting Click events and we need another timer to control the frequency of this posting. Windows provides two very good timer functions, SetTimer and KillTimer, and a timer message WM_TIMER.
In order to implement the repeated click you should add the following code:
Private Const m_TimerDelay = 1
Private Const m_TimerLapse = 2
Private Const m_RepeatDelay = 250
Private Const m_RepeatLapse = 125
Private Const WM_TIMER = &H113
Private Declare Function SetTimer Lib "user32" ( _
ByVal hwnd As Long, _
ByVal nIDEvent As Long, _
ByVal uElapse As Long, _
ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" ( _
ByVal hwnd As Long, _
ByVal nIDEvent As Long) As Long
Private Sub m_Sniff_NewMessage(ByVal hwnd As Long, uMsg As Long, wParam As Long, lParam As Long, Cancel As Boolean)
Select Case uMsg
Case WM_MOUSELEAVE
m_MouseOver = False
UserControl_Paint
Case WM_LBUTTONDBLCLK
uMsg = WM_LBUTTONDOWN
Case WM_TIMER
Select Case wParam
Case m_TimerDelay
KillTimer UserControl.hwnd, m_TimerDelay
If m_MouseDown Then
SetTimer UserControl.hwnd, m_TimerLapse, m_RepeatLapse, 0
End If
Case m_TimerLapse
If m_MouseDown Then
RaiseEvent Click
End If
End Select
End Select
End Sub
Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then
m_MouseDown = True
UserControl_Paint
If m_RepeatDelay > 0 Then
SetTimer UserControl.hwnd, m_TimerDelay, m_RepeatDelay, 0
End If
End If
End Sub
Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then
m_MouseDown = False
KillTimer UserControl.hwnd, m_TimerDelay
KillTimer UserControl.hwnd, m_TimerLapse
UserControl_Paint
RaiseEvent Click
End If
End Sub
Now the flat button starts waiting m_RepeatDelay milliseconds once the user down-clicks. After this time it will start posting Click events every m_RepeatLapse milliseconds.
Let's review the solution: we've modified MouseDown to program the first timer (m_TimerDelay). When the "sniffer" gets a WM_TIMER message it checks for its timer ID. If it is the first timer, the delay lapse has expired and it programs the second timer (m_TimerLapse). It also kills the first timer. Otherwise, if the WM_TIMER message belongs to the second timer, it posts a Click event (the user is holding the mouse down). Finally, the MouseUp event only has to kill both timers.
Well, that's it! Now you have a flat button working that only needs extra properties like Caption, Font, Picture, ForeColor... I will leave it up to you to implement the enhancements.
by gini at 3:44 AM
Format numbers in VB
Labels: VisualBasic 0 commentsThis is a FAQ for VB Beginners that deals with the problem of numbers that have more digits after the decimal point than you want to use or display.
Topics covered are:
a. Use the "Fixed" Format and Format$
b. Use the "Standard" Format and Format$
c. Use Format$ and your own settings
d. Use FormatNumber
e. Use the Round Function
Sometimes calculations in your project will result in numbers with a lot of decimal places - users input numbers with multiple digits after the decimal point or the calculation throws up a long list of decimal digits that you don't want or need you want to restrict these numbers to, say, 2 decimal places, here are a few ways you can do this:
a. Use the "Fixed" Format and Format$
This example takes a user input from a textbox and performs a calculation on it. The result, correct to 2 decimal places, is shown in a label. If your project needs are different, you can adapt the code as necessary.
Add a textbox (Text1), a commandbutton(Command1) and a Label (Label1) to a form, then copy and paste this code:-
Code:Option Explicit
Dim lngDemoNo As Double
Private Sub Form_Load()
Text1 = 123764.76464646 ' You can change this at run time if you want
lngDemoNo = Text1 * 3.142 ' Create some demo data
End Sub
Private Sub Command1_Click()
' For demo purposes, display the result
Label1 = "Your Input Number * Pi = " & Format$(lngDemoNo, "Fixed")
End Sub
b. Use the "Standard" Format and Format$
The only difference to the above is that this will insert commas if the value of the number is greater than 999 (ie. 1,000.00 instead of 1000.00).
You can recyle the code example above and just change the code line in the Command1_Click event to:
Code:Label1 = "Your Input Number * Pi = " & Format$(lngDemoNo, "Standard")
c. Use Format$ and your own settings
You can force the result to appear in whatever format you like by using Format$ and creating the settings yourself. Re-use the first example and change the code line in the Command1_Click Event to:
Code:Label1 = "Your Input Number * Pi = " & Format$(lngDemoNo, "0.000")
Notice that I have put three zeros after the decimal point, so the resulting label display is shown correct to three decimal places. You can, of course, change this to whatever suits your purposes.
d. Use FormatNumber
You can also use the FormatNumber Function provided by VB. This function will accept several arguments that can be used to present a number in different ways, but we will just use one in this FAQ.
Once again, replace the Command Button code line with this one:
Code:Label1 = "Your Input Number * Pi = " & FormatNumber(lngDemoNo, 3)
The "3" digit is the number of decimal places to use. Again, you can change this to whatever you want.
e. Use the Round Function
Similar to most of the above options, the Round Function will return a value set to the number of places you decide and will round the last digit up or down.
The replacement code line in this case is:
Code:Label1 = "Your Input Number * Pi = " & Round(lngDemoNo, 2)
So there you have various ways of achieving the same thing – dictating how many digits you want to have after the decimal point.
by gini at 3:42 AM
support and powered by colorvibes | visit Blog and Web