
Beginning Visual Basic 2005 (2006)
.pdf
Chapter 14
Responding to Clicks
Your control is going to fire an event whenever the left or right mouse button is clicked on a color button. To that end, in the next Try It Out you add some events to your ColorPalette control that the control will raise. The application using this control will be able to add the event handlers and take action when the event has been raised by this control.
Try It Out |
Responding to Clicks |
1.Go back to the Code Editor for ColorPalette. Add these events to the top of the class after your public members:
‘Public events
Public Event LeftClick(ByVal sender As Object, ByVal e As EventArgs) Public Event RightClick(ByVal sender As Object, ByVal e As EventArgs)
2.You need a general-purpose method that will return the button that’s positioned directly beneath the mouse. Add this method:
Public Function GetButtonAt(ByVal x As Integer, ByVal y As Integer) _ As ColorPaletteButton
‘Set the default return value GetButtonAt = Nothing
‘Go through each button in the collection
For Each objColorPaletteButton As ColorPaletteButton In Buttons ‘Is this button in the rectangle?
If objColorPaletteButton.Rectangle.Contains(x, y) Then Return objColorPaletteButton
End If
Next
End Function
3.Now, select (ColorPalette Events) in the Class Name combo box and then select the MouseUp event in the Method Name combo box. Your motivation for using MouseUp rather than MouseDown will become apparent soon. Add this highlighted code to the event handler:
Private Sub ColorPalette_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
‘Find the button that we clicked
Dim objColorPaletteButton As ColorPaletteButton = GetButtonAt(e.X, e.Y)
If Not objColorPaletteButton Is Nothing Then
‘Was the left button clicked
If e.Button = MouseButtons.Left Then
‘Set the color
LeftColor = objColorPaletteButton.Color
‘Raise the event
446

