该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-01-01
最后修改:2010-01-01
转载:http://today.java.net/article/2006/12/21/implementing-copy-and-paste-java-me-textbox
One of the most convenient and frequently used features of desktop-based text processing applications is copy (or cut) and paste. This is a feature that would be especially useful in Java ME applications because text entry can be quite tedious on a mobile phone. The text-handling classes in ME do not provide direct support for copy and paste, but it is not very difficult to build up such a capability. In this article we look at one approach to implementing this feature.
I assume that the reader is familiar with ME and, in order to try out the examples described here, that she has the J2ME Wireless Toolkit 2.2 installed on her computer.
The copy action has two components:
Similarly, paste needs to do the following:
Additionally, of course, supporting activities like highlighting the selected text and undoing a paste are also needed. These functionalities are required in the case of a Java ME implementation too. Before we look at how we are going to achieve our goal, however, let us examine how we perform the basic tasks on a desktop.
In order to select a part of the text, the mouse is clicked on the left of the first character to be selected and then the mouse is dragged (i.e., moved while the left button is held down) up to the right of the last character for selection. While the dragging is being done, the part of the text being selected gets highlighted. The selection can also be done backwards; that is, from the right of the last character to the left of the first. Once selection is done, we activate the copy command (from a menu, for example, or by typing Ctrl-C). Similarly, for pasting, we position the caret at the point of insertion and choose the paste command.
Now we can look at the mobile approach. A Java ME device cannot be expected to have a mouse. So we have to move the caret by using arrow keys. As in the case of a desktop, we position the caret at one end of the text to be selected. However, no dragging action is possible which means we have to use a command to start the selection process. Then we have to move the caret to the other end of the text we want to select and, again, use a command to signal to the application that the selection process is over. Now the application has to show us what has been selected and this can be done by showing the selected portion on a screen. Once we signal, through an appropriate command, that the selection is right, the selected text can be saved in a record store.
Pasting is even simpler. All we need to do is position the caret where we want the saved text to be pasted and select the Paste command. This will cause the contents of the record store to be retrieved and inserted at the right place.
Implementing the simple activities described above does not raise any theoretical problem. In practice though, things are different. Generally speaking, the textbox from which something has to be copied will have a number of associated commands. When we want to start copying, therefore, we'll have to pop up a menu, and therein lies our problem. To see actually what happens on some devices let's run a simple MIDlet--TryCursor--on WTK.
This MIDlet has just one screen with an Exit command and three others labeled One, Two and Three. The last three commands display an alert that shows the command selected and the caret position as read by the getCaretPosition method of the TextBox class, which is executed in the commandAction method. So let us key in some text and position the caret at any place within the text, as shown in as shown in Figure 1.
If we now select the Menu option, a pop-up menu will appear. We can see this in Figure 2. Note that the caret is still at index 14.
Try this out with the caret at various positions and you'll see that no matter where you position the caret, the getCaretPosition method always returns the index of the last position of the string! So what do we do?
The QwertyDevice on the WTK offers us a clue. When we run TryCursor on QwertyDevice, the command One is shown on the screen while the other two can be called up by clicking the Menu button. If One is selected, then the application behaves the way we expect it to, and the alert shows the correct caret position. But if we click on Menu and select one of the other commands the problem recurs. What does that tell us? When a pop-up menu hides a part (or all) of the screen, then the screen has to be redrawn afterwards. It appears that, during the process of redrawing the screen, the position of the caret (14 in the above example) is not taken into account; the screen is redrawn with the caret at the end of the text and then the position is read. So as long as we can work without having to pop up a menu we're safe.
The implication here is that the commands required for copy and paste actions must always be on the screen. Then we won't need a pop-up menu for copy/paste operations. In general, of course, this will be difficult to achieve, as our screen will require a number of other commands and we cannot always guarantee that the command required next for copy (or paste) operation will be on the screen. While this may be achieved by constantly removing a used command and adding the one that will required next (so that we always have a small number of active commands), in a generalized scenario this will mean a lot of juggling with commands and will add to the burden of the programmer writing the application. Even with all that effort, we may not succeed in eliminating a pop-up when we want to.
We therefore propose to create a dedicated set of screens that will be invoked only for copying and pasting. For example, the copy command will display a screen with the text we have entered and a maximum of two commands so that the commands are available onscreen and a pop-up menu will not be required. A similar thing will happen for pasting. This approach has three benefits:
Our "API" is composed of the following classes:
In addition to the above, we need the Clipboard MIDlet to initialize the clipboard. The Clipboard MIDlet is very simple; its only function is to create a record store named clipboard:
clipboard = RecordStore.openRecordStore("clipboard", true,
Once the record store has been created, we can test our copy and paste application. To do that, we create two MIDlet suites: ClipDemo1 and ClipDemo2. Actually, the two are identical except for the names of the respective MIDlet classes. This difference has been introduced to underline the fact that the clipboard can be used from any MIDlet.
In both the demos, the MIDlets (SourceScreen and SourceScreen2) are just entry points. They instantiate the ClipboardDemo class and display it. The four classes mentioned above are present in both the demos and the ClipboardDemo class in each case extends the ClipboardCompatible class, which is really a customized TextBox. The assumption here is that the text to be copied from or pasted into will be entered into a subclass of TextBox. ClipboardCompatible contains all the items essential for implementing our copy-and-paste function such as the commands and their listeners. It also declares, creates, and uses two instances of the Scratchpad class--Copyboard, to be used for copying, and Pasteboard, to be used for pasting. There are two abstract methods whose implementations are left unspecified to meet any special requirement of the text-handling application. Finally, it has a concrete method, clearClipboard, for deleting the contents of clipboard.
The ClipboardDemo class is the one that does the actual text handling and wants to incorporate the copy-and-paste functionality. We can see that all this class needs to do is take care of its own functional requirements. As for copy-and-paste actions, it only has to implement the two abstract methods. Since ClipboardCompatible implements CommandListener, its subclass (ClipboardDemo) doesn't have to explicitly do that again. In the commandAction method, ClipboardDemo handles only the command it has added and invokes the same method in its superclass for Copy and Paste commands.
The real actions for copy and paste functions take place within the Scratchpad class working in conjunction with the ClipboardCommandProcessor--which handles all commands associated with the scratchpad instances--and the ClipboardHandler that provides the interface to the clipboard. Copyboard and Pasteboard provide the necessary sequencing of commands making sure that there are never more than two commands on the user interface.
Let us now see how the copy and paste functions work. For copying text, we need to select the Copy command on ClipboardDemo (see Figure 4).
This displays the Copyboard, which has the text that was on ClipboardDemo. This can be seen in Figure 5. Note that the command that we'll need next--"Start selection"--is available onscreen.
Next we need to move the caret to the left of the first character of the part to be copied and select the "Start selection" command, as shown in Figure 6.
We can see the result in Figure 7. This command is processed by ClipboardCommandProcessor and we see an alert that tells us where the start position is.
The alert is displayed for two seconds, after which Copyboard is brought to the foreground. At this time, the "Start selection" command is removed from the screen and the Copy command takes its place. This is illustrated in Figure 8.
Then we have to position the caret at the right of the last character to be copied and select the Copy command. Again ClipboardCommandProcessor takes over and shows the string that has been selected. But before that, it checks to see if the selection was done backwards and adjusts the copying action accordingly:
if(endposition<startposition)
//show the selected string
Once we approve the text selection through the OK command, the saveCopiedInfo method of ClipboardHandler class is invoked to save the copied text into clipboard. Of course, we have to the option to cancel the copying process at each step.
Similarly, we initiate pasting by selecting the Paste command on ClipboardDemo. This brings up the Pasteboard with the contents of ClipboardDemo. Again we position the caret where we want the saved text to be pasted and select Paste (Figure 10).
We get an alert to inform us that the pasting operation has been done and then we see the result as in Figure 11. At this point, we can either accept or reject the pasting action.
The one thing that we have not talked about is how the demo MIDlets get to access the common clipboard. The trick lies in knowing how to address this common record store. We have seen earlier how clipboard was created with universal access authorization by the Clipboard MIDlet. While setting up the Clipboard project on WTK, I had entered the name of a fictitious vendor in the required field of project settings. Record store names are internally constructed from the name of the MIDlet suite that create them, the name of the vendor of the MIDlet, and the name given to the record store by the MIDlet. So the full name of clipboard is a combination of "clipboard" (record store name), "V. Endor" (vendor name), and "Clipboard" (with a capital "C"--the name of the creator). Any other MIDlet can access clipboard if all these parameters are specified. This can be seen in the openRecord method of ClipboardHandler:
private void openRecord() throws Exception
There is one feature that is definitely desirable, if not essential: clearing clipboard. In desktop applications, this usually happens automatically when we close the source. Applications on mobile phones, however, run one at a time, which means the source must always be closed before the destination can be opened. So automatic deletion is not a good option here. On the other hand, the user may not like to leave the copied matter on the clipboard if the content is confidential. That is why we display a reminder alert when the Exit command is selected. If the user doesn't want to clear the clipboard, the application is closed. If, on the other hand, she decides to delete whatever had been saved, the clearClipboard method of ClipboardCompatible is called. This call ripples through to ClipboardHandler, which saves an empty string thus deleting whatever was on clipboard. The application is then closed.
With Clipboard, ClipDemo1, and ClipDemo2 installed on a phone, you have to run Clipboard first to create clipboard. Thereafter, you can exchange text between the two demo applications by copying from one and pasting into the other.
A close look at Scratchpad and ClipboardCommandProcessor will reveal that as a command gets removed and another is added to the instances of Scratchpad, there is always another screen that is sandwiched between the two actions. For example, when we select the starting position on Copyboard, the "Start selection" command is removed, the Copy command is added, and an alert is shown for two seconds, after which the Copyboard is displayed once more. While these intervening displays keep the user informed of what is happening, they do serve another purpose as well.
When a command is added to a Displayable that is "actually visible on the display, and this call affects the set of visible commands, the implementation should update the display as soon as it is feasible to do so." The quote is from ME documentation. In some devices the visual updating does not occur, while in some of them the added command does not become functional until the screen is moved to background and then made visible again. Thus the alerts and other screens that keep popping up during copying and pasting ensure smooth functioning of newly added commands by temporarily hiding Copyboard and Pasteboard.
We have seen how we can incorporate copy and paste functions into an ME TextBox. Along the way, we have also seen that ME implementations can vary subtly but significantly from one device to another and considerable effort is required to write, test, and debug applications that work on a wide range of devices. The application described here has been tested on the WTK22 devices (with the modification mentioned below), and also on a Nokia 6101 and on a Samsung 309. On WTK, the universal access mechanism for record stores does not seem to work. So if you want to test the basic performance on WTK, you'll need to comment out the first line of the openRecord method of ClipboardHandler shown above and uncomment the second. However, in that case, each MIDlet will have its own clipboard and copying from one to the other will not be possible. On the Nokia and Samsung phones the application works just as expected.
Along with Copy and Paste, there is another function that is used widely--Cut. This third function is actually a combination of Copy and Delete. I have not shown its implementation here because I believe it'll be an enjoyable experience for you to enhance this application by incorporating this missing function.
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 2685 次