Author Topic: Using "cancel" In Qtopia Apps  (Read 4333 times)

kopsis

  • Sr. Member
  • ****
  • Posts: 329
    • View Profile
    • http://kopsisengineering.com
Using "cancel" In Qtopia Apps
« on: November 23, 2004, 02:57:33 pm »
For a while now I've had a Qtopia application where I wanted to use the "Cancel" button to do something other than close the app. None of my Google or ZUG searches ever turned up the answer so today I decided to dig around a bit in the Qtopia source code. What I discovered is the following very simple trick:

Assuming you have a pointer "main" to your QMainWindow object, you can simply do the following:
Code: [Select]
main->setWFlags(main->getWFlags() | WStyle_Customize);
This causes the QPEApplication class to ignore the "Cancel" button and pass it on as a normal key event. The only side effect that I've noticed is that the "Ok" button will no longer be mapped to "Return" but if your app needs "Cancel" control, that may actually be a bonus.

This is probably old news to most Qtopia developers, but I wasn't able to find this info anywhere. Sooner or later someone else is going to need this so hopefully this post will save them from trudging through the Qtopia source code.

vanstrien

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
    • http://www.vanstrien.net
Using "cancel" In Qtopia Apps
« Reply #1 on: November 23, 2004, 03:37:48 pm »
Good timing.  I was just about to ask a question regarding closing apps, but this might be the answer I need.

Please tell me what you think:

My apps save conifguration values when the app closes down.  I use the destructive close, not really knowing how it works, but because a posting I read somewhere said to use it.  This means that if the user closes an app with the X on the title bar, the app calls all the destructors.  

However, if the user closes the app with the cancel button, I don't get my destructors called and my apps don't save any configuration information.  Is this a good time to use the code you pasted above?  Or is there a better way to do it?
C860 Cacko ROM | 5500 tkcROM
256MB SD | 128MB SD
512MB CF | 256MB CF
D-Link DWL 660 WiFi| Linksys WCF12 WiFi
Socket Bluetooth | Socket Ethernet

zenyatta

  • Sr. Member
  • ****
  • Posts: 366
    • View Profile
    • http://
Using "cancel" In Qtopia Apps
« Reply #2 on: November 23, 2004, 04:59:18 pm »
I once desperately needed to solve this in a Python/PyQt app. What I came up with is about 1000% more complicated than kopsis' solution but it worked for me. The thing is, when you press the Cancel button you actually do receive the keypress but only *after* the corresponding CloseEvent. So I created an event filter that, upon catching a CloseEvent, sets up a 50ms timer. If it catches a Cancel KeyEvent during those 50ms, the app goes on and the Cancel keypress is processed. If the timer times out and there is no Cancel key, the app closes (because you've tapped the X button on the title bar).

Of course, all that would mean that you can *never* close the app with the Cancel key so my filter can be turned off when you don't need to capture the Cancel key.

In retrospect, maybe I shouldn't've been so scared of the WStyle_Customize flag

z.
« Last Edit: November 23, 2004, 05:01:43 pm by zenyatta »
SL-5500, 256MB Kingston CF card, 128MB EDGE SD card, Thomson HED-155 headphones
OpenZaurus 3.5.3 / Opie (kernel 64-0)

kopsis

  • Sr. Member
  • ****
  • Posts: 329
    • View Profile
    • http://kopsisengineering.com
Using "cancel" In Qtopia Apps
« Reply #3 on: November 23, 2004, 11:03:14 pm »
Quote
However, if the user closes the app with the cancel button, I don't get my destructors called and my apps don't save any configuration information.  Is this a good time to use the code you pasted above?  Or is there a better way to do it?
I've always subscribed to the philosophy that destructors are for cleaning up memory and not much else. What I usually do is put all my application "cleanup" code (generally saving state info) in a dedicated member function in my QPEApplication derived class. Then I put a call to that method in my "main" right after the call to run(). Doing it that way seems to catch all the normal exit paths.

