Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 45 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
45
Dung lượng
415,28 KB
Nội dung
10 TheGraphics Library“Arthur” In XOR mode (QPainter::CompositionMode_Xor),the Painter links thealpha value of thesource(subtracted from theinverse of thedestination)tothe destination, thealpha value of which it subtractsfromthe inverse of thesource. Theresultof this operation is shownonthe left side of Figure 10.17. The clear mode displayed on theright (QPainter::CompositionMode_Clear) is used, for example, to stencilout masksfromfigures. Foreach pixel in thesourcein which thealpha channelhas avalue otherthan0,the Painter in clearmode sets thealpha value of thedestination pixel to 0,thus making thecorresponding pixel transparent. Figure 10.17: TheXOR operator links source and destinationwithan exclusiveOR; Clear enables complete figures to be stencilledout of images. Usingthe DestinationOutOperatoronaPainterPath We willadjustthe examplefromSection 10.10.2 (page 309) so that acompositing operatorcoversthe area in adarkcolor.The result should matchthatshownin Figure 10.18. ThePainter pathinpaintEvent()remains thesame; weagaininstantiate thePainter andactivateanti-aliasing.Thenwedrawthebackground.For thepaintbrush, weselectblack withasemitransparentalpha channel. With theDestinationOut operator, thePainter paththus acquires itsblack andsemitransparentcoloring: // composition/paintwidget.cpp #include <QtGui> #include "paintwidget.h" PaintWidget::PaintWidget(QWidget * parent) :QWidget(parent) { } 314 10.10 ComplexGraphics voidPaintWidget::paintEvent(QPaintEvent * / * ev * /) { QPainterPathpath; path.cubicTo(rect().topLeft(),rect().bottomLeft(), rect().bottomRight()); path.cubicTo(rect().topRight(),rect().bottomRight(), rect().bottomLeft()); QPainterp(this); p.setRenderHint(QPainter::Antialiasing, true); p.drawTiledPixmap(rect(),QPixmap("qt.png")); p.setBrush(QColor::fromRgba(qRgba(0,0,0,128))); p.setCompositionMode(QPainter::CompositionMode_DestinationOut); p.drawPath(path); } Thefact that thewidgetitselfisopaquemeans that most of thecompositingop- eratorsinthisexam pleare notveryexciting,astheyonlyrevealtheir full effectsif asourceand destinationhaveanon-opaquealpha channel. Figure 10.18: DestinationOut darkens thePainter path. Nevertheless, compositingisaninteresting alternativetoclipping,which cannot offercapabilitiessuchasalpha transparencyor anti-aliasing.Thisadvantage is offset at times, however,particularlyunder X11, byprogramsthatrun considerably more slowly. 315 11 Chapter Input/OutputInterfaces Youcan hardlyimagine anyapplicat iontodaythat does notaccess files,networks, or externalprocesses. Consequently,Qt4provides interfaces for communicating withthe environment that areindependent of theoperating system. Althougheach of theoperating systemssupported byQt provides interfaces to deal withthe various kindsofI/O,there is sadlyno uniformstandardfor managing this functionality.These circumstances often force programmers to completelyredesign thecode if theywantto, for example, send adatastreamacrossanetworkinstead of savingittoafile. Qt 4gets around this problembyprovidingabase classcalled QIODevice, which provides aplatformfor allI/O interfaces. 11.1The QIODevice ClassHierarchy QIODeviceimplementsoperationssuchasreading andwriting on onedevice. Qt also considersanetworkconnectiontobeadevice. Of course,there aresome 317 11 Input/OutputInterfaces restrictions,because stream-oriented connections (alsocalled sequentialconnec- tions ), such as thoseimplemented via TCP, arenot available for limitless access. Figure 11.1: Thebaseclass QIODevice andits specializations QUdpSocket QTcpSocket QAbstractSocket QBuffer QTemporaryFile QFile QProcess QIODevice QIODeviceisanabstract class, so thedeveloperonlyever instantiates itssubclasses. It represents thelowestcommonden ominator of alltypesofinput andoutput operations. Fi gure 11.1provides an overviewof theinput/output classesthatare basedonQIODevice. 11.1.1 DerivedClasses QAbstract Socketcannotbeuseddirectlyas thebaseclass for socket-basedcom- munication,incontrasttoits subclassesQUdpSocketand QTcpSocket. QUdpSocket enablescommunicationsvia the UserDatagram Protocol (UDP). This works with- outaconnectionand provides no guarantee that thedatasentwillarriveintact or in thecorrect order. Due to the lack of correctivemeasures, however,itisconsid- erablyfaster than the Transmission Control Protocol (TCP),via which theQTcp- Socketclass se ndsdata. In contrasttoUDP,TCP connections areconnectionoriented andensureareliable transfer of data. Manyof theprotocols populartoday,suchasHTTP,which is used commonlyin theWorld Wide Webfor transmitting web pagesand downloads,are basedonTCP. TheQBuffe rclass allowsyou to write to QByteArrayinstancesasiftheywereQIO- Device-baseddevices.Wewerealreadyintroducedtothisprocedure in Section8.8 on page 243, andwewilltake afurther look at it on page 322 in connectionwith QDataStream. Probablythemostfrequentlyused subclass of QIODeviceisthe QFile subclass.We learnedabout it sabilityto read andwrite files on thelocal filesystem for thefirst time on page 113. In casethere is notenoughmemoryto storetemporarydatavia QBufferina QByteArray,QTemporaryFileisavailable.IncontrasttoQFile,thisclass generates afilename independentlyandensures that this name is unique, so that it will not 318 11.1 TheQIODevice ClassHierarchy overwrite ot herfilesbymistake.The temporaryfileisstoredbyQTemporaryFile beneaththe temporarydirectoryused byQt. This directory’s location is revealed bythestaticmethod QDir::tempPath(). As soon as theQTemporaryFileobject is deleted,the temporaryfileassociatedwithitisalsoautomaticallydeleted. QProcess is also ba sedonQIODevice. This classenablesprocessestobestarted withadditional argumentsand permitscommunication withthemvia theQIODe- vicemethods.Inaddition theclass can select ivelymanipulate theenvironment variablesofthe process. 11.1.2Opening I/ODevices EveryQIODevicemustfirstbeopenedbeforeitcan be used.The open() method is available for this purpose, an dits argumentsdescribe in detail howthedevice in question is to be accessed, for example, whether theprogram (and thus the enduseraswell) should haveonlywrite or onlyread permissions. This method is thereforesimilartothe POSIXfunction open(). Table11.1: Parameters of the QIODevices::open() method Flag Value Description QIODevice::NotOpen 0x0000 Deviceisnot open(notauseful detail for open()) QIODevice::ReadOnly0x0001Deviceisopenedfor reading QIODevice::WriteOnly0x0002Deviceisopenedfor writing QIODevice::ReadWrite ReadOnly| WriteOnly Deviceisopenedfor reading and writing QIODevice::Append 0x0004Deviceisopenedinappend mode and alldataaddedtothe end QIODevice::Truncate0x0008Ifpossible,all previous contents are deleted whendeviceisopened QIODevice::Text0x0010When reading text, linebreaks are converted to thesystem-specific end-of-lineindicators(Windows: \r\f, Unix/OSX:\r) andvice-versa when writing QIODevice::Unbuffered0x0020Direct access, allbuffers under device areignored Table 11.1showsthe possible accessflags represented as powersofbase2,sothat theycanbecombined in anywayyou like(at leasttheoretically)byusingalogical OR operator(|).WithReadWrite, Qt doesthisitself: This flagcombines ReadOnly 319 11 Input/OutputInterfaces andWriteOnly.Since each devicemayignore individualflags that do notapplyto it,there is littleriskthatthe devicedoesnot behaveexactlyto theprogrammer’s expectations. In this case, you should checkthe APIdocsfor exceptions. This meansthatthere is no reason not to make useofthe veryfinelystructured accessmethods.Inplain language,ifyou onlywan ttoreadfromafile, then you should openthe filewithReadOnly.The operating system can under certain circumstances manage without resource-intensivelocking,and theprogram will getthe files it wants muchmorequickly.Inaddition theapplicationdoesnot run anydangerofoverwriting files byaccidentwhenreading. 11.2Access to LocalFiles TheQFile classwas used to openfilesanumber of timesinthe precedingchapters. When doing this wepassedthe filetobeopenedasanargument in theconstruc- torand then openedthe file. Belowwehaveanewsituation, in which weopen traditional FILE pointerswithQFile. To demonstratethiswewillwrite asmall program that removes allthe emptylines andcomment lines from afile.The hash symbol (#)atthe beginning of alineis assumedtobethe comment sign. Ourprogram is invoked from thecommand lineand expectsthe name of thefile to be analyzed as thefirstargument.Ifthere is asecondargument,itwrites the output to thefile namedthere.Otherwise, themodifiedfile appears on theconsole via thestandardoutput, stdout. It is remarkable that wedonot even requireaQCoreApplicationobject for this example, sinceQFile is notdependent on an eventloop. In themain() function wefirstcheck whether thereisatleast oneargument apart from thenameofthe executable.Thenwetryto openthe filefor reading.Ifitdoes notexist, open() announces an errordue to theReadOnlyaccess, which wecatch withanerror message.Thankstothe TextFlag, QFile converts thelineendings whenreading to thecorresponding Unixconventionsifnecessary,for example, under Windows(seeTable 11.1): // extractessentials/main.cpp #include <QtCore> #include <iostream> #include <stdio.h> using namespace std; intmain(intargc, char * argv[]) { if (argc <2) { 320 11.2 Access to LocalFiles cout << "Usage: "<< argv[0]<< "infile [outfile]"<< endl; return1; } QFile in(argv[1]); if(!in.open(QIODevice::ReadOnly|QIODevice::Text)) { cerr << "File "<< argv[1]<< "doesnotexist" << endl; } QFile out; if (argc >= 3) { out.setFileName(argv[2]); if (out.exists()) { cerr << "File"<< argv[2]<< "alreadyexists" << endl; return1; } if(!out.open(QIODevice::WriteOnly|QIODevice::Text)) { cerr << "Failed toopen file "<< argv[2]<< "forwriting"<< endl; return1; } } else if(!out.open(stdout,QIODevice::WriteOnly|QIODevice::Text)) { cerr << "Failed toopen standardoutput forwriting"<< endl; return1; } while (!in.atEnd()) { QByteArrayline =in.readLine(); if (!line.trimmed().isEmpty() && !line.trimmed().startsWith(’#’)) out.write(line); } in.close(); out.close(); return0; } Then wecheck whether thereisatleast onemoreparameter suppliedonthe com- mand line. Whether or notthere is one, werequire asecondQFile instance,which weallocate on thestack without passing an argument to theconstructor.Ifthe second parameter exists,thenwepassittothe QFile object ,via setFileName(), as a filename. Beforeweoverwrite thefile,using theQIODevice::WriteOnlyparameter, weuse theexists() method to warnthe user andexit theprogram.Onlynowdo we openthe file. If theuserhas notpassedasecond parameter to theprogram,wedirectthe output to thestandardoutput. To do this weuse an overloadedvariation of open(), which apartfromthe accesspermissions, expectsaFILE pointer as thefirstargument.The 321 11 Input/OutputInterfaces CInclude stdio.hdefinesaseries of FI LE pointers, includingstdout, which pointsto thestandardoutput. In thefollowingloop wereadout thecontents of thefile namedbythefirst command-lineargument,linebyline. Foreach line, wecheck whether theline is emptyor if it begins withacomment sign.trimmed()additionallyremoves all whitespaces at thebeginning andend of alinesothatthe program willalsorec- ognizelines consisting of forgotten emptyspacesasemptylines andindented commentsascomment lines. Alllines that do notmat ch thecriteria for exclusionlandinout,which is either the standardoutputoranewfile, dependingonthe parameters. Finallyweclose both files,tobeonthe safe side.However,aslongasweplace the QFile object on thestack or ensure that objectslocat ed on theheapare deleted beforethe program terminates,anexplicit close()isnot necessary,because the QFile destructor doe sthisfor us. 11.3SerializingObjects In C++, dataisusuallyrepresented as an object .Whendataisinthisform, pro- gramscannotsaveitinfilesorsenditacrossthe networkdirectly.Instead, the developermustfirstspecifywhich propertiesofanobject he wants to saveand in whatsequencehewants to send them. What is involved is taking theobjectsapart andplacing theirbasic components “onaconveyor belt.” To restorethem, dataistakenfromthe conveyor belt and packedback into an object.These procedures arereferredtoas serializing and deserializing.(In interprocesscommunication,where this procedureisalsoapplied, theterms marshalling and demarshalling arealsoused.) TheQDataStream classisresponsible in Qt for theserializationofall datatypes. It thereforeworks on allQIODeviceclasses. On page 243 weusedthe classtopack a listofstringlists into aQByteArrayused for adrag-and-drop operation: QByteArrayencodedData; QDataStreamstream(&encodedData,QIODevice::WriteOnly); ThealternativeQDataStream constructor used here simplifies handlingthe QByteAr- ray,whereas themainconstructor demands, as an argument,apointer to the QIODevicewithwhich it is to operate. Theabovecode thereforecorresponds to thefollowingcode that uses thestandardconstruct or: QByteArrayencodedData; QBufferbuffer(&encodedData); buffer.open(QBuffer::WriteOnly); QDataStreamstream(&buffer); 322 11.3 SerializingObjects To serializethe dataofaQByteArray,therefore, you essentiallyuseaQBuffer. We alreadykn owoneapplicationofthisfromSection 8.8: sendingdatabetween pro- gramsvia drag anddrop. So that this can also function across networkconnections,for example, theformat of QDataStream is platformindependent.Thus,astream serialized on aPowerPC can thereforebetransferred back to an object on an Intel computer wit hout any problem. TheQDataStream format haschanged several timesthroughoutthe development of Qt, however,and willcontinue to do so in thefuture. This is whytheclass has different version types: If you tryto bindaQDataStream to aspe cific version using setVersion(), then it will be sent correctlyin this format, even in later Qt versions, andwillbereadable on theoth er side. In ordertoreaddataintoadatastreamyou useits << operator: QByteArrayencodedData; QDataStreamstream(&encodedData,QIODevice::WriteOnly); QString text ="Nowcomesatimestamp"; QTime currentTime =QTime::currentTime(); stream<<text << currentTime; We can observehowQDataStream is used in practice to savedatatoafile in the followingexample, in which datasets arerepresented byaDataset classdefinedas follows: // record/record.h #ifndef RECORD_H #define RECORD_H #include <QString> #include <QDataStream> #include <QDebug> class Dataset { private: QString m_surname; QString m_name; QString m_street; intm_streetnumber; intm_zip; QString m_locality; public: Dataset(QString name, QString surname, QString street, intstreetnumber,intzip,QString locality) 323 [...]... library called QtNetwork To make this accessible to a Qt application, the pro file must contain the following line: QT += network There is also a separate meta-include file for the QtNetwork library that contains all the other headers The following line is sufficient to integrate this into the application source code: 332 11.5 Communication in the Network #include The module consists of the QIODevice... for the g_queue queue in which we save integer data, we use the QQueue class, explained in more detail in Appendix B on page 40 4 This contains the methods enqueue(), which places a datum into the queue, and dequeue(), which reads out the oldest datum The integer g_maxlen specifies the maximum number of elements in the queue, and the mutex g_mutex will protect the code sections that access the queue The. .. }; In the critical section we check whether there is still room in the queue If this is not the case, the wait condition comes into force Since the mutex must not be blocked during the waiting period, we hand it to be looked after by the g_mutex 343 12 Threading with QThread method This unlocks the mutex, provided the thread is waiting In consequence, you need to ensure that there is room in the queue... process.setWorkingDirectory(QString::fromLocal8Bit(argv[1])); process.start("ls", QStringList() start(); } The actual work is done by the ConnectionThread class As a Qt thread, it inherits from QThread and must therefore implement, in addition to the constructor, the purely abstract run() method run() is a protected method that is called by start(), so it must implement the functionality of the thread: // threadedtimeserver/connectionthread.h... point about the error, you can call the QTcpSocket method error(), which returns a member of the SocketError enumerator 340 12.2 Synchronizing Threads As in the example from Section 11.5.2, we now obtain the current date and time and write both as a QString to the socket The write() call immediately returns However, since we want to process one call after another in the thread, we use the waitFor*... put to good use in the so-called consumer/producer use-case, in which a producer thread makes data available for processing by a consumer thread To move data from one thread to the other, the producer places it in a queue, from which the consumer takes them out As a shared resource, the queue must be protected by a mutex before it is accessed by either the producer or the consumer If the consumer works... quickly than the producer, it is possible that the queue will become empty If the producer works faster than the consumer, the queue may fill up In either case, one of the two threads has to sleep: the consumer until more data are available, or the producer until the queue has free space We implement this scenario below using only Qt tools To do this we first declare a few global variables: As the data structure . 10 TheGraphics Library“Arthur” In XOR mode (QPainter::CompositionMode_Xor) ,the Painter links thealpha value of thesource(subtracted from theinverse of thedestination)tothe destination, thealpha. QStringobjects, making useofthe toLocal8Bit()method internally. 11.4Startingand ControllingProcesses Nowandagainyou maywanttomake useofthe services of command-linebased programs, particularlyon Unix-based operating. eventloop. In themain() function wefirstcheck whether thereisatleast oneargument apart from thenameofthe executable.Thenwetryto openthe filefor reading.Ifitdoes notexist, open() announces an errordue to theReadOnlyaccess,