I am using Python with PyQt5 for programming user interface.
Now I have a variable inside the UI class in Python(type: ctypes.c_long), and it is changed by calling a function inside a .dll file with ctypes. Python passes this variable with C++ by address.
MyVariable = ctypes.c_long(0)
MyUI.MyDll.MyFunc(ctypes.byref(MyUI.MyVariable))
And in C++ (.dll file), the codes could be like:
int MyFunc(int& my_var){
my_var = 5;
return 1;
}
Since I cannot emit signal inside the C++ code (.dll file), I wish to have an elegent way to detect the value changing of with variable to sync with a progress bar.
Thank you!
Related
Constellation / Context:
A C++ Executable (1) which dynamically links a C++ shared library emb.so (2)
which in turn is running an embedded python interpreter (3) that calls custom python functions (4).
Embedding the Python interpreter (3) is happening by using pybind11.
A call to a Python function from C++ can be simplified as:
py::module::import("test").attr("my_func")();
The executable (1) has a main loop in which it can do some other work, but it will call the python function at regular intervals.
Observation:
Variant 1: If I block inside the python function, the python code executes smoothly and quickly, but the main executable loop is obviously blocked
Variant 2: If I create a python thread inside the python function to return from the function immediately, the main executable is running, but the python code is running extremely slow (I can watch the iterations of a for-loop with a print one by one)
Question:
Why is Variant 2 so slow and how can I fix it?
My guess is that this has something to do with the GIL, and I tried to release the GIL inside the wrapper emb.so before returning to the main loop, but I wasn't able to do this without a segfault.
Any ideas?
It turned out that this is very much related to the following question:
Embedding python in multithreaded C application
(see answer https://stackoverflow.com/a/21365656/12490068)
I solved the issue by explicitely releasing the GIL after calling embedded Python code like this:
state = PyGILState_Ensure();
// Call Python/C API functions...
PyGILState_Release(state);
If you are doing this in a function or other C++ scope and you are creating python objects, you have to make sure that the python object's desctructor is not called after releasing the GIL.
So don't do:
void my_func() {
gil_state = PyGILState_Ensure();
py::int_ ret = pymodule->attr("GiveMeAnInt")();
PyGILState_Release(gil_state);
return ret.cast<int>();
}
but instead do
void my_func() {
int ret_value;
gil_state = PyGILState_Ensure();
{
py::int_ ret = pymodule->attr("GiveMeAnInt")();
ret_value = ret.cast<int>();
}
PyGILState_Release(gil_state);
return ret_value;
}
I'm making GUI application using Tkinter and I'm using tkinter.font.families() for making pull down list of selecting fonts.
Now, I'm wondering how this function works
I tried reading the code but I can't understand it because of my lack of enough knowledge...
def families(root=None, displayof=None):
"Get font families (as a tuple)"
if not root:
root = tkinter._default_root
args = ()
if displayof:
args = ('-displayof', displayof)
return root.tk.splitlist(root.tk.call("font", "families", *args))
This is a code of the function(https://github.com/python/cpython/blob/c4928fc1a853f3f84e2b4ec1253d0349137745e5/Lib/tkinter/font.py#L180).
my qeustion is
What is the meaning of args = ('-displayof', displayof)?
Where does tk.call() function came from?(I can't find this function in Tk class)
How does tk.call("font", "families", *args) function works?
Thank you for reading my question.
What is the meaning of args = ('-displayof', displayof)?
Tkinter is a small python wrapper around a tcl interepreter which has the tk package installed. All of the actual work of creating widgets, querying fonts, etc, is done by the tcl/tk libraries.
Tcl/tk commands use a leading dash to represent an option name, and the option is typically followed by a value. This code is preparing to call a tcl function, so it is building up a list of arguments required by tcl.
In this specific case, it's adding the -displayof option if the displayof argument was passed to the function.
Where does tk.call() function came from?
It comes from a C-based library. It is defined in a file named _tkinter.c. More specifically, it's the function Tkapp_Call. It is a small wrapper that allows python to execute commands within an embedded tcl interpreter.
How does tk.call("font", "families", *args) function works?
The tk library has a command named font. From within a tcl interpreter you would call it with something like this:
font families
The code tk.call("font", "families", *args) is simply sending that command to the tcl interpreter.
The underlying tcl/tk library has platform-specific functions for dealing with fonts. See tkMacOSXFont.c, tkUnixFont.c, and tkWinFont.c.
objective:
executing a string of c(++) code with some kind of function comparable to the exec() function in python.
example in python:
exec('print("hello world")')
#out:
#hello world
question:
is there a c++ version of exec in python?
but, is there a c++ version of exec in python?
you wan to execute C language statements from a string! so that is not possible with c.
why
because c is compiled language, the program first compiled and then executed.
its possible in python as its interpreted language,means program is compiled by
just-in-time compiler at runtime.
hope this will help.
Well, technicall, you (maybe) can. But it's hardly a justifiable effort, there are other scripting languages that can be integrated in C++. For example Lua. Just to think about it, the following could work, if you have a method int excuteCode(std::string code)
Copy that string into a template that wraps it in some function. The following is an idea of such a template:
int userFunc()
{
%code%
}
Write the template to a file
Build a dynamic library (e.g. a .dll on windows) from that file (call compiler and linker via system or OS-specific methods)
Load the dynamic library into your running program (again, OS-specific methods)
Load the required method userFunc and execute it.
#include <iostream>
int main(void) {
system("python -c \"print('hello world')\"");
return 0;
}
For system commands...?
I'm trying to run tcl script from python,
tcl script requires command line arguments to execute, when I source the tcl file from python, it then shows the error says
tclsh.eval('source "test.tcl"' )
_tkinter.TclError: can't read "::argv": no such variable
I've done many searches, majority of them asks how to pass arguments to python in tcl.
python code
import tkinter
import sys
tclsh.eval('source "test.tcl"' )
if __name__ == '__main__':
print("hi")
tcl code
puts [lindex $::argv 0]
Is there anyway for me pass python arguments to tcl ?
or
not pass arguments and still compile ?
since if I compile tcl script only without arguments, it still compiles
Note:
In tkinter documentation it says tkinter.Tk is
The Tk class is instantiated without arguments
Is there a way to instantiated with arguments ?
Sol:
tclsh.eval('set argv [list]')
tclsh.eval('set argc 0')
I tried to set a global variable and it works for me under python 3.6
The global argv variable is, apart from being set during the startup of a standard Tcl script, not special in any way. You can therefore just set it prior to doing source. In this case, doing so with lappend in a loop is probably best as it builds the structure of the variable correctly. There are two other variables that ought to be set as well (argc and argv0); overall you do it like this (as a convenient function):
def run_tcl_script(script_name, *args):
tclsh.eval('set argv0 {{{}}}'.format(script_name))
tclsh.eval('set argv {}; set argc 0')
for a in args:
tclsh.eval('lappend argv {{{}}}; incr argc'.format(a))
tclsh.eval('source $argv0')
The {{{}}} with Python's str.format results in a single layer of braces being put around the argument, defending against most quoting issues.
I am porting a program (VMD, Visual Molecular Dynamics), which is written in C++ and has both Python and TCL interpreters embedded, to Python 3.x. Most of its UI is hard coded using the TCL/TK framework and OpenGl, so UI refreshs are done manually. When the Python interpreter is running it is possible to dynamically create new windows and even add new menus to the main UI using Tkinter. In this case all TK events are flushed by periodically calling some code in the Python side (see below). This ensures that all updates are thread-safe and don't break the interpreter.
int PythonTextInterp::doTkUpdate() {
// Don't recursively call into dooneevent - it makes Tkinter crash for
// some infathomable reason.
if (in_tk) return 0;
if (have_tkinter) {
in_tk = 1;
int rc = evalString(
"import Tkinter\n"
"while Tkinter.tkinter.dooneevent(Tkinter.tkinter.DONT_WAIT):\n"
" pass\n"
);
in_tk = 0;
if (rc) {
return 1; // success
}
// give up
have_tkinter = 0;
}
return 0;
}
However the function tkinter.dooneevent was removed from Python 3 and I can not find a substitute for it. I tried calling the low-level Tcl_DoOneEvent(TCL_DONT_WAIT) but when I dynamically created a new window I ended up crashing the Python interpreter with the error Fatal Python error: PyEval_RestoreThread: NULL tstate.
The answers in tkinter woes when porting 2.x code to 3.x, 'tkinter' module attribute doesn't exist doesn't help since I don't have a list of all windows that may created by the user.
Does anyone have any suggestion on how to flush the TK events in this case? It could be either on the Python side or in C++.
Thanks in advance
It looks like this is equivalent:
root = tkinter.Tk()
# Here's your event handler. Put it in a loop somewhere.
root.tk.dooneevent(tkinter._tkinter.DONT_WAIT)
# I don't know if it's possible to access this method without a Tk object.
Now, I don't know how exactly to convert this into your code- do you have a root Tk object with which you can access dooneevent? I'm not at all familiar with python 2 tkinter so I don't know exactly how evenly my code maps to yours. However, I discovered this when I was doing something very similar to you- trying to integrate the tkinter event loop into the asyncio event loop. I was able to create a coroutine that calls this method in a loop, yielding each time (and sleeping occasionally), so that the GUI remains responsive without blocking the asyncio event loop with tkinter._tkinter.create().
#asyncio.coroutine
def update_root(root):
while root.tk.dooneevent(tkinter._tkinter.DONT_WAIT):
yield
EDIT: I just read your comment about not having a widget. I know that the root.tk object is a tkinter._tkinter.TkappType instance created by calling tkinter._tkinter.create, and I don't think it's global. I'm pretty sure it's the core Tcl interpreter. You might be able to create your own by calling create. While it isn't documented, you can look at its usage in tkinter.Tk.__init__