TIE-11300 Tietotekniikan vaihtuva-alainen kurssi Graafisen käyttöliittymän ohjelmointi Syksy 2013 Luento 6 Interaktiivinen käyttöliittymä ja Drag-and-Drop Juha-Matti Vanhatupa
Sisältö Hiiri- ja Näppäintapahtumat Event filterit Drag-and-Drop
Qt Eventit QEvent kantaluokka Qt:n eventeille Qt:n tapahtumasilmukka purkaa ikkunointijärjestelmän eventit jonoista ja muuttaa ne QEvent:eiksi, ja lähettää ne QObjecteille kutsumalla sen event()-funktiota. Funktio kutsuu eventin tyypin mukaan oikeaa käsittelijäfunktiota.
Qt Eventit Eventin tyyppi kerrotaan enum QEvent::Type. Listattuna n. 140 erilaista eventtiä. Accept / Ignore Kertoo onko eventti käsitelty Eventtejä voi myös lähettää itse sendevent() käsittelee eventin heti postevent() event menee jonoon odottamaan käsittelyä. Qt:n tapahtumasilmukka käsittelee ne ja saattaa myös optimoida niitä.
Hiiritapahtumat QWidget tarjoaa joukon funktioita, joilla hiiritapahtumia voidaan napata. Enter Kutsutaan kun hiiren kursori siirtyy ikkunan päälle void QWidget::enterEvent ( QEvent * event ) void QWidget::dragEnterEvent ( QDragEnterEvent * event ) Leave Kutsutaan kun hiiren kursori poistuu objektin päältä void QWidget::leaveEvent ( QEvent * event ) void QWidget::dragLeaveEvent ( QDragEnterEvent * event )
Hiiritapahtumat Move Kutsutaan kun hiiren kursori liikkuu ikkunan päällä void QWidget::mouseMoveEvent ( QMouseEvent * event ) void QWidget::dragMoveEvent ( QDragEnterEvent * event ) Down Kutsutaan kun hiiren painike painetaan pohjaan void QWidget::mousePressEvent ( QMouseEvent * event )
Hiiritapahtumat Up Kutsutaan kun hiiren painike vapautetaan void QWidget::mouseReleaseEvent ( QMouseEvent * event ) Drop Kutsutaan kun drag-and-drop päätetään. void QWidget::dropEvent ( QDropEvent * event )
Hiiritapahtumat Mouse-eventit lähetetään ensisijaisesti sille ikkunalle, jonka päällä kursori on. Koordinaatit lasketaan suhteessa tähän ikkunaan
Capture Mahdollistaa hiiri-tapahtumien vastaanottamisen vaikka kursori olisi ikkunan ulkopuolella. - void QWidget::grabMouse () - void QWidget::releaseMouse () grabmouse()-funktiokutsun jälkeen widgetti vastaanottaa kaikki hiiri-tapahtumat, eivätkä muut widgetit saa niitä. Käytettävä varoen. Ei vaikutusta näppäinsanomiin.
Näppäintapahtumat Periaate sama kuin hiiritapahtumissa. QWidget tarjoaa tapahtumankäsittelijäfunktioita, joita ylikirjoittamalla voidaan luoda omaa toiminnallisuutta.
Näppäintapahtumat Focus In Kutsutaan kun widgetti saa fokuksen void QWidget::focusInEvent ( QFocusEvent * event ) Focus Out Kutsutaan kun widgetti menettää fokuksen void QWidget::focusOutEvent ( QFocusEvent * event ) Key Down Kutsutaan kun näppäin painetaan pohjaan void QWidget::keyPressEvent ( QKeyEvent * event ) Key Up Kutsutaan kun näppäin vapautetaan void QWidget::keyReleaseEvent ( QKeyEvent * event )
QKeyEvent Näppäinkoodi int QKeyEvent::key () const ei erottele isoja ja pieniä kirjaimia. Käytä text() jos tarvitaan. Keyboard modifiers (QInputEvent) Kertoo onko esim ALT tai SHIFT painike pohjassa toiminnon aikana
Esimerkki oma tabulaattori-käsittely Normaalisti tabulaattori siirtää focusta. Mutta jos widgetti jostain syystä tarvitsee itse tabulaattoria, voidaan se toteuttaa widgetin event()-funktiossa. bool MyWidget::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = qobject_cast<qkeyevent *>(event); if (ke->key() == Qt::Key_Tab) { // special tab handling here return true; return QWidget::event(event);
Esimerkki omien event-tyyppien käsittely Myös omia event-tyyppejä voi käsitellä event()-funktiossa. Tämä voidaan tehdä joko ennen tai jälkeen normaalin event käsittelyn. bool MyWidget::event(QEvent *event) { if (event->type() == CustomEventType) { CustomEvent *myevent = static_cast<customevent *>(event); // custom event handling here return true; return QWidget::event(event);
Capture Mahdollistaa näppäin-sanomien vastaanottamisen vaikka focus vaihtuisi. - void QWidget::grabKeyboard () - void QWidget::releaseKeyboard () grabkeyboard() -kutsun jälkeen widgetti vastaanottaa näppäintapahtumat eivätkä muut saa niitä. Focus liikkuu normaalisti, mutta sen omaava widgetti ei saa näppäintapahtumia, ennen kuin releasekeyboard() on kutsuttu. Ei vaikutusta hiiritapahtumiin. Myös käytettävä varoen.
Event filter Mahdollistaa eventtien monitoroinnin widgetin ulkopuolelta QObject::installEventFilter(QObject * filterobj); Eventit lähetetään ensin installoidulle filter oliolle ja ne kulkevat olion eventfilter()-funktion kautta
Event filterin toteutus class KeyPressEater : public QObject { Q_OBJECT protected: bool eventfilter(qobject *obj, QEvent *event); ; bool KeyPressEater::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { return true; else return QObject::eventFilter(obj, event);
Event filterin asettaminen KeyPressEater *keypresseater = new KeyPressEater(this); QPushButton *pushbutton = new QPushButton(this); pushbutton->installeventfilter(keypresseater); Luokan rakentaja on hyvä paikka filterin asentamiseksi. Jos olioon asennettu useita filtereitä, viimeisenä asennettu aktivoidaan ensin.
Qt:n Tapahtumankäsittelyn viisi tasoa Tapahtumakäsittelijän toteuttaminen. QObject:n event() funktion toteuttaminen. EventFilterin asentaminen QObject:iin. EventFilterin asentaminen QApplication olioon. Oma toteutus QApplication::notify()-funktiolle. Luettelon prioriteetti alhaalta ylös.
Drag and Drop Keino siirtää tietoa joko ohjelman sisällä tai prosessien välillä.
Drag and Drop Voi sisältää saman datan useana eri tyyppinä - Esim. sovellus käsittelee Dataobjekteja, mutta esim Paintsovellus käsittelee Bitmaptyyppisiä olioita. Bitmap Data
Drag & Drop Koostuu kolmesta vaiheesta: 1. Raahauksen aloittaminen 2. Raahaaminen 3. Droppaus Oman sovelluksen sisällä 3. osapuolen sovellukseen
Drag and Drop Qt Kaikkiin QWidgetistä periytettyihin luokkiin voidaan toteuttaa D&D toiminnallisuus. Widgetit voivat tukea joko raahauksen aloitusta tai lopettamista tai molempia.
1. Raahauksen aloittaminen Toteuta widgetille mousepress-event käsittelijä Periyttämällä oma toteutus Event filtterin avulla Aseta raahattava data QDrag objektiin Data voidaan asettaa useassa eri formaatissa Kerro raahauksen tyyppi ja aloita Dragoperaatio QDrag* pdrag = new QDrag(this); pdrag->exec(qt::copyaction);
Esim class CDraggableLabel : public QLabel { public: CDraggableLabel(); protected: void mousepressevent( QMouseEvent *e); ; void mousepressevent( ) { QDrag* drag = new QDrag(this); QMimeData* mimedata = new QMimeData; QString text = this->text(); mimedata->settext(text); drag->setmimedata(mimedata); drag->exec(qt::copyaction);
2. Raahaaminen Raahauksen tyyppi Qt::CopyAction Qt::MoveAction Raahauksen hyväksyminen Oletuksena QWidget ei hyväksy droppia
Esim class CDraggableLabel : public QLabel { public: CDraggableLabel(); protected: void mousepressevent( QMouseEvent *e); void dragenterevent( QDragEnterEvent *e); ; CDraggableLabel() { setacceptdrops(true); void dragenterevent(qdragenterevent *e) { if (e->mimedata()->hastext()) { e->accept(); else { e->ignore();
3. Droppaus Datan kysyminen Toteuta dropevent Otetaan talteen data QString text = event->mimedata()->text(); QByteArray data = event->mimedata()- >data("application/x-omaformaatti");
Esim class CDraggableLabel : public QLabel { public: CDraggableLabel(); protected: void mousepressevent( QMouseEvent *e); void dragenterevent( QDragEnterEvent *e); void dropevent(qdropevent *e); ; CDraggableLabel() { setacceptdrops(true); void dropevent(qdropevent *e) { if (e->mimedata()->hastext()) { this->settext(e->mimedata->text()); e->accept(); else { e->ignore();
QMimeData Voi sisältää saman data useassa eri formaatissa QStringList formats(); // palauttaa listan käytettävissä olevista formaateista. Huolehtii siitä, että dataa voidaan siirtää eri sovellusten välillä. Yleensä QMimeData olio luodaan new:llä, ja annetaan QDrag/QClipboard oliolle.
QMimeData Yleisimmille tyypeille QMimeData tarjoaa erilliset funktiot. Datan kysyminen binäärimuodossa QByteArray data(qstring mimetype); http://doc.qt.nokia.com/stable/qmimedata.html#details
QMimeData Tarjoaa kolme eri tapaa varastoida oman tyyppistä dataa. 1) Suoraan QByteArray:na QByteArray csvdata =...; QMimeData *mimedata = new QMimeData; mimedata->setdata("text/csv", csvdata); 2) Periyttämällä QMimeData ja ylikirjoittamalla hasformat(), formats() ja retrievedata()
QMimeData 3) Jos dataa käytetään saman sovelluksen sisällä, voidaan drag and drop:ssa tehdä tyyppimuunnos QMimeData:sta oman aliluokan olioksi ja asettaa/purkaa oma data siitä. void MyWidget::dropEvent(QDropEvent *event) { const MyMimeData *mydata = qobject_cast<const MyMimeData *>(event->mimedata()); if (mydata) { // access mydata's data through MyMimeData interface
QApplication globaalit asetukset QApplication::startDragTime() kertoo ajan, joka käyttäjän tulee pitää hiiren näppäintä painettuna ennen kuin raahaus alkaa. Oletus 500ms, voidaan muuttaa setdragtime(int ms) funktiolla. QApplication::startDragDistance() kertoo matkan, joka käyttäjän tulee liikuttaa objektia ennen kuin se tulkitaan raahausoperaatioksi. Oletus 4 pikseliä, voidaan muuttaa setstartdragdistance(int l) funktiolla.