Manning Windows Forms Programming (phần 6) pps

50 407 0
Manning Windows Forms Programming (phần 6) pps

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

216 CHAPTER 7 DRAWING AND SCROLLING Our focus in this section will be the Panel class. This class can contain and posi- tion controls just like the Form class, and supports automated scrolling since it inherits from the ScrollableControl class. 2 We will not position controls within a panel in this chapter, but we will use this class to fix some of the problems we have seen when drawing directly on the form. We will draw our photo directly in a Panel, and solve the following problems we noticed when drawing directly on the form: • Our image was off-center vertically for the Scale to Fit display option. The DisplayRectangle property included the vertical space occupied by the scroll bar, which threw our calculations off. Here, we will use the panel’s Dis- playRectangle property, so that the image will be centered exactly inside the panel. • The 3-D border we used for the PictureBox control was gone. We could have attempted to draw a border inside the form using the Control- Paint.DrawBorder3D method, but a Panel provides a much easier solution. The Panel class provides a BorderStyle property much like the correspond- ing PictureBox property, so the .NET framework will draw the border for us. • The status bar was part of the scrollable area. Since the Form object managed the scrolling, the StatusBar control on the form was caught up in the scroll- ing logic. In this section, the scrolling will be managed by the Panel class independent of the form and status bar. As a result, our status bar will return to and remain at its natural position at the base of the form. Before we get into the required changes, figure 7.5 shows how our three display modes will appear by the end of this section. As you can see, the application looks much more polished here than when we drew directly on the form. Note especially the excellent centering, the fine border, and the well-behaved scroll bars. 2 For the curious, the GroupBox control inherits from the Control class and does not support scrolling. Figure 7.5 This shows an image drawn inside a panel with the Scale to Fit, Stretch to Fit, and Actual Size display modes. PANELS 217 As you will see, the code to draw the image inside a panel is very similar to drawing the image directly on the form. We will need to add a new panel, update some of our menu handlers and the drawing of the status bar, and finally draw the image into the panel. 7. 4 . 1 A DDING A PANEL Adding a Panel object in Visual Studio is much like adding any other control. You open the Toolbox and drag a Panel onto the form. In the source code, the panel is added using the Control property of the parent form. We will look at both of these, beginning with the use of Visual Studio. Set the version number of the MyPhotos application to 7.4. Take a look at the MainForm.cs source file to see how the panel is created. As you can see, this code looks very similar to the code for other controls from prior chapters. A private instance is created in the MainForm class, initialized in the Initialize- Component method, and added to the form using the Form.Controls property. private System.Windows.Forms.Panel pnlPhoto; . . . private void InitializeComponent() { . . . this.pnlPhoto = new System.Windows.Forms.Panel (); . . . // // pnlPhoto // this.pnlPhoto.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.pnlPhoto.Dock = System.Windows.Forms.DockStyle.Fill; this.pnlPhoto.Name = "pnlPhoto"; this.pnlPhoto.Size = new System.Drawing.Size(292, 233); this.pnlPhoto.TabIndex = 3; . . . this.Controls.AddRange(new System.Windows.Forms.Control[] { this.pnlPhoto, this.statusBar1}); ADD A PANEL TO THE FORM Action Result 1 In the MainForm.cs [Design] window, drag a Panel control from the Toolbox onto the form. A Panel control is added to the window. 2 Set the panel’s properties as shown. Settings Property Value (Name) pnlPhoto BorderStyle Fixed3D Dock Fill 218 CHAPTER 7 DRAWING AND SCROLLING The Panel class depends largely on its base classes for exported functionality, with the BorderStyle property just about the only new member added by the class. An overview of the Panel class appears in .NET Table 7.5. 7. 4 . 2 U PDATING THE MENU HANDLERS With our panel on the form, we need to update the code for drawing our image to use the new panel rather than interacting with the form itself. We will begin with the menu handlers for the Image submenu. The menuImage_Popup method simply sets the Enabled and Checked menu properties as required for the current display mode. This behavior does not change, so no modifications are required. The menuImage_ChildClick method sets scrolling properties for the form. Since our scrolling will be managed from the Panel object now, we need to use the corresponding Panel members rather than those in the Form itself. .NET Table 7.5 Panel class The Panel class represents a scrollable control that acts as a container for other controls. This class is often used to define a region of controls within a Form. This class is part of the Sys- tem.Windows.Forms namespace and inherits from the ScrollableControl class. See .NET Table 7.1 on page 196 for a list of members inherited from the ScrollableControl class. Public Properties BorderStyle Gets or sets the type of border to display around the control. DisplayRectangle (inherited from Control) Gets the display area for the control. When scrolling is enabled, this property represents the entire scrollable area for the panel. The ClientRectangle property represents the visible portion of the control. Enabled (inherited from Control) Gets or sets whether the panel is enabled. Controls within the panel are disabled whenever the panel itself is disabled. Visible (inherited from Control) Gets or sets whether the panel is visible. Controls within the panel are invisible if the panel itself is invisible. UPDATE THE MENUIMAGE_CHILDCLICK METHOD TO USE THE NEW PANEL Action Result 1 Locate the menuImage_ChildClick method in the MainForm.cs source window. protected void menuImage_ChildClick (object sender, System.EventArgs e) { . . . 2 Modify the code for the ScaleToFit and StretchToFit display mode to set drawing-related properties on the Panel rather than the parent Form. case DisplayMode.ScaleToFit: case DisplayMode.StretchToFit: SetStyle(ControlStyles.ResizeRedraw, true); pnlPhoto.AutoScroll = false; pnlPhoto.Invalidate(); break; PANELS 219 That’s it for our menu handlers. The SetStyle method is a protected member and cannot be modified for our Panel class, so we just force the redraw to happen at the Form level as we did before. This will redraw the entire form and not just our panel, but it gets the job done. In this case, the drawing required outside of our panel is not overly complex, so this extra drawing should not be a problem. On a more complex form, it would make sense to handle the Resize event for the pnlPhoto object instead of setting a form-level style as we do here. Handling the Resize event would allow us to only redraw the panel itself, and not the other parts of the Form. The AutoScroll property is a public member of the ScrollableControl class, so we can set its value for the pnlPhoto object directly. As you can see, because the Panel and Form classes are based on a similar class hierarchy, design changes like this are very easy to make in .NET. Let’s move on to our owner-drawn status bar. 7. 4 . 3 D RAWING THE STATUS BAR PANEL Our status bar is drawn in the statusBar1_DrawItem method. This method must calculate the percentage of the image shown in the window. Since the image will now be displayed inside the Panel object, we must modify this routine to use the Panel client area rather than the MainForm one. 3 Modify the code for the ActualSize display mode in a similar manner. case DisplayMode.ActualSize: SetStyle(ControlStyles.ResizeRedraw, false); pnlPhoto.AutoScroll = true; pnlPhoto.Invalidate(); break; . . . } UPDATE THE MENUIMAGE_CHILDCLICK METHOD TO USE THE NEW PANEL Action Result UPDATE THE STATUSBAR1_DRAWITEM METHOD TO USE THE PANEL Action Result 1 Locate the statusBar1_DrawItem method in the MainForm.cs file. protected void statusBar1_DrawItem (object sender, StatusBarDrawItemEventArgs sbdevent) { . . . 220 CHAPTER 7 DRAWING AND SCROLLING Once again this change simply uses our private Panel field rather than the this keyword. Our last change is to draw the image inside the panel rather than on the form itself. 7. 4 . 4 D RAWING THE IMAGE When drawing the image on the form, we were able to override the protected OnPaint method that raises the Paint event. For the Panel object, we do not have access to protected members, so we must use the public Paint event to update the panel. Internally in the Windows Forms library, of course, the Panel control will use its own version of the OnPaint method to invoke our event handler. Note that the Paint event handler receives a PaintEventArgs instance containing the event data. As we saw earlier in the chapter, this class contains the Graphics object for drawing inside the panel. Our code uses this object in the same way as when the image was drawn in the form. Continuing our previous steps: 2 Modify the calculation of the percent variable to use the panel rather than the form. // Calculate percent of image shown int percent = 100; if (_selectedMode == DisplayMode.ActualSize) { Photograph photo = _album.CurrentPhoto; Rectangle dr = pnlPhoto.ClientRectangle; int imgWidth = photo.Image.Width; int imgHeight = photo.Image.Height; percent = 100 * Math.Min(dr.Width, imgWidth) * Math.Min(dr.Height, imgHeight) / (imgWidth * imgHeight); } . . . } UPDATE THE STATUSBAR1_DRAWITEM METHOD TO USE THE PANEL (continued) Action Result ADD A PAINT HANDLER FOR THE PNLPHOTO OBJECT Action Result 1 Add a Paint event handler for the panel. How-to Double-click the Panel control. Note: The Paint event is the default event for the panel control in Visual Studio. Other events can be added via the Properties window. Visual Studio generates the appropriate code in the source file. protected void pnlPhoto_Paint (object sender, System.Windows.Forms.PaintEventArgs e) { } PANELS 221 TRANSFER THE DRAWING CODE INTO THE NEW PAINT HANDLER Action Result 2 In the pnlPhoto_Paint method, use the given Graphics to draw the image when the album is not empty. protected void pnlPhoto_Paint (object sender, System.Windows.Forms.PaintEventArgs e) { if (_album.Count > 0) { // Paint the current photo Photograph photo = _album.CurrentPhoto; Graphics g = e.Graphics; 3 Copy the switch statement for drawing the image from the existing OnPaint method. switch (_selectedMode) { . . . } } else { // No image to paint } } 4 Update this switch block to use the pnlPhoto object as appropriate. switch (_selectedMode) { default: case DisplayMode.ScaleToFit: // Preserve aspect ratio of image g.DrawImage(photo.Image, photo.ScaleToFit( pnlPhoto.DisplayRectangle)); break; case DisplayMode.StretchToFit: // Fill entire panel with image g.DrawImage(photo.Image, pnlPhoto.DisplayRectangle); break; case DisplayMode.ActualSize: // Draw portion of image g.DrawImage(photo.Image, pnlPhoto.AutoScrollPosition.X, pnlPhoto.AutoScrollPosition.Y, photo.Image.Width, photo.Image.Height); pnlPhoto.AutoScrollMinSize = photo.Image.Size; break; } 5 If the album is empty, draw the standard system control color onto the panel. else { // No image to paint e.Graphics.Clear(SystemColors.Control); } } 222 CHAPTER 7 DRAWING AND SCROLLING It may look like a lot of code, but the number of changes is actually quite small, as indicated by the few number of bolded lines. The program is all set now. Verify that your code compiles and runs properly. Change display modes, use different-sized images, and resize the form to observe the effect. TRY IT! If you are feeling brave, try adding a Fit to Width menu item to the Image submenu. This should preserve the aspect ratio of the image by scaling the image to match the width of the panel window. You will need to add a FitToWidth enumeration value to the DisplayMode enumeration. Calculate the height using code similar to the Photo- graph.ScaleToFit method where the width is preserved. The tricky part is setting the pnlPhoto.AutoScrollMinSize property appropri- ately and drawing the image into this same rectangle. 7. 5 R ECAP This chapter has looked at some drawing and scrolling aspects of the Form class. In particular, we removed the PictureBox control from our application and learned 6 Remove the corresponding drawing code from the existing OnPaint method. The OnPaint method now looks as follows: protected override void OnPaint (PaintEventArgs e) { if (_album.Count > 0) { // Paint the current image Photograph photo = _album.CurrentPhoto; // Update the status bar. pnlFileName.Text = photo.Caption; pnlFileIndex.Text = String.Format("{0:#}/{1:#}", _album.CurrentIndex+1, _album.Count); pnlImageSize.Text = String.Format("{0:#} x {1:#}", photo.Image.Width, photo.Image.Height); statusBar1.ShowPanels = true; } else { // Indicate the album is empty statusBar1.Text = "No Photos in Album"; statusBar1.ShowPanels = false; } 7 At the end of this method, invalidate the panel to ensure it is redrawn. // Ensure contained controls are redrawn pnlPhoto.Invalidate(); statusBar1.Invalidate(); base.OnPaint(e); } TRANSFER THE DRAWING CODE INTO THE NEW PAINT HANDLER (continued) Action Result RECAP 223 how to draw our image directly onto the form. We used the protected OnPaint method and made use of the automated scroll bars inherited by the Form class to scroll our image. This did not work exactly as we wanted, so we modified our code to use the Panel class instead as a way to draw the image independent of the rest of the form. The next chapter will continue our investigation of the Form class by looking at dialog boxes. 224 CHAPTER 8 Dialog boxes 8.1 Message boxes 225 8.2 The Form.Close method 233 8.3 Modal dialog boxes 237 8.4 Modeless dialogs 252 8.5 Recap 262 So far we have only used a single window in our MyPhotos application. We have changed its appearance in each chapter, adding controls such as a menu bar, status bar, and panel, but all controls, events, painting, and other activities have occurred within our one Form window. In this chapter we branch out. The previous chapter introduced the Form class and demonstrated drawing and scrolling in both it and the Panel class. Both of these classes can be used to support intricate drawing interfaces from those seen in basic drawing applications such as Microsoft Paint to a full-fledged Internet browser window. Another common use for Form classes is the creation of dialog boxes. The Form class , as well as the Panel class, allows other controls to be positioned and managed inside its boundaries. In this chapter we look at how dialog boxes are created for both simple message boxes and more complex custom dialogs. This will consist of the fol- lowing topics. • Create simple message dialogs with the MessageBox class. • Discuss the use of Close and Dispose for Form objects. • Use the OnClosing method to intercept when a form or dialog box closes. MESSAGE BOXES 225 • Explain the difference between modal and modeless dialogs. • Create dialog boxes using the Form class. Before we get into generating custom dialog boxes, we will first look at how simple messages are displayed using the MessageBox class. 8.1 MESSAGE BOXES Developers, especially object-oriented developers, are always looking for shortcuts. Classes such as OpenFileDialog and SaveFileDialog not only provide a stan- dard way to prompt a user for files, they also save programmers a lot of time and effort by encapsulating the required window display and interaction code. Another common task programmers face is the need to display a simple message to the user. Our photo album application, for example, should really display an error message when an album cannot be saved successfully, or it could pose a question by asking the user if they would like to save the album to an alternate file location. The .NET Framework provides a MessageBox class for this purpose. This class is very similar to the MFC function of the same name. This section will show how this class is used to handle simple interactions with a user. While this class is not actually a Form object, it is the most basic type of modal dialog box. All dialog boxes are either modal or modeless. A modal dialog box requires the user to respond before the associated program will continue. Modeless or nonmodal dia- log boxes allow the application to continue while the dialog box is displayed. All MessageBox windows are modal, while Form windows are modal if invoked via the Form.ShowDialog method and modeless if invoked via the Form.Show method. Figure 8.1 These examples show the four types of icons available to MessageBox dialogs. [...]... Visual Studio to manage certain controls on the form private System .Windows. Forms. Button btnOK; private System .Windows. Forms. Button btnCancel; private System .Windows. Forms. Label label1; private System .Windows. Forms. Label label2; private System .Windows. Forms. Label lblImage; private System .Windows. Forms. TextBox txtCaption; /// /// Required designer variable /// private System.ComponentModel.Container... using the new keyword this.btnOK = new System .Windows. Forms. Button (); this.btnCancel = new System .Windows. Forms. Button (); this.label1 = new System .Windows. Forms. Label (); this.label2 = new System .Windows. Forms. Label (); this.lblImage = new System .Windows. Forms. Label (); this.txtCaption = new System .Windows. Forms. TextBox (); • Next the nondefault properties are set for each control This section is quite... this.Controls.AddRange(new System .Windows. Forms. Control[] { this.txtCaption, this.lblImage, this.label2, this.label1, this.btnCancel, this.btnOK}); this.FormBorderStyle = System .Windows. Forms. FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "CaptionDlg"; this.ShowInTaskbar = false; this.StartPosition = System .Windows. Forms. FormStartPosition.CenterParent; this.Text... are shown in NET Table 8.2, and correspond to the kinds of buttons typically found in Windows dialogs .NET Table 8.2 DialogResult enumeration The DialogResult enumeration represents a value returned by a dialog box This class is part of the System .Windows. Forms namespace, and is used with all dialog boxes in Windows Forms In particular, a DialogResult is returned by the MessageBox.Show method as well... portion of the file: this.SuspendLayout(); // // btnOK // this.btnOK.DialogResult = System .Windows. Forms. DialogResult.OK; this.btnOK.Location = new System.Drawing.Point(82, 88); this.btnOK.Name = "btnOK"; this.btnOK.TabIndex = 0; this.btnOK.Text = "&OK"; // // btnCancel // this.btnCancel.DialogResult = System .Windows. Forms. DialogResult.Cancel; this.btnCancel.Location = new System.Drawing.Point(187, 88);... CaptionDlg : System .Windows. Forms. Form { • Each control is created as a private member of the class The organization used by Visual Studio can be a bit confusing, so I have used the power of cut and paste to rearrange these code excerpts to be a bit more logical If you recall, the components member is required by Visual Studio to manage certain controls on the form private System .Windows. Forms. Button btnOK;... set these properties to the appropriate values while creating the buttons, so the InitializeComponent method already defines these settings btnOK.DialogResult = System .Windows. Forms. DialogResult.OK; btnCancel.DialogResult = System .Windows. Forms. DialogResult.Cancel; We will see how the settings interact with the ShowDialog method when we display the dialog from our MainForm class This is our next topic... constructor #region Windows Form Designer generated code /// MODAL DIALOG BOXES 245 /// Required method for Designer support - do not modify /// the contents of this method with the code editor /// private void InitializeComponent() { • Inside the InitializeComponent method, the controls are first created using the new keyword this.btnOK = new System .Windows. Forms. Button (); this.btnCancel... click the push-pin graphic at the top right of this window Note: The order of controls in your toolbox may differ from those shown here You can sort this list alphabetically by right-clicking on the Windows Forms title and selecting the Sort Items Alphabetically option 4 Add an OK button to the base of the form How-to Drag a Button control from the toolbox onto the form, and assign its properties as indicated... 8.1 .NET Table 8.1 MessageBox class The MessageBox class represents a modal dialog box that displays a message or question to the user and waits for their response This class is part of the System .Windows. Forms namespace A MessageBox cannot be instantiated as an object with the new keyword; instead the static Show method is used to display the dialog By default, a message box displays with no icon and . Form.Controls property. private System .Windows. Forms. Panel pnlPhoto; . . . private void InitializeComponent() { . . . this.pnlPhoto = new System .Windows. Forms. Panel (); . . . // // pnlPhoto . . // // pnlPhoto // this.pnlPhoto.BorderStyle = System .Windows. Forms. BorderStyle.Fixed3D; this.pnlPhoto.Dock = System .Windows. Forms. DockStyle.Fill; this.pnlPhoto.Name = "pnlPhoto"; . returned by a dialog box. This class is part of the System .Windows. Forms namespace, and is used with all dialog boxes in Win- dows Forms. In particular, a DialogResult is returned by the MessageBox.Show

Ngày đăng: 07/07/2014, 04:20

Tài liệu cùng người dùng

Tài liệu liên quan