I only recommend the Cancel button capture technique when your app wants to do something other than exit when cancel is pressed. For example, in my app cancel is like a "back" button.
« Last Edit: November 23, 2004, 11:06:08 pm by kopsis »

zenyatta

  • Sr. Member
  • ****
  • Posts: 366
    • View Profile
    • http://
Using "cancel" In Qtopia Apps
« Reply #4 on: November 24, 2004, 05:10:03 am »
In my case Cancel is used to finish in-place editing of a table cell, discarding the changes.
SL-5500, 256MB Kingston CF card, 128MB EDGE SD card, Thomson HED-155 headphones
OpenZaurus 3.5.3 / Opie (kernel 64-0)

lpotter

  • Sr. Member
  • ****
  • Posts: 450
    • View Profile
    • http://qtopia.net
Using "cancel" In Qtopia Apps
« Reply #5 on: November 28, 2004, 01:38:27 pm »
Why not override keyPressEvent( QKeyEvent *e) or keyReleaseEvent( QKeyEvent *e)
and handle it that way?
Code: [Select]
void myApp::keyReleaseEvent( QKeyEvent *e) {
  switch ( e->key() ) {
   case Key_Cancel:
        someRemarkableFunction();
        break;
  };
}
Software Engineer, Systems Group, MES, Trolltech
irc.freenode.net #qtopia
http://qtopia.net

kopsis

  • Sr. Member
  • ****
  • Posts: 329
    • View Profile
    • http://kopsisengineering.com
Using "cancel" In Qtopia Apps
« Reply #6 on: November 29, 2004, 08:34:23 am »
Quote
Why not override keyPressEvent( QKeyEvent *e) or keyReleaseEvent( QKeyEvent *e)
and handle it that way?
That was the first thing I tried but (at least in Python + PyQt) it doesn't work. In looking at the Qtopia source code for the QPEApplication class, it appears that there's a protected QPEApplication::qwsEventFilter() method that snags the "special" Qtopia keys (Ok, Cancel, App buttons, etc.) and has it's way with them before they make it to keyPressEvent(). Though Cancel will eventually propogate to keyPressEvent(), it happens only after qwsEventFilter() has called close() on the active window. You can use Zenyatta's technique of disregarding the close() in certain circumstances, but that's quite a bit more complicated.

The next logical approach ... overriding qwsEventFilter() in my QPEApplication derived class ... also failed. I suspect that's because qwsEventFilter() is protected and non-virtual, but it could also just be a Python thing (I didn't try it in C++). In any case, the only simple, reliable technique I found for PyQt was my WStyle_Customize hack.

lpotter

  • Sr. Member
  • ****
  • Posts: 450
    • View Profile
    • http://qtopia.net
Using "cancel" In Qtopia Apps
« Reply #7 on: November 29, 2004, 01:35:01 pm »
You then also need to use this function:
Code: [Select]
QPEApplication::grabKeyboard();QPEApplication::grabKeyboard();
« Last Edit: November 29, 2004, 01:38:46 pm by lpotter »
Software Engineer, Systems Group, MES, Trolltech
irc.freenode.net #qtopia
http://qtopia.net

kopsis

  • Sr. Member
  • ****
  • Posts: 329
    • View Profile
    • http://kopsisengineering.com
Using "cancel" In Qtopia Apps
« Reply #8 on: November 29, 2004, 04:55:54 pm »
Ok, out of curiosity I tried adding grabKeyboard(). It successfully captured the app launching keys but, as I expected, the Cancel button waltzes right through.

Keep in mind that I'm working with the Sharp ROM which is somewhere between Qtopia 1.4 and 1.5. If you take a look at the source for QPEApplication::qwsEventFilter() in old versions of qpeapplication.cpp you'll see that Key_Escape, Key_F30, and Key_F33 each get special handling that is not circumvented by grabKeyboard(). Only Key_F1 through Key_F29 go through the if (d->kbgrabbed) logic. I just pulled down Qtopia 1.7 and this problem has definitely been fixed there, but until someone at Trolltech persuades Sharp to release a ROM with up-to-date Qtopia libraries, I'm gonna have to stick with my Cancel hack.