QDialogButtonBox instance does not receive manually create MouseButtonPress event

edited July 2015 in Ruby Scripting

I am trying to unit test a Qt interface. It looks like QDialog->QDialogButtonBox with Cancel and OK buttons.
In the test code I generate a mouse event this way:

evt = QMouseEvent.new(QEvent::MouseButtonPress, point,
     Qt_MouseButton::LeftButton, Qt_MouseButton::LeftButton, Qt::NoModifier)
QCoreApplication::sendEvent(@btn_box, evt);

I try to receive the event with this code:

@btn_box.clicked { |btn|            
case btn
when @btn_box.button(QDialogButtonBox::Ok)
    puts 'Initial densities updated'
when @btn_box.button(QDialogButtonBox::Cancel)
    puts 'Initial densities not updated'
else
    puts 'Unknown Button'
end

Normally generated mouse presses do exercise the @btn_box.clicked code, but my unit testing, manually generated event gets lost. I have tested to learn the block of @btn_box.clicked is not called by my unit tests and have checked the event's accepted() method after the sendEvent() call and found it to return false. In the event sending and event receiving code @btn_box is the same instance of RBA::QDialogButtonBox_Native.

Does anyone know why the event is lost, how to trace it, or what I'm doing wrong?

My tool versions: KLayout 0.24 python eval (I'm using ruby), Qt 4.8.5, and Ruby 1.9.3 all on Linux.

Thanks,
Dave.

Comments

  • edited November -1

    Hi Dave,

    Initially I have tried to include a UI test framework into KLayout. I basically recorded all events and tried to play them back. While doing so I learned that it's pretty important to really mimic the events with all their followers ("released" following "pressed" and so forth). Sometimes it was even necessary to wait a little between events (for example combo box drop-down events). Finally even with recording the actual events, I could not reliably trigger a specific behaviour. That's when I finally gave up.

    I don't want to discourage you, but I think it's worth mentioning. In your case I think it's important first of all to send both a press and release event. But more important, I guess you'll have to target the event to the real button object - the button box I think is just a container for the actual button objects. QDialogButtonBox#button should give you the right button.

    Matthias

  • edited July 2015

    Matthias,

    I have stripped out a small sample of code from my unit tests to remove complexity. Below Is code that catches events delivered by sendEvent() in one type of run and NOT in another.

    require 'Qt'
    
    include RBA
    
    APP ||= Application::instance
    
    OK_SYM = QDialogButtonBox::Ok
    
    class C < QDialog
        attr_reader :btn_box
    
        def initialize
            @btn_box = QDialogButtonBox.new(self)
            @btn_box.setStandardButtons(OK_SYM)
        end
    end
    
    c = C.new
    c.show
    # Intermittently misses press events with out the following line
    QCoreApplication::processEvents
    
    btn = c.btn_box.button(OK_SYM)
    btn.clicked { STDERR << "got a click\n" }
    
    QCoreApplication::processEvents
    
    evt = QKeyEvent.new(QEvent::KeyPress, 0x4f, RBA::Qt::AltModifier, 'O')
    
    STDERR << "before: key press accepted? #{evt.accepted}\n"
    QCoreApplication::sendEvent(btn, evt);
    STDERR << "key press accepted? #{evt.accepted}\n"
    
    evt2 = QKeyEvent.new(QEvent::KeyRelease, 0x4f, RBA::Qt::AltModifier, 'O')
    
    STDERR << "before: key release accepted? #{evt2.accepted}\n"
    QCoreApplication::sendEvent(btn, evt2);
    STDERR << "key release accepted? #{evt2.accepted}\n"
    
    APP.exec
    

    The above prints "got a click" without a user hitting a mouse button when run this way:

    klayout -r send_event_bug.rb
    

    It sees no click event when run this way:

    klayout -z -rx -nc -rd no_autorun=true -rm send_event_bug.rb
    

    You'll note the keyPress event is 'accepted' only in the case where a click is detected. In both cases the keyRelease is not 'accepted'.

    Do you know if there is a way to get the non-interactive invocation to process the events?

    Thanks,
    Dave

  • edited July 2015

    Hi Dave,

    I'm able to trigger a "got a click" message with the following code on my 0.24 working version:

    include RBA
    
    OK_SYM = QDialogButtonBox::Ok
    
    class C < QDialog
        attr_reader :btn_box
    
        def initialize
            @btn_box = QDialogButtonBox.new(self)
            @btn_box.setStandardButtons(OK_SYM)
        end
    end
    
    c = C.new
    c.show
    
    btn = c.btn_box.button(OK_SYM)
    btn.clicked { STDERR << "got a click\n" }
    
    evt = QMouseEvent.new(QEvent::MouseButtonPress, QPoint::new(10, 10), Qt::LeftButton, Qt::LeftButton, RBA::Qt::NoModifier)
    
    STDERR << "before: mouse button press accepted? #{evt.accepted}\n"
    QCoreApplication::sendEvent(btn, evt);
    STDERR << "mouse button press accepted? #{evt.accepted}\n"
    
    evt2 = QMouseEvent.new(QEvent::MouseButtonRelease, QPoint::new(10, 10), Qt::LeftButton, Qt::LeftButton, RBA::Qt::NoModifier)
    
    STDERR << "before: mouse button release accepted? #{evt2.accepted}\n"
    QCoreApplication::sendEvent(btn, evt2);
    STDERR << "mouse button release accepted? #{evt2.accepted}\n"
    
    c._destroy
    

    The sendEvent calls send mouse button press and release events to the Ok button which triggers the "got a click" callback. I run this script the first way:

    klayout -r send_event_bug.rb
    

    Note that

    • I removed the "require 'Qt'" because I somehow suspect that there is some interaction between qtruby and the built-in Qt binding (which is not the same).
    • I used QMouseEvent, not QKeyEvent. QKeyEvent won't help since it's not the key event which triggers the button click.
    • The final line "c._destroy" is required because the dialog does not have a parent and is not being destroyed before the Ruby interpreter shuts down. The Ruby interpreter lives post-destruction of the QApplication and destruction of the Ruby objects will happen then. By that time the application is already destroyed and it's too late: you'll get a segmentation fault. I have to debug the precise way this happens, but the c._destroy helps to avoid this. If you use a parent for the dialog (for example the main window), that won't be an issue.

    Regards,

    Matthias

  • edited July 2015

    (I have been gone a few days on vacation)

    Matthias,

    Wonderful! Your fixes will help me make progress.

    Regarding your notes:

    • require 'Qt' removal seems to make sense, I seem to have had problems that are consistent with a conflict.

    • I'm not sure about the QKeyEvent issue. In my tests, the QKeyEvent seemed to trigger the button click in one of the two cases. However, I am happy to use QMouseEvents in my tests for now.

    • c._destroy issue: THANKS! I have had intermittent seg faults that I could not explain. This should help me a lot.

    I have tested your code on KLayout 0.24, the python eval version, with success using both forms of invocation.

    Thanks for the help,

    Dave

Sign In or Register to comment.