📄 ch5.htm
字号:
if ((currentRow < numRows) && (currentCol< numColumns)) {<BR> // See if it fits in the column...<BR> if ((xHit >= x) && (xHit <(x + cellWidth))) {<BR> //See if it fits in the row...<BR> if((yHit >= y) && (yHit < (y + cellHeight))) {<BR> paintIndex= index;<BR> paintX= x;<BR> paintY= y;<BR> returnmatrix[index];<BR> }// end if<BR> } // end if<BR> } // end inner if<BR> } // end else<BR> // Adjust column display of cells<BR> if (j == 0)<BR> currentCol = leftCell;<BR> else<BR> ++currentCol;<BR> } // end column for<BR> // Now start data cells at appropriate top...<BR> if (i == 0)<BR> currentRow = topCell;<BR> else<BR> ++currentRow;<BR> } // end row for<BR> return null; // Only used if paint is false...<BR>}</TT></BLOCKQUOTE><HR><P>The painting begins with the <TT>update()</TT>method. Recall that the earlier versions of the spreadsheet applethave a brief flicker of white when the spreadsheet area is repainted.This is because the <TT>update()</TT>method, by default, clears out the area before the <TT>paint()</TT>area is called; this clearing results in the flicker, which canbe solved by overriding the <TT>update()</TT>method. In this case, it calls the <TT>paint()</TT>method directly. This method, in turn, calls the <TT>calculatePaint()</TT>method.<P>The <TT>calculatePaint()</TT> methodis at the heart of the SpreadsheetContainer class. It is not onlyused for painting, but also is called by other routines to calculatewhere a cell is located. The second parameter of <TT>calculatePaint()</TT>indicates whether the method should repaint the region or simplycalculate a value. The first part of the method calculates howmany rows and columns of SpreadsheetCells can be displayed inthe current canvas area. The <TT>size()</TT>method returns the area's size, and the <TT>getFontMetrics()</TT>methods are used to calculate the cell dimensions. Note that thedimensions will change when the font of the spreadsheet is resized,as discussed in the previous chapter's section on fonts.<P>The next step is to loop through all the rows and columns to bedisplayed. The <TT>currentRow</TT>and <TT>currentCol</TT> variablesindicate which SpreadsheetCell is to be painted. These valuesare initially set to <TT>0</TT> sothat the row and column headers are displayed. At the bottom ofthe <TT>for</TT> loops, these areadjusted to the top cell or leftmost column. In the ensuing iterations,the variables are simply incremented to get the new row or column.<P>If the mode of the <TT>calculatePaint()</TT>method is true, then the cells are to be painted. In this case,the code checks to see whether the item falls in the clippingrectangle, retrieved by the <TT>getClipRect()</TT>method. This actually represents the area to be painted. The clippingrectangle could be the whole screen or a single cell. The codethat sets a highlighted cell or marks an area (to be discussed)only forces the area affected to be repainted. If it does fallin the region, the individual SpreadsheetCell is painted at thecurrent coordinates. Recall that the cell has colors and a fontassociated with it. Highlighting or marking a cell is really nothingmore than changing a SpreadsheetCell object's internal color variablesand forcing it to be repainted. See the <A HREF="ch3.htm" >Chapter 3</A>,"Building a Spreadsheet Applet," tutorial for how theSpreadsheetCell class works.<P>Painting affects only those objects that fall in the clippingrectangle. The <TT>intersects()</TT>method is used to see whether two Rectangle objects overlap. Bypainting only the cells that intersect the clipping region, thecode saves some unnecessary processing.<P>If the method is not in painting mode, then the processing isused to check which cell an x-y coordinate belongs to. This isuseful when the user clicks on a cell to be highlighted and whenmarking occurs.<P>By using a central routine for determining the locations of SpreadsheetCells,such activities as painting, scrolling, marking, and highlightingbecome relatively easy. If something goes wrong, it probably couldbe traced back to the <TT>calculatePaint()</TT>method.<H2><A NAME="MarkingCells"><FONT SIZE=5 COLOR=#FF0000>MarkingCells</FONT></A></H2><P>It is useful to mark cells to indicate that they are subject tosome upcoming operation, such as cutting or copying, or, in thiscase, producing a graph. Marking is performed in this applet byclicking on a valid cell, holding the mouse key down, and draggingin a southeasterly direction. When the mouse is released, markingis complete. Figure 5.2 shows what a spreadsheet with some cellsmarked looks like.<P><A HREF="f5-2.gif" ><B>Figure 5.2 :</B><I> A spreadsheet with cells marked.</I></A><P>Marking cells is actually a simple extension of the techniquesthat have been developed through the last three chapters. Thereare three key aspects to marking: tracking mouse movements, keepingtrack of the cells selected, and changing the color of the markedcells.<P>To track mouse movements, the SpreadsheetContainer <TT>handleEvent()</TT>method is modified to manage the mouse actions. The modified codeis detailed in Listing 5.3.<HR><BLOCKQUOTE><B>Listing 5.3. SpreadsheetContainer event handler.<BR></B></BLOCKQUOTE><BLOCKQUOTE><TT>public boolean handleEvent(Event evt){<BR> switch(evt.id) {<BR> // Mouse clicks. See whether you should highlight<BR> // cell on spreadsheet...<BR> case Event.MOUSE_DOWN:<BR> setMouseHighlight(evt.x,evt.y);<BR> // Handle cell marking...<BR> toggleMarking(evt.x,evt.y);<BR> return false;<BR> case Event.MOUSE_DRAG:<BR> // Select cells if marking...<BR> dragMarking(evt.x,evt.y);<BR> return false;<BR> case Event.MOUSE_UP:<BR> // If marking, then you are done!<BR> stopMarking(evt.x,evt.y);<BR> return false;<BR> }<BR> default:<BR> return false;<BR> }<BR>}</TT></BLOCKQUOTE><HR><P>The marking code is too long and involved to list here; referto the CD-ROM for the complete code. However, the general approachand highlights can be presented.<P>When you click the mouse over a valid cell (not a row or columnheader), the cell becomes the current focus and is highlighted.This is done through the <TT>setMouseHighlight()</TT>method, which calls <TT>calculatePaint()</TT>to find the reference of the selected SpreadsheetCell. After thecell is highlighted, the <TT>toggleMarking()</TT>method is called to either begin marking or to reset the markingif there were cells selected at the time of the mouse click. The<TT>startMarking()</TT> method beginstracking the mouse, and <TT>resetMarking()</TT>resets the marking state. SpreadsheetCell objects are set to theirdefault colors through the <TT>setNewColors()</TT>method, which is used to set the normal and highlighted valuesof the spreadsheet. This method is called by the color dialogdiscussed in the previous chapter, and is called here with thecurrent normal and highlighted colors as a simple way of resettingcolors.<P>As the mouse is being dragged (which means the mouse key is stilldown), <TT>MOUSE_DRAG</TT> eventsare issued. If marking is on, the <TT>dragMarking()</TT>method checks to see whether the mouse has left the current cell;if it has, then new cells are marked. The <TT>paintMarked()</TT>method looks at the first cell marked and the last cell markedand figures out the rectangular area to be painted. It then setsthe colors of each of the cells that are marked. The method thenforces a limited repaint of the SpreadsheetContainer so that paintingoccurs quickly. The following code from <TT>paintMarked()</TT>takes the top-left and bottom-right areas that are marked andforces them to be repainted:<BLOCKQUOTE><TT>repaint(startX,startY,endX-startX,endY-startY);</TT></BLOCKQUOTE><P>When the paint message is processed, the marked cells are drawnin their new color. Cells outside the clipping rectangle issuedby the <TT>repaint()</TT> method arenot drawn.<P>When the mouse is released, the <TT>stopMarking()</TT>method is called, and the marking is finished. The marked areascan then be used for further operations.<H2><A NAME="DrawingGraphs"><FONT SIZE=5 COLOR=#FF0000>DrawingGraphs</FONT></A></H2><P>The last feature of the spreadsheet applet to be developed isdrawing graphs from the marked cells. Most of the work is donein the <TT>graphCanvas()</TT> class.However, the graph is displayed inside a dialog object based onthe GraphDialog class.<P>Two spreadsheet applets can produce two types of graphs: a linegraph and a bar chart. The latter is shown in Figure 5.3. Theyare invoked by new menu items off the SpreadsheetFrame object.The menu items result in a call to the SpreadsheetFrame method<TT>launchGraphicsDialog()</TT>, whichgets the currently marked data and then displays the graphicsdialog box (which was instantiated in the frame's constructor).If nothing is marked, an error message in the status bar indicatesthat nothing was drawn.<P><A HREF="f5-3.gif" ><B>Figure 5.3 :</B> <I>Spreadsheet applet bar chart.</I></A><P>The GraphData class is an accessor class used to store the datato be displayed. It contains an array of double values representingthe data to be plotted and an array of Strings used as the columnlabels. These arrays are prepared in the SpreadsheetContainermethod <TT>getGraphData()</TT>, whichis called by the frame's <TT>launchGraphicsDialog()</TT>method just discussed. The <TT>getGraphData()</TT>checks to see whether something is marked; if not, an IllegalArgumentExceptionobject is thrown. Otherwise, it stores the marked data in theGraphData object by moving across the columns. The bottom rowmarked is used to generate the data to be plotted and is placedin the double array. The top row is used to represent the columnString headers. If only one row is marked, the cell headers (A1,A2, and so forth) are used as the column headers. The middle rowsthat are marked are ignored. As a further exercise, you can modifythe graph-<BR>plotting algorithms to support multiple rows of data.<P>Once the graph data is collected, the GraphDialog is displayed.The dialog box is very simple, consisting of only two components:the GraphCanvas object for drawing the graph and a button forshutting down the dialog box. The only interesting code in thedialog box involves resizing the dialog box to take up most ofthe screen.<BLOCKQUOTE><TT>// Get the screen dimensions...<BR>Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();<BR>// Get the font and use to calculate some margins...<BR>FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(getFont());<BR>resize(screen.width,screen.height - (4 * fm.getHeight()) );</TT></BLOCKQUOTE><P>This code uses the AWT Toolkit to get the screen size and thecurrent font. The dialog box then resizes itself to take up thescreen's full width and most of its height.<P>When the dialog box is shown, it first calls the GraphCanvas <TT>prepareNewGraph()</TT>method, which takes the GraphData and prepares it for presentation.When the dialog box appears and a paint event is issued, the GraphCanvasobject draws the graph.<P>Listing 5.4 gives the full code for the GraphCanvas class. Ituses two constants to indicate the two graph modes it supports:line or bar graph. When the canvas is constructed, it createsan array of six Color objects. This array is used to randomlygenerate colors for each bar chart or line so that they are moreeasily distinguished. When the <TT>prepareNewGraph()</TT>method is called, which must happen before painting occurs, themaximum value is calculated and stored in the <TT>maxValue</TT>variable. This is an important figure since it represents therange of values the data is plotted against. The maximum valueis not the highest value in the data area, but actually is thehighest value rounded up to the nearest power of 10. Therefore,if the top value is <TT>66</TT>, themaximum value will be set to <TT>100</TT>.Doing this makes it easy to divide the range of data values intointervals of one-tenth the maximum. The data in Figure 5.3 showsthe plotting of values when the highest data value is <TT>66</TT>and the range is set from <TT>0</TT>to <TT>100</TT>.<HR><BLOCKQUOTE><B>Listing 5.4. The GraphCanvas class.<BR></B></BLOCKQUOTE><BLOCKQUOTE><TT>// Not a public class. Importsare in GraphDialog class<BR>// This paints a graph on a canvas...<BR>class GraphCanvas extends Canvas {<BR> // Types of graphs...<BR> static final int LINE_GRAPH = 0;<BR> static final int BAR_GRAPH = 1;<BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -