개정판 2281dace
issue #000: remove opencv module
Change-Id: I269f4ccc5449d46c5b12f57b440b526c8441cad9
HYTOS/HYTOS/AppDocData.py | ||
---|---|---|
89 | 89 |
self.imgWidth = 0 |
90 | 90 |
self.imgHeight = 0 |
91 | 91 |
self._OCRData = None |
92 |
self._imgSrc = None |
|
93 | 92 |
|
94 | 93 |
self._areas = [] |
95 | 94 |
self.equipments = [] |
... | ... | |
139 | 138 |
self.imgName = None |
140 | 139 |
self.imgWidth = 0 |
141 | 140 |
self.imgHeight = 0 |
142 |
self._imgSrc = None |
|
143 | 141 |
|
144 | 142 |
self._areas.clear() |
145 | 143 |
self.equipments.clear() |
... | ... | |
270 | 268 |
self.imgName = os.path.splitext(os.path.basename(self._imgFilePath))[0] |
271 | 269 |
|
272 | 270 |
''' |
273 |
@brief getter of imgSrc |
|
274 |
@author humkyung |
|
275 |
@date 2018.07.30 |
|
276 |
''' |
|
277 |
@property |
|
278 |
def imgSrc(self): |
|
279 |
import cv2 |
|
280 |
|
|
281 |
if self._imgSrc is None and self._imgFilePath is not None and os.path.isfile(self._imgFilePath): |
|
282 |
self._imgSrc = cv2.cvtColor(cv2.imread(self._imgFilePath), cv2.COLOR_BGR2GRAY) |
|
283 |
kernel = np.array([[-1,-1,-1], |
|
284 |
[-1, 9,-1], |
|
285 |
[-1,-1,-1]]) |
|
286 |
self._imgSrc = cv2.filter2D(self._imgSrc, -1, kernel) |
|
287 |
#blur = cv2.GaussianBlur(self._imgSrc , (5,5), 0) |
|
288 |
#smooth = cv2.addWeighted(blur, 1.5, self._imgSrc, -0.5, 0) |
|
289 |
#self._imgSrc = cv2.threshold(smooth, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1] |
|
290 |
self._imgSrc = cv2.threshold(self._imgSrc, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1] |
|
291 |
|
|
292 |
return self._imgSrc |
|
293 |
|
|
294 |
''' |
|
295 |
@brief setter of imgSrc |
|
296 |
@author humkyung |
|
297 |
@date 2018.07.30 |
|
298 |
''' |
|
299 |
@imgSrc.setter |
|
300 |
def imgSrc(self, value): |
|
301 |
self._imgSrc = value |
|
302 |
|
|
303 |
''' |
|
304 |
@brief reset imgSrc |
|
305 |
@author humkyung |
|
306 |
@date 2018.07.30 |
|
307 |
''' |
|
308 |
def resetImgSrc(self): |
|
309 |
self._imgSrc = None |
|
310 |
|
|
311 |
''' |
|
312 | 271 |
@brief getter of line type configs |
313 | 272 |
@author humkyung |
314 | 273 |
@date 2018.06.28 |
HYTOS/HYTOS/Commands/AreaZoomCommand.py | ||
---|---|---|
11 | 11 |
except ImportError: |
12 | 12 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
13 | 13 |
|
14 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
|
15 |
|
|
16 | 14 |
class AreaZoomCommand(AbstractCommand.AbstractCommand): |
17 | 15 |
onRejected = pyqtSignal(AbstractCommand.AbstractCommand) |
18 | 16 |
|
HYTOS/HYTOS/Commands/CreateSymbolCommand.py | ||
---|---|---|
1 |
import os.path |
|
2 |
import AbstractCommand |
|
3 |
try: |
|
4 |
from PyQt5.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR |
|
5 |
from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QCursor |
|
6 |
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog |
|
7 |
except ImportError: |
|
8 |
try: |
|
9 |
from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR |
|
10 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QCursor |
|
11 |
except ImportError: |
|
12 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
13 |
import sys, os |
|
14 |
from AppDocData import AppDocData |
|
15 |
import cv2 |
|
16 |
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) |
|
17 |
import SymbolEditorDialog |
|
18 |
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '\\Shapes') |
|
19 |
from SymbolSvgItem import SymbolSvgItem |
|
20 |
|
|
21 |
class CreateSymbolCommand(AbstractCommand.AbstractCommand): |
|
22 |
''' |
|
23 |
@history 2018.05.04 Jeongwoo Add Parameter |
|
24 |
''' |
|
25 |
def __init__(self, imageViewer, resultTreeWidget, symbolTreeWidget): |
|
26 |
super(CreateSymbolCommand, self).__init__(imageViewer) |
|
27 |
self.name = 'CreateSymbol' |
|
28 |
self.imageViewer.setCursor(QCursor(Qt.CrossCursor)) |
|
29 |
self.resultTreeWidget = resultTreeWidget |
|
30 |
self.symbolTreeWidget = symbolTreeWidget |
|
31 |
|
|
32 |
''' |
|
33 |
@brief crop image by rectangle selected by user |
|
34 |
@history 2018.05.02 Jeongwoo Init self.offsetX and self.offsetY |
|
35 |
Add QtImageViewer.startPointChanged.emit |
|
36 |
2018.05.03 Jeongwoo Make Svg/Image File Path by SymbolBase.getSvgFileFullePath() and SymbolBase.getImageFileFullPath() |
|
37 |
2018.05.04 Jeongwoo Add self.symbolTreeWidget.initTreeWidget() |
|
38 |
2018.06.08 Jeongwoo Add Parameter on SymbolSvgItem.buildItem() |
|
39 |
''' |
|
40 |
def execute(self, param): |
|
41 |
event = param[1] |
|
42 |
scenePos = param[2] |
|
43 |
if 'mousePressEvent' == param[0] and event.button() == Qt.LeftButton: |
|
44 |
self.imageViewer.setDragMode(QGraphicsView.RubberBandDrag) |
|
45 |
self.imageViewer.leftMouseButtonPressed.emit(scenePos.x(), scenePos.y()) |
|
46 |
QGraphicsView.mousePressEvent(self.imageViewer, event) |
|
47 |
elif 'mouseReleaseEvent' == param[0] and event.button() == Qt.LeftButton: |
|
48 |
try: |
|
49 |
QGraphicsView.mouseReleaseEvent(self.imageViewer, event) |
|
50 |
viewBBox = self.imageViewer.zoomStack[-1] if len(self.imageViewer.zoomStack) else self.imageViewer.sceneRect() |
|
51 |
selectionBBox = self.imageViewer.scene.selectionArea().boundingRect().intersected(viewBBox) |
|
52 |
if selectionBBox.isValid(): |
|
53 |
croppedImage = self.imageViewer.image().copy(selectionBBox.toAlignedRect()) |
|
54 |
symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self.imageViewer, croppedImage, AppDocData.instance().getCurrentProject()) |
|
55 |
(isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog() |
|
56 |
self.symbolTreeWidget.initSymbolTreeWidget() |
|
57 |
if isAccepted: |
|
58 |
if isImmediateInsert: |
|
59 |
svgPath = newSym.getSvgFileFullPath() |
|
60 |
img = cv2.imread(newSym.getImageFileFullPath(), 1) |
|
61 |
w, h = (0, 0) |
|
62 |
if len(img.shape[::-1]) == 2: |
|
63 |
w, h = img.shape[::-1] |
|
64 |
else: |
|
65 |
_chan, w, h = img.shape[::-1] |
|
66 |
svg = SymbolSvgItem(svgPath) |
|
67 |
svg.buildItem(newSym.getName(), newSym.getType(), 0, [selectionBBox.x()+offsetX, selectionBBox.y()+offsetY], [w, h], [float(x) for x in newSym.getOriginalPoint().split(',')], [(float(x.split(',')[0]), float(x.split(',')[1])) for x in newSym.getConnectionPoint().split('/')], newSym.getBaseSymbol(), newSym.getAdditionalSymbol()) |
|
68 |
|
|
69 |
#### lambda param=svg : bind 'svg' object to lambda('param') |
|
70 |
#### If case of 'lambda svg=svg:', function uses the 'svg' value bound to lambda |
|
71 |
svg.clicked.connect(lambda param=svg: self.resultTreeWidget.findItem(param)) |
|
72 |
svg.transfer.onRemoved.connect(self.resultTreeWidget.itemRemoved) |
|
73 |
svg.addSvgItemToScene(self.imageViewer.scene) |
|
74 |
for connector in svg.connectors: |
|
75 |
self.imageViewer.scene.addItem(connector) |
|
76 |
|
|
77 |
finally: |
|
78 |
self.imageViewer.setDragMode(QGraphicsView.NoDrag) |
|
79 |
self.imageViewer.leftMouseButtonReleased.emit(scenePos.x(), scenePos.y()) |
|
80 |
pass |
|
81 |
self.isTreated = False |
|
82 |
|
|
83 |
def undo(self): |
|
84 |
pass |
|
85 |
|
|
86 |
def redo(self): |
|
87 |
pass |
HYTOS/HYTOS/Commands/FenceCommand.py | ||
---|---|---|
10 | 10 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QCursor |
11 | 11 |
except ImportError: |
12 | 12 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
13 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
|
14 | 13 |
|
15 | 14 |
class FenceCommand(AbstractCommand.AbstractCommand): |
16 | 15 |
onSuccess = pyqtSignal(float, float, float, float) |
HYTOS/HYTOS/Commands/FitImageCommand.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 |
|
|
3 |
import os.path |
|
4 |
import sys |
|
5 |
|
|
6 |
try: |
|
7 |
from PyQt5.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR, QRect |
|
8 |
from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QCursor, QColor |
|
9 |
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog |
|
10 |
except ImportError: |
|
11 |
try: |
|
12 |
from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR, QRect |
|
13 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QCursor, QColor |
|
14 |
except ImportError: |
|
15 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
16 |
import numpy as np |
|
17 |
|
|
18 |
import AbstractCommand |
|
19 |
|
|
20 |
class FitImageCommand(AbstractCommand.AbstractCommand): |
|
21 |
WHITE_PIXEL = (255, 255, 255, 255) |
|
22 |
BLACK_PIXEL = (0, 0, 0, 255) |
|
23 |
|
|
24 |
''' |
|
25 |
@history 2018.05.02 Jeongwoo Change variable name (adjustX, adjustY → offsetX, offsetY) |
|
26 |
''' |
|
27 |
def __init__(self, imageViewer): |
|
28 |
super(FitImageCommand, self).__init__(imageViewer) |
|
29 |
self.name = 'FitImage' |
|
30 |
self.imageViewer.setCursor(QCursor(Qt.CrossCursor)) |
|
31 |
|
|
32 |
boundingBox = self.getImageBoundingBox() |
|
33 |
croppedImage = self.imageViewer.image().copy(boundingBox) |
|
34 |
self.imageViewer.setImage(croppedImage) |
|
35 |
self.offsetX = boundingBox.left() |
|
36 |
self.offsetY = boundingBox.top() |
|
37 |
|
|
38 |
''' |
|
39 |
@history 2018.05.02 Jeongwoo Change method name (getAdjust → getOffset) |
|
40 |
''' |
|
41 |
def getOffset(self): |
|
42 |
return (self.offsetX, self.offsetY) |
|
43 |
|
|
44 |
def convertQImageToMat(self, incomingImage): |
|
45 |
''' Converts a QImage into an opencv MAT format ''' |
|
46 |
|
|
47 |
try: |
|
48 |
incomingImage = incomingImage.convertToFormat(QImage.Format_RGBA8888) |
|
49 |
|
|
50 |
width = incomingImage.width() |
|
51 |
height = incomingImage.height() |
|
52 |
|
|
53 |
ptr = incomingImage.bits() |
|
54 |
ptr.setsize(incomingImage.byteCount()) |
|
55 |
arr = np.array(ptr).reshape(height, width, 4) # Copies the data |
|
56 |
return arr |
|
57 |
except Exception as ex: |
|
58 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
|
59 |
|
|
60 |
''' |
|
61 |
@brief get minimum image bouding box |
|
62 |
@author jeongwoo |
|
63 |
@date |
|
64 |
''' |
|
65 |
def getImageBoundingBox(self): |
|
66 |
import cv2 |
|
67 |
black = 0 |
|
68 |
|
|
69 |
image = self.convertQImageToMat(self.imageViewer.image()) |
|
70 |
image = cv2.threshold(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1] |
|
71 |
indices = np.where(image == [0]) |
|
72 |
minx, maxx = min(indices[1]), max(indices[1]) |
|
73 |
miny, maxy = min(indices[0]), max(indices[0]) |
|
74 |
|
|
75 |
return QRect(minx, miny, (maxx - minx) + 1, (maxy - miny) + 1) |
|
76 |
|
|
77 |
''' |
|
78 |
@brief DO NOTHING |
|
79 |
''' |
|
80 |
def execute(self, param): |
|
81 |
pass |
|
82 |
|
|
83 |
def undo(self): |
|
84 |
pass |
|
85 |
|
|
86 |
def redo(self): |
|
87 |
pass |
HYTOS/HYTOS/Commands/PlaceLineCommand.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 |
""" |
|
3 |
This is place line module |
|
4 |
""" |
|
5 |
|
|
6 |
import os.path |
|
7 |
import AbstractCommand |
|
8 |
try: |
|
9 |
from PyQt5.QtCore import Qt, QPointF, QRectF, pyqtSignal, QT_VERSION_STR |
|
10 |
from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QCursor, QTransform |
|
11 |
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog |
|
12 |
except ImportError: |
|
13 |
try: |
|
14 |
from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR |
|
15 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QCursor |
|
16 |
except ImportError: |
|
17 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
18 |
|
|
19 |
class PlaceLineCommand(AbstractCommand.AbstractCommand): |
|
20 |
""" |
|
21 |
This is place line class |
|
22 |
""" |
|
23 |
|
|
24 |
onSuccess = pyqtSignal() |
|
25 |
onRejected = pyqtSignal(AbstractCommand.AbstractCommand) |
|
26 |
|
|
27 |
def __init__(self, imageViewer): |
|
28 |
super(PlaceLineCommand, self).__init__(imageViewer) |
|
29 |
self.name = 'PlaceLine' |
|
30 |
self.imageViewer.setCursor(QCursor(Qt.CrossCursor)) |
|
31 |
|
|
32 |
self._polyline = None |
|
33 |
|
|
34 |
''' |
|
35 |
@brief reset command status |
|
36 |
@author humkyung |
|
37 |
@date 2018.07.23 |
|
38 |
''' |
|
39 |
def reset(self): |
|
40 |
self._polyline = None |
|
41 |
|
|
42 |
''' |
|
43 |
@brief place a line |
|
44 |
@author humkyung |
|
45 |
@date 2018.07.23 |
|
46 |
''' |
|
47 |
def execute(self, param): |
|
48 |
import shapely |
|
49 |
from EngineeringConnectorItem import QEngineeringConnectorItem |
|
50 |
from SymbolSvgItem import SymbolSvgItem |
|
51 |
from EngineeringPolylineItem import QEngineeringPolylineItem |
|
52 |
from EngineeringLineItem import QEngineeringLineItem |
|
53 |
|
|
54 |
self.isTreated = False |
|
55 |
|
|
56 |
event = param[1] |
|
57 |
if 'mousePressEvent' == param[0] and event.button() == Qt.LeftButton: |
|
58 |
if self._polyline is None: |
|
59 |
selected = self.imageViewer.scene.itemAt(param[2], QTransform()) |
|
60 |
if selected is not None and type(selected) is QEngineeringConnectorItem: |
|
61 |
self._polyline = QEngineeringPolylineItem() |
|
62 |
self._polyline._vertices.append(selected.center()) |
|
63 |
self.imageViewer.scene.addItem(self._polyline) |
|
64 |
self.imageViewer.scene.setFocusItem(self._polyline) |
|
65 |
elif selected is not None and type(selected) is QEngineeringLineItem: |
|
66 |
length = selected.length()*0.5 |
|
67 |
dir = selected.perpendicular() |
|
68 |
start = [param[2].x() - dir[0]*length, param[2].y() - dir[1]*length] |
|
69 |
end = [param[2].x() + dir[0]*length, param[2].y() + dir[1]*length] |
|
70 |
pt = selected.intersection([start, end]) |
|
71 |
if (pt is not None) and (type(pt) == shapely.geometry.point.Point): |
|
72 |
self._polyline = QEngineeringPolylineItem() |
|
73 |
self._polyline._vertices.append([pt.x, pt.y]) |
|
74 |
self.imageViewer.scene.addItem(self._polyline) |
|
75 |
self.imageViewer.scene.setFocusItem(self._polyline) |
|
76 |
else: |
|
77 |
try: |
|
78 |
QGraphicsView.mouseReleaseEvent(self.imageViewer, event) |
|
79 |
self._polyline._vertices.append(self._polyline._pt) |
|
80 |
self._polyline.update() |
|
81 |
finally: |
|
82 |
pass |
|
83 |
elif 'mouseReleaseEvent' == param[0] and event.button() == Qt.RightButton and self._polyline is not None: |
|
84 |
self.onSuccess.emit() |
|
85 |
elif 'mouseReleaseEvent' == param[0] and event.button() == Qt.RightButton and self._polyline is None: |
|
86 |
self.onRejected.emit(self) |
|
87 |
elif 'mouseMoveEvent' == param[0] and self._polyline is not None: |
|
88 |
self._polyline.onMouseMoved(event, param[2]) |
|
89 |
elif 'keyPressEvent' == param[0]: |
|
90 |
if event.key() == Qt.Key_Escape: |
|
91 |
self.onRejected.emit(self) |
|
92 |
self.isTreated = False |
|
93 |
elif event.key() == Qt.Key_A: # axis lock mode |
|
94 |
self._polyline.drawing_mode = QEngineeringPolylineItem.AXIS_MODE |
|
95 |
elif event.key() == Qt.Key_F: # free drawing mode |
|
96 |
self._polyline.drawing_mode = QEngineeringPolylineItem.FREE_MODE |
|
97 |
|
|
98 |
def undo(self): |
|
99 |
pass |
|
100 |
|
|
101 |
def redo(self): |
|
102 |
pass |
HYTOS/HYTOS/Commands/PlacePolygonCommand.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 |
import os.path |
|
3 |
import AbstractCommand |
|
4 |
try: |
|
5 |
from PyQt5.QtCore import * |
|
6 |
from PyQt5.QtGui import * |
|
7 |
from PyQt5.QtWidgets import * |
|
8 |
except ImportError: |
|
9 |
try: |
|
10 |
from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR |
|
11 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QCursor |
|
12 |
except ImportError: |
|
13 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
14 |
|
|
15 |
class PlacePolygonCommand(AbstractCommand.AbstractCommand): |
|
16 |
""" |
|
17 |
This is place polygon class |
|
18 |
""" |
|
19 |
|
|
20 |
onSuccess = pyqtSignal() |
|
21 |
onRejected = pyqtSignal(AbstractCommand.AbstractCommand) |
|
22 |
|
|
23 |
def __init__(self, imageViewer): |
|
24 |
super(PlacePolygonCommand, self).__init__(imageViewer) |
|
25 |
self.name = 'PlaceLine' |
|
26 |
self.imageViewer.setCursor(QCursor(Qt.CrossCursor)) |
|
27 |
|
|
28 |
self._polyline = None |
|
29 |
|
|
30 |
|
|
31 |
|
|
32 |
''' |
|
33 |
@brief reset command status |
|
34 |
@author humkyung |
|
35 |
@date 2018.07.23 |
|
36 |
''' |
|
37 |
def reset(self): |
|
38 |
self._polyline = None |
|
39 |
|
|
40 |
''' |
|
41 |
@brief place a line |
|
42 |
@author humkyung |
|
43 |
@date 2018.07.23 |
|
44 |
''' |
|
45 |
def execute(self, param): |
|
46 |
import shapely |
|
47 |
from EngineeringConnectorItem import QEngineeringConnectorItem |
|
48 |
from EngineeringPolylineItem import QEngineeringPolylineItem |
|
49 |
from EngineeringLineItem import QEngineeringLineItem |
|
50 |
|
|
51 |
self.isTreated = False |
|
52 |
|
|
53 |
event = param[1] |
|
54 |
if 'mousePressEvent' == param[0] and event.button() == Qt.LeftButton: |
|
55 |
try: |
|
56 |
if self._polyline is None: |
|
57 |
self._polyline = QEngineeringPolylineItem() |
|
58 |
self._polyline.drawing_mode = QEngineeringPolylineItem.FREE_MODE |
|
59 |
self._polyline._vertices.append((param[2].x(), param[2].y())) |
|
60 |
self.imageViewer.scene.addItem(self._polyline) |
|
61 |
self.imageViewer.scene.setFocusItem(self._polyline) |
|
62 |
else: |
|
63 |
QGraphicsView.mouseReleaseEvent(self.imageViewer, event) |
|
64 |
self._polyline._vertices.append(self._polyline._pt) |
|
65 |
self._polyline.update() |
|
66 |
finally: |
|
67 |
pass |
|
68 |
elif 'mouseReleaseEvent' == param[0] and event.button() == Qt.RightButton and self._polyline is not None: |
|
69 |
self.onSuccess.emit() |
|
70 |
elif 'mouseReleaseEvent' == param[0] and event.button() == Qt.RightButton and self._polyline is None: |
|
71 |
self.onRejected.emit(self) |
|
72 |
elif 'mouseMoveEvent' == param[0] and self._polyline is not None: |
|
73 |
self._polyline.onMouseMoved(event, param[2]) |
|
74 |
elif 'keyPressEvent' == param[0]: |
|
75 |
if event.key() == Qt.Key_Escape: |
|
76 |
self.onRejected.emit(self) |
|
77 |
self.isTreated = False |
|
78 |
|
|
79 |
def undo(self): |
|
80 |
pass |
|
81 |
|
|
82 |
def redo(self): |
|
83 |
pass |
|
84 |
|
|
85 |
|
|
86 |
|
HYTOS/HYTOS/Commands/SelectAttributeCommand.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 |
""" This is select attribute command module """ |
|
3 |
|
|
4 |
import os.path |
|
5 |
import sys |
|
6 |
import AbstractCommand |
|
7 |
|
|
8 |
try: |
|
9 |
from PyQt5.QtCore import * |
|
10 |
from PyQt5.QtGui import * |
|
11 |
from PyQt5.QtWidgets import * |
|
12 |
except ImportError: |
|
13 |
try: |
|
14 |
from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR, QEvent |
|
15 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImge, QPixmap, QPainterPath, QFileDialog, QCursor, QMouseEvent |
|
16 |
except ImportError: |
|
17 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
18 |
|
|
19 |
''' |
|
20 |
@brief QtImageViewer Select Attribute Command |
|
21 |
@author kyouho |
|
22 |
@date 18.04.10 |
|
23 |
''' |
|
24 |
class SelectAttributeCommand(AbstractCommand.AbstractCommand): |
|
25 |
onSuccess = pyqtSignal() |
|
26 |
|
|
27 |
def __init__(self, item, attr, imageViewer): |
|
28 |
super(SelectAttributeCommand, self).__init__(imageViewer) |
|
29 |
self.name = 'SelectAttribute' |
|
30 |
self.imageViewer.setCursor(QCursor(Qt.ArrowCursor)) |
|
31 |
self._item = item |
|
32 |
self._attr = attr |
|
33 |
|
|
34 |
''' |
|
35 |
@brief Select Attribuew |
|
36 |
@author kyouho |
|
37 |
@date 18.07.19 |
|
38 |
@history euising 2019.01.15 add specbreak |
|
39 |
@history add Valve Oper Item 2019.04.15 by humkyung |
|
40 |
''' |
|
41 |
def execute(self, param): |
|
42 |
from SymbolAttr import SymbolAttr |
|
43 |
from SymbolAttr import SymbolProp |
|
44 |
|
|
45 |
event = param[1] |
|
46 |
scenePos = param[2] |
|
47 |
|
|
48 |
try: |
|
49 |
if 'mouseReleaseEvent' == param[0] and event.button() == Qt.LeftButton: |
|
50 |
from EngineeringAbstractItem import QEngineeringAbstractItem |
|
51 |
from SymbolSvgItem import SymbolSvgItem |
|
52 |
from EngineeringTextItem import QEngineeringTextItem |
|
53 |
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem |
|
54 |
from EngineeringRunItem import QEngineeringRunItem |
|
55 |
from QEngineeringTagNoTextItem import QEngineeringTagNoTextItem |
|
56 |
from EngineeringLineItem import QEngineeringLineItem |
|
57 |
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem |
|
58 |
from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem |
|
59 |
from EngineeringConnectorItem import QEngineeringConnectorItem |
|
60 |
from EngineeringEndBreakItem import QEngineeringEndBreakItem |
|
61 |
from EngineeringVendorItem import QEngineeringVendorItem |
|
62 |
from EngineeringReservedWordTextItem import QEngineeringReservedWordTextItem |
|
63 |
|
|
64 |
if self._attr is not None and type(self._attr) is SymbolAttr: |
|
65 |
item = self.imageViewer.scene.itemAt(scenePos, QTransform()) |
|
66 |
if item is not None and self._attr.AttributeType == 'Line Item' and issubclass(type(item), QEngineeringLineItem): |
|
67 |
self._item.conns.clear() |
|
68 |
self._item.conns.append(item) |
|
69 |
self.onSuccess.emit() |
|
70 |
elif item is not None and self._attr.AttributeType == 'CONN' and (issubclass(type(item), QEngineeringLineItem) or issubclass(type(item), SymbolSvgItem) or type(item) is QEngineeringVendorItem or type(item) is QEngineeringReservedWordTextItem): |
|
71 |
self._item.connectors[self._attr.AttrAt - 1].connect(item, QEngineeringAbstractItem.CONNECTED_AT_BODY) |
|
72 |
if type(item) is QEngineeringReservedWordTextItem: |
|
73 |
item.owner = self._item |
|
74 |
self.onSuccess.emit() |
|
75 |
elif item is not None and self._attr.AttributeType == 'CONN' and (type(item) is QEngineeringConnectorItem): |
|
76 |
self._item.connectors[self._attr.AttrAt - 1].connect(item.parent, QEngineeringAbstractItem.CONNECTED_AT_PT) |
|
77 |
self.onSuccess.emit() |
|
78 |
elif item is not None and issubclass(type(self._item), QEngineeringSpecBreakItem) and self._attr.AttributeType == 'Comp Item' and type(item) is not QGraphicsPixmapItem: |
|
79 |
self._item.attrs[self._attr] = str(item.uid) |
|
80 |
self.onSuccess.emit() |
|
81 |
elif item is not None and (type(self._item) is not QEngineeringEndBreakItem) and (type(item) is QEngineeringLineNoTextItem) and self._attr.AttributeType == 'OWNER': |
|
82 |
if not item.runs: |
|
83 |
item.runs.append(QEngineeringRunItem()) |
|
84 |
|
|
85 |
if 1 == len(item.runs): item.runs[0].items.append(self._item) |
|
86 |
|
|
87 |
self._item.owner = item |
|
88 |
self.onSuccess.emit() |
|
89 |
elif item is not None and (type(self._item) is QEngineeringEndBreakItem or issubclass(type(self._item), QEngineeringTextItem)) and (type(item) is QEngineeringLineItem or issubclass(type(item), SymbolSvgItem)) and self._attr.AttributeType == 'OWNER': |
|
90 |
self._item.owner = item |
|
91 |
self.onSuccess.emit() |
|
92 |
#elif item is not None and (type(self._item) is QEngineeringEndBreakItem) and (type(item) is QEngineeringLineItem) and self._attr.Attribute == 'Connected Line': |
|
93 |
# self._item.attrs[self._attr] = str(item.uid) |
|
94 |
# self.onSuccess.emit() |
|
95 |
elif item is not None and self._attr.AttributeType == QEngineeringAbstractItem.assoc_type(item): |
|
96 |
if self._attr.Freeze: |
|
97 |
self.onSuccess.emit() |
|
98 |
return |
|
99 |
|
|
100 |
if self._attr.AttributeType not in self._item._associations: |
|
101 |
self._item._associations[self._attr.AttributeType] = [] |
|
102 |
|
|
103 |
while len(self._item._associations[self._attr.AttributeType]) <= self._attr.AttrAt: |
|
104 |
self._item._associations[self._attr.AttributeType].append(None) |
|
105 |
self._item.add_assoc_item(item, self._attr.AttrAt) |
|
106 |
for key in self._item.attrs.keys(): |
|
107 |
if key.Attribute == self._attr.Attribute: |
|
108 |
key.AssocItem = item |
|
109 |
break |
|
110 |
if issubclass(type(item), QEngineeringTextItem): item.owner = self._item |
|
111 |
self.onSuccess.emit() |
|
112 |
elif self._attr is not None and type(self._attr) is SymbolProp: |
|
113 |
item = self.imageViewer.scene.itemAt(scenePos, QTransform()) |
|
114 |
if item is not None and self._attr.match_type(item): |
|
115 |
self._item.set_property(self._attr.Attribute, item) |
|
116 |
if issubclass(type(item), QEngineeringTextItem): item.owner = self._item |
|
117 |
self.onSuccess.emit() |
|
118 |
except Exception as ex: |
|
119 |
from App import App |
|
120 |
from AppDocData import MessageType |
|
121 |
|
|
122 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
123 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
124 |
|
|
125 |
self.isTreated = True |
|
126 |
|
|
127 |
def undo(self): |
|
128 |
pass |
|
129 |
|
|
130 |
def redo(self): |
|
131 |
pass |
|
132 |
|
|
133 |
''' |
|
134 |
@brief Find TextItem contain Point |
|
135 |
@author kyouho |
|
136 |
@date 18.07.19 |
|
137 |
''' |
|
138 |
def findTextItemInPoint(self, point): |
|
139 |
from EngineeringTextItem import QEngineeringTextItem |
|
140 |
|
|
141 |
for item in self.imageViewer.items(): |
|
142 |
if type(item) is QEngineeringTextItem: |
|
143 |
if self.isOverlapItemAndPoint(item, point): |
|
144 |
return (True, item) |
|
145 |
|
|
146 |
return (False,) |
|
147 |
|
|
148 |
''' |
|
149 |
@brief Find Symbol Item contain Point |
|
150 |
@author kyouho |
|
151 |
@date 18.07.19 |
|
152 |
''' |
|
153 |
def findSymbolItemInPoint(self, point): |
|
154 |
from SymbolSvgItem import SymbolSvgItem |
|
155 |
|
|
156 |
for item in self.imageViewer.items(): |
|
157 |
if issubclass(type(item), SymbolSvgItem): |
|
158 |
if self.isOverlapItemAndPoint(item, point): |
|
159 |
return (True, item) |
|
160 |
|
|
161 |
return (False,) |
|
162 |
|
|
163 |
''' |
|
164 |
@brief Check Overlap |
|
165 |
@author kyouho |
|
166 |
@date 18.07.17 |
|
167 |
''' |
|
168 |
def isOverlapItemAndPoint(self, item, point): |
|
169 |
x = point.x() |
|
170 |
y = point.y() |
|
171 |
loc = item.loc |
|
172 |
size = item.size |
|
173 |
|
|
174 |
if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y: |
|
175 |
return True |
|
176 |
else: |
|
177 |
return False |
HYTOS/HYTOS/ConnectAttrDialog.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 |
|
|
3 |
from PyQt5.QtCore import * |
|
4 |
from PyQt5.QtGui import * |
|
5 |
from PyQt5.QtWidgets import * |
|
6 |
import ConnectAttr_UI |
|
7 |
import sys |
|
8 |
import os |
|
9 |
import cv2 |
|
10 |
from AppDocData import * |
|
11 |
from LineDetector import LineDetector |
|
12 |
from EngineeringLineItem import QEngineeringLineItem |
|
13 |
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem |
|
14 |
from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem |
|
15 |
from SymbolSvgItem import SymbolSvgItem |
|
16 |
from EngineeringTextItem import QEngineeringTextItem |
|
17 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
|
18 |
|
|
19 |
''' |
|
20 |
''' |
|
21 |
class Worker(QThread): |
|
22 |
""" This is Worker class """ |
|
23 |
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QGridLayout, QListWidget |
|
24 |
from QtImageViewer import QtImageViewer |
|
25 |
import sys |
|
26 |
|
|
27 |
''' |
|
28 |
''' |
|
29 |
finished = pyqtSignal() |
|
30 |
intReady = pyqtSignal(int) |
|
31 |
displayMessage = pyqtSignal(str) |
|
32 |
updateProgress = pyqtSignal(int) |
|
33 |
|
|
34 |
def __init__(self, graphicsView, update_line_type): |
|
35 |
QThread.__init__(self) |
|
36 |
self.graphicsView = graphicsView |
|
37 |
self._update_line_type = update_line_type |
|
38 |
|
|
39 |
''' |
|
40 |
@brief execute connecting attributes |
|
41 |
@author humkyung |
|
42 |
@date 2018.06.17 |
|
43 |
''' |
|
44 |
def run(self): # A slot takes no params |
|
45 |
from LineNoTracer import connectAttrImpl |
|
46 |
|
|
47 |
try: |
|
48 |
connectAttrImpl(self, self._update_line_type) |
|
49 |
except Exception as ex: |
|
50 |
from App import App |
|
51 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
52 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
53 |
|
|
54 |
class QConnectAttrDialog(QDialog): |
|
55 |
""" This is connect attr dialog class """ |
|
56 |
|
|
57 |
def __init__(self, parent, graphicsView): #Parent is MainWindow |
|
58 |
import ConnectAttr_UI |
|
59 |
|
|
60 |
QDialog.__init__(self, parent) |
|
61 |
|
|
62 |
self.parent = parent |
|
63 |
self.graphicsView = graphicsView |
|
64 |
self.ui = ConnectAttr_UI.Ui_ConnectAttr() |
|
65 |
self.ui.setupUi(self) |
|
66 |
self.ui.pushButtonStart.setFocus() |
|
67 |
self.ui.buttonBox.setEnabled(True) |
|
68 |
self.ui.listWidget.model().rowsInserted.connect(self.rowInserted) ## connect to func rowInserted(self, item) |
|
69 |
self.isAccepted = False |
|
70 |
|
|
71 |
self.ui.pushButtonStart.clicked.connect(self.connStart) |
|
72 |
|
|
73 |
def connStart(self): |
|
74 |
''' |
|
75 |
@brief connection start |
|
76 |
@author euisung |
|
77 |
@date 2019.02.25 |
|
78 |
''' |
|
79 |
self.ui.buttonBox.setEnabled(False) |
|
80 |
self.ui.pushButtonStart.setEnabled(False) |
|
81 |
self.ui.progressBar.setValue(0) |
|
82 |
self.startThread() |
|
83 |
""" for DEBUG |
|
84 |
from LineNoTracer import connectAttrImpl |
|
85 |
connectAttrImpl(self) |
|
86 |
""" |
|
87 |
|
|
88 |
''' |
|
89 |
@brief QListWidget Row Inserted Listener |
|
90 |
Whenever row inserted, scroll to bottom |
|
91 |
@author Jeongwoo |
|
92 |
@date 18.04.12 |
|
93 |
''' |
|
94 |
def rowInserted(self, item): |
|
95 |
self.ui.listWidget.scrollToBottom() |
|
96 |
|
|
97 |
''' |
|
98 |
@brief add item to list widget |
|
99 |
@author humkyung |
|
100 |
@date 2018.06.17 |
|
101 |
''' |
|
102 |
def addListItem(self, msg): |
|
103 |
self.ui.listWidget.addItem(msg) |
|
104 |
|
|
105 |
def accept(self): |
|
106 |
self.isAccepted = True |
|
107 |
QDialog.accept(self) |
|
108 |
|
|
109 |
''' |
|
110 |
@brief update progressbar with given value |
|
111 |
@author humkyung |
|
112 |
@date 2018.06.17 |
|
113 |
@history humkyung 2018.06.27 reset value if maxValue is -1 |
|
114 |
''' |
|
115 |
def updateProgress(self, maxValue): |
|
116 |
if maxValue != -1: |
|
117 |
self.ui.progressBar.setMaximum(maxValue) |
|
118 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
119 |
else: |
|
120 |
self.ui.progressBar.setValue(0) |
|
121 |
|
|
122 |
''' |
|
123 |
@brief start thread |
|
124 |
@author humkyung |
|
125 |
@date 2018.06.17 |
|
126 |
''' |
|
127 |
def startThread(self): |
|
128 |
import timeit |
|
129 |
from LineNoTracer import connectAttrImpl |
|
130 |
|
|
131 |
try: |
|
132 |
self.ui.buttonBox.setDisabled(True) |
|
133 |
|
|
134 |
# 1 - create Worker and Thread inside the Form |
|
135 |
self.obj = Worker(self.graphicsView, self.ui.checkBoxUpdateLineType.isChecked()) |
|
136 |
|
|
137 |
# 2 - Connect Worker Signals to the Thread slots |
|
138 |
self.obj.displayMessage.connect(self.addListItem) |
|
139 |
self.obj.updateProgress.connect(self.updateProgress) |
|
140 |
|
|
141 |
# 3 - Thread finished signal will close the app if you want! |
|
142 |
self.obj.finished.connect(self.dlgExit) |
|
143 |
|
|
144 |
# 4 - Start the thread |
|
145 |
self.obj.start() |
|
146 |
|
|
147 |
self.tmStart = timeit.default_timer() |
|
148 |
except Exception as ex: |
|
149 |
from App import App |
|
150 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
151 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
152 |
finally: |
|
153 |
self.ui.buttonBox.setDisabled(False) |
|
154 |
|
|
155 |
''' |
|
156 |
@brief set buttonbox's enabled flag |
|
157 |
@author humkyung |
|
158 |
@date 2018.06.17 |
|
159 |
@history humkyung 2018.06.17 add flow mark for pipe run |
|
160 |
humkyung 2018.08.16 don't update line type according to connected items |
|
161 |
''' |
|
162 |
def dlgExit(self): |
|
163 |
import timeit |
|
164 |
|
|
165 |
try: |
|
166 |
self.ui.progressBar.setValue(self.ui.progressBar.maximum()) |
|
167 |
self.ui.buttonBox.setEnabled(True) |
|
168 |
except Exception as ex: |
|
169 |
from App import App |
|
170 |
|
|
171 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
172 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
173 |
finally: |
|
174 |
self.tmStop = timeit.default_timer() |
|
175 |
seconds = self.tmStop - self.tmStart |
|
176 |
self.ui.listWidget.addItem("\nRunning Time : {} min".format(str(round(seconds/60, 1))) + "\n") |
HYTOS/HYTOS/ConnectAttr_UI.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
|
3 |
# Form implementation generated from reading ui file '.\UI\dlgConnectAttr.ui' |
|
4 |
# |
|
5 |
# Created by: PyQt5 UI code generator 5.11.3 |
|
6 |
# |
|
7 |
# WARNING! All changes made in this file will be lost! |
|
8 |
|
|
9 |
from PyQt5 import QtCore, QtGui, QtWidgets |
|
10 |
|
|
11 |
class Ui_ConnectAttr(object): |
|
12 |
def setupUi(self, ConnectAttr): |
|
13 |
ConnectAttr.setObjectName("ConnectAttr") |
|
14 |
ConnectAttr.setWindowModality(QtCore.Qt.WindowModal) |
|
15 |
ConnectAttr.resize(845, 453) |
|
16 |
font = QtGui.QFont() |
|
17 |
font.setFamily("맑은 고딕") |
|
18 |
ConnectAttr.setFont(font) |
|
19 |
self.gridLayout = QtWidgets.QGridLayout(ConnectAttr) |
|
20 |
self.gridLayout.setObjectName("gridLayout") |
|
21 |
self.listWidget = QtWidgets.QListWidget(ConnectAttr) |
|
22 |
self.listWidget.setObjectName("listWidget") |
|
23 |
self.gridLayout.addWidget(self.listWidget, 3, 0, 1, 1) |
|
24 |
self.horizontalLayout = QtWidgets.QHBoxLayout() |
|
25 |
self.horizontalLayout.setObjectName("horizontalLayout") |
|
26 |
self.progressBar = QtWidgets.QProgressBar(ConnectAttr) |
|
27 |
self.progressBar.setProperty("value", 0) |
|
28 |
self.progressBar.setObjectName("progressBar") |
|
29 |
self.horizontalLayout.addWidget(self.progressBar) |
|
30 |
self.buttonBox = QtWidgets.QDialogButtonBox(ConnectAttr) |
|
31 |
self.buttonBox.setEnabled(False) |
|
32 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) |
|
33 |
sizePolicy.setHorizontalStretch(0) |
|
34 |
sizePolicy.setVerticalStretch(0) |
|
35 |
sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) |
|
36 |
self.buttonBox.setSizePolicy(sizePolicy) |
|
37 |
self.buttonBox.setOrientation(QtCore.Qt.Horizontal) |
|
38 |
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) |
|
39 |
self.buttonBox.setObjectName("buttonBox") |
|
40 |
self.horizontalLayout.addWidget(self.buttonBox, 0, QtCore.Qt.AlignRight) |
|
41 |
self.gridLayout.addLayout(self.horizontalLayout, 6, 0, 1, 1) |
|
42 |
self.horizontalLayout_2 = QtWidgets.QHBoxLayout() |
|
43 |
self.horizontalLayout_2.setObjectName("horizontalLayout_2") |
|
44 |
self.checkBoxUpdateLineType = QtWidgets.QCheckBox(ConnectAttr) |
|
45 |
self.checkBoxUpdateLineType.setObjectName("checkBoxUpdateLineType") |
|
46 |
self.horizontalLayout_2.addWidget(self.checkBoxUpdateLineType) |
|
47 |
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) |
|
48 |
self.horizontalLayout_2.addItem(spacerItem) |
|
49 |
self.pushButtonStart = QtWidgets.QPushButton(ConnectAttr) |
|
50 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) |
|
51 |
sizePolicy.setHorizontalStretch(0) |
|
52 |
sizePolicy.setVerticalStretch(0) |
|
53 |
sizePolicy.setHeightForWidth(self.pushButtonStart.sizePolicy().hasHeightForWidth()) |
|
54 |
self.pushButtonStart.setSizePolicy(sizePolicy) |
|
55 |
self.pushButtonStart.setObjectName("pushButtonStart") |
|
56 |
self.horizontalLayout_2.addWidget(self.pushButtonStart) |
|
57 |
self.gridLayout.addLayout(self.horizontalLayout_2, 2, 0, 1, 1) |
|
58 |
|
|
59 |
self.retranslateUi(ConnectAttr) |
|
60 |
self.buttonBox.clicked['QAbstractButton*'].connect(ConnectAttr.accept) |
|
61 |
QtCore.QMetaObject.connectSlotsByName(ConnectAttr) |
|
62 |
ConnectAttr.setTabOrder(self.pushButtonStart, self.listWidget) |
|
63 |
|
|
64 |
def retranslateUi(self, ConnectAttr): |
|
65 |
_translate = QtCore.QCoreApplication.translate |
|
66 |
ConnectAttr.setWindowTitle(_translate("ConnectAttr", "Connect Attribute")) |
|
67 |
self.checkBoxUpdateLineType.setText(_translate("ConnectAttr", "Update Line Type")) |
|
68 |
self.pushButtonStart.setText(_translate("ConnectAttr", "Start")) |
|
69 |
|
HYTOS/HYTOS/DetectSymbolDialog.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 |
""" |
|
3 |
This is fluid code dialog module |
|
4 |
""" |
|
5 |
import sys |
|
6 |
import sqlite3 |
|
7 |
import os |
|
8 |
import cv2 |
|
9 |
import math |
|
10 |
import threading |
|
11 |
import multiprocessing |
|
12 |
from multiprocessing import Process, Queue |
|
13 |
|
|
14 |
from shapely.geometry import Point |
|
15 |
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse |
|
16 |
from PyQt5.QtCore import * |
|
17 |
from PyQt5.QtGui import * |
|
18 |
from PyQt5.QtWidgets import * |
|
19 |
|
|
20 |
from AppDocData import AppDocData |
|
21 |
import DetectSymbol_UI |
|
22 |
|
|
23 |
class QDetectSymbolDialog(QDialog): |
|
24 |
|
|
25 |
def __init__(self, parent): |
|
26 |
QDialog.__init__(self) |
|
27 |
self.parent = parent |
|
28 |
self.ui = DetectSymbol_UI.Ui_DetectSymbolDialog() |
|
29 |
self.ui.setupUi(self) |
|
30 |
|
|
31 |
self.table = self.ui.tableWidgetSymbol |
|
32 |
self.currentRow = 0 |
|
33 |
self.currentColumn = 0 |
|
34 |
|
|
35 |
## box dir setting |
|
36 |
self.boxDir = AppDocData.instance().getCurrentProject().path + '/box/' |
|
37 |
if not os.path.exists(self.boxDir): |
|
38 |
os.makedirs(self.boxDir) |
|
39 |
## drawing file setting |
|
40 |
self.drawingDir = AppDocData.instance().getCurrentProject().path + '/drawings/' |
|
41 |
if os.path.exists(self.drawingDir): |
|
42 |
files = os.listdir(self.drawingDir) |
|
43 |
for file in files: |
|
44 |
listItem = QListWidgetItem() |
|
45 |
listItem.setData(32, file) |
|
46 |
listItem.setText(os.path.splitext(file)[0]) |
|
47 |
self.ui.listWidgetDrawings.addItem(listItem) |
|
48 |
|
|
49 |
self.ui.listWidgetDrawings.currentTextChanged.connect(self.currentTextChangedEvent) |
|
50 |
self.ui.pushButtonDetectSymbol.clicked.connect(self.detectSymbol) |
|
51 |
|
|
52 |
if self.ui.listWidgetDrawings.count(): |
|
53 |
self.ui.listWidgetDrawings.setCurrentRow(0) |
|
54 |
|
|
55 |
self.table.cellDoubleClicked.connect(self.cellDoubleClickedEvent) |
|
56 |
self.table.currentCellChanged.connect(self.currentCellChangedEvent) |
|
57 |
|
|
58 |
self.setAllSymbolsTable() |
|
59 |
|
|
60 |
''' |
|
61 |
@brief current cell chage event |
|
62 |
@author kyouho |
|
63 |
@date 2018.10.01 |
|
64 |
''' |
|
65 |
def currentCellChangedEvent(self, currentRow, currentColumn, previousRow, previousColumn): |
|
66 |
currentItem = self.table.cellWidget(currentRow, currentColumn) |
|
67 |
if currentItem is not None: |
|
68 |
self.currentRow = currentRow |
|
69 |
self.currentColumn = currentColumn |
|
70 |
else: |
|
71 |
self.currentRow = -1 |
|
72 |
self.currentColumn = -1 |
|
73 |
|
|
74 |
''' |
|
75 |
@brief cell double click event |
|
76 |
@author kyouho |
|
77 |
@date 2018.10.01 |
|
78 |
''' |
|
79 |
def cellDoubleClickedEvent(self, row, column): |
|
80 |
cell = self.table.cellWidget(row,column) |
|
81 |
if cell is not None: |
|
82 |
import SymbolEditorDialog |
|
83 |
symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, cell.pixmap(), AppDocData.instance().getCurrentProject()) |
|
84 |
(isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog() |
|
85 |
if isAccepted: |
|
86 |
self.table.removeCellWidget(row, column) |
|
87 |
self.parent.symbolTreeWidget.initSymbolTreeWidget() |
|
88 |
self.setAllSymbolsTable() |
|
89 |
|
|
90 |
''' |
|
91 |
@brief text changed Event |
|
92 |
@author kyouho |
|
93 |
@date 2018.09.18 |
|
94 |
''' |
|
95 |
def currentTextChangedEvent(self, text): |
|
96 |
self.imageName = text |
|
97 |
self.imgPath = self.drawingDir + self.ui.listWidgetDrawings.currentItem().data(32) |
|
98 |
self.tableSetting() |
|
99 |
|
|
100 |
''' |
|
101 |
@brief text changed Event |
|
102 |
@author kyouho |
|
103 |
@date 2018.10.11 |
|
104 |
''' |
|
105 |
def setAllSymbolsTable(self): |
|
106 |
table = self.ui.tableWidgetAllSymbols |
|
107 |
table.setRowCount(0) |
|
108 |
|
|
109 |
imageFiles = [] |
|
110 |
imageDir = AppDocData.instance().getCurrentProject().path + '/image/' |
|
111 |
self.findFiles(imageDir, imageFiles) |
|
112 |
|
|
113 |
table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) |
|
114 |
size = table.maximumWidth() - 40 |
|
115 |
|
|
116 |
table.setRowCount(len(imageFiles)) |
|
117 |
row = 0 |
|
118 |
for path in imageFiles: |
|
119 |
cell = QLabel() |
|
120 |
pixmap = QPixmap(path) |
|
121 |
cell.setPixmap(pixmap.scaled(size, size, Qt.KeepAspectRatio)) |
|
122 |
table.setCellWidget(row, 0, cell) |
|
123 |
row = row + 1 |
|
124 |
|
|
125 |
table.resizeRowsToContents() |
|
126 |
|
|
127 |
''' |
|
128 |
@brief find image files |
|
129 |
@author kyouho |
|
130 |
@date 2018.10.11 |
|
131 |
''' |
|
132 |
def findFiles(self, dir, list): |
|
133 |
fileList = os.listdir(dir) |
|
134 |
for file in fileList: |
|
135 |
path = os.path.join(dir, file) |
|
136 |
if os.path.isdir(path): |
|
137 |
self.findFiles(path, list) |
|
138 |
elif os.path.splitext(path)[1] == '.png': |
|
139 |
list.append(path) |
|
140 |
|
|
141 |
|
|
142 |
|
|
143 |
''' |
|
144 |
@brief text changed Event |
|
145 |
@author kyouho |
|
146 |
@date 2018.09.18 |
|
147 |
''' |
|
148 |
def detectSymbol(self): |
|
149 |
if not self.ui.listWidgetDrawings.count(): |
|
150 |
return |
|
151 |
|
|
152 |
self.progress = QProgressDialog("잠시만 기다려주세요", "Cancel", 0, 100, self) |
|
153 |
self.progress.setWindowModality(Qt.WindowModal) |
|
154 |
self.progress.setAutoReset(True) |
|
155 |
self.progress.setAutoClose(True) |
|
156 |
self.progress.setMinimum(0) |
|
157 |
self.progress.resize(600,100) |
|
158 |
self.progress.setWindowTitle("인식 중...") |
|
159 |
self.progress.show() |
|
160 |
self.progress.setMaximum(100) |
|
161 |
self.progress.setValue(0) |
|
162 |
QApplication.processEvents() |
|
163 |
|
|
164 |
from TextDetector import TextDetector |
|
165 |
import numpy as np |
|
166 |
|
|
167 |
appDocData = AppDocData.instance() |
|
168 |
## textDetector에서 사용하기 때문에 설정 |
|
169 |
appDocData.imgName = self.imageName |
|
170 |
|
|
171 |
## 흑색 이미지로 변환 |
|
172 |
img = cv2.imread(self.imgPath, 1) |
|
173 |
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
|
174 |
|
|
175 |
## 프로젝트의 Drawing Area data |
|
176 |
area = appDocData.getArea('Drawing') |
|
177 |
|
|
178 |
## area 영역 자른 offset |
|
179 |
offset = (area.x, area.y) if area is not None else (0,0) |
|
180 |
|
|
181 |
## 이미지 이진화 |
|
182 |
thresholdImg = cv2.threshold(imgGray , 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] |
|
183 |
## 프로젝트의 Area 영역만큼만 자른 이미지 |
|
184 |
areaImg = thresholdImg[round(area.y):round(area.y+area.height), round(area.x):round(area.x+area.width)] |
|
185 |
|
|
186 |
## 선제거 전에 먼저 작은 영역 제거 |
|
187 |
## contours 추출을 위한 색반전 |
|
188 |
areaImg = cv2.bitwise_not(areaImg) |
|
189 |
## contours 추출 |
|
190 |
image, contours, hierarchy = cv2.findContours(areaImg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
191 |
for contour in contours: |
|
192 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
193 |
|
|
194 |
if (w < 40 or h < 40): |
|
195 |
areaImg[y:y+h,x:x+w] = 0 |
|
196 |
## 다시 색반전 |
|
197 |
areaImg = cv2.bitwise_not(areaImg) |
|
198 |
|
|
199 |
## find lines |
|
200 |
verticalLineList = [] |
|
201 |
horizontalLineList = [] |
|
202 |
self.findLines(areaImg, verticalLineList, horizontalLineList) |
|
203 |
|
|
204 |
## chage color |
|
205 |
for vLine in verticalLineList: |
|
206 |
p1 = vLine[0] |
|
207 |
p2 = vLine[1] |
|
208 |
x = p1[0] |
|
209 |
areaImg[p1[1]:p2[1], x] = 255 |
|
210 |
## chage color |
|
211 |
for vLine in horizontalLineList: |
|
212 |
p1 = vLine[0] |
|
213 |
p2 = vLine[1] |
|
214 |
y = p1[1] |
|
215 |
areaImg[y, p1[0]:p2[0]] = 255 |
|
216 |
|
|
217 |
## contours 추출을 위한 색반전 |
|
218 |
areaImg = cv2.bitwise_not(areaImg) |
|
219 |
## contours 추출 |
|
220 |
recList = self.getContours(areaImg) |
|
221 |
|
|
222 |
## to xml |
|
223 |
self.toXml(recList, offset) |
|
224 |
|
|
225 |
## table setting |
|
226 |
self.tableSetting() |
|
227 |
|
|
228 |
self.progress.setValue(self.progress.maximum()) |
|
229 |
|
|
230 |
''' |
|
231 |
@brief find lines |
|
232 |
@author kyouho |
|
233 |
@date 2018.10.01 |
|
234 |
''' |
|
235 |
def findLines(self, areaImg, verticalLineList, horizontalLineList): |
|
236 |
|
|
237 |
## for multiprocessing |
|
238 |
verticalProcessList = [] |
|
239 |
horizontalProcessList = [] |
|
240 |
|
|
241 |
## Find VerticalLine using multiprocessing |
|
242 |
## Set Vertical Line |
|
243 |
jumpValue = int(areaImg.shape[1] / os.cpu_count()) |
|
244 |
value = 0 |
|
245 |
for cpuIndex in range(os.cpu_count()): |
|
246 |
_queue = Queue() |
|
247 |
_range = value + jumpValue |
|
248 |
if os.cpu_count() -1 == cpuIndex: |
|
249 |
_range = areaImg.shape[1] |
|
250 |
|
|
251 |
_process = Process(target=isVerticalLineThread, args=(value, _range, areaImg, _queue)) |
|
252 |
_process.daemon = True |
|
253 |
verticalProcessList.append((_process, _queue)) |
|
254 |
value = value + jumpValue |
|
255 |
|
|
256 |
## Set Horizontal Line |
|
257 |
jumpValue = int(areaImg.shape[0] / os.cpu_count()) |
|
258 |
value = 0 |
|
259 |
for cpuIndex in range(os.cpu_count()): |
|
260 |
_queue = Queue() |
|
261 |
_range = value + jumpValue |
|
262 |
if os.cpu_count() -1 == cpuIndex: |
|
263 |
_range = areaImg.shape[0] |
|
264 |
|
|
265 |
_process = Process(target=isHorizontalLineThread, args=(value, _range, areaImg, _queue)) |
|
266 |
_process.daemon = True |
|
267 |
horizontalProcessList.append((_process, _queue)) |
|
268 |
value = value + jumpValue |
|
269 |
|
|
270 |
## set percent |
|
271 |
progressCount = len(verticalProcessList) + len(horizontalProcessList) + 1 |
|
272 |
percentGage = int(100 / progressCount) |
|
273 |
percent = percentGage |
|
274 |
self.progress.setValue(percent) |
|
275 |
QApplication.processEvents() |
|
276 |
|
|
277 |
## process start |
|
278 |
for process in verticalProcessList: |
|
279 |
process[0].start() |
|
280 |
|
|
281 |
## Wait Vertical And Start Horizontal |
|
282 |
for index in range(len(verticalProcessList)): |
|
283 |
verticalLineList.extend(verticalProcessList[index][1].get()) |
|
284 |
verticalProcessList[index][0].join() |
|
285 |
verticalProcessList[index][1].close() |
|
286 |
|
|
287 |
percent = percent + percentGage |
|
288 |
self.progress.setValue(percent) |
|
289 |
QApplication.processEvents() |
|
290 |
|
|
291 |
horizontalProcessList[index][0].start() |
|
292 |
|
|
293 |
## Wait Horizontal |
|
294 |
for process in horizontalProcessList: |
|
295 |
horizontalLineList.extend(process[1].get()) |
|
296 |
process[0].join() |
|
297 |
process[1].close() |
|
298 |
|
|
299 |
percent = percent + percentGage |
|
300 |
self.progress.setValue(percent) |
|
301 |
QApplication.processEvents() |
|
302 |
|
|
303 |
''' |
|
304 |
@brief get contours |
|
305 |
@author kyouho |
|
306 |
@date 2018.10.01 |
|
307 |
''' |
|
308 |
def getContours(self, areaImg): |
|
309 |
|
|
310 |
image, contours, hierarchy = cv2.findContours(areaImg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
311 |
|
|
312 |
## RecList 정리 |
|
313 |
lineWidth = 5 |
|
314 |
recList = [] |
|
315 |
tempRecList = [] |
|
316 |
for contour in contours: |
|
317 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
318 |
tempRecList.append([x-lineWidth, y-lineWidth, x+w+lineWidth, y+h+lineWidth]) |
|
319 |
|
|
320 |
## Overlap Rec 합침 |
|
321 |
while len(tempRecList): |
|
322 |
rec1 = tempRecList[0] |
|
323 |
_temp = [] |
|
324 |
for index in range(1, len(tempRecList)): |
|
325 |
rec2 = tempRecList[index] |
|
326 |
if rec1[0] <= rec2[2] and rec1[2] >= rec2[0] and rec1[1] <= rec2[3] and rec1[3] >= rec2[1]: |
|
327 |
_temp.append(rec2) |
|
328 |
|
|
329 |
if len(_temp): |
|
330 |
x1 = rec1[0] |
|
331 |
y1 = rec1[1] |
|
332 |
x2 = rec1[2] |
|
333 |
y2 = rec1[3] |
|
334 |
|
|
335 |
for rec in _temp: |
|
336 |
x1 = min(x1, rec[0]) |
|
337 |
y1 = min(y1, rec[1]) |
|
338 |
x2 = max(x2, rec[2]) |
|
339 |
y2 = max(y2, rec[3]) |
|
340 |
tempRecList.remove(rec) |
|
341 |
tempRecList.append([x1, y1, x2, y2]) |
|
342 |
|
|
343 |
else: |
|
344 |
recList.append(rec1) |
|
345 |
|
|
346 |
tempRecList.remove(rec1) |
|
347 |
|
|
348 |
return recList |
|
349 |
|
|
350 |
''' |
|
351 |
@brief key press event |
|
352 |
@author kyouho |
|
353 |
@date 2018.10.01 |
|
354 |
''' |
|
355 |
def keyPressEvent(self, event): |
|
356 |
if event.key() == Qt.Key_Delete and self.currentRow != -1 and self.currentColumn != -1: |
|
357 |
self.table.removeCellWidget(self.currentRow, self.currentColumn) |
|
358 |
|
|
359 |
|
|
360 |
''' |
|
361 |
@brief box to xml |
|
362 |
@author kyouho |
|
363 |
@date 2018.10.01 |
|
364 |
''' |
|
365 |
def toXml(self, recList, offset): |
|
366 |
xml = Element('BOXES') |
|
367 |
|
|
368 |
## to xml |
|
369 |
for rec in recList: |
|
370 |
[x1, y1, x2, y2] = rec |
|
371 |
w = x2-x1 |
|
372 |
h = y2-y1 |
|
373 |
if w < 20 or h < 20: continue |
|
374 |
elif w*4<h or h*4<w: continue |
|
375 |
|
|
376 |
boxElement = Element('BOX') |
|
377 |
|
|
378 |
xElement = Element('X') |
|
379 |
xElement.text = str(x1 + offset[0]) |
|
380 |
boxElement.append(xElement) |
|
381 |
|
|
382 |
yElement = Element('Y') |
|
383 |
yElement.text = str(y1 + offset[1]) |
|
384 |
boxElement.append(yElement) |
|
385 |
|
|
386 |
widthElement = Element('WIDTH') |
|
387 |
widthElement.text = str(x2-x1) |
|
388 |
boxElement.append(widthElement) |
|
389 |
|
|
390 |
heightElement = Element('HEIGHT') |
|
391 |
heightElement.text = str(y2-y1) |
|
392 |
boxElement.append(heightElement) |
|
393 |
|
|
394 |
xml.append(boxElement) |
|
395 |
|
|
396 |
ElementTree(xml).write(self.boxDir + self.imageName + '.box') |
|
397 |
|
|
398 |
''' |
|
399 |
@brief table setting |
|
400 |
@author kyouho |
|
401 |
@date 2018.09.18 |
|
402 |
''' |
|
403 |
def tableSetting(self): |
|
404 |
columnCount = 3 |
|
405 |
self.table.setColumnCount(columnCount) |
|
406 |
self.table.setRowCount(0) |
|
407 |
boxCount = 0 |
|
408 |
|
|
409 |
xmlPath = self.boxDir + self.imageName + '.box' |
|
410 |
if os.path.exists(xmlPath): |
|
411 |
_pixmap = QPixmap(self.imgPath) |
|
412 |
|
|
413 |
xml = parse(xmlPath) |
|
414 |
root = xml.getroot() |
|
415 |
|
|
416 |
for box in root.iter('BOX'): |
|
417 |
rowIndex = int(boxCount / columnCount) |
|
418 |
self.table.setRowCount(rowIndex + 1) |
|
419 |
|
|
420 |
_x = int(box.find('X').text) |
|
421 |
_y = int(box.find('Y').text) |
|
422 |
_width = int(box.find('WIDTH').text) |
|
423 |
_height = int(box.find('HEIGHT').text) |
|
424 |
|
|
425 |
rect = QRect(_x, _y, _width, _height) |
|
426 |
boxImg = _pixmap.copy(rect) |
|
427 |
|
|
428 |
cell = QLabel() |
|
429 |
cell.setPixmap(boxImg) |
|
430 |
cell.rect = [_x, _y, _width, _height] |
|
431 |
self.table.setCellWidget(rowIndex, boxCount % columnCount, cell) |
|
432 |
|
|
433 |
boxCount = boxCount + 1 |
|
434 |
|
|
435 |
|
|
436 |
self.table.resizeColumnsToContents() |
|
437 |
self.table.resizeRowsToContents() |
|
438 |
|
|
439 |
''' |
|
440 |
@brief accept |
|
441 |
@author kyouho |
|
442 |
@date 2018.10.01 |
|
443 |
''' |
|
444 |
def accept(self): |
|
445 |
columnCount = 3 |
|
446 |
recList = [] |
|
447 |
for rowIndex in range(self.table.rowCount()): |
|
448 |
for columnIndex in range(columnCount): |
|
449 |
cell = self.table.cellWidget(rowIndex, columnIndex) |
|
450 |
if cell is not None: |
|
451 |
[x, y, w, h] = cell.rect |
|
452 |
recList.append([x, y, x+w, y+h]) |
|
453 |
|
|
454 |
self.toXml(recList, (0, 0)) |
|
455 |
|
|
456 |
QDialog.accept(self) |
|
457 |
|
|
458 |
''' |
|
459 |
@brief Check Vertical Line using Multiprocessing |
|
460 |
@author kyouho |
|
461 |
@date 2018.09.27 |
|
462 |
''' |
|
463 |
def isVerticalLineThread(start, end, img, _queue): |
|
464 |
minLineSize = 40 |
|
465 |
|
|
466 |
## Vertical |
|
467 |
find = False |
|
468 |
startY = 0 |
|
469 |
lineList = [] |
|
470 |
for x in range(start, end): |
|
471 |
for y in range(0, img.shape[0]): |
|
472 |
if img[y,x] == 0: |
|
473 |
if find: |
|
474 |
continue |
|
475 |
else: |
|
476 |
find = True |
|
477 |
startY = y |
|
478 |
else: |
|
479 |
if find: |
|
480 |
if y - startY > minLineSize: |
|
481 |
lineList.append(((x,startY), (x,y))) |
|
482 |
find = False |
|
483 |
_queue.put(lineList) |
|
484 |
|
|
485 |
''' |
|
486 |
@brief Check Horizontal Line using Multiprocessing |
|
487 |
@author kyouho |
|
488 |
@date 2018.09.27 |
|
489 |
''' |
|
490 |
def isHorizontalLineThread(start, end, img, _queue): |
|
491 |
minLineSize = 40 |
|
492 |
|
|
493 |
## Horizontal |
|
494 |
find = False |
|
495 |
startX = 0 |
|
496 |
lineList = [] |
|
497 |
for y in range(start, end): |
|
498 |
for x in range(0, img.shape[1]): |
|
499 |
if img[y,x] == 0: |
|
500 |
if find: |
|
501 |
continue |
|
502 |
else: |
|
503 |
find = True |
|
504 |
startX = x |
|
505 |
else: |
|
506 |
if find: |
|
507 |
if x - startX > minLineSize: |
|
508 |
lineList.append(((startX,y), (x,y))) |
|
509 |
|
|
510 |
find = False |
|
511 |
_queue.put(lineList) |
HYTOS/HYTOS/DetectSymbol_UI.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
|
3 |
# Form implementation generated from reading ui file '.\UI\DetectSymbol.ui' |
|
4 |
# |
|
5 |
# Created by: PyQt5 UI code generator 5.11.2 |
|
6 |
# |
|
7 |
# WARNING! All changes made in this file will be lost! |
|
8 |
|
|
9 |
from PyQt5 import QtCore, QtGui, QtWidgets |
|
10 |
|
|
11 |
class Ui_DetectSymbolDialog(object): |
|
12 |
def setupUi(self, DetectSymbolDialog): |
|
13 |
DetectSymbolDialog.setObjectName("DetectSymbolDialog") |
|
14 |
DetectSymbolDialog.resize(1313, 813) |
|
15 |
font = QtGui.QFont() |
|
16 |
font.setFamily("맑은 고딕") |
|
17 |
DetectSymbolDialog.setFont(font) |
|
18 |
self.gridLayout = QtWidgets.QGridLayout(DetectSymbolDialog) |
|
19 |
self.gridLayout.setObjectName("gridLayout") |
|
20 |
self.gridLayout_2 = QtWidgets.QGridLayout() |
|
21 |
self.gridLayout_2.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) |
|
22 |
self.gridLayout_2.setObjectName("gridLayout_2") |
|
23 |
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) |
|
24 |
self.gridLayout_2.addItem(spacerItem, 0, 1, 1, 1) |
|
25 |
self.pushButtonDetectSymbol = QtWidgets.QPushButton(DetectSymbolDialog) |
|
26 |
self.pushButtonDetectSymbol.setMinimumSize(QtCore.QSize(0, 25)) |
|
27 |
self.pushButtonDetectSymbol.setMaximumSize(QtCore.QSize(16777215, 25)) |
|
28 |
self.pushButtonDetectSymbol.setObjectName("pushButtonDetectSymbol") |
|
29 |
self.gridLayout_2.addWidget(self.pushButtonDetectSymbol, 0, 0, 1, 1) |
|
30 |
self.gridLayout.addLayout(self.gridLayout_2, 0, 0, 1, 1) |
|
31 |
self.buttonBox = QtWidgets.QDialogButtonBox(DetectSymbolDialog) |
|
32 |
self.buttonBox.setOrientation(QtCore.Qt.Horizontal) |
|
33 |
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) |
|
34 |
self.buttonBox.setObjectName("buttonBox") |
|
35 |
self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 1) |
|
36 |
self.splitter_2 = QtWidgets.QSplitter(DetectSymbolDialog) |
|
37 |
self.splitter_2.setOrientation(QtCore.Qt.Horizontal) |
|
38 |
self.splitter_2.setObjectName("splitter_2") |
|
39 |
self.splitter = QtWidgets.QSplitter(self.splitter_2) |
|
40 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) |
|
41 |
sizePolicy.setHorizontalStretch(0) |
|
42 |
sizePolicy.setVerticalStretch(0) |
|
43 |
sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth()) |
|
44 |
self.splitter.setSizePolicy(sizePolicy) |
|
45 |
self.splitter.setMinimumSize(QtCore.QSize(0, 0)) |
|
46 |
self.splitter.setMaximumSize(QtCore.QSize(300, 16777215)) |
|
47 |
self.splitter.setOrientation(QtCore.Qt.Vertical) |
|
48 |
self.splitter.setObjectName("splitter") |
내보내기 Unified diff