⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch11.htm

📁 JAVA Developing Professional JavaApplets
💻 HTM
📖 第 1 页 / 共 5 页
字号:
be lost. Given this, it's possible that the clients might nothave received some earlier updates. However, you could increasethe rebroadcast time to a higher value, such as 30 minutes, anhour, or more. The right figure for this will depend on a varietyof factors, including the size and sensitivity of your data.<H4>Database</H4><P>The database used in this chapter is generally the same dBASEIV table described in the previous chapter. An UPDATED field wasadded so that changes can be timestamped, thus allowing the serverto download only the state information that has changed.<P>A couple of other things should be mentioned about the database.First of all, a blank version of the database can be found inthe file NEWELECT.DBF located on the CD-ROM. It has all the states,candidates, and electoral votes. Data that changes over time,such as the popular vote, is initialized to zero. Since the runtimeserver uses ELECT.DBF, you can simply replace NEWELECT.DBF togenerate a clean database after the ELECT.DBF data is modifiedfor testing.<P>Another peculiarity of the table is that the ELECTORAL field initiallyhas negative numbers. The absolute value of the negative numberssymbolizes the number of electoral votes a state carries. If thenumber is positive, it indicates that the corresponding candidatehas won the state. A normalized database would have been a bettersolution here (separate tables for state information and declaredwinners), but it didn't seem appropriate to focus on this aspectof the project.<P>Yet another curiosity is the UPDATED field. Since the native method'sODBC driver implements only character data types, all the fieldsin the database need to be of a character type. Unfortunately,this makes timestamping a little tricky, so timestamps in thisproject have the following format: <TT>000XXX</TT>.That is, all timestamps need to be prefixed by zeroes to producea timestamp six characters long. So the first stamp would be 000001,the hundredth would be 000100, and so on. If your server updatesaren't working properly, be careful how you enter the timestampsin the database.<P>After sending data down the first time, the server retrieves partialupdates based on a timestamp. Although internally it is a number,it's in the format just described in the database. Any databaserows with a timestamp higher than the last timestamp are madepart of any new partial update broadcasts. Once the database timestampis surpassed by the external timestamp, the corresponding rowis no longer sent down as part of a partial update. The serverwill always print out the current timestamp it is working on.Suppose it is 000003, and you want to update the data. You cando this by changing <I>both</I> entries of the candidates in astate and setting the timestamp to 000004. The data will thenbe sent down in the next partial update broadcast and should showup in your applet.<H3><A NAME="AppletClient">Applet Client</A></H3><P>The Election applet continually gives you updated election resultsas they arrive to the server. The applet consists of basicallytwo parts: back-end threads to manage the arrival of datagramswith the latest election results from the server and a front-endthat displays the results in either a graphical or text-basedformat. The network-processing classes were mostly developed inthe previous two chapters; the display classes are new for thischapter.<H4>Class Organization</H4><P>Table 11.2 lists the classes used in this chapter's Election applet.Since many of these classes were created in the previous section,the new classes are specified by having their names in boldfacetype; the classes that were modified have their names italicized.<BR><P><CENTER><B>Table 11.2. The Election applet classes and interfaces.</B></CENTER><P><CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%><TR VALIGN=TOP><TD WIDTH=186><I>Class/Interface</I></TD><TD WIDTH=404><I>Description</I></TD></TR><TR VALIGN=TOP><TD WIDTH=186><B>Candidate</B></TD><TD WIDTH=404>An accessor class that keeps vote totals for a specific candidate.</TD></TR><TR VALIGN=TOP><TD WIDTH=186>ClientPacketAssembler</TD><TD WIDTH=404>Tracks and assembles blocks of data packets.</TD></TR><TR VALIGN=TOP><TD WIDTH=186>ClientRegistration</TD><TD WIDTH=404>For registering as a new client.</TD></TR><TR VALIGN=TOP><TD WIDTH=186>ClientUnregistration</TD><TD WIDTH=404>For removing client registration with server.</TD></TR><TR VALIGN=TOP><TD WIDTH=186>DGTPClient</TD><TD WIDTH=404>To receive dynamic data updates from server.</TD></TR><TR VALIGN=TOP><TD WIDTH=186>Election</TD><TD WIDTH=404>The class for the Election applet that implements the LiveDataNotify interface to manage dynamic data from the server and creates components for visual display.</TD></TR><TR VALIGN=TOP><TD WIDTH=186><B>ElectionTable</B></TD><TD WIDTH=404>Keeps local copy of election results from the server. Uses synchronization so that incoming DGTP data does not collide with reads from visual components.</TD></TR><TR VALIGN=TOP><TD WIDTH=186><B>ElectionUpdater</B></TD><TD WIDTH=404>Periodically causes update of Election's visual components.</TD></TR><TR VALIGN=TOP><TD WIDTH=186>LiveDataNotify</TD><TD WIDTH=404>Interface that defines methods for handling dynamic delivery of data from the server.</TD></TR><TR VALIGN=TOP><TD WIDTH=186>PartialPacket</TD><TD WIDTH=404>Private class used by ClientPacketAssembler for assembling packets.</TD></TR><TR VALIGN=TOP><TD WIDTH=186><B>StateBreakdownCanvas</B></TD><TD WIDTH=404>ElectionTable observer that displays results of individual states in text or graphics format.</TD></TR><TR VALIGN=TOP><TD WIDTH=186><B>StateEntry</B></TD><TD WIDTH=404>Simple accessor class that keeps all election data related to a specific state.</TD></TR><TR VALIGN=TOP><TD WIDTH=186><B>SummaryCanvas</B></TD><TD WIDTH=404>ElectionTable observer that displays national election totals.</TD></TR></TABLE></CENTER><P><H4>How It Works</H4><P>Figure 11.5 illustrates the workflow of the Election applet. TheDGTPClient object receives datagrams from the server indicatingthe latest election results. This data may be a partial updateof just the states that have changed, or it may be a broadcastof the full election results. In either case, the Election objectreceives the new data since it implements the LiveDataNotify interface.<P><A HREF="f11-5.gif" ><B>Figure 11.5 : </B><I>Data flow of the Election applet.</I></A><P>The Election object parses the data and passes it to the ElectionTableobject. The ElectionTable class has only one instance since ithas a private constructor; objects that use the data must geta reference to the table object from a public ElectionTable method.The Election object is the only object that updates the tableand does so when it's notified by the DGTPClient with new data.When you get the first full batch of election data, with all thestates identified, the ElectionTable object creates a privatetable of the individual state and summary totals. This table isupdated by any calls that follow.<P>ElectionTable is an instance of the Observable class. It notifiesits two Observers, the StateBreakdownCanvas and SummaryCanvas,whenever its data change. These two Canvas objects implement theObserver interface and are mainly responsible for displaying theelection information. The ElectionUpdater thread runs in the background,periodically forcing refreshes of the Canvas objects.<P>Since the underlying classes that implement the network interfaceshaven't changed since the previous chapter, the discussion thatfollows will focus on the classes involved in the visual interface.<H4>The Election Class</H4><P>The Election class runs the Election applet. It implements theLiveDataNotify interface so that it can be notified whenever theDGTPClient gets new election data packets. The Election classalso creates the two components that display the election results-theStateBreakdownCanvas and SummaryCanvas classes. Listing 11.2 showsthe Election class's code.<P>Several important things happen at initialization. In the <TT>init()</TT>method, the first step is to get an applet parameter that specifiesthe port the server is listening on, then initializes the display.It creates a panel at the top of the screen so that you can togglebetween a text-based or graphical display. The Election classthen creates the components that display the election resultsand starts a simple thread, ElectionThread, that periodicallycauses the applet to repaint. This is needed because paint messagescould be lost if election returns come in rapid-fire fashion.The last step in the <TT>init()</TT>method is to resize the applet so that it's large enough to showall of the state returns.<P>The other major thing that happens at initialization occurs whenthe <TT>start()</TT> method is firstcalled. The Election class creates an instance of the DGTPClientclass, specifying itself as the LiveDataNotify parameter-thisensures that the Election applet is notified of all incoming datagrams.<P>The DGTPClient calls the Election class's <TT>recvNewData()</TT>method when data has arrived. The Election class then parses thisdata into a large two-dimensional String array, which is thenpassed to the ElectionTable class that provides the data's finalstorage location.<HR><BLOCKQUOTE><B>Listing 11.2. The Election class.<BR></B></BLOCKQUOTE><BLOCKQUOTE><TT>// This class starts the Election applet.It implements<BR>// the LiveDataNotify interface that sends the latest<BR>// results to it.&nbsp;&nbsp;It creates objects to display the<BR>// returns as they arrive.<BR>public class Election extends Applet<BR>&nbsp;&nbsp;&nbsp;&nbsp;implements LiveDataNotify<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;private static final int SPACING = 70;<BR>&nbsp;&nbsp;&nbsp;&nbsp;private boolean init = false;<BR>&nbsp;&nbsp;&nbsp;&nbsp;DGTPClient ct = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;int destPort;<BR>&nbsp;&nbsp;&nbsp;&nbsp;String destHost = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;String numUsers = &quot;Unknown at thistime&quot;;<BR>&nbsp;&nbsp;&nbsp;&nbsp;String users = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;String results[][];<BR>&nbsp;&nbsp;&nbsp;&nbsp;int nRows = 0, nCols = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;// Place canvas drawing objects...<BR>&nbsp;&nbsp;&nbsp;&nbsp;SummaryCanvas sc;<BR>&nbsp;&nbsp;&nbsp;&nbsp;StateBreakdownCanvas states;<BR>&nbsp;&nbsp;&nbsp;&nbsp;Checkbox graphView,textView;<BR>&nbsp;&nbsp;&nbsp;&nbsp;Panel p;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public void init()<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ( init == false)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Initialize network connections...<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;init= true;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringstrPort = getParameter(&quot;PORT&quot;);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( strPort == null )<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;ERROR:PORT parameter is missing&quot;);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strPort= &quot;4545&quot;;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;destPort= Integer.valueOf(strPort).intValue();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;destHost= getDocumentBase().getHost();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Initialize AWT components...<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Do basic setup...<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setLayout(newBorderLayout());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Add panel to set views...<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p= new Panel();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CheckboxGroupcg = new CheckboxGroup();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;graphView= new Checkbox(&quot;Graphical View&quot;,cg,false);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;textView= new Checkbox(&quot;Text View&quot;,cg,true);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.add(graphView);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.add(textView);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add(&quot;North&quot;,p);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Add summary information at top of applet<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sc= new SummaryCanvas(this);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Show state breakdowns...<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;states= new StateBreakdownCanvas(this);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Create update thread...<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Threadt = new ElectionUpdater(this);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Resize to fit all the states...<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Dimensiond = size();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FontMetricsfm = Toolkit.getDefaultToolkit().getFontMetrics(getFont());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;intheight = sc.getHeight() + states.getHeight()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+(2 * fm.getHeight());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resize(d.width,height);<BR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -