add support for QT5, fallback to QT4
This commit is contained in:
parent
c7ddf4a3ef
commit
2beed27cf2
57
.travis.yml
57
.travis.yml
@ -1,5 +1,8 @@
|
|||||||
# vim: set ts=2 et:
|
# vim: set ts=2 et:
|
||||||
|
|
||||||
|
# run xvfb with 32-bit color
|
||||||
|
# xvfb-run -s '-screen 0 1600x1200x24+32' command_goes_here
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
|
||||||
@ -15,13 +18,59 @@ matrix:
|
|||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- cmake
|
- cmake
|
||||||
|
- python-qt4
|
||||||
- pyqt4-dev-tools
|
- pyqt4-dev-tools
|
||||||
- xvfb
|
- xvfb
|
||||||
before_install:
|
before_install:
|
||||||
- sudo pip install lxml
|
- sudo pip install lxml
|
||||||
- make qt4
|
- make qt4py2
|
||||||
- ( xvfb-run python2.7 labelImg.py ) & sleep 10 ; kill $!
|
- ( xvfb-run python2.7 labelImg.py ) & sleep 10 ; kill $!
|
||||||
|
|
||||||
|
# Python 2 + QT5
|
||||||
|
# disabled; can't get it to work
|
||||||
|
#- os: linux
|
||||||
|
# dist: trusty
|
||||||
|
# sudo: required
|
||||||
|
# language: generic
|
||||||
|
# python: "2.7"
|
||||||
|
# env:
|
||||||
|
# - QT=5
|
||||||
|
# addons:
|
||||||
|
# apt:
|
||||||
|
# packages:
|
||||||
|
# - cmake
|
||||||
|
# - pyqt5-dev-tools
|
||||||
|
# - xvfb
|
||||||
|
# before_install:
|
||||||
|
# - sudo apt-get update
|
||||||
|
# - sudo apt-get install -y python-pip
|
||||||
|
# - sudo pip install lxml
|
||||||
|
# - pyrcc5 --help || true # does QT5 support python2 out of the box?
|
||||||
|
# - make qt5py3
|
||||||
|
# - ( xvfb-run python2.7 labelImg.py ) & sleep 10 ; kill $!
|
||||||
|
|
||||||
|
# Python 3 + QT4
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
|
language: generic
|
||||||
|
python: "3.4"
|
||||||
|
env:
|
||||||
|
- QT=4
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- cmake
|
||||||
|
- python3-pyqt4
|
||||||
|
- pyqt4-dev-tools
|
||||||
|
- xvfb
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get install -y python3-pip
|
||||||
|
- sudo pip3 install lxml
|
||||||
|
- make qt4py3
|
||||||
|
- ( xvfb-run python3 labelImg.py ) & sleep 10 ; kill $!
|
||||||
|
|
||||||
# Python 3 + QT5
|
# Python 3 + QT5
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
@ -34,13 +83,13 @@ matrix:
|
|||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- cmake
|
- cmake
|
||||||
|
- pyqt5-dev-tools
|
||||||
- xvfb
|
- xvfb
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- sudo apt-get install -y pyqt5-dev-tools
|
|
||||||
- sudo apt-get install -y python3-pip
|
- sudo apt-get install -y python3-pip
|
||||||
- sudo pip3 install lxml
|
- sudo pip3 install lxml
|
||||||
- make qt5
|
- make qt5py3
|
||||||
- ( xvfb-run python3 labelImg.py ) & sleep 10 ; kill $!
|
- ( xvfb-run python3 labelImg.py ) & sleep 10 ; kill $!
|
||||||
|
|
||||||
# OS X Python 3 + QT5
|
# OS X Python 3 + QT5
|
||||||
@ -61,7 +110,7 @@ matrix:
|
|||||||
- sudo -H easy_install-3.6 lxml || true
|
- sudo -H easy_install-3.6 lxml || true
|
||||||
- python3 -c 'import sys; print(sys.path)'
|
- python3 -c 'import sys; print(sys.path)'
|
||||||
- python3 -c 'import lxml'
|
- python3 -c 'import lxml'
|
||||||
- make qt5
|
- make qt5py3
|
||||||
- python3 -c 'help("modules")'
|
- python3 -c 'help("modules")'
|
||||||
- ( python3 labelImg.py ) & sleep 10 ; kill $!
|
- ( python3 labelImg.py ) & sleep 10 ; kill $!
|
||||||
|
|
||||||
|
|||||||
16
Makefile
16
Makefile
@ -1,6 +1,16 @@
|
|||||||
|
|
||||||
all: resources.py
|
all: qt4
|
||||||
|
|
||||||
%.py: %.qrc
|
qt4: qt4py2
|
||||||
pyrcc4 -o $@ $<
|
|
||||||
|
qt5: qt4py3
|
||||||
|
|
||||||
|
qt4py2:
|
||||||
|
pyrcc4 -py2 -o resources.py resources.qrc
|
||||||
|
|
||||||
|
qt4py3:
|
||||||
|
pyrcc4 -py3 -o resources.py resources.qrc
|
||||||
|
|
||||||
|
qt5py3:
|
||||||
|
pyrcc5 -o resources.py resources.qrc
|
||||||
|
|
||||||
|
|||||||
90
labelImg.py
90
labelImg.py
@ -10,6 +10,17 @@ import subprocess
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
except ImportError:
|
||||||
|
# needed for py3+qt4
|
||||||
|
# ref: http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html
|
||||||
|
# ref: http://stackoverflow.com/questions/21217399/pyqt4-qtcore-qvariant-object-instead-of-a-string
|
||||||
|
if sys.version_info.major >= 3:
|
||||||
|
import sip
|
||||||
|
sip.setapi('QVariant', 2)
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
@ -31,13 +42,22 @@ __appname__ = 'labelImg'
|
|||||||
|
|
||||||
|
|
||||||
def u(x):
|
def u(x):
|
||||||
'''unicode helper'''
|
'''py2/py3 unicode helper'''
|
||||||
try:
|
try:
|
||||||
return x.decode('utf8') # py2
|
return x.decode('utf8') # py2
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return x # py3
|
return x # py3
|
||||||
|
|
||||||
|
|
||||||
|
def have_qstring():
|
||||||
|
'''p3/qt5 get rid of QString wrapper as py3 has native unicode str type'''
|
||||||
|
return not (sys.version_info.major >= 3 or QT_VERSION_STR.startswith('5.'))
|
||||||
|
|
||||||
|
|
||||||
|
def util_qt_strlistclass():
|
||||||
|
return QStringList if have_qstring() else list
|
||||||
|
|
||||||
|
|
||||||
class WindowMixin(object):
|
class WindowMixin(object):
|
||||||
def menu(self, title, actions=None):
|
def menu(self, title, actions=None):
|
||||||
menu = self.menuBar().addMenu(title)
|
menu = self.menuBar().addMenu(title)
|
||||||
@ -56,6 +76,14 @@ class WindowMixin(object):
|
|||||||
return toolbar
|
return toolbar
|
||||||
|
|
||||||
|
|
||||||
|
# PyQt5: TypeError: unhashable type: 'QListWidgetItem'
|
||||||
|
class HashableQListWidgetItem(QListWidgetItem):
|
||||||
|
def __init__(self, *args):
|
||||||
|
super(HashableQListWidgetItem, self).__init__(*args)
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(id(self))
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow, WindowMixin):
|
class MainWindow(QMainWindow, WindowMixin):
|
||||||
FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = list(range(3))
|
FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = list(range(3))
|
||||||
|
|
||||||
@ -332,19 +360,40 @@ class MainWindow(QMainWindow, WindowMixin):
|
|||||||
|
|
||||||
# XXX: Could be completely declarative.
|
# XXX: Could be completely declarative.
|
||||||
# Restore application settings.
|
# Restore application settings.
|
||||||
|
|
||||||
|
if have_qstring():
|
||||||
types = {
|
types = {
|
||||||
'filename': QString,
|
'filename': QString,
|
||||||
'recentFiles': QStringList,
|
'recentFiles': QStringList,
|
||||||
'window/size': QSize,
|
'window/size': QSize,
|
||||||
'window/position': QPoint,
|
'window/position': QPoint,
|
||||||
'window/geometry': QByteArray,
|
'window/geometry': QByteArray,
|
||||||
|
'line/color': QColor,
|
||||||
|
'fill/color': QColor,
|
||||||
|
'advanced': bool,
|
||||||
# Docks and toolbars:
|
# Docks and toolbars:
|
||||||
'window/state': QByteArray,
|
'window/state': QByteArray,
|
||||||
'savedir': QString,
|
'savedir': QString,
|
||||||
'lastOpenDir': QString,
|
'lastOpenDir': QString,
|
||||||
}
|
}
|
||||||
|
else:
|
||||||
|
types = {
|
||||||
|
'filename': str,
|
||||||
|
'recentFiles': list,
|
||||||
|
'window/size': QSize,
|
||||||
|
'window/position': QPoint,
|
||||||
|
'window/geometry': QByteArray,
|
||||||
|
'line/color': QColor,
|
||||||
|
'fill/color': QColor,
|
||||||
|
'advanced': bool,
|
||||||
|
# Docks and toolbars:
|
||||||
|
'window/state': QByteArray,
|
||||||
|
'savedir': str,
|
||||||
|
'lastOpenDir': str,
|
||||||
|
}
|
||||||
|
|
||||||
self.settings = settings = Settings(types)
|
self.settings = settings = Settings(types)
|
||||||
self.recentFiles = list(settings['recentFiles'])
|
self.recentFiles = list(settings.get('recentFiles', []))
|
||||||
size = settings.get('window/size', QSize(600, 500))
|
size = settings.get('window/size', QSize(600, 500))
|
||||||
position = settings.get('window/position', QPoint(0, 0))
|
position = settings.get('window/position', QPoint(0, 0))
|
||||||
self.resize(size)
|
self.resize(size)
|
||||||
@ -358,13 +407,18 @@ class MainWindow(QMainWindow, WindowMixin):
|
|||||||
|
|
||||||
# or simply:
|
# or simply:
|
||||||
#self.restoreGeometry(settings['window/geometry']
|
#self.restoreGeometry(settings['window/geometry']
|
||||||
self.restoreState(settings['window/state'])
|
self.restoreState(settings.get('window/state', QByteArray()))
|
||||||
self.lineColor = QColor(settings.get('line/color', Shape.line_color))
|
self.lineColor = QColor(settings.get('line/color', Shape.line_color))
|
||||||
self.fillColor = QColor(settings.get('fill/color', Shape.fill_color))
|
self.fillColor = QColor(settings.get('fill/color', Shape.fill_color))
|
||||||
Shape.line_color = self.lineColor
|
Shape.line_color = self.lineColor
|
||||||
Shape.fill_color = self.fillColor
|
Shape.fill_color = self.fillColor
|
||||||
|
|
||||||
if settings.get('advanced', QVariant()).toBool():
|
def xbool(x):
|
||||||
|
if isinstance(x, QVariant):
|
||||||
|
return x.toBool()
|
||||||
|
return bool(x)
|
||||||
|
|
||||||
|
if xbool(settings.get('advanced', False)):
|
||||||
self.actions.advancedMode.setChecked(True)
|
self.actions.advancedMode.setChecked(True)
|
||||||
self.toggleAdvancedMode()
|
self.toggleAdvancedMode()
|
||||||
|
|
||||||
@ -540,7 +594,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
|||||||
else:
|
else:
|
||||||
shape = self.canvas.selectedShape
|
shape = self.canvas.selectedShape
|
||||||
if shape:
|
if shape:
|
||||||
self.labelList.setItemSelected(self.shapesToItems[shape], True)
|
self.shapesToItems[shape].setSelected(True)
|
||||||
else:
|
else:
|
||||||
self.labelList.clearSelection()
|
self.labelList.clearSelection()
|
||||||
self.actions.delete.setEnabled(selected)
|
self.actions.delete.setEnabled(selected)
|
||||||
@ -550,7 +604,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
|||||||
self.actions.shapeFillColor.setEnabled(selected)
|
self.actions.shapeFillColor.setEnabled(selected)
|
||||||
|
|
||||||
def addLabel(self, shape):
|
def addLabel(self, shape):
|
||||||
item = QListWidgetItem(shape.label)
|
item = HashableQListWidgetItem(shape.label)
|
||||||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||||||
item.setCheckState(Qt.Checked)
|
item.setCheckState(Qt.Checked)
|
||||||
self.itemsToShapes[item] = shape
|
self.itemsToShapes[item] = shape
|
||||||
@ -694,17 +748,16 @@ class MainWindow(QMainWindow, WindowMixin):
|
|||||||
self.resetState()
|
self.resetState()
|
||||||
self.canvas.setEnabled(False)
|
self.canvas.setEnabled(False)
|
||||||
if filename is None:
|
if filename is None:
|
||||||
filename = self.settings['filename']
|
filename = self.settings.get('filename')
|
||||||
filename = filename
|
|
||||||
|
|
||||||
# Tzutalin 20160906 : Add file list and dock to move faster
|
# Tzutalin 20160906 : Add file list and dock to move faster
|
||||||
# Highlight the file item
|
# Highlight the file item
|
||||||
if filename and self.fileListWidget.count() > 0:
|
if filename and self.fileListWidget.count() > 0:
|
||||||
index = self.mImgList.index(filename)
|
index = self.mImgList.index(filename)
|
||||||
fileWidgetItem = self.fileListWidget.item(index)
|
fileWidgetItem = self.fileListWidget.item(index)
|
||||||
self.fileListWidget.setItemSelected(fileWidgetItem, True)
|
fileWidgetItem.setSelected(True)
|
||||||
|
|
||||||
if QFile.exists(filename):
|
if filename and QFile.exists(filename):
|
||||||
if LabelFile.isLabelFile(filename):
|
if LabelFile.isLabelFile(filename):
|
||||||
try:
|
try:
|
||||||
self.labelFile = LabelFile(filename)
|
self.labelFile = LabelFile(filename)
|
||||||
@ -791,7 +844,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
|||||||
s = self.settings
|
s = self.settings
|
||||||
# If it loads images from dir, don't load it at the begining
|
# If it loads images from dir, don't load it at the begining
|
||||||
if self.dirname is None:
|
if self.dirname is None:
|
||||||
s['filename'] = self.filename if self.filename else QString()
|
s['filename'] = self.filename if self.filename else ''
|
||||||
else:
|
else:
|
||||||
s['filename'] = ''
|
s['filename'] = ''
|
||||||
|
|
||||||
@ -967,7 +1020,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
|||||||
dlg = QFileDialog(self, caption, openDialogPath, filters)
|
dlg = QFileDialog(self, caption, openDialogPath, filters)
|
||||||
dlg.setDefaultSuffix(LabelFile.suffix[1:])
|
dlg.setDefaultSuffix(LabelFile.suffix[1:])
|
||||||
dlg.setAcceptMode(QFileDialog.AcceptSave)
|
dlg.setAcceptMode(QFileDialog.AcceptSave)
|
||||||
dlg.setConfirmOverwrite(True)
|
|
||||||
filenameWithoutExtension = os.path.splitext(self.filename)[0]
|
filenameWithoutExtension = os.path.splitext(self.filename)[0]
|
||||||
dlg.selectFile(filenameWithoutExtension)
|
dlg.selectFile(filenameWithoutExtension)
|
||||||
dlg.setOption(QFileDialog.DontUseNativeDialog, False)
|
dlg.setOption(QFileDialog.DontUseNativeDialog, False)
|
||||||
@ -1108,10 +1160,20 @@ class Settings(object):
|
|||||||
|
|
||||||
def _cast(self, key, value):
|
def _cast(self, key, value):
|
||||||
# XXX: Very nasty way of converting types to QVariant methods :P
|
# XXX: Very nasty way of converting types to QVariant methods :P
|
||||||
t = self.types[key]
|
print('_cast', key, repr(value))
|
||||||
if t != QVariant:
|
t = self.types.get(key)
|
||||||
|
print('t', t)
|
||||||
|
if t is not None and t != QVariant:
|
||||||
|
if t is str:
|
||||||
|
return str(value)
|
||||||
|
else:
|
||||||
|
# XXX: awful
|
||||||
|
try:
|
||||||
method = getattr(QVariant, re.sub('^Q', 'to', t.__name__, count=1))
|
method = getattr(QVariant, re.sub('^Q', 'to', t.__name__, count=1))
|
||||||
return method(value)
|
return method(value)
|
||||||
|
except AttributeError as e:
|
||||||
|
print(e)
|
||||||
|
return value
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
except ImportError:
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
#from PyQt4.QtOpenGL import *
|
#from PyQt4.QtOpenGL import *
|
||||||
|
|
||||||
from shape import Shape
|
from shape import Shape
|
||||||
@ -85,7 +92,7 @@ class Canvas(QWidget):
|
|||||||
|
|
||||||
def mouseMoveEvent(self, ev):
|
def mouseMoveEvent(self, ev):
|
||||||
"""Update line with last point and current coordinates."""
|
"""Update line with last point and current coordinates."""
|
||||||
pos = self.transformPos(ev.posF())
|
pos = self.transformPos(ev.pos())
|
||||||
|
|
||||||
self.restoreCursor()
|
self.restoreCursor()
|
||||||
|
|
||||||
@ -169,7 +176,8 @@ class Canvas(QWidget):
|
|||||||
self.hVertex, self.hShape = None, None
|
self.hVertex, self.hShape = None, None
|
||||||
|
|
||||||
def mousePressEvent(self, ev):
|
def mousePressEvent(self, ev):
|
||||||
pos = self.transformPos(ev.posF())
|
pos = self.transformPos(ev.pos())
|
||||||
|
|
||||||
if ev.button() == Qt.LeftButton:
|
if ev.button() == Qt.LeftButton:
|
||||||
if self.drawing():
|
if self.drawing():
|
||||||
if self.current and self.current.reachMaxPoints() is False:
|
if self.current and self.current.reachMaxPoints() is False:
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
|
try:
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtWidgets import QColorDialog, QDialogButtonBox
|
||||||
|
except ImportError:
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
|
try:
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
except ImportError:
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
@ -32,11 +37,20 @@ class LabelDialog(QDialog):
|
|||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
try:
|
||||||
if self.edit.text().trimmed():
|
if self.edit.text().trimmed():
|
||||||
self.accept()
|
self.accept()
|
||||||
|
except AttributeError:
|
||||||
|
# PyQt5: AttributeError: 'str' object has no attribute 'trimmed'
|
||||||
|
if self.edit.text().strip():
|
||||||
|
self.accept()
|
||||||
|
|
||||||
def postProcess(self):
|
def postProcess(self):
|
||||||
|
try:
|
||||||
self.edit.setText(self.edit.text().trimmed())
|
self.edit.setText(self.edit.text().trimmed())
|
||||||
|
except AttributeError:
|
||||||
|
# PyQt5: AttributeError: 'str' object has no attribute 'trimmed'
|
||||||
|
self.edit.setText(self.edit.text())
|
||||||
|
|
||||||
def popUp(self, text='', move=True):
|
def popUp(self, text='', move=True):
|
||||||
self.edit.setText(text)
|
self.edit.setText(text)
|
||||||
@ -47,6 +61,10 @@ class LabelDialog(QDialog):
|
|||||||
return self.edit.text() if self.exec_() else None
|
return self.edit.text() if self.exec_() else None
|
||||||
|
|
||||||
def listItemClick(self, tQListWidgetItem):
|
def listItemClick(self, tQListWidgetItem):
|
||||||
|
try:
|
||||||
text = tQListWidgetItem.text().trimmed()
|
text = tQListWidgetItem.text().trimmed()
|
||||||
|
except AttributeError:
|
||||||
|
# PyQt5: AttributeError: 'str' object has no attribute 'trimmed'
|
||||||
|
text = tQListWidgetItem.text().strip()
|
||||||
self.edit.setText(text)
|
self.edit.setText(text)
|
||||||
self.validate()
|
self.validate()
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
# Copyright (c) 2016 Tzutalin
|
# Copyright (c) 2016 Tzutalin
|
||||||
# Create by TzuTaLin <tzu.ta.lin@gmail.com>
|
# Create by TzuTaLin <tzu.ta.lin@gmail.com>
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt5.QtGui import QImage
|
||||||
|
except ImportError:
|
||||||
from PyQt4.QtGui import QImage
|
from PyQt4.QtGui import QImage
|
||||||
|
|
||||||
from base64 import b64encode, b64decode
|
from base64 import b64encode, b64decode
|
||||||
from pascal_voc_io import PascalVocWriter
|
from pascal_voc_io import PascalVocWriter
|
||||||
import os.path
|
import os.path
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
from math import sqrt
|
from math import sqrt
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
except ImportError:
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
except ImportError:
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,12 @@
|
|||||||
|
try:
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
except ImportError:
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
|
|
||||||
class ToolBar(QToolBar):
|
class ToolBar(QToolBar):
|
||||||
def __init__(self, title):
|
def __init__(self, title):
|
||||||
super(ToolBar, self).__init__(title)
|
super(ToolBar, self).__init__(title)
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
|
try:
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
except ImportError:
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user