mirror of https://gitlab.com/ita1024/waf.git
Merge pull request #1790 from fedepell/pyqt5-separate
pyqt5 extra to support qt5 files to python conversion
This commit is contained in:
commit
1308001a9e
|
@ -0,0 +1,2 @@
|
|||
change me to see qrc dependencies!
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file alias="test.txt">res/test.txt</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,130 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>myfirstgui</class>
|
||||
<widget class="QDialog" name="myfirstgui">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>411</width>
|
||||
<height>247</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>My First Gui!</string>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>210</y>
|
||||
<width>381</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="myTextInput">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>101</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>120</x>
|
||||
<y>10</y>
|
||||
<width>281</width>
|
||||
<height>192</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="clearBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>180</y>
|
||||
<width>101</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="addBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>40</y>
|
||||
<width>101</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>myfirstgui</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>258</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>myfirstgui</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>clearBtn</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>listWidget</receiver>
|
||||
<slot>clear()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>177</x>
|
||||
<y>253</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>177</x>
|
||||
<y>174</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -0,0 +1,24 @@
|
|||
import sys
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from firstgui import Ui_myfirstgui
|
||||
|
||||
class MyFirstGuiProgram(Ui_myfirstgui):
|
||||
def __init__(self, dialog):
|
||||
Ui_myfirstgui.__init__(self)
|
||||
self.setupUi(dialog)
|
||||
|
||||
# Connect "add" button with a custom function (addInputTextToListbox)
|
||||
self.addBtn.clicked.connect(self.addInputTextToListbox)
|
||||
|
||||
def addInputTextToListbox(self):
|
||||
txt = self.myTextInput.text()
|
||||
self.listWidget.addItem(txt)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
dialog = QtWidgets.QDialog()
|
||||
|
||||
prog = MyFirstGuiProgram(dialog)
|
||||
|
||||
dialog.show()
|
||||
sys.exit(app.exec_())
|
|
@ -0,0 +1,29 @@
|
|||
#! /usr/bin/env python
|
||||
# encoding: utf-8#
|
||||
# Federico Pellegrin, 2016 (fedepell)
|
||||
|
||||
"""
|
||||
Python QT5 helper tools example:
|
||||
converts QT5 Designer tools files (UI and QRC) into python files with
|
||||
the appropriate tools (pyqt5 and pyside2 searched) and manages their
|
||||
python compilation and installation using standard python waf Tool
|
||||
|
||||
"""
|
||||
def options(opt):
|
||||
# Load also python to demonstrate mixed calls
|
||||
opt.load('python pyqt5')
|
||||
|
||||
def configure(conf):
|
||||
# Load also python to demonstrate mixed calls
|
||||
conf.load('python pyqt5')
|
||||
conf.check_python_version((2,7,4))
|
||||
|
||||
def build(bld):
|
||||
# Demostrates mixed usage of py and pyqt5 module, and tests also install_path and install_from
|
||||
# (since generated files go into build it has to be reset inside the pyqt5 tool)
|
||||
bld(features="py pyqt5", source="src/sample.py src/firstgui.ui", install_path="${PREFIX}/play/", install_from="src/")
|
||||
|
||||
# Simple usage on a resource file. If a file referenced inside the resource changes it will be rebuilt
|
||||
# as the qrc XML is parsed and dependencies are calculated
|
||||
bld(features="pyqt5", source="sampleRes.qrc")
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Federico Pellegrin, 2016 (fedepell) adapted for Python
|
||||
|
||||
"""
|
||||
This tool helps with finding Python Qt5 tools and libraries,
|
||||
and provides translation from QT5 files to Python code.
|
||||
|
||||
The following snippet illustrates the tool usage::
|
||||
|
||||
def options(opt):
|
||||
opt.load('py pyqt5')
|
||||
|
||||
def configure(conf):
|
||||
conf.load('py pyqt5')
|
||||
|
||||
def build(bld):
|
||||
bld(
|
||||
features = 'py pyqt5',
|
||||
source = 'main.py textures.qrc aboutDialog.ui',
|
||||
)
|
||||
|
||||
Here, the UI description and resource files will be processed
|
||||
to generate code.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Load the "pyqt5" tool.
|
||||
|
||||
Add into the sources list also the qrc resources files or ui5
|
||||
definition files and they will be translated into python code
|
||||
with the system tools (PyQt5 or pyside2 are searched in this
|
||||
order) and then compiled
|
||||
"""
|
||||
|
||||
try:
|
||||
from xml.sax import make_parser
|
||||
from xml.sax.handler import ContentHandler
|
||||
except ImportError:
|
||||
has_xml = False
|
||||
ContentHandler = object
|
||||
else:
|
||||
has_xml = True
|
||||
|
||||
import os, sys
|
||||
from waflib.Tools import python
|
||||
from waflib import Task, Utils, Options, Errors, Context
|
||||
from waflib.TaskGen import feature, extension
|
||||
from waflib.Configure import conf
|
||||
from waflib import Logs
|
||||
|
||||
EXT_RCC = ['.qrc']
|
||||
"""
|
||||
File extension for the resource (.qrc) files
|
||||
"""
|
||||
|
||||
EXT_UI = ['.ui']
|
||||
"""
|
||||
File extension for the user interface (.ui) files
|
||||
"""
|
||||
|
||||
|
||||
class XMLHandler(ContentHandler):
|
||||
"""
|
||||
Parses ``.qrc`` files
|
||||
"""
|
||||
def __init__(self):
|
||||
self.buf = []
|
||||
self.files = []
|
||||
def startElement(self, name, attrs):
|
||||
if name == 'file':
|
||||
self.buf = []
|
||||
def endElement(self, name):
|
||||
if name == 'file':
|
||||
self.files.append(str(''.join(self.buf)))
|
||||
def characters(self, cars):
|
||||
self.buf.append(cars)
|
||||
|
||||
@extension(*EXT_RCC)
|
||||
def create_pyrcc_task(self, node):
|
||||
"Creates rcc and py task for ``.qrc`` files"
|
||||
rcnode = node.change_ext('.py')
|
||||
self.create_task('pyrcc', node, rcnode)
|
||||
if getattr(self, 'install_from', None):
|
||||
self.install_from = self.install_from.get_bld()
|
||||
else:
|
||||
self.install_from = self.path.get_bld()
|
||||
self.install_path = getattr(self, 'install_path', '${PYTHONDIR}')
|
||||
self.process_py(rcnode)
|
||||
|
||||
@extension(*EXT_UI)
|
||||
def create_pyuic_task(self, node):
|
||||
"Create uic tasks and py for user interface ``.ui`` definition files"
|
||||
uinode = node.change_ext('.py')
|
||||
self.create_task('ui5py', node, uinode)
|
||||
if getattr(self, 'install_from', None):
|
||||
self.install_from = self.install_from.get_bld()
|
||||
else:
|
||||
self.install_from = self.path.get_bld()
|
||||
self.install_path = getattr(self, 'install_path', '${PYTHONDIR}')
|
||||
self.process_py(uinode)
|
||||
|
||||
@extension('.ts')
|
||||
def add_pylang(self, node):
|
||||
"""Adds all the .ts file into ``self.lang``"""
|
||||
self.lang = self.to_list(getattr(self, 'lang', [])) + [node]
|
||||
|
||||
@feature('pyqt5')
|
||||
def apply_pyqt5(self):
|
||||
"""
|
||||
The additional parameters are:
|
||||
|
||||
:param lang: list of translation files (\*.ts) to process
|
||||
:type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension
|
||||
:param langname: if given, transform the \*.ts files into a .qrc files to include in the binary file
|
||||
:type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension
|
||||
"""
|
||||
if getattr(self, 'lang', None):
|
||||
qmtasks = []
|
||||
for x in self.to_list(self.lang):
|
||||
if isinstance(x, str):
|
||||
x = self.path.find_resource(x + '.ts')
|
||||
qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.qm')))
|
||||
|
||||
|
||||
if getattr(self, 'langname', None):
|
||||
qmnodes = [x.outputs[0] for x in qmtasks]
|
||||
rcnode = self.langname
|
||||
if isinstance(rcnode, str):
|
||||
rcnode = self.path.find_or_declare(rcnode + '.qrc')
|
||||
t = self.create_task('qm2rcc', qmnodes, rcnode)
|
||||
k = create_pyrcc_task(self, t.outputs[0])
|
||||
|
||||
|
||||
class pyrcc(Task.Task):
|
||||
"""
|
||||
Processes ``.qrc`` files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${QT_PYRCC} ${SRC} -o ${TGT}'
|
||||
ext_out = ['.py']
|
||||
|
||||
def rcname(self):
|
||||
return os.path.splitext(self.inputs[0].name)[0]
|
||||
|
||||
def scan(self):
|
||||
"""Parse the *.qrc* files"""
|
||||
if not has_xml:
|
||||
Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!')
|
||||
return ([], [])
|
||||
|
||||
parser = make_parser()
|
||||
curHandler = XMLHandler()
|
||||
parser.setContentHandler(curHandler)
|
||||
fi = open(self.inputs[0].abspath(), 'r')
|
||||
try:
|
||||
parser.parse(fi)
|
||||
finally:
|
||||
fi.close()
|
||||
|
||||
nodes = []
|
||||
names = []
|
||||
root = self.inputs[0].parent
|
||||
for x in curHandler.files:
|
||||
nd = root.find_resource(x)
|
||||
if nd: nodes.append(nd)
|
||||
else: names.append(x)
|
||||
return (nodes, names)
|
||||
|
||||
|
||||
class ui5py(Task.Task):
|
||||
"""
|
||||
Processes ``.ui`` files for python
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${QT_PYUIC} ${SRC} -o ${TGT}'
|
||||
ext_out = ['.py']
|
||||
|
||||
class ts2qm(Task.Task):
|
||||
"""
|
||||
Generates ``.qm`` files from ``.ts`` files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'
|
||||
|
||||
class qm2rcc(Task.Task):
|
||||
"""
|
||||
Generates ``.qrc`` files from ``.qm`` files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
after = 'ts2qm'
|
||||
def run(self):
|
||||
"""Create a qrc file including the inputs"""
|
||||
txt = '\n'.join(['<file>%s</file>' % k.path_from(self.outputs[0].parent) for k in self.inputs])
|
||||
code = '<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>' % txt
|
||||
self.outputs[0].write(code)
|
||||
|
||||
def configure(self):
|
||||
self.find_pyqt5_binaries()
|
||||
|
||||
# warn about this during the configuration too
|
||||
if not has_xml:
|
||||
Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!')
|
||||
|
||||
|
||||
|
||||
@conf
|
||||
def find_pyqt5_binaries(self):
|
||||
"""
|
||||
Detects PyQt5 or pyside2 programs such as pyuic5/pyside2-uic, pyrcc5/pyside2-rcc
|
||||
"""
|
||||
env = self.env
|
||||
|
||||
self.find_program(['pyuic5','pyside2-uic'], var='QT_PYUIC')
|
||||
if not env.QT_PYUIC:
|
||||
self.fatal('cannot find the uic compiler for python for qt5')
|
||||
|
||||
self.find_program(['pyrcc5','pyside2-rcc'], var='QT_PYRCC')
|
||||
if not env.QT_PYUIC:
|
||||
self.fatal('cannot find the rcc compiler for python for qt5')
|
||||
|
||||
self.find_program(['pylupdate5', 'pyside2-lupdate'], var='QT_PYLUPDATE')
|
||||
self.find_program(['lrelease-qt5', 'lrelease'], var='QT_LRELEASE')
|
||||
|
Loading…
Reference in New Issue