Programming Custom Graphics
RaiseEvent LeftClick(Me, New EventArgs())
ElseIf e.Button = MouseButtons.Right Then
‘Set the color
RightColor = objColorPaletteButton.Color
‘Raise the event
RaiseEvent RightClick(Me, New EventArgs())
End If
End If
End Sub
4.To test the new method, open the Forms Designer for Form1. Select the PaintCanvas control and set its Name property to Canvas.
5.Now open up the Code Editor for Form1. Select paletteColor in the Class Name combo box, and select the LeftClick event in the Method Name combo box. Add this highlighted code to the event handler:
Private Sub paletteColor_LeftClick(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles paletteColor.LeftClick
Canvas.GraphicColor = paletteColor.LeftColor
End Sub
6.Now run your project. You should be able to use the color palette to change the color laid down by the left mouse button.
How It Works
Although you’ve called your buttons ColorPaletteButton, they don’t behave in the way you’re used to seeing buttons behave. Button controls, like the ones you have been using until now, have the intelligence to detect when they’ve been clicked and fire an event to tell you what happened. Your color palette buttons, on the other hand, have until now been areas on the control painted in a pretty color. Now you actually need to write the logic to determine when a button is clicked.
The key to this is the GetButtonAt method. This method takes a set of client coordinates and returns the ColorPaletteButton object that contains the point you asked for. In this case, you use the Contains method of the Rectangle object to see whether the coordinates are contained within the rectangle.
Public Function GetButtonAt(ByVal x As Integer, ByVal y As Integer) _ As ColorPaletteButton
‘Set the default return value GetButtonAt = Nothing
‘Go through each button in the collection
For Each objColorPaletteButton As ColorPaletteButton In Buttons ‘Is this button in the rectangle?
447

Chapter 14
If objColorPaletteButton.Rectangle.Contains(x, y) Then
Return objColorPaletteButton
End If
Next
End Function
Of course, it could be the case that there is no button under the coordinates if the user clicks the mouse on a blank area of the control. If this is the case, GetButtonAt will return Nothing:
As you know, the Button property of MouseEventArgs tells you which button was used, or in this case, released. If it’s the left button, you update LeftColor and raise the LeftClick event:
Private Sub ColorPalette_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
‘Find the button that we clicked
Dim objColorPaletteButton As ColorPaletteButton = GetButtonAt(e.X, e.Y)
If Not objColorPaletteButton Is Nothing Then
‘Was the left button clicked
If e.Button = MouseButtons.Left Then
‘Set the color
LeftColor = objColorPaletteButton.Color
‘Raise the event
RaiseEvent LeftClick(Me, New EventArgs())
Alternatively, it could be the right mouse button:
ElseIf e.Button = MouseButtons.Right Then
‘Set the color
RightColor = objColorPaletteButton.Color
‘Raise the event
RaiseEvent RightClick(Me, New EventArgs())
End If
End If
End Sub
At the moment, PaintCanvas can deal with only one color, which is why you’ve only hooked up the LeftClick event. When you receive this event, you set the appropriate property on Canvas, and this new color will be used when creating new GraphicsCircle objects:
Private Sub paletteColor_LeftClick(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles paletteColor.LeftClick
Canvas.GraphicColor = paletteColor.LeftColor
End Sub
448

Programming Custom Graphics
Dealing with Two Colors
In the next Try It Out you extend PaintCanvas so that it can deal with two colors. You’ll do this by adding two public members that will track the color chosen for the left mouse button and the right mouse button. You’ll also be modifying your existing code to determine whether the left mouse button was clicked or whether the right mouse button was clicked.
Try It Out |
Dealing with Two Colors |
1.You need an additional property in PaintCanvas that will let you store the alternative color. For the sake of clarity, you’ll also change the name of the existing GraphicColor property to GraphicLeftColor. Open the Code Editor for the PaintCanvas class and make these changes:
‘Public members
Public GraphicsItems As New ArrayList()
Public GraphicTool As GraphicTools = GraphicTools.CirclePen Public GraphicSize As GraphicSizes = GraphicSizes.Medium
Public GraphicLeftColor As Color = Color.Black
Public GraphicRightColor As Color = Color.White
2.In the DoMousePaint method you need to examine the Button property of MouseEventArgs to determine which color you want to use. Make these two changes to DoMousePaint as highlighted:
Private Sub DoMousePaint(ByVal e As MouseEventArgs) ‘Store the new item somewhere
Dim objGraphicsItem As GraphicsItem
‘What color do we want to use?
Dim objColor As Color = GraphicLeftColor
If e.Button = MouseButtons.Right Then objColor = GraphicRightColor
End If
‘What tool are you using? Select Case GraphicTool
‘Circlepen
Case GraphicTools.CirclePen
‘Create a new graphics circle
Dim objGraphicsCircle As New GraphicsCircle()
‘Set the point for drawing
objGraphicsCircle.SetPoint(e.X, e.Y, GraphicSize, _ objColor, True)
‘Store this for addition objGraphicsItem = objGraphicsCircle
449

Chapter 14
End Select
‘Were you given an item?
If objGraphicsItem IsNot Nothing Then
‘Add it to the list GraphicsItems.Add(objGraphicsItem)
‘Invalidate the Control
Me.Invalidate(objGraphicsItem.Rectangle)
End If
End Sub
3.At the moment, MouseDown and MouseMove events will call DoMousePaint only if the left button is pressed. You need to change this so that it will accept either the left or right button. Make these changes as highlighted:
Private Sub PaintCanvas_MouseDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
‘Is the left or right mouse button down?
If e.Button = MouseButtons.Left Or e.Button = MouseButtons.Right Then DoMousePaint(e)
End If End Sub
Private Sub PaintCanvas_MouseMove(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
‘Is the left or right mouse button down?
If e.Button = MouseButtons.Left Or e.Button = MouseButtons.Right Then DoMousePaint(e)
End If End Sub
4.Next, you need to change the event handler in Form1 to set the GraphicLeftColor property rather than the GraphicColor property. Open the Code Editor for Form1 and make this change as highlighted:
Private Sub paletteColor_LeftClick(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles paletteColor.LeftClick
Canvas.GraphicLeftColor = paletteColor.LeftColor
End Sub
5.Finally, you need to add an event handler for the RightClick event. Select paletteColor in the Class Name combo box and the RightClick event in the Method Name combo box. Add this highlighted code:
Private Sub paletteColor_RightClick(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles paletteColor.RightClick
Canvas.GraphicRightColor = paletteColor.RightColor
End Sub
450

Programming Custom Graphics
Now, if you run the project, you should be able to assign different colors to the left and right mouse buttons and use both of the buttons to paint on the form.
Indicating the Assigned Buttons
You’ve no doubt noticed that, at this point, using WroxPaint is a little confusing. There’s no indication as to which color is assigned to which button. You need to resolve this issue, so in the next Try It Out you’ll display the letter L on the color assigned to the left button and the letter R on the color assigned to the right button.
Try It Out |
Indicating the Assigned Buttons |
1.First, you’ll make the ColorPaletteButton objects aware of which button they’re assigned to, if any. Open the Code Editor for the ColorPaletteButton class and add this enumeration to the top of the class:
Public Class ColorPaletteButton
‘Public enumerations
Public Enum ButtonAssignments As Integer None = 0
LeftButton = 1
RightButton = 2
End Enum
2.Next, add this new member (highlighted), which will keep track of the button’s assignment:
‘Public members
Public Color As Color = System.Drawing.Color.Black Public Rectangle As Rectangle
Public ButtonAssignment As ButtonAssignments = ButtonAssignments.None
3.After the button has a way of storing what it’s assigned to, you can change the Draw method to draw the L or R as appropriate. Add the following highlighted code to Draw:
‘Draw the button
Public Sub Draw(ByVal graphics As Graphics) ‘Draw the color block
Dim objSolidBrush As New SolidBrush(Color) graphics.FillRectangle(objSolidBrush, Rectangle)
‘Draw an edge around the control
Dim objPen As New Pen(System.Drawing.Color.Black) graphics.DrawRectangle(objPen, Rectangle)
‘Are you selected?
If ButtonAssignment <> ButtonAssignments.None Then
‘Create a font
Dim objFont As New Font(“verdana”, 8, FontStyle.Bold)
‘Set the default button assignment Dim strButtonText As String = “L”
451

Chapter 14
‘Update the button assignment if necessary
If ButtonAssignment = ButtonAssignments.RightButton Then strButtonText = “R”
End If
‘What brush do you want?
If Color.R < 100 Or Color.B < 100 Or Color.G < 100 Then objSolidBrush = New SolidBrush(System.Drawing.Color.White)
Else
objSolidBrush = New SolidBrush(System.Drawing.Color.Black)
End If
‘Draw the text ‘L’ or ‘R’ graphics.DrawString(strButtonText, objFont, objSolidBrush, _
Rectangle.Left, Rectangle.Top)
End If End Sub
4.To keep track of which button is selected, you need to add some private members to the ColorPalette class. Open the Code Editor for this class and add this code:
‘Private members
Private LeftButton As ColorPaletteButton Private RightButton As ColorPaletteButton
5.The next wrinkle you have to fix is quite verbose but relatively straightforward. Basically, you have to make sure that a button cannot be assigned to both the left and right buttons — for no other reason than that you just don’t have a way of reporting that information to the user. Also, you have to muddle with the invalidation code. You’ll detail that once you have the example working. Make these changes to ColorPalette_MouseUp as highlighted:
Private Sub ColorPalette_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
‘Find the button that we clicked
Dim objColorPaletteButton As ColorPaletteButton = GetButtonAt(e.X, e.Y)
If Not objColorPaletteButton Is Nothing Then
‘Was the left button clicked
If e.Button = MouseButtons.Left Then
‘Make sure that this button is not the current right button
If objColorPaletteButton IsNot RightButton Then
‘Set the color
LeftColor = objColorPaletteButton.Color
‘Clear the existing selection. If LeftButton IsNot Nothing Then
LeftButton.ButtonAssignment = _
ColorPaletteButton.ButtonAssignments.None
452

Programming Custom Graphics
Me.Invalidate(LeftButton.Rectangle)
End If
‘Mark the button objColorPaletteButton.ButtonAssignment = _
ColorPaletteButton.ButtonAssignments.LeftButton
Me.Invalidate(objColorPaletteButton.Rectangle)
LeftButton = objColorPaletteButton
‘Raise the event
RaiseEvent LeftClick(Me, New EventArgs())
End If
ElseIf e.Button = MouseButtons.Right Then
‘Make sure this button is not the current left button
If objColorPaletteButton IsNot LeftButton Then
‘Set the color
RightColor = objColorPaletteButton.Color
‘Clear the existing selection
If RightButton IsNot Nothing Then
RightButton.ButtonAssignment = _
ColorPaletteButton.ButtonAssignments.None
Me.Invalidate(RightButton.Rectangle)
End If
‘Mark the button objColorPaletteButton.ButtonAssignment = _
ColorPaletteButton.ButtonAssignments.RightButton
Me.Invalidate(objColorPaletteButton.Rectangle)
RightButton = objColorPaletteButton
‘Raise the event
RaiseEvent RightClick(Me, New EventArgs()) End If
End If
End If
End Sub
453

Chapter 14
6.Finally, you have to set up the first two colors added to the control as being the selected buttons when the control is started. This involves updating your leftButton and rightButton members as well as setting the ButtonAssignment property on the button itself. Add the highlighted code to AddColor:
‘Add a new color button to the control Public Sub AddColor(ByVal newColor As Color)
‘Create the button
Dim objColorPaletteButton As New ColorPaletteButton(newColor)
‘Add it to the list Buttons.Add(objColorPaletteButton)
‘Do we have a button assigned to the left button yet? If LeftButton Is Nothing Then
objColorPaletteButton.ButtonAssignment = _ ColorPaletteButton.ButtonAssignments.LeftButton
LeftButton = objColorPaletteButton
ElseIf RightButton Is Nothing Then ‘How about the right button?
objColorPaletteButton.ButtonAssignment = _ ColorPaletteButton.ButtonAssignments.RightButton
RightButton = objColorPaletteButton
End If
End Sub
7.Run the project now, and you should see that when you change the color selection, an L and R appear on the buttons, as shown in Figure 14-4.
Figure 14-4
454

Programming Custom Graphics
How It Works
The first thing you did was add an enumeration to the ControlPaletteButton class that could be used to set the state of the button:
‘Public enumerations
Public Enum ButtonAssignments As Integer None = 0
LeftButton = 1
RightButton = 2 End Enum
As you can see from the enumeration, a palette button can either be assigned to no mouse buttons, the left mouse button, or the right mouse button. You also added members to the ControlPalette class to keep track of which button was selected. This makes your life a little easier when it comes to changing the selection. When you select a new palette button, you have to set the ButtonAssignment property of the old button to ButtonAssignments.None. Just being able to look in the LeftButton or RightButton member, as appropriate, saves you from having to look through the entire list of buttons to find the one you need to change. The ColorPalette_MouseUp method starts to look a little more complex when you add this new functionality. When you want to assign the left mouse button to a palette button, you have to make sure that the palette button is not already assigned to the right mouse button:
Private Sub ColorPalette_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
‘Find the button that we clicked
Dim objColorPaletteButton As ColorPaletteButton = GetButtonAt(e.X, e.Y)
If Not objColorPaletteButton Is Nothing Then
‘Was the left button clicked
If e.Button = MouseButtons.Left Then
‘Make sure that this button is not the current right button If objColorPaletteButton IsNot RightButton Then
If you can set the color, you update the LeftColor property as you did before:
‘Set the color
LeftColor = objColorPaletteButton.Color
If another button is already assigned to the left mouse button, you need to set its ButtonAssignment property back to None. You also have to invalidate this button so that the button is redrawn and the L is removed:
‘Clear the existing selection. If LeftButton IsNot Nothing Then
LeftButton.ButtonAssignment = _
ColorPaletteButton.ButtonAssignments.None
Me.Invalidate(LeftButton.Rectangle)
End If
455