Status Bar DEMO - Version 3.00 By: M. J. Rodriguez CIS ID: 100321,620 Internet: 100321.620@compuserve.com jrodrigu@cpd.hqusareur.army.mil This compressed file contains the following files: CONSTANT.GLB - A supporting file for the demo FORM1.FRM - Demo Form for the project FORM1.FRX - VB Support Graphic file for FORM1.FRM README.TXT - This File SBARDEMO.EXE - Executable of the Demo SBARDEMO.MAK - Project MAK file STATBAR.BAS - Status Bar Module you need for any status bar STATBAR.BMP - BMP file used for the SBAR_MINICON Panels Contents: ------------------------------------------------- About the Code Status Bar Implementation How the Status Bar is Drawn Adding the StatusBar to your project How the Code Works Use of the Status Bar with Menu's and Mouse Movements. VB 4.0 Disclaimer ------------------------------------------------- About the Code: ------------------------------------------------- In early May I put out a project in CompuServe for a status bar that could be displayed using just a label, a timer, and a picture box. Then a week later, I modified it by removing the label and just went with the timer and PictureBox. Suffice it to say, I have had over 1000 downloads of it and have received many compliments. Then as always, it doesn't quite meet just what the user wants and so the questions came in. This third iteration is the result of some of those requests and includes some tips, although modified here, from other users. Unfortunately, I cannot find the name of the few who did send in suggestions and additions, but if you see it again, I apologize for not including your name... however, VC..(you know who you are because I remember your initials), you get credit for the SBAR_FIXEDTEXT which was a great idea and your code is included. The person who sent me the SBAR_BUTTON idea (without the code, so what you see is what I did) you get at least partial credit for it. And a special thanks to the Los Angeles Visual Basic User's Group for their many kind comments. I hope this will get added to your Top Ten list again. I have modularized this code to the point where you should be able to just drop it into your projects and go. If you have any problems let me know. Status Bar Implementation: ------------------------------------------------- In this concept, the Status bar is divided into panels. Each panel is drawn individually. Each panel has properties which you can change. How you change the panel is determined by your needs. The properties are kept in an array of a user-defined type called PanelType. Here is the structure of PanelType.. Type PanelType sCaption As String 'Caption contained in the panel PanelStyle As PanelStyleType 'Panel Information iFontBold As Integer 'Whether or not font is bold iFont3D As Integer 'Whether or not font is 3D sFontName As String 'Font Name - Defaults to statusbar setting sFontSize As String 'Font Size - Defaults to statusbar setting lFontColor As Long 'Font Color - Defaults to statusbar setting bVisible As Integer 'Let's you hide or show any panel you wish End Type The PanelStyle element is a user-defined type called PanelStyleType. There is no particular reason why I did it this way other than to isolate some properties. In the original implementation, the Status Bar passed the PanelStyle element for drawing purposes. Now, it isn't done that way, so instead of changing it to be one complete element, I left it the way it was and expanded it. Probably not good coding, but it works. Here is the PanelStyleType. Type PanelStyleType iLeft As Integer 'Left Position of the panel iTop As Integer 'Top position of the panel iWidth As Integer 'Width of the panel iHeight As Integer 'Height of the Panel iBorderStyle As Integer 'Type of panel 0-Recessed, 1-Raised, 2-Flat: User Defined iFormat As Integer 'Format of the panel - Text, Date, Time, etc...: User Defined iTextFormat As Integer 'Format of Text in the panel VCENTER, CENTER, etc.: User Defined iOther As Integer 'Used for Icon Information or Percentage in the Meter Bar lOther As Long 'User for color of the meter bar or whatever else needs to be used End Type These properties change as you need them to. Once they are changed, they will be reflected the next time the panel is drawn. The following are the types of panels as defined by global constants. These are not the only types you are limited to as you certainly can add any type you want. It's entirely up to you. 'Format of the panels Global Const SBAR_TEXT = 0 'Panel just contains text Global Const SBAR_DATE = 1 'Panel contains the date Global Const SBAR_TIME = 2 'Panel contains the time Global Const SBAR_WEEKDAY = 3 'Panel contains the weekday Global Const SBAR_FULLDATE = 4 'Panel Shows date as Tuesday Jan 1, 1995 Global Const SBAR_CAPSLOCK = 5 'Panel is a CAPLOCK toggle display Global Const SBAR_NUMLOCK = 6 'Panel is a NUMLOCK toggle display Global Const SBAR_SCROLL = 7 'Panel is a SCROLL LOCK toggle display Global Const SBAR_COUNTER = 8 'Panel is a counter display Global Const SBAR_FIXEDTEXT = 9 'Panel contains a fixed text Global Const SBAR_MINICON = 10 'Panel is a miniature icon display Global Const SBAR_ICONMIX = 11 'Panel is a miniature icon/text display Global Const SBAR_BUTTON = 12 'Panel will emulate a button and fire and event when clicked Global Const SBAR_METER = 13 'Panel is a meter control that displays progress The SBAR_MINICON and SBAR_ICONMIX are unique in that they reference small icons. In reality, I use another PictureBox names sbar_pics and include a single bitmap of all the small "icons" I want to use. The individual pieces of the bitmap are 16 x 16 pixels and drawn using PaintBrush. The program makes the assumption that you will do the same otherwise, the pictures may not come out correctly. In the project, you will need to add at least one picture box named sbar_pics. It doesn't have to big and can be invisible. If you don't want to add the sbar_pics PictureBox, then remark out or delete all the references in the code that work with these types. Most of them are in Select..Case statements and a few If..Then..Else.. blocks which are easily remarked out. The panels are displayed in one of three ways: Flat, Raised, or Recessed. Here are the constants used in the implementation. Global Const SBAR_PANEL_RECESSED = 0 Global Const SBAR_PANEL_RAISED = 1 Global Const SBAR_PANEL_FLAT = 2 By setting the iBorderStyle element in the PanelStyle UDT, you determine what the appearance of the panel will be. How the Status Bar is Drawn. ------------------------------------------------- The Status Bar is drawn using the DrawText API call and the Line Method. Each panel size is determined by a number of conditions. Every panel except SBAR_TEXT, SBAR_ICONMIX, and SBAR_METER is determined by the size of the element being displayed using a predefined format. For example, the SBAR_FULLDATE size is determined by the width of the text of a formatted string containing capital X's and usually is represented the largest character count of the possible text. This allows for constant size. The SBAR_TEXT and SBAR_ICONMIX are displayed if any space is left over after all the fixed sized panels are subtracted from the available width minus the size of the border of the status bar around the panels and the gaps between each panel. SBAR_METER is a globally defined constant which can be changed by you. It is currently set to 100 pixels in width. Here are the constants used in determining sizes of borders and gaps. Global Const SBAR_BORDERSIZE = 2 'Space between StatusBar borders and panels in pixels Global Const SBAR_PANELGAP = 4 'Gap between panels in Pixels Global Const SBAR_TEXTGAP = 1 'Gap in between the text and the border in pixels Global Const SBAR_METERWIDTH = 100 'Width in pixels of the Meter panel These measurements are determined by you and will affect the size of the status bar's height. Width is automatically decided as the status bar is anchored to the bottom of the form. This can be changed by adjusting the Align property of the StatusBar control. Adding the StatusBar to your project ------------------------------------------------- First thing, decide which form or forms your Status bar is going on. You aren't limited to just one form. You can have a status bar on any form you want or as many. There may be a performance sacrifice if you have like GOBS of forms with Status Bars, but whatever makes you happy, I always say... If this is not a MDI form, and you have panels for CapLock, NumLock, or ScrollLock, or add anyother toggle function, then you want to change the forms KeyPreview property to True and then add in the Form_KeyDown procedure the follwing snippet: UpdateKeyPanels StatusBar, sb_panels() This procedure takes care of just toggle keys. If you have an MDI form, obviously, you can't use this because there is no KeyPreview property. The Timer procedure does take care of this. In the Forms Declaration section of the form, add the following: Dim sb_panels() As PanelType Dim sb_initialized As Integer The sb_panels() is for the status bar for that form. For any other form, just add the same thing. It doesn't matter. You will need to add a procedure in the General Declarations section called CreatePanels. A remarked out copy of the procedure is available in the General Declaration Section of the STATBAR.BAS file. You can use it as a template for your setting properties and the number of panels you want to create. You can also use the copy that is available in the sample project. Just look in the general section and look for the CreatePanels procedure. A simple cut and paste will make it real easy to add. In the Form_Load event, you will need to add the following code snippet. Dim bSuc% CreatePanels bSuc% = InitializeStatusBar(Me, sb_panels()) sb_initialized = True Now you are ready to add the status bar to your project. In the form, you need to add a picture box to your form. If this is a MDI form, it will be auto-aligned to the top. It can be changed programatically later so don't worry. Set the Name property of the Picture box to 'StatusBar'. That's all you need to do with it. In the StatusBar_Resize Event, add the following snippet: If Me.WindowState <> 1 Then If sb_initialized Then DisplayStatusBar Me.StatusBar, sb_panels() End If If you are using the SBAR_BUTTON panel, then add the following code to the StatusBar_MouseDown and StatusBar_MouseMove procedures: SBarMouseDown StatusBar, Button, Shift, X, Y, sb_panels() then add the following snippet to the StatusBar_MouseUp procedure: SBarMouseUp StatusBar, Button, Shift, X, Y, sb_panels() These procedures have been setup to deal with the SBAR_BUTTON type panels. Once you have done this, now add a timer and set the properties to the following: Enabled True Interval 200 Name StatTimer In the StatTimer_Timer procedure, add the following snippet: UpdateTimePanels StatusBar, sb_panels() unless you are using an MDI form, then you want to use this procedure: UpdateStatusPanels StatusBar, sb_panels() which takes care of the toggle keys you want to use. The last control you need to add is another picture box for the SBAR_MINICONS if you want them in your project. Add the PictureBox and set the following properties: AutoRedraw True AutoSize True Name sbar_pics ScaleMode 3 - Pixel Visible False The Picture property does not have to be set at design time, but it's up to you. Again, if you don't want to use SBAR_MINICONS or SBAR_ICONMIX, then don't add the controls and remark out the lines that perform operations on the sbar_pics control. How the Code Works ------------------------------------------------- The process involves, first, initializing the status bar by creating the panels and then actually drawing the initial status bar. Then as changes to the status bar panels occur, they are redrawn. They are redrawn on an as-needed-basis, meaning that if the information changes in the panel, it is redrawn and only redrawn for that panel. The whole status bar does not have to be redrawn unless the user resizes the form. In this case, the resizing is necessary because some parts of the status bar will go away and in order for the user to see it, it has to be redrawn. The dynamic panels of SBAR_TEXT and SBAR_ICONMIX will adjust sizes if the status bar changes width. What this does is make it easier for the system to not make a change unless needed and significantly speed up the updating of the status bar. This is especially useful for the Timer procedure because in many cases, it will be a quick in and out process. As such, if you make a change, just update the panel you want. In most cases, you will want to update only the text panel as you will probably use that to display feedback to your user. There are no VBX's or DLL's used except for the DrawText, GetKeyState and BitBlt API functions. That's all that's needed. The rest is done all through VB code. Use of the Status Bar with Menu's and Mouse Movements. ------------------------------------------------- I purposely did not include examples of how to use menu events to update the Status Bar. You are probably going to need a VBX that intercepts Window's messages. As far as mouse movements are concerned, you add those to wherever you wish by simple calling the UpdateTextPanel procedure and pass the StatusBar control, the Panel element from the array, and the new caption. In this case, there is enough flexibility to abstract some of that by calling one procedure that makes the decision of which panel gets updated and when and then you call one procedure for any changes. In my usage of this code, I usually have the main form have a StatusBar only (such as an MDI form) and then modularly declare the status panels in my application's main module. In that module, I have an initialization procedure and a procedure which handles the display of the status bar. Also, I have added pop-up menu support for turning on and turning off specific panels by the user. That info is saved in an INI file so if the user wants to add GDI meter and FSR meter and a CapsLock panel, they can do it by right clicking the mouse on the StatusBar and having a Pop-up menu which turns off or turns on different configurations and even changes what the panels actually show. Some may want to have three SBAR_METER panels, a SBAR_FULLDATE panel, the SBAR_CAPSLOCK panel, and two SBAR_MINICON panels which monitor printing and incoming mail. Again, it is easy to add procedures which can increase the functionality of your StatusBar and make it effective for your application. While I could have added all that functionality, time is something I don't have a lot of. Suffice it to say, this code is not a solution as it is more of a template. One small not if you allow users to dynamically change or you dynamically change the status bar panels configuration - call the DisplayStatusBar procedure to redraw the status bar after you change the configuration so you don't get a funny looking status bar. An example would be like you changed panel 2 from an SBAR_METER to an SBAR_ICONMIXED format. Obviously, you are going to have to redraw the whole thing again to make it look correct. Again, the DisplayStatusBar procedure will take care of this for you. A better method would be to call the Form_Resize event which automatically redraws the status bar. There is also those who like to use what I call a Flash Message method. What this does is redraw the entire status bar and displays just a message. To use the FlashMessage, pass the StatusBar and the message you want to display and voila. At some point, you will need to restore the status bar. Just call the DisplayStatusBar procedure. Real quick. I would encourage you to look at the sample project to see how easy it is to add functionality. You can experiment with it to better understand how it works and really get a sense of how well this can work in your application. VB 4.0 ------------------------------------------------- VB 4.0 may make this obsolete so I don't think I will do anymore with this code. However, if they do something and it turns out that it can't do what this code can do.. guess what.. I will make it VB 4.0 compatible.. Disclaimer ------------------------------------------------- I hate to do this but the reason is very simple. This code is for you to use for FREE. You may modify it in whatever manner you choose. I am more interested in helping those who are looking for something with some good functionality, but can be tailored to fit a specific need. Because of this: I MAKE NO WARRANTY EITHER EXPRESSED OR IMPLIED ON THE RELIABILITY OR USEFULNESS OF THIS PRODUCT. I ASSUME NO LIABILITY OR RESPONSIBILITY FOR ANY DAMAGES CAUSED BY USE OF THIS PRODUCT. THE USER ASSUMES ALL RISK FOR USE OF THIS PRODUCT. If you have any questions or comments, and especially if you have suggestions or things to add to it, you are encouraged to make contact with me. I am very interested to see what types of changes you make or improvements you add. I would very much like a copy of what you did. I never claim nor do I ever try to imply that I know everything, but I like to share information and if you have some stuff for me, I would certainly love the opportunity to share code or say hello. Good Luck and Enjoy! M. John Rodriguez