mirror of https://github.com/KLayout/klayout.git
Qt signals can be bound to functions with less args in Python
With this change it is possible to bind signals to functions
accepting less arguments. For example:
def triggered():
...
b = pya.QPushButton()
b.clicked(triggered)
b.emit_clicked(True)
wasn't working before since triggered() gets one parameter
(checked) and the call fails. Now, additional parameters are
ignored.
This commit is contained in:
parent
ede58ae728
commit
1f60e7729e
|
|
@ -44,13 +44,14 @@ reuse=0
|
|||
qt="/opt/qt/4.6.3/include"
|
||||
qt5="/opt/qt/5.5.1/include"
|
||||
inst_dir_common=`pwd`/scripts/mkqtdecl_common
|
||||
inst_dir=`pwd`/scripts/mkqtdecl
|
||||
inst_dir4=`pwd`/scripts/mkqtdecl4
|
||||
inst_dir5=`pwd`/scripts/mkqtdecl5
|
||||
src_dir=`pwd`/src
|
||||
src_name4=gsiqt4
|
||||
src_name5=gsiqt5
|
||||
|
||||
src_name=$src_name4
|
||||
inst_dir=$inst_dir4
|
||||
|
||||
while [ "$1" != "" ]; do
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "pyaObject.h"
|
||||
#include "pyaMarshal.h"
|
||||
#include "pyaUtils.h"
|
||||
#include "pyaConvert.h"
|
||||
#include "pya.h"
|
||||
|
||||
#include "tlLog.h"
|
||||
|
|
@ -214,19 +215,46 @@ void SignalHandler::call (const gsi::MethodBase *meth, gsi::SerialArgs &args, gs
|
|||
|
||||
tl::Heap heap;
|
||||
|
||||
PythonRef argv (PyTuple_New (std::distance (meth->begin_arguments (), meth->end_arguments ())));
|
||||
|
||||
// TODO: callbacks with default arguments?
|
||||
int args_avail = int (std::distance (meth->begin_arguments (), meth->end_arguments ()));
|
||||
PythonRef argv (PyTuple_New (args_avail));
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); args && a != meth->end_arguments (); ++a) {
|
||||
PyTuple_SetItem (argv.get (), int (a - meth->begin_arguments ()), pop_arg (*a, args, NULL, heap).release ());
|
||||
}
|
||||
|
||||
PythonRef result;
|
||||
for (std::vector<CallbackFunction>::const_iterator c = m_cbfuncs.begin (); c != m_cbfuncs.end (); ++c) {
|
||||
|
||||
// determine the number of arguments required
|
||||
int arg_count = args_avail;
|
||||
if (args_avail > 0) {
|
||||
|
||||
PythonRef fc (PyObject_GetAttrString (c->callable ().get (), "__code__"));
|
||||
if (fc) {
|
||||
PythonRef ac (PyObject_GetAttrString (fc.get (), "co_argcount"));
|
||||
if (ac) {
|
||||
arg_count = python2c<int> (ac.get ());
|
||||
if (PyObject_HasAttrString (c->callable ().get (), "__self__")) {
|
||||
arg_count -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// use less arguments if applicable
|
||||
if (arg_count == 0) {
|
||||
result = PythonRef (PyObject_CallObject (c->callable ().get (), NULL));
|
||||
} else if (arg_count < args_avail) {
|
||||
PythonRef argv_less (PyTuple_GetSlice (argv.get (), 0, arg_count));
|
||||
result = PythonRef (PyObject_CallObject (c->callable ().get (), argv_less.get ()));
|
||||
} else {
|
||||
result = PythonRef (PyObject_CallObject (c->callable ().get (), argv.get ()));
|
||||
}
|
||||
|
||||
if (! result) {
|
||||
check_error ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
push_arg (meth->ret_type (), ret, result.get (), heap);
|
||||
|
|
|
|||
|
|
@ -480,6 +480,73 @@ class QtBindingTest(unittest.TestCase):
|
|||
self.assertEqual(parent._destroyed(), True)
|
||||
self.assertEqual(child._destroyed(), True)
|
||||
|
||||
def test_45(self):
|
||||
|
||||
triggered = ""
|
||||
|
||||
class TriggerLog:
|
||||
triggered = ""
|
||||
def triggered1(self, b):
|
||||
if b:
|
||||
self.triggered += "1"
|
||||
else:
|
||||
self.triggered += "0"
|
||||
def triggered0(self):
|
||||
self.triggered += "*"
|
||||
|
||||
# Ability to connect to signals while ignoring arguments and
|
||||
# to emit signals
|
||||
|
||||
b = pya.QPushButton()
|
||||
|
||||
log = TriggerLog()
|
||||
|
||||
b.clicked(log.triggered1)
|
||||
|
||||
self.assertEqual(log.triggered, "")
|
||||
b.emit_clicked(True)
|
||||
self.assertEqual(log.triggered, "1")
|
||||
b.emit_clicked(False)
|
||||
self.assertEqual(log.triggered, "10")
|
||||
|
||||
b.clicked(log.triggered0)
|
||||
|
||||
b.emit_clicked(True)
|
||||
self.assertEqual(log.triggered, "10*")
|
||||
b.emit_clicked(False)
|
||||
self.assertEqual(log.triggered, "10**")
|
||||
|
||||
# We do the same with free functions since they behave differently in Python:
|
||||
|
||||
global trigger_log
|
||||
trigger_log = ""
|
||||
|
||||
def triggered_f0():
|
||||
global trigger_log
|
||||
trigger_log += "x"
|
||||
|
||||
def triggered_f1(b):
|
||||
global trigger_log
|
||||
if b:
|
||||
trigger_log += "+"
|
||||
else:
|
||||
trigger_log += "-"
|
||||
|
||||
b.clicked(triggered_f1)
|
||||
|
||||
self.assertEqual(trigger_log, "")
|
||||
b.emit_clicked(True)
|
||||
self.assertEqual(trigger_log, "+")
|
||||
b.emit_clicked(False)
|
||||
self.assertEqual(trigger_log, "+-")
|
||||
|
||||
b.clicked(triggered_f0)
|
||||
|
||||
b.emit_clicked(True)
|
||||
self.assertEqual(trigger_log, "+-x")
|
||||
b.emit_clicked(False)
|
||||
self.assertEqual(trigger_log, "+-xx")
|
||||
|
||||
|
||||
# run unit tests
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -567,6 +567,31 @@ class QtBinding_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
def test_45
|
||||
|
||||
# Ability to connect to signals while ignoring arguments and
|
||||
# to emit signals
|
||||
|
||||
b = RBA::QPushButton::new
|
||||
|
||||
triggered = ""
|
||||
b.clicked { |checked| triggered += (checked ? "1" : "0") }
|
||||
|
||||
assert_equal(triggered, "")
|
||||
b.emit_clicked(true)
|
||||
assert_equal(triggered, "1")
|
||||
b.emit_clicked(false)
|
||||
assert_equal(triggered, "10")
|
||||
|
||||
b.clicked { triggered += "*" }
|
||||
|
||||
b.emit_clicked(true)
|
||||
assert_equal(triggered, "10*")
|
||||
b.emit_clicked(false)
|
||||
assert_equal(triggered, "10**")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue