mirror of
https://gitlab.com/eql/EQL5.git
synced 2025-12-15 14:50:58 -08:00
add tutorial in 'Qt_EQL/' for accessing C++ apps from Lisp
This commit is contained in:
parent
490c878dee
commit
28d5d133fb
6 changed files with 174 additions and 0 deletions
19
Qt_EQL/tutorial/README.md
Normal file
19
Qt_EQL/tutorial/README.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
## Info
|
||||
|
||||
This is a basic demo showing how to access a C++ app from Lisp, including the
|
||||
creation of instances of a C++ class (the implementation of which is not really
|
||||
elegant, but it works).
|
||||
|
||||
It also starts a simple REPL for playing around interactively.
|
||||
|
||||
|
||||
## Build
|
||||
|
||||
qmake
|
||||
make
|
||||
|
||||
|
||||
## Run
|
||||
|
||||
./test
|
||||
|
||||
27
Qt_EQL/tutorial/main.cpp
Normal file
27
Qt_EQL/tutorial/main.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include "test.h"
|
||||
#include <eql5/eql.h>
|
||||
#include <QApplication>
|
||||
#include <QLabel>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QLabel* main = new QLabel("<h2>Main Window</h2>");
|
||||
main->setAlignment(Qt::AlignCenter);
|
||||
main->resize(600, 400);
|
||||
main->show();
|
||||
|
||||
// we need an instance for 'define-qt-wrappers' and 'new-instance' to work;
|
||||
// we pass the main widget as parent and a unique 'objectName', so we can
|
||||
// find it from Lisp
|
||||
|
||||
Test test(main, "test");
|
||||
|
||||
EQL eql;
|
||||
EQL::eval("(in-package :eql-user)");
|
||||
EQL::eval("(load \"test.lisp\")"); // will start a REPL
|
||||
app.processEvents(); // needed for 'qlater' in 'test.lisp'
|
||||
|
||||
return 0; // no 'app.exec()' because of REPL
|
||||
}
|
||||
|
||||
37
Qt_EQL/tutorial/test.cpp
Normal file
37
Qt_EQL/tutorial/test.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include "test.h"
|
||||
#include <QtDebug>
|
||||
#include <eql5/eql_fun.h>
|
||||
|
||||
Test::Test(QObject* parent, const QString& name) : QObject(parent) {
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
QObject* Test::newInstance(QObject* parent, const QString& name) {
|
||||
return new Test(parent, name);
|
||||
}
|
||||
|
||||
QString Test::concat(const QStringList& list) {
|
||||
return list.join(", ");
|
||||
}
|
||||
|
||||
void Test::processData(cl_object data) {
|
||||
// meant for passing complex Lisp data to be processed in C++
|
||||
|
||||
if(cl_listp(data) == ECL_T) {
|
||||
for(cl_object l_dolist = data; cl_car(l_dolist) != ECL_NIL; l_dolist = cl_cdr(l_dolist)) {
|
||||
cl_object l_el = cl_car(l_dolist);
|
||||
cl_print(1, l_el);
|
||||
}
|
||||
cl_terpri(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Test::printMe() {
|
||||
// you may pass up to 10 arguments of any type found in
|
||||
// '~/eql5/src/ecl_fun.cpp::toMetaArg()', wrapped in macro Q_ARG;
|
||||
// C++ class instances are passed as pointers of a vanilla Qt class
|
||||
// known to EQL5, here: 'QObject*'
|
||||
|
||||
eql_fun("eql-user:print-qt-object", Q_ARG(QObject*, this));
|
||||
}
|
||||
|
||||
27
Qt_EQL/tutorial/test.h
Normal file
27
Qt_EQL/tutorial/test.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef APP_H
|
||||
#define APP_H
|
||||
|
||||
#include <QObject>
|
||||
#include <ecl/ecl.h>
|
||||
|
||||
class Test : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Test(QObject*, const QString&);
|
||||
|
||||
// define function acting as constructor (callable from Lisp)
|
||||
// N.B. return a vanilla Qt class (here: QObject*) known to EQL5
|
||||
Q_INVOKABLE QObject* newInstance(QObject*, const QString&);
|
||||
|
||||
public Q_SLOTS:
|
||||
// you may pass any type found in '~/eql5/src/ecl_fun.cpp::toMetaArg()'
|
||||
QString concat(const QStringList&);
|
||||
|
||||
// pass Lisp data
|
||||
void processData(cl_object);
|
||||
|
||||
// call back to Lisp
|
||||
void printMe();
|
||||
};
|
||||
|
||||
#endif
|
||||
45
Qt_EQL/tutorial/test.lisp
Normal file
45
Qt_EQL/tutorial/test.lisp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
(in-package :eql-user)
|
||||
|
||||
;; find main widget of app
|
||||
(defvar *main-widget* (first (|topLevelWidgets.QApplication|)))
|
||||
|
||||
;; find 'Test' instance by its 'objectName'
|
||||
(defvar *test* (qfind-child *main-widget* "test"))
|
||||
|
||||
;; the following defines generic functions for all Qt signals,
|
||||
;; Qt slots and functions declared Q_INVOKABLE
|
||||
|
||||
(define-qt-wrappers *test*)
|
||||
|
||||
;; now we can call those functions
|
||||
|
||||
(defun test ()
|
||||
;; make new instance
|
||||
(format t "~%Creating instance of 'Test': ~A~%"
|
||||
(new-instance *test* *main-widget* "test-1"))
|
||||
;; call Qt slot
|
||||
(format t "~%Calling 'Test::concat()': ~S~%"
|
||||
(concat *test* (list "one" "two" "three")))
|
||||
;; pass Lisp data
|
||||
(format t "~%Processing complex Lisp data in C++:")
|
||||
(process-data *test* (list 1 "virus" #\Esc 'the #(l a b)))
|
||||
;; call C++ which will call back to Lisp
|
||||
(print-me *test*)
|
||||
(terpri))
|
||||
|
||||
(defun print-qt-object (object)
|
||||
(format t "~%This is an instance of 'Test': ~S~%" object))
|
||||
|
||||
(defun repl ()
|
||||
;; for playing around interactively (taken from '~/eql5/src/eql.cpp')
|
||||
(setf *qtpl* t
|
||||
*break-on-errors* t)
|
||||
(when (directory (in-home "lib/ecl-readline.fas*"))
|
||||
(load (x:check-recompile (in-home "lib/ecl-readline"))))
|
||||
(qsingle-shot 500 'eql::start-read-thread)
|
||||
(eql::exec-with-simple-restart)) ; start event loop
|
||||
|
||||
(progn
|
||||
(test)
|
||||
(qlater 'repl)) ; QLATER: don't block call from 'main.cpp'
|
||||
|
||||
19
Qt_EQL/tutorial/test.pro
Normal file
19
Qt_EQL/tutorial/test.pro
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
QT += widgets printsupport uitools
|
||||
TEMPLATE = app
|
||||
CONFIG += no_keywords release
|
||||
INCLUDEPATH += /usr/local/include
|
||||
LIBS += -L/usr/local/lib -lecl -L$$[QT_INSTALL_LIBS] -leql5
|
||||
TARGET = test
|
||||
DESTDIR = ./
|
||||
OBJECTS_DIR = ./tmp/
|
||||
MOC_DIR = ./tmp/
|
||||
|
||||
win32 {
|
||||
include(../../src/windows.pri)
|
||||
}
|
||||
|
||||
HEADERS += test.h
|
||||
|
||||
SOURCES += test.cpp \
|
||||
main.cpp
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue