Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ebook) Visual Studio .NET Mastering Visual Basic.pdf
Скачиваний:
120
Добавлен:
17.08.2013
Размер:
15.38 Mб
Скачать

DESIGNING IRREGULARLY SHAPED CONTROLS 421

The code also compares the current date/time to the setting of the m_AlarmTime property, and if the difference is negative, it means that the alarm must go off. If so, it raises the TimeOut event.

Designing Irregularly Shaped Controls

With VB.NET it’s quite easy to create irregularly shaped controls. It’s possible to create irregularly shaped forms too, but, unlike irregularly shaped controls, an irregularly shaped form is still quite uncommon. By the way, you can also create semitransparent forms with VB.NET—if you can come up with a good reason to do so.

To change the default shape of a custom control, you must use the Region object. This is another graphics-related object that specifies a closed area. You can even use Bezier curves to make highly unusual and smooth shapes for your controls. In this section, we’ll do something less ambitious: We’ll create controls with the shape of an ellipse, as shown in Figure 9.9.

Figure 9.9

Two instances of an ellipse-shaped control

You can turn any control to any shape you like by creating the appropriate Region object and then applying it to the Region property of the control. This must take place from within the control’s Load event. Listing 9.17 shows the statements that change the shape of the control.

Listing 9.17: Creating a Non-Rectangular Control

Private Sub RoundButton_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load

Dim G As Graphics

G = Me.CreateGraphics

Dim roundPath As New GraphicsPath()

Dim R As New Rectangle(0, 0, Me.Width, Me.Height) roundPath.AddEllipse(R)

Me.Region = New Region(roundPath) Me.CreateGraphics.DrawEllipse(New Pen(Color.DarkGray, 3), R)

End Sub

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

422 Chapter 9 BUILDING CUSTOM WINDOWS CONTROLS

First, we retrieve the Graphics object of the UserControl object and store it in the G variable. Then we create a GraphicsPath, the roundPath object, and add an ellipse to it. The ellipse is based on the rectangle that encloses the ellipse. The R object is used temporarily to specify the ellipse. The new path is then used to create a Region object, which is assigned to the Region property of the UserControl object. This gives our control the shape of an ellipse. The last statement draws an ellipse with the dark gray pen around the perimeter of the control. This step is optional, but it’s equivalent to adding a border to the control.

To demonstrate the design of an irregularly shaped control, we’ll build the RoundButton control, which was shown in Figure 9.9 earlier. You can find this control along with its test form in the NonRectangular project on the CD. The most important section of the control’s code is the Load event handler, which was shown in Listing 9.17.

Irregularly shaped controls are used in fancy interfaces, and they usually react to movement of the mouse. The control of Figure 9.9 changes its background color and caption when the mouse is over the control. Listing 9.18 shows the code behind the control’s MouseEnter and MouseLeave events. When the mouse enters the control’s area (this is detected by the control automatically—you won’t have to write a single line of code for it), the currentState variable is set to Active, the control’s background color to green, and its caption to “Play.” Similar actions take place in the control’s MouseLeave event handler: the control’s background color changes to red and its caption to “Pause”. In addition, each time the control switches state (from Pause to Play or vice versa), one of the NowPlaying and NowPausing events is fired.

Listing 9.18: The RoundButton Control’s MouseEnter and MouseLeave Events

