NET User Interfaces in Csharp Windows Forms and Custom Controls [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

NET User Interfaces in Csharp Windows Forms and Custom Controls [Electronic resources] - نسخه متنی

Matthew MacDonald

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید



























Creating Button Controls


The label controls are fairly easy to develop because they are essentially static pieces of user interface. Other controls may need to support user interaction. For example, a button control needs to receive mouse clicks and a text box needs to handle key presses. To create one of these controls can require significant extra code and thorough testing to verify that its behavior is consistent under all circumstances.

To illustrate some of these considerations, the next example presents a button that's been created from scratch by deriving from the base Control class.


A Hot Tracking Button


This example develops a HotTrackButton that displays an image and text. When the mouse is positioned over the image, it appears with a raised border (see Figure 13-4).


Figure 13-4: The HotTrackButton

This control project raises some unique, subtle challenges:



The clickable portion of the button should only include the image. Thus, the control needs to use hit testing when a click is detected, and suppress click events if the text portion is clicked.



The button can appear in several states, including disabled, selected (when the mouse is positioned above the image), depressed (when the button is pushed), and normal.



The button must be able to deal with any valid image size.



The first step is to create a control class that provides a member variable to track its current state. In our example, a State enumeration is defined to help track the valid button states.


public class HotTrackButton : Control
{
public enum State
{
Normal,
MouseOver,
Pushed
}
private State state = State.Normal;
// (Other code omitted.)
}

Next, you need to create the button's public interface. This includes an Image property to store the picture it will display, and a Text property to store the caption text. Every control automatically inherits the Text property; however, the HotTrackButton class needs to override it to make sure that the control is invalidated (and thus repainted) when the text is changed.


private Image image;
private Rectangle bounds;
public Image Image
{
get
{
return image;
}
set
{
image = value;
bounds = new Rectangle(0, 0, image.Width + 5, image.Height + 5);
this.Invalidate();
}
}
// You must override this property to invalidate the display and
// provide automatic refresh when the property is changed.
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
this.Invalidate();
}
}

Notice that a private member variable called bounds is used to track the drawing area of the control. This rectangle is slightly larger than the image itself, because it needs to accommodate the focus rectangle. When the button changes state in response to a mouse action, the control class code can then invalidate just the region defined by the bounds rectangle, guaranteeing a faster refresh.

The next step is to override four mouse-related methods, including OnMouseMove(), OnMouseDown(), OnMouseUp(), and OnMouseLeave(). The code in these methods sets the button state appropriately, and forces a repaint if the state has changed.


protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
{
base.OnMouseMove(e);
// Check if the mouse pointer is over the button.
// If the mouse moves off the button surface, it will be deactivated,
// even if the button is being held in a pressed position.
// The code repaints the button only if needed.
if (bounds.Contains(e.X, e.Y))
{
if (state == State.Normal)
{
state = State.MouseOver;
this.Invalidate(bounds);
}
}
else
{
if (state != State.Normal)
{
state = State.Normal;
this.Invalidate(bounds);
}
}
}
protected override void OnMouseLeave(System.EventArgs e)
{
// Reset the button appearance. This will also deactivate the button
// if it has been pressed but not released.
// The code repaints the button only if needed.
if (state != State.Normal)
{
state = State.Normal;
this.Invalidate(bounds);
}
}
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
// Change the button to a pushed state, provided the mouse pointer is
// over the image and the Left mouse button has been clicked
if (bounds.Contains(e.X, e.Y) &&
(e.Button & MouseButtons.Left) == MouseButtons.Left)
{
state = State.Pushed;
this.Invalidate(bounds);
}
}
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
{
// Change the button to a normal state and repaint if needed.
if (!((e.Button & MouseButtons.Left) == MouseButtons.Left))
{
state = State.Normal;
if (bounds.Contains(e.X, e.Y))
{
state = State.MouseOver;
}
else
{
state = State.Normal;
}
this.Invalidate(bounds);
}
}

Finally, the paint logic renders the button in the appropriate state and the associated text. It uses a raised three-dimensional border when the mouse is positioned over the button, and a sunken border when it is clicked, which is similar to the image bar style used in Microsoft Outlook. The text is placed to the right of the picture, and is vertically centered with the mid-point of the image by measuring the image and font sizes.



protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (image == null)
{
// Draw the text without the image.
e.Graphics.DrawString(this.Text, this.Font,
new SolidBrush(this.ForeColor), 10, 0);
}
else
{
if (!this.Enabled)
{
// Paint the picture in a disabled state.
ControlPaint.DrawImageDisabled(e.Graphics, image, 2, 2,
this.BackColor);
}
else
{
// Paint the image according to the button state.
switch (state)
{
case State.Normal:
e.Graphics.DrawImage(image, 2, 2);
break;
case State.MouseOver:
ControlPaint.DrawBorder3D(e.Graphics, bounds,
Border3DStyle.Raised, Border3DSide.All);
e.Graphics.DrawImage(image, 2, 2);
break;
case State.Pushed:
ControlPaint.DrawBorder3D(e.Graphics, bounds,
Border3DStyle.Sunken, Border3DSide.All);
e.Graphics.DrawImage(image, 3, 3);
break;
}
}
// Paint the caption text next to the image.
e.Graphics.DrawString(this.Text, this.Font,
new SolidBrush(this.ForeColor), bounds.Width + 3,
(bounds.Height - this.Font.Height) / 2);
}
}

The drawing logic benefits from the ControlPaint class, which provides the DrawBorder3D() and the DrawImageDisabled() methods. This class, which was described in the previous chapter, could also help with the DrawFocusRect() method if you wanted to expand the control to be able to handle keyboard events.

The only remaining task is to make sure the click event is only raised when the image is clicked. You can accomplish this by overriding the OnClick() method, and only calling the base implementation (which raises the event) if the mouse is currently positioned over the image.


protected override void OnClick(System.EventArgs e)
{
// Only propagate the click to the client if it was detected over the image.
if (state == State.Pushed)
{
base.OnClick(e);
}
}

There's clearly a lot more you could add to this button control. For example, you could allow the user to change the orientation, place the text under the image, add support for text wrapping, or even create a compound control that contains a collection of images. From a conceptual point of view, these additions are easy. However, you'll find that the code can grow quite lengthy with the additional commands needed to evaluate the state and render the button control appropriately.


Note

If creating an owner-drawn button control is so much work, why bother? The answer is simple: it allows you to develop a proprietary graphical look for your application. If you do this successfully, your application appears to be more sophisticated, slick, and powerful than a competitor's application. Microsoft recognizes this reality, and outfits business-centric applications like Access and Excel with finely tooled graphics-using controls they don't release to anyone else. Never underestimate the appeal of an attractive user interface on your users!




/ 142