Qt + PySideハイブリッドアプリケーションの作成

おそらく、Qt用のPythonバインダーであるPySideについてご存知でしょう。 同様の機能を提供するPyQtライブラリもありますが、残念ながらGPLまたは商用バージョンに制限されています。 PySideはLGPLライセンスの下で配布されているため、商用アプリケーションでの使用に便利です。



Pythonは非常に迅速に動作するアプリケーションを作成することを可能にし、PySideはQt開発者にそのような機会を提供します。 私の経験では、同様の機能を作成することは、C ++の1.5〜2倍高速です。



多くの場合、C ++ライブラリ(Qtのようなインターフェイス)をPySideアプリケーションにすばやくアタッチする必要があります。逆の場合、タスクはQt(C ++)アプリケーションでPythonスクリプトを使用することです。 どちらの場合も、QtからのAPIクラスの自動サポートと、アプリケーションのQt(C ++)とPython(PySide)部分間の信号スロット接続の可能性が必要です。 残念ながら、この問題は実質的にカバーされておらず、すべてをすぐに行うことは非常に困難です。



そのため、C ++とPythonの両方のパーツで構成され、QtをメインGUIライブラリとして使用するハイブリッドアプリケーションを作成します。



Qt、Python、PySideをインストールする必要があります。

次のディレクトリとファイル構造を作成します。

 HybridApp /
  | -data /
  |  | -global.h
  |  | -typesystem.xml
  |-ハイブリッド/
  |  | -MainWindow.h
  |  | -MainWindow.cpp
  |  | -hybrid.pro
  | -hybridpy /
  |  | -hybridpy.pro
  | -build.sh
  | -Main.py




ハイブリッドディレクトリには、dll / dylib / soにコンパイルされるアプリケーションのC ++部分が含まれます

Katalog hybridpyには、アプリケーションのPython部分にインポートされるC ++部分のラッパー(ラッピング)が含まれています。