Private Sub RoundButton_MouseEnter(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles MyBase.MouseEnter If currentState = State.Active Then

Me.BackColor = Color.Green currentCaption = “Play” RaiseEvent NowPlaying()

End If End Sub

Private Sub RoundButton_MouseLeave(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles MyBase.MouseLeave If currentState = State.Active Then

Me.BackColor = Color.Red currentCaption = “Pause” RaiseEvent NowPausing()

End If End Sub

These two events set up the appropriate variables, and the drawing of the control takes place in the OnPaint method, which is shown in Listing 9.19.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

DESIGNING IRREGULARLY SHAPED CONTROLS 423

Listing 9.19: The RoundButton Control’s OnPaint Method

Protected Overrides Sub OnPaint(ByVal pe As PaintEventArgs) Dim roundPath As New GraphicsPath()

Dim R As New Rectangle(0, 0, Me.Width, Me.Height) roundPath.AddEllipse(R)

Me.Region = New Region(roundPath) pe.Graphics.DrawEllipse(New Pen(Color.DarkGray, 3), R) Dim fnt As Font

If currentState = State.Active Then

If Me.BackColor.Equals(Color.Silver) Then Me.BackColor = Color.Green fnt = New Font(“Verdana”, 24, FontStyle.Bold)

Else

fnt = New Font(“Verdana”, 14, FontStyle.Regular) End If

Dim X As Integer = (Me.Width - pe.Graphics.MeasureString( _ currentCaption, fnt).Width) / 2

Dim Y As Integer = (Me.Height - pe.Graphics.MeasureString( _ currentCaption, fnt).Height) / 2

pe.Graphics.DrawString(currentCaption, fnt, Brushes.White, X, Y) End Sub

The OnPaint method uses graphics methods to center the string on the control. They’re the same methods we used in the example of the user-drawn control, earlier in this chapter. The drawing methods are discussed in detail in Chapter 14.

The code makes use of the currentState variable, which can take on two values: Active and Inactive. These two values are members of the State enumeration, which is shown next:

Public Enum State

Active

Inactive

End Enum

The control can be in two states. In the Active state, it behaves as described. In the Inactive state, the control turns gray and doesn’t respond to the movement of the mouse. In addition, its caption becomes “Resume” and the user can switch between states by clicking the control. The control’s click event handler is shown next:

Private Sub RoundButton_Click(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles MyBase.Click If currentState = State.Active Then

currentState = State.Inactive Me.BackColor = Color.Silver currentCaption = “Resume”

Else

currentState = State.Active currentCaption = “Play”

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

424 Chapter 9 BUILDING CUSTOM WINDOWS CONTROLS

End If

Me.Invalidate()

End Sub

The code changes the control’s state and, when the control is switched to the Inactive state, it fills it with a gray shade. To restore the control to its Active state, the user must click the control again.

The test form of the project shows how the RoundButton control behaves on a form. You can use the techniques described in this section to make a series of round controls to emulate the look of VCR controls. When the mouse hovers over the control, you can display the icon of the button (Play, Pause, Resume, and so on). When the mouse moves outside the area of the control, you can display the same icon with washed-out colors. Or you can place a nice colored dot on the control, which will be green when the button is pressed and red when it’s released.

The control raises two events to notify the application that its state has changed. The two event names must be declared outside any procedure with the following statements:

Public Event NowPlaying()

Public Event NowPausing()

The two events are raised from within the MouseEnter and MouseLeave event handlers with the following statements:

RaiseEvent NowPlaying()

RaiseEvent NowPaused()

To test these events, switch to the test form and enter the following statements in the two event handlers of the RoundButton control. They’re two simple statements that display the control’s current status on the form’s title bar. They simply demonstrate how to capture the changes in the control’s status and use it in the host application to control other activities:

Private Sub RoundButton1_NowPlaying() Handles RoundButton1.NowPlaying

Me.Text = “Playing...”

End Sub

Private Sub RoundButton1_NowPausing() Handles RoundButton1.NowPausing

Me.Text = “Paused...”

End Sub

In Chapter 14, you’ll learn more about shapes and paths, and you may wish to experiment with other oddly shaped controls. How about a progress indicator control that looks like a thermometer?

Building Owner-Drawn Controls

In this section, I’ll show a couple of examples that demonstrate how to customize existing controls. You’re not going to build new custom controls in this section; actually, you’ll hook custom code into certain events of a control to direct the rendering of the control. Some of the .NET Windows controls can be customized far more than it is possible through their properties. These are the listlike controls (menus, ListBox controls), and they allow you to supply your own code for drawing each item. Using this technique, you can create a menu with a separate font for each menu item, a ListBox control with alternating background colors, and so on. You can even put bitmaps on the

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com