Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 74 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
74
Dung lượng
265,91 KB
Nội dung
351 Chapter 14 ✦ Drag and Drop 5 #include <qdragobject.h> 6 #include <qclipboard.h> 7 #include <qpushbutton.h> 8 #include “cutpaste.h” 9 10 int main(int argc,char **argv) 11 { 12 KApplication app(argc,argv,”cutpaste”); 13 CutPaste *cutpaste = new CutPaste(); 14 cutpaste->show(); 15 app.setMainWidget(cutpaste); 16 return(app.exec()); 17 } 18 19 CutPaste::CutPaste(QWidget *parent,const char *name) 20 : QWidget(parent,name) 21 { 22 QPushButton *button; 23 QHBoxLayout *hlayout = new QHBoxLayout(this,5); 24 QVBoxLayout *vlayout = new QVBoxLayout(); 25 26 pixmap = NULL; 27 28 button = new QPushButton(“Load”,this); 29 connect(button,SIGNAL(clicked()), 30 this,SLOT(loadButton())); 31 vlayout->addWidget(button); 32 33 button = new QPushButton(“Copy”,this); 34 connect(button,SIGNAL(clicked()), 35 this,SLOT(copyButton())); 36 vlayout->addWidget(button); 37 38 button = new QPushButton(“Cut”,this); 39 connect(button,SIGNAL(clicked()), 40 this,SLOT(cutButton())); 41 vlayout->addWidget(button); 42 43 button = new QPushButton(“Paste”,this); 44 connect(button,SIGNAL(clicked()), 45 this,SLOT(pasteButton())); 46 vlayout->addWidget(button); 47 48 widget = new QWidget(this); 49 widget->setFixedSize(257,303); 50 widget->setBackgroundColor(QColor(“white”)); 51 52 hlayout->addWidget(widget); 53 hlayout->addLayout(vlayout); 54 55 resize(10,10); 56 hlayout->activate(); 57 } 4682-1 ch14.f.qc 11/20/00 15:42 Page 351 352 Part II ✦ Step by Step 58 void CutPaste::loadButton() 59 { 60 if(pixmap != NULL) 61 delete pixmap; 62 pixmap = new QPixmap(“logo.xpm”); 63 widget->setBackgroundPixmap(*pixmap); 64 } 65 void CutPaste::copyButton() 66 { 67 if(pixmap != NULL) { 68 QImage image = pixmap->convertToImage(); 69 QDragObject *drag = new QImageDrag(image,this); 70 QClipboard *clipboard = QApplication::clipboard(); 71 clipboard->setData(drag); 72 } 73 } 74 void CutPaste::cutButton() 75 { 76 if(pixmap != NULL) { 77 copyButton(); 78 widget->setBackgroundColor(QColor(“white”)); 79 delete pixmap; 80 pixmap = NULL; 81 } 82 } 83 void CutPaste::pasteButton() 84 { 85 QClipboard *clipboard = QApplication::clipboard(); 86 QMimeSource *mime = clipboard->data(); 87 QImage image; 88 if(QImageDrag::decode(mime,image)) { 89 QPixmap *newPixmap = new QPixmap(); 90 if(newPixmap->convertFromImage(image)) { 91 if(pixmap != NULL) 92 delete pixmap; 93 pixmap = newPixmap; 94 widget->setBackgroundPixmap(*pixmap); 95 } 96 } 97 } The constructor, beginning on line 19, initializes the data and creates the display by inserting a set of buttons into a vertical box, and then inserts the vertical box and a widget into a horizontal box. No initial pixmap is being displayed, so it is initialized to NULL on line 26. The graphic display widget is created on line 48, and it is initial- ized with a solid white background. The slot method loadButton() on line 58 loads a new pixmap from a file. Lines 60 and 61 delete any previously existing pixmap, and the call to setBackground Pixmap() on line 63 displays the newly loaded pixmap. 4682-1 ch14.f.qc 11/20/00 15:42 Page 352 353 Chapter 14 ✦ Drag and Drop The slot method copyButton() on line 65 tests whether a pixmap exists and, if so, copies it to the clipboard. The call to convertToImage() on line 68 converts the pixmap to a QImage, because that is the form of the graphic required by QImageDrag. The address of the QClipboard object is returned from the call to the clipboard() method on line 70, and the data is stored in the clipboard with the call to setData() on line 71. The slot method cutButton() on line 74 tests whether a pixmap exists and, if so, copies it to the clipboard and deletes it locally. The call to copyButton() copies the pixmap to the clipboard. The call to setBackgroundColor() clears the pixmap from the window, and lines 79 and 80 remove the pixmap from memory. The slot method pasteButton() on line 83 reads a pixmap from the clipboard to this application. The call to the static method clipboard() on line 85 retrieves the address of the system clipboard. The clipboard holds data as a QMineSource object, which is retrieved by the call to data() on line 86. Several different types of data can be stored on the clipboard, so the Boolean return value from the call to decode() on line 88 must be checked to ensure that the data was successfully converted to a QImage object. If the conversion succeeded, the call to convertFromImage() on line 90 creates a pixmap from the data, and lines 91 through 94 replace the existing pixmap with the new one, and store it in the widget as the new display background. Summary Dragging data from one location to another, or cutting data from one location and pasting it into another, requires that both the sender and the receiver agree on the type of the data and how it is packaged. From the application’s point of view, trans- mitting and receiving data is not much more than simply making a function call. This chapter described the fundamentals of dragging and dropping data, including: ✦ To drag data to another location, it first must be encapsulated in a QDrag Object . For a window to receive a dropped object, it must be prepared to decode the data in the QDragObject. ✦ A call to setAcceptDrops() must be made before a widget will accept dropped data. ✦ The cut and paste operations are fundamentally the same as drag and drop, except that the system QClipboard object is used as an intermediary to store the data. The next chapter discusses applets — the small icon-like windows that appear on the panel at the bottom (or some other edge) of the main window in the KDE envi- ronment.The chapter also discusses some other methods of passing data from one application to another. ✦✦✦ 4682-1 ch14.f.qc 11/20/00 15:42 Page 353 4682-1 ch14.f.qc 11/20/00 15:42 Page 354 Interprocess Communications and Applets T here are two basic ways that data are passed from one program to another. At startup, arguments can be sup- plied on the command line, and during execution, blocks of data can be generated by one application and passed to another process that is expecting it. KDE has made some spe- cial provisions for both of these communications methods. There is a command-line class that analyzes and stores infor- mation from the command line. More than that, it provides access to the KDE option flags that, to some extent, standard- ize the settings available to the applications. That is, by using this object, different applications can be programmed to respond in a standard way to a standard set of flags. The interprocess communications model requires a server run- ning in the background to handle messages. This server is sort of like a post office. Each application gets a P.O. box that is identified by a name, and other applications can store messages in it. An applet is a special application that displays its window as an icon in the KDE panel (sometimes call the KDE kicker) that is present at one edge of the main KDE window. An applet has the disadvantage of having a very small window as its top- level window, but it has the advantage of always being visible to the user. This chapter explains the various ways that your program can take advantage of these data-exchange methods and applets. 15 15 CHAPTER ✦✦✦✦ In This Chapter Passing arguments on the command line Sending blocks of data from one running application to another Providing user access through applets on the panel Guaranteeing that only one instance of a process is in execution at any one time ✦✦✦✦ 4682-1 ch15.f.qc 11/13/00 14:13 Page 355 356 Part II ✦ Step by Step The DCOP Communications Model The DCOP (Desktop Communications Protocol) software was developed to provide a very simple method of establishing interprocess communications among a group of processes. All communications pass through a daemon process called dcop server . A process wishing to send or receive messages first registers its name with dcopserver, and other processes can then address messages to it by sending them to that name in care of the dcopserver. DCOP is actually a simple form of an RPC (Remote Procedure Call) mechanism. A message is sent in the form of a function call that may or may not require arguments, and may or may not return a value. The following example consists of three programs. The program named wilbur registers itself with dcopserver and waits for a message to arrive. The program tellwilbur sends a message to wilbur and does not wait for a response, while askwilbur sends a message and waits for the response. Wilbur Header 1 /* wilbur.h */ 2 #ifndef WILBUR_H 3 #define WILBUR_H 4 5 #include <qmultilineedit.h> 6 #include <dcopobject.h> 7 8 class WilReceiver: public QMultiLineEdit, public DCOPObject 9 { 10 public: 11 WilReceiver(const char *name=0); 12 bool process(const QCString &function, 13 const QByteArray &data,QCString &replyType, 14 QByteArray &replyData); 15 double cubeRoot(double value); 16 private: 17 }; 18 19 #endif The WilReceiver is a DCOPObject, so it is capable of receiving messages, execut- ing a local procedure, and returning the result to the originator of the message. WilReceiver is also a widget because it inherits from the QMultiLineEdit widget. The method process(), declared on line 12, is required because it is a pure virtual method in the DCOPObject class. It is the method that is called whenever a message is received from another process. The method cubeRoot() declared on line 15 is the one that can be called from other processes. 4682-1 ch15.f.qc 11/13/00 14:13 Page 356 357 Chapter 15 ✦ Interprocess Communications and Applets Wilbur 1 /* wilbur.cpp */ 2 #include <kapp.h> 3 #include <qcstring.h> 4 #include <qmultilineedit.h> 5 #include <dcopclient.h> 6 #include <math.h> 7 #include “wilbur.h” 8 9 int main(int argc,char **argv) 10 { 11 QString str; 12 KApplication app(argc,argv,”wilbur”); 13 14 DCOPClient *client = app.dcopClient(); 15 QCString dcopID = client->registerAs(app.name(),FALSE); 16 17 WilReceiver *wilbur = new WilReceiver(“wilreceiver”); 18 app.setMainWidget(wilbur); 19 20 str.sprintf(“wilbur registered as \”%s\””, 21 dcopID.data()); 22 wilbur->insertLine(str); 23 24 int returnValue = app.exec(); 25 client->detach(); 26 return(returnValue); 27 } 28 WilReceiver::WilReceiver(const char *name) 29 : DCOPObject(name) 30 { 31 setReadOnly(TRUE); 32 show(); 33 } 34 bool WilReceiver::process(const QCString &function, 35 const QByteArray &data, 36 QCString &replyType, 37 QByteArray &replyData) 38 { 39 if(function == “cubeRoot(double)”) { 40 double inValue; 41 double outValue; 42 QDataStream inStream(data,IO_ReadOnly); 43 inStream >> inValue; 44 outValue = cubeRoot(inValue); 45 QDataStream outStream(replyData,IO_WriteOnly); 46 outStream << outValue; 47 replyType = “double”; 48 return(TRUE); 49 } else { 4682-1 ch15.f.qc 11/13/00 14:13 Page 357 358 Part II ✦ Step by Step 50 QString string; 51 string.sprintf(“call to unknown function %s”, 52 function.data()); 53 insertLine(string); 54 return(FALSE); 55 } 56 } 57 double WilReceiver::cubeRoot(double value) 58 { 59 QString string; 60 double root = cbrt(value); 61 string.sprintf(“Cube root of %g is %g”,value,root); 62 insertLine(string); 63 return(root); 64 } This program uses a WilReceiver object as its top-level widget. This gives it the ability to both display text and respond to incoming messages. Every process that is to communicate through the dcopserver must register itself as a client. The call to dcopClient() on line 14 creates a local DCOPClient object and returns its address. The call to registerAs() on line 15 registers the name of this client with the dcopserver daemon. The name of this application — specified on line 12 — is “wilbur”, so from now on, any message sent to “wilbur” will come to this application. The actual registration name is the return value stored as a string in dcopID on line 15. No two processes can be registered by the same name, so the dcopserver detects collisions and modifies the registration name The first collision will result in the reg- istration name being “wilbur-2,” the next will be “wilbur-3,” and so on. Alternatively, you can choose to generate unique registration names by using TRUE as the second argument to registerAs(), causing the process ID number to be appended as part of the name. For example, if the process ID of an instance wilbur is 34212, the regis- tration name would be “wilbur-34212.” This is guaranteed to always produce a unique registration name. The top-level widget is established on lines 17 and 18. The name assigned to the widget is “wilreceiver.” It is perfectly valid for a single process to contain more than one DCOPObject, and each one of them can be used to receive messages, so it is necessary to supply a name for each one. Lines 20 through 22 display the registered name of this DCOPClient. The main loop of the GUI application is executed by the call to exec() on line 24. The call to detach() on line 25 is made to remove the registration from dcopserver. This is not strictly necessary because the registration is removed automatically whenever a process ceases execution. 4682-1 ch15.f.qc 11/13/00 14:13 Page 358 359 Chapter 15 ✦ Interprocess Communications and Applets The constructor of WilReceiver on line 28 sets the QMultiLineEdit window to read-only, which means that the text displayed there cannot be edited. The process() method on line 34 is called whenever a message arrives from the dcopserver. There are four arguments to the method: const QCString function The name and argument types of the procedure to be called const QByteArray &data The arguments to be passed to the called procedure QCString &replyType The data type of the value returned from the procedure QByteArray &replyData The returned value The if statement on line 39 verifies that the function and data type match the one that is available. A number of local procedures can be available —it is only necessary to add a test for each one to determine which is to be called. The terminology tends to get a bit confusing with remote procedure calls. The remote process requests a call to a procedure named cubeRoot(double), which could be either a function or a method. Or it could be simply an inline execution, or even implemented in an entirely different language. As long as the interface is con- sistent, and the results are achieved, the details of the actual process don’t matter. The argument (or arguments) to be passed to the procedure arrive packed into a QByteArray, so it is necessary to use the QDataStream created on line 42 to extract the actual values. In this example, there is only one argument, and it is extracted into inValue on line 43. The method cubeRoot() is called on line 44, with the results stored in outValue. The return value is packed into replyData on line 46 using the output stream created on line 45. The data type of the return value is stored in replyType on line 47. The return value of TRUE is used to indicate success. If the code required to respond to a message seems a bit clumsy, that is because it has been designed for automatic generation. This entire process should all be simplified in the near future because there is a project underway to have the con- tents of the process() method automatically generated by a compiler, much like the MOC compiler generates the code for signals and slots. The cubeRoot() method on line 57 accepts a double value as an argument and returns its cube root. It also displays the incoming number, and its root, as a line of text in the window. This method is called remotely, but it is a normal method and could be called locally as well. Note Note 4682-1 ch15.f.qc 11/13/00 14:13 Page 359 360 Part II ✦ Step by Step TellWilbur 1 /* tellwilbur.cpp */ 2 #include <kapp.h> 3 #include <qcstring.h> 4 #include <dcopclient.h> 5 6 int main(int argc,char **argv) 7 { 8 KApplication app(argc,argv,”tellwilbur”); 9 10 DCOPClient *client = app.dcopClient(); 11 QCString dcopID = client->registerAs(app.name()); 12 13 QByteArray params; 14 QDataStream stream(params,IO_WriteOnly); 15 stream << (double)999.0; 16 if(!client->send(“wilbur”,”wilreceiver”, 17 “cubeRoot(double)”,params)) { 18 qDebug(“Well, that didn’t work!”); 19 } 20 21 client->detach(); 22 return(0); 23 } This program sends a message to wilbur, but does not wait for the response. To be able to communicate using DCOP, it is necessary to register with dcopserver. This means that it is necessary to create a KApplication object, use it to retrieve the address of the local DCOPClient, and then call registerAs() with the name of this application. Because the arguments to the remote procedure are sent packed into a QByteArray, it is necessary to create a QDataStream object on line 14 and store a double argu- ment value in it on line 15. The call to send() on line 16 sends the message, but does not wait for an answer. The first argument is “wilbur”, which is the registered name of the application to receive the message. The second argument is “wilreceiver”, which is the name of a DCOPObject inside the application. The procedure to be called is named “cubeRoot(double)”. The final argument, params, contains the argument values to be passed to the procedure. As described earlier, the registration name may have a number appended to it, such as “wilbur-29003.” To discover what the actual name is, your application may need to call registeredApplications() of the DCOPClient class. This method returns a QCStringList object containing all of the registered names, and your application can search it to find the name (or names) you need. Note 4682-1 ch15.f.qc 11/13/00 14:13 Page 360 [...]... hText “HORIZ” int main(int argc,char **argv) { KCmdLineArgs::init(argc,argv, “mailapplet”, 367 468 2-1 ch15.f.qc 368 11/13/00 14:13 Page 368 Part II ✦ Step by Step 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 “Mail Applet Example”, “Version 0.0”); KApplication app; MailApplet *applet = new MailApplet(0,”mailapplet”);... endl; 468 2-1 ch 16. f.qc 11/13/00 14:13 Page 375 Chapter 16 ✦ Some General Utility Classes 35 36 37 38 39 } cout . QPixmap(“logo.xpm”); 63 widget->setBackgroundPixmap(*pixmap); 64 } 65 void CutPaste::copyButton() 66 { 67 if(pixmap != NULL) { 68 QImage image = pixmap->convertToImage(); 69 QDragObject *drag. 2; 63 int x = (width() - fm.width(vText)) / 2; 64 p.drawText(x,y,vText); 65 } else { 66 int y = height() / 2; 67 y += (fm.ascent() - fm.descent()) / 2; 468 2-1 ch15.f.qc 11/13/00 14:13 Page 368 369 Chapter. return(FALSE); 55 } 56 } 57 double WilReceiver::cubeRoot(double value) 58 { 59 QString string; 60 double root = cbrt(value); 61 string.sprintf(“Cube root of %g is %g”,value,root); 62 insertLine(string); 63 return(root); 64