データディレクトリには、C ++モジュールで使用される型(typesystem)の説明が含まれています。 これは、オブジェクトをPythonオブジェクトとして表すときのオブジェクトのタイプと機能を記述するXMLファイルです。 タイプシステムの作成に関する詳細については、PySide Webサイト( http://www.pyside.org/docs/shiboken/contents.html )を参照してください



ハイブリッドディレクトリで、アプリケーションのC ++(Qt)部分を作成します。 最も単純なQMainWindowアプリケーションを作成しましょう。

hybrid / hybrid.pro

TEMPLATE = app CONFIG += qt QT += core gui UI_DIR = build RCC_DIR = build MOC_DIR = build OBJECTS_DIR = build HEADERS += MainWindow.h SOURCES += MainWindow.cpp Main.cpp
      
      





ハイブリッド/ Main.cpp

 #include <QtGui> #include "MainWindow.h" int main(int argc, char ** argv) { QApplication app(argc, argv); MainWindow window; window.resize(1000,700); window.show(); return app.exec(); }
      
      





ハイブリッド/ MainWindow.h

 #ifndef MainWindow_H #define MainWindow_H #include <QMainWindow> class QPushButton; class QGraphicsView; class QGraphicsScene; class QPlainTextEdit; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget * parent = 0L); virtual ~MainWindow(); signals: void runPythonCode(QString); private slots: void runPythonCode(); public: QGraphicsView * viewer; QGraphicsScene * scene; QPlainTextEdit * editor; QPushButton * pb_commit; }; #endif // MainWindow_H
      
      





ハイブリッド/ MainWindow.cpp

 #include <QtGui> #include "MainWindow.h" MainWindow::MainWindow(QWidget * parent):QMainWindow(parent) { QSplitter * splitter = new QSplitter; setCentralWidget(splitter); QWidget * editorContent = new QWidget; splitter->addWidget(editorContent); QVBoxLayout * layout = new QVBoxLayout; editorContent->setLayout(layout); editor = new QPlainTextEdit; layout->addWidget(editor); pb_commit = new QPushButton(tr("Commit")); connect(pb_commit, SIGNAL(clicked()), this, SLOT(runPythonCode())); layout->addWidget(pb_commit); scene = new QGraphicsScene(this); viewer = new QGraphicsView; viewer->setScene(scene); splitter->addWidget(viewer); splitter->setSizes(QList<int>() << 400 << 600); } MainWindow::~MainWindow() {;} void MainWindow::runPythonCode() { emit runPythonCode(editor->toPlainText()); }
      
      





コンパイル後、左側のパネルにエディターがあり、右側にキャンバスがあるアプリケーションがあります。

画像



PySide用にこの部分を準備できます。

1. proファイルを変更してdll / dylib / soをビルドします

2. MainWindowクラスのラッパーを作成します

3.入力関数のC main()の代わりにMain.pyを使用します



proファイルの変更は非常に簡単です。TEMPLATEをlibに変更し、リストからmain.cppを削除し、アプリケーションのルート(HybridApp、プロジェクトルート)にTARGETを配置します。

hybrid / hybrid.pro

 TEMPLATE = lib TARGET = ../Hybrid CONFIG += qt QT += core gui UI_DIR = build RCC_DIR = build MOC_DIR = build OBJECTS_DIR = build HEADERS += MainWindow.h SOURCES += MainWindow.cpp
      
      





結果は、 HybridAppフォルダー(プロジェクトルート)のlibHybrid.dylibです。

次に、アプリケーションのC ++部分のラッパーを作成します。 アセンブリは、プロジェクトのルートでbuild.shスクリプトを使用します。 (スクリプトはすべてを収集します:C ++パーツとラッパー)

build.sh

 #!/bin/sh cd hybrid qmake make cd .. cd hybridpy QTGUI_INC=/Library/Frameworks/QtGui.framework/Versions/4/Headers QTCORE_INC=/Library/Frameworks/QtCore.framework/Versions/4/Headers QTTYPESYSTEM=/usr/local/share/PySide/typesystems generatorrunner --generatorSet=shiboken \ ../data/global.h \ --include-paths=../hybrid:$QTCORE_INC:$QTGUI_INC:/usr/include \ --typesystem-paths=../data:$QTTYPESYSTEM \ --output-directory=. \ ../data/typesystem.xml qmake make cd .. rm -rf PyHybrid.so ln -s libPyHybrid.dylib PyHybrid.so
      
      





ラッパーの作成はすべて、generatorrunnerへの1回の呼び出しで、Qtヘッダー、Qtタイプシステム、およびタイプシステム(タイプの説明)へのパスが含まれます。 次にhybridpyフォルダーで、qmakeを呼び出してpythonモジュールをビルドします。

data / typesystem.xml

 <?xml version="1.0"?> <typesystem package="PyHybrid"> <load-typesystem name="typesystem_core.xml" generate="no"/> <load-typesystem name="typesystem_gui.xml" generate="no"/> <object-type name="MainWindow"/> </typesystem>
      
      







data / global.h

 #undef QT_NO_STL #undef QT_NO_STL_WCHAR #ifndef NULL #define NULL 0 #endif #include <MainWindow.h>
      
      





そして、Pythonモジュールを構築するためのプロファイル:

hybridpy / hybridpy.pro

 TEMPLATE = lib QT += core gui INCLUDEPATH += hybrid INCLUDEPATH += ../hybrid INCLUDEPATH += /usr/include/python2.6 INCLUDEPATH += /usr/local/include/shiboken INCLUDEPATH += /usr/local/include/PySide INCLUDEPATH += /usr/local/include/PySide/QtCore INCLUDEPATH += /usr/local/include/PySide/QtGui LIBS += -ldl -lpython2.6 LIBS += -lpyside LIBS += -lshiboken LIBS += -L.. -lHybrid TARGET = ../PyHybrid SOURCES += \ pyhybrid/pyhybrid_module_wrapper.cpp \ pyhybrid/mainwindow_wrapper.cpp \
      
      





おそらくこのアセンブリでは、シボケンなどへのパスを自動的に見つけることができるcmakeを使用する方が良いでしょうが、 qmakeプロジェクトが選択されたファイルを示すためです。



ほとんど準備ができているように見えます-build.shを実行すると、アプリケーションのC ++部分を含むpythonモジュールが作成されます。 Main.pyの両方の部分を接続する瞬間:

Main.py

 import sys from PySide.QtCore import * from PySide.QtGui import * from PyHybrid import * class RunScript(QObject): def __init__(self, mainWindow): QObject.__init__(self) self.mainWindow = mainWindow def runScript(self, script): mainWindow = self.mainWindow exec(str(script)) a = QApplication(sys.argv) w = MainWindow() r = RunScript(w) w.setWindowTitle('PyHybrid') w.resize(1000,800) w.show() a.connect(w, SIGNAL('runPythonCode(QString)'), r.runScript) a.connect(a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()') ) a.exec_()
      
      





このpythonスクリプトを実行すると、C ++アプリケーションの同じウィンドウが表示されますが、多少の違いはあります-エディターに入力されたpythonコードは、アプリケーションのC ++オブジェクトにアクセスしてアプリケーションで直接実行できるようになりました。



少しコードを試してみましょう:

 mainWindow.statusBar().show()
      
      





また、アプリケーションにはステータスバーがあります。

Canvasの背景を変更しますか?

 mainWindow.scene.setBackgroundBrush(QColor('#e0e0ff'))
      
      





オブジェクトを作成できます:

 li1 = QGraphicsLineItem(10,10, 500,500) li1.setPen(QPen(QBrush(QColor("#ff0000")), 3.0, Qt.DashLine)) mainWindow.scene.addItem(li1)
      
      





次に、実行時に新しいクラスを作成できますが、なぜですか?

 mainWindow.viewer.setRenderHint(QPainter.Antialiasing) class MyItem(QGraphicsItem): def boundingRect(self): return QRectF(-100,-100,200,200) def paint(self, painter, option, widget): g = QLinearGradient(-100,-100, 100,100) g.setColorAt(0, QColor('#00ff00')) g.setColorAt(1, QColor('#ffffff')) painter.setBrush(g) p = QPen(QBrush(QColor("#ff0000")), 4, Qt.DashLine) painter.setPen(p) painter.drawRoundedRect(-100,-100,200,200, 30,30) my1 = MyItem() mainWindow.scene.addItem(my1) my1.setPos(200,200)
      
      





画像



小さなアプリケーションには小さなユニークな機会がありました:実行時に直接プログラムでき、このプログラミングは既存のAPIに制限されませんが、Pythonで独自のクラスを作成して、それらを共通インターフェース(たとえばQOBject / QWidget )があるC ++パーツに転送できます処理して使用できます。



Qt + PySideハイブリダイゼーションの使用は非常に広く、ゲーム開発では、実行時に何かを直接修正し、ゲーム内のオブジェクトのスクリプトを作成する機能が必要になることがよくあります。 さらに、PySideの助けを借りて、新しいクラスをすばやく作成し、アイデアをテストしてからC ++に転送できます(または速度に重要なフラグメントのみをC ++に非常に迅速に転送できます)。



上記のアプリケーションに関しては、アプリケーションが実行時に直接エンコードおよび変更される場合、プログラミングに対するわずかに異なるアプローチを示しています。 もちろん、実行されたすべてのフラグメントを自動的にファイルに保存する必要があります。そうしないと、アプリケーションの停止後にすべてのコードが消えます。



All Articles