프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / QtImageViewer.py @ d1bd7708

이력 | 보기 | 이력해설 | 다운로드 (25.7 KB)

1
# coding: utf-8
2
import sys
3
import os.path
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 *
11
        from PyQt4.QtGui import *
12
    except ImportError:
13
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
14
    
15
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Commands')
16
import DefaultCommand
17

    
18
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Shapes')
19
from EngineeringLineItem import QEngineeringLineItem
20
from EngineeringTextItem import QEngineeringTextItem
21
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
22
from TrainingEditorDialog import QTrainingEditorDialog
23
from SymbolSvgItem import SymbolSvgItem
24

    
25
__author__ = "Marcel Goldschen-Ohm <marcel.goldschen@gmail.com>"
26
__version__ = '0.9.0'
27

    
28

    
29
class QtImageViewer(QGraphicsView):
30
    """ PyQt image viewer widget for a QPixmap in a QGraphicsView scene with mouse zooming and panning.
31
    Displays a QImage or QPixmap (QImage is internally converted to a QPixmap).
32
    To display any other image format, you must first convert it to a QImage or QPixmap.
33
    Some useful image format conversion utilities:
34
        qimage2ndarray: NumPy ndarray <==> QImage    (https://github.com/hmeine/qimage2ndarray)
35
        ImageQt: PIL Image <==> QImage  (https://github.com/python-pillow/Pillow/blob/master/PIL/ImageQt.py)
36
    Mouse interaction:
37
        Left mouse button drag: Pan image.
38
        Right mouse button drag: Zoom box.
39
        Right mouse button doubleclick: Zoom to show entire image.
40
    """
41

    
42
    # Mouse button signals emit image scene (x, y) coordinates.
43
    # !!! For image (row, column) matrix indexing, row = y and column = x.
44
    leftMouseButtonPressed = pyqtSignal(float, float)
45
    rightMouseButtonPressed = pyqtSignal(float, float)
46
    leftMouseButtonMoved = pyqtSignal(float, float)
47
    rightMouseButtonMoved = pyqtSignal(float, float)
48
    leftMouseButtonReleased = pyqtSignal(float, float)
49
    rightMouseButtonReleased = pyqtSignal(float, float)
50
    leftMouseButtonDoubleClicked = pyqtSignal(float, float)
51
    rightMouseButtonDoubleClicked = pyqtSignal(float, float)
52
    #itemRemoved = pyqtSignal(QGraphicsItem)
53
    startPointChanged = pyqtSignal(float, float)
54

    
55
    '''
56
        @history    2018.06.27  Jeongwoo    Change zoom rule (Qt.KeepAspectRatioByExpanding → Qt.KeepAspectRatio)
57
    '''
58
    def __init__(self, mainWindow = None):
59
        QGraphicsView.__init__(self)
60

    
61
        self.mainWindow = mainWindow
62
        # Image is displayed as a QPixmap in a QGraphicsScene attached to this QGraphicsView.
63
        self.command = None
64
        self.scene = QGraphicsScene(self)
65
        self.setScene(self.scene)
66
        self.scene.setBackgroundBrush(Qt.gray)
67

    
68
        self.scaleFactor = 1.0
69
        self.numScheduledScalings = 0
70
        self.isOriginalPointSelected = False
71

    
72
        # Store a local handle to the scene's current image pixmap.
73
        self._pixmapHandle = None
74

    
75
        # Image aspect ratio mode.
76
        # !!! ONLY applies to full image. Aspect ratio is always ignored when zooming.
77
        #   Qt.IgnoreAspectRatio: Scale image to fit viewport.
78
        #   Qt.KeepAspectRatio: Scale image to fit inside viewport, preserving aspect ratio.
79
        #   Qt.KeepAspectRatioByExpanding: Scale image to fill the viewport, preserving aspect ratio.
80
        self.aspectRatioMode = Qt.KeepAspectRatio
81

    
82
        # Scroll bar behaviour.
83
        #   Qt.ScrollBarAlwaysOff: Never shows a scroll bar.
84
        #   Qt.ScrollBarAlwaysOn: Always shows a scroll bar.
85
        #   Qt.ScrollBarAsNeeded: Shows a scroll bar only when zoomed.
86
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
87
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
88

    
89
        # Stack of QRectF zoom boxes in scene coordinates.
90
        self.zoomStack = []
91

    
92
        self.setRenderHint(QPainter.Antialiasing)
93

    
94
        self.setAcceptDrops(True)  # enable drop
95

    
96
        # Flags for enabling/disabling mouse interaction.
97
        self.canZoom = True
98
        self.canPan = True
99
        self.setMouseTracking(True)
100
        self.command = None
101
        
102
        self.guidesEnabled = False
103
        self._guidePen = QPen()
104
        self._guidePen.setColor(QColor(180, 180, 180))
105
        self._guidePen.setStyle(Qt.DashLine)
106
        self._guidePen.setWidthF(0.3)
107

    
108
        # set currentAttribute
109
        self.currentAttribute = ''
110

    
111
    '''
112
        @brief      Return Pixmap Handler
113
        @author     Jeongwoo
114
        @date       2018.06.11
115
    '''
116
    def getPixmapHandle(self):
117
        return self._pixmapHandle
118

    
119
    '''
120
        @brief      Use Default ImageViewer Command
121
        @author     Jeongwoo
122
        @date       18.04.10
123
        @history    .
124
    '''
125
    def useDefaultCommand(self):
126
        """ Use Default Command
127
        """
128
        self.command = DefaultCommand.DefaultCommand(self)
129

    
130
    def hasImage(self):
131
        """ Returns whether or not the scene contains an image pixmap.
132
        """
133
        return self._pixmapHandle is not None
134

    
135
    def clearImage(self):
136
        """ Removes the current image pixmap from the scene if it exists.
137
        """
138
        if self.hasImage():
139
            self.scene.removeItem(self._pixmapHandle)
140
            self._pixmapHandle = None
141

    
142
    def pixmap(self):
143
        """ Returns the scene's current image pixmap as a QPixmap, or else None if no image exists.
144
        :rtype: QPixmap | None
145
        """
146
        if self.hasImage():
147
            return self._pixmapHandle.pixmap()
148
        return None
149

    
150
    def image(self):
151
        """ Returns the scene's current image pixmap as a QImage, or else None if no image exists.
152
        :rtype: QImage | None
153
        """
154
        if self.hasImage():
155
            return self._pixmapHandle.pixmap().toImage()
156
        return None
157

    
158
    def setImage(self, image):
159
        """ Set the scene's current image pixmap to the input QImage or QPixmap.
160
        Raises a RuntimeError if the input image has type other than QImage or QPixmap.
161
        :type image: QImage | QPixmap
162
        """
163
        try:
164
            if type(image) is QPixmap:
165
                pixmap = image
166
            elif type(image) is QImage:
167
                pixmap = QPixmap.fromImage(image)
168
            else:
169
                raise RuntimeError("ImageViewer.setImage: Argument must be a QImage or QPixmap.")
170

    
171
            self.clearImage()
172
            self.scene.clear()
173

    
174
            if self.hasImage():
175
                self._pixmapHandle.setPixmap(pixmap)
176
            else:
177
                self._pixmapHandle = self.scene.addPixmap(pixmap)
178
                self._pixmapHandle.setFlags(QGraphicsItem.ItemClipsChildrenToShape)
179

    
180
            self.setSceneRect(QRectF(pixmap.rect()))  # Set scene size to image size.
181
            self.updateViewer()
182
        except Exception as ex:
183
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
184

    
185
    '''
186
        @brief  open a image file selected by user
187
        @author 
188
        @date
189
    '''
190
    def loadImageFromFile(self, folder='', fileName=""):
191
        import cv2
192

    
193
        """ Load an image from file.
194
        Without any arguments, loadImageFromFile() will popup a file dialog to choose the image file.
195
        With a fileName argument, loadImageFromFile(fileName) will attempt to load the specified image file directly.
196
        """
197
        try:
198
            if len(fileName) == 0:
199
                options = QFileDialog.Options()
200
                options |= QFileDialog.DontUseNativeDialog
201
                if QT_VERSION_STR[0] == '4':
202
                    fileName = QFileDialog.getOpenFileName(self, "Open image file", os.getcwd() if folder == '' else folder, "Image files(*.png *.jpg)", options=options)
203
                elif QT_VERSION_STR[0] == '5':
204
                    fileName, dummy = QFileDialog.getOpenFileName(self, "Open image file", os.getcwd() if folder == '' else folder, "Image files(*.png *.jpg)", options=options)
205
            if len(fileName) and os.path.isfile(fileName):
206
                cvImg = cv2.cvtColor(cv2.imread(fileName), cv2.COLOR_BGR2GRAY)
207
                #blur = cv2.GaussianBlur(cvImg, (5,5),0)
208
                cvImg = cv2.threshold(cvImg, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
209
                bytesPerLine = cvImg.shape[1]
210
                image = QImage(cvImg.data, cvImg.shape[1], cvImg.shape[0], bytesPerLine, QImage.Format_Indexed8)
211
                self.setImage(image)
212
        except Exception as ex:
213
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
214

    
215
        return fileName
216

    
217
    '''
218
        @history    2018.06.27  Jeongwoo    Change zoom rule (Qt.KeepAspectRatioByExpanding → Qt.KeepAspectRatio)
219
    '''
220
    def updateViewer(self):
221
        """ Show current zoom (if showing entire image, apply current aspect ratio mode).
222
        """
223
        if not self.hasImage():
224
            return
225
        if len(self.zoomStack):# and self.sceneRect().contains(self.zoomStack[-1]):
226
            self.fitInView(self.zoomStack[-1], Qt.KeepAspectRatio)  # Show zoomed rect (ignore aspect ratio).
227
        else:
228
            self.zoomStack = []  # Clear the zoom stack (in case we got here because of an invalid zoom).
229
            self.fitInView(self.sceneRect(), self.aspectRatioMode)  # Show entire image (use current aspect ratio mode).
230

    
231
    def zoomImageInit(self):
232
        if self.hasImage():
233
            self.zoomStack = []
234
            self.updateViewer()
235
            self.setCursor(QCursor(Qt.ArrowCursor))
236

    
237
    '''
238
        @brief      Zoom in & out image
239
        @author     Jeongwoo
240
        @date       -
241
        @history    18.04.11    Jeongwoo    add parameter 'adjust' (@ref ResultTreeWidget.itemClickEvent(self, item, columnNo))
242
    '''
243
    def zoomImage(self, isZoomIn, event, adjust = 1):
244
        """ Zoom in & out
245
        """
246
        HALF_SIZE = 300
247
        clickPos = event.pos()
248
        scenePos1 = self.mapToScene(clickPos.x() - HALF_SIZE//adjust, clickPos.y() - HALF_SIZE//adjust)
249
        scenePos2 = self.mapToScene(clickPos.x() + HALF_SIZE//adjust, clickPos.y() + HALF_SIZE//adjust)
250
        if isZoomIn:
251
            zoomArea = QRectF(QPointF(scenePos1.x() if scenePos1.x() > 0 else 0, scenePos1.y() if scenePos1.y() > 0 else 0), QPointF(scenePos2.x(), scenePos2.y()))
252
            #self.fitInView(zoomArea, Qt.KeepAspectRatioByExpanding)
253
            viewBBox = self.zoomStack[-1] if len(self.zoomStack) else self.sceneRect()
254
            selectionBBox = zoomArea.intersected(viewBBox)
255
            self.scene.setSelectionArea(QPainterPath())  # Clear current selection area.
256
            if selectionBBox.width() > HALF_SIZE*2 and selectionBBox.height() > HALF_SIZE*2:
257
                if selectionBBox.isValid() and (selectionBBox != viewBBox):
258
                    self.zoomStack.append(selectionBBox)
259
                    self.updateViewer()
260
        else:
261
            self.scene.setSelectionArea(QPainterPath())  # Clear current selection area.
262
            if len(self.zoomStack):
263
                self.zoomStack.pop()
264
            self.updateViewer()
265

    
266
    def resizeEvent(self, event):
267
        """ Maintain current zoom on resize.
268
        """
269
        self.updateViewer()
270

    
271
    '''
272
        @brief  mouse move event
273
    '''
274
    def mouseMoveEvent(self, event):
275
        try:
276
            if self.command is not None:
277
                scenePos = self.mapToScene(event.pos())
278
                self.command.execute(['mouseMoveEvent', event, scenePos])
279
                if self.command.name == "SelectAttribute":
280
                    QGraphicsView.mouseMoveEvent(self, event)
281
                    #attrType = self.command._type
282
                    #item = self.scene.itemAt(scenePos, QTransform())
283
                    #if item is not None and attrType == 'Text Item' and type(item) is QEngineeringTextItem:
284
                    #    QGraphicsView.mouseMoveEvent(self, event)
285
                    #elif item is not None and attrType == 'Symbol Item' and issubclass(type(item), SymbolSvgItem):
286
                    #    QGraphicsView.mouseMoveEvent(self, event)
287
                    #elif item is not None and attrType == 'Line Item' and type(item) is QEngineeringLineItem:
288
                    #    QGraphicsView.mouseMoveEvent(self, event)
289

    
290
                if self.command.isTreated == True: return
291
        except Exception as ex:
292
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
293

    
294
        if self.guidesEnabled:
295
            self.coords = self.mapToScene(event.pos())
296
            self.scene.invalidate()
297

    
298
        QGraphicsView.mouseMoveEvent(self, event)
299

    
300
    '''
301
        @brief      
302
        @author     
303
        @date       
304
        @history    block clear selection when right mouse button is clicked
305
    '''
306
    def mousePressEvent(self, event):
307
        try:
308
            if self.command is not None:
309
                scenePos = self.mapToScene(event.pos())
310
                self.command.execute(['mousePressEvent', event, scenePos])
311
                if self.command.isTreated == True: return
312
        except Exception as ex:
313
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
314

    
315
        if event.button() != Qt.RightButton:
316
            QGraphicsView.mousePressEvent(self, event)
317

    
318
    '''
319
        @brief      
320
        @author     
321
        @date       
322
    '''
323
    def mouseReleaseEvent(self, event):
324
        try:
325
            if self.command is not None:
326
                scenePos = self.mapToScene(event.pos())
327
                instance = self.command.execute(['mouseReleaseEvent', event, scenePos])
328
                if instance is not None:
329
                    self.scene.addItem(instance)
330

    
331
                if self.command is not None and self.command.isTreated == True: 
332
                    if self.command.name == 'Default' and self.command.isCopy:
333
                        return
334
                    self.command = DefaultCommand.DefaultCommand(self)
335
                    cursor = QCursor(Qt.ArrowCursor)
336
                    QApplication.instance().setOverrideCursor(cursor)
337
                    return
338
        except Exception as ex:
339
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
340

    
341
        QGraphicsView.mouseReleaseEvent(self, event)
342
    
343
    """
344
        @brief      Show entire image.
345
    """
346
    def mouseDoubleClickEvent(self, event):
347
        scenePos = self.mapToScene(event.pos())
348
        if self.command is not None:
349
            instance = self.command.execute(['mouseDoubleClickEvent', event, scenePos])
350
            if self.command.isTreated == True: return
351

    
352
        if event.button() == Qt.LeftButton:
353
            self.leftMouseButtonDoubleClicked.emit(scenePos.x(), scenePos.y())
354
        elif event.button() == Qt.RightButton:
355
            if self.canZoom:
356
                self.zoomStack = []  # Clear zoom stack.
357
                self.updateViewer()
358
            self.rightMouseButtonDoubleClicked.emit(scenePos.x(), scenePos.y())
359
        
360
        QGraphicsView.mouseDoubleClickEvent(self, event)
361

    
362
    '''
363
        @brief      key press event
364
        @author     Jeongwoo
365
        @date       2018.??.??
366
        @history    send escape key event to command
367
    '''
368
    def keyPressEvent(self, event):
369
        try:
370
            if event.key() == Qt.Key_Delete:
371
                for item in self.scene.selectedItems():
372
                    item.transfer.onRemoved.emit(item)
373
            elif event.key() == Qt.Key_Escape:
374
                if self.command is not None:
375
                    self.command.execute(['keyPressEvent', event, []])
376
                    if self.command.isTreated: return
377
            else:
378
                if self.command is not None:
379
                    self.command.execute(['keyPressEvent', event, []])
380
                    if self.command.isTreated: return
381
            if type(self.mainWindow) is QTrainingEditorDialog:
382
                self.mainWindow.keyPressEvent(event)
383

    
384
            QGraphicsView.keyPressEvent(self, event)
385
        except Exception as ex:
386
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
387

    
388
    '''
389
        @brief  key release event
390
        @author Jeongwoo
391
        @date   2018.??.??
392
    '''
393
    def keyReleaseEvent(self, event):
394
        if event.key() == Qt.Key_Delete:
395
            pass
396

    
397
        QGraphicsView.keyReleaseEvent(self, event)
398

    
399
    '''
400
        @brief      mouse wheel event
401
        @autor      humkyung
402
        @date       
403
    '''
404
    def wheelEvent(self, event):
405
        if event.modifiers() == Qt.ControlModifier:
406
            if self.canZoom and self.hasImage():
407
                numDegrees = event.angleDelta() / 8
408
                if numDegrees is not None:
409
                    if numDegrees.y() > 0:
410
                        self.zoomImage(True, event)
411
                    elif numDegrees.y() < 0:
412
                        self.zoomImage(False, event)
413
        else:
414
            super().wheelEvent(event)
415

    
416
    '''
417
        @brief      
418
    '''
419
    def drawForeground(self, painter, rect):
420
        if hasattr(self, 'coords') and self.guidesEnabled:
421
            painter.setClipRect(rect)
422
            painter.setPen(self._guidePen)
423
            painter.drawLine(round(self.coords.x()), rect.top(), round(self.coords.x()), rect.bottom())
424
            painter.drawLine(rect.left(), round(self.coords.y()), rect.right(), round(self.coords.y()))
425

    
426
        '''
427
        image = self.image()
428
        if image is not None:
429
            width = rect.width()
430
            height = rect.height()
431
            if self.crosshairPos is not None:
432
                pen = QPen()
433
                pen.setColor(QColor(180, 180, 180))
434
                pen.setStyle(Qt.DashLine)
435
                pen.setWidthF(0.3)
436
                painter.setClipRect(rect)
437
                painter.setPen(pen)
438
                painter.drawLine(self.crosshairPos.x(), 0, self.crosshairPos.x(), height)#Vertical
439
                painter.drawLine(0, self.crosshairPos.y(), width, self.crosshairPos.y())#Horizontal
440
            #else:
441
            #    painter.eraseRect(QRectF(0, 0, width, height))
442
        '''
443

    
444
    '''
445
        @brief      draw background
446
        @author     humkyung
447
        @date       2018.07.23
448
    '''        
449
    def drawBackground(self, painter, rect):
450
        QGraphicsView.drawBackground(self, painter, rect) 
451

    
452
    '''
453
        @history    2018.06.11  Jeongwoo    Change method to manage guideline items
454
                    humkyung 2018.08.28 remove guide lines before drawing
455
    '''
456
    GUIDELINE_ITEMS = []
457
    def showGuideline(self, pos, isShow):
458
        image = self.image()
459
        width = image.width()
460
        height = image.height()
461
        pen = QPen()
462
        pen.setColor(QColor(180, 180, 180))
463
        pen.setStyle(Qt.DashLine)
464
        pen.setWidthF(0.5)
465
        if isShow:
466
            items = self.scene.items()
467
            for item in self.GUIDELINE_ITEMS:
468
                if item in items:
469
                    self.scene.removeItem(item)
470
            self.GUIDELINE_ITEMS.clear()
471

    
472
            if pos is not None:
473
                verticalLine = self.scene.addLine(pos.x(), 0, pos.x(), height, pen)
474
                horizontalLine = self.scene.addLine(0, pos.y(), width, pos.y(), pen)
475
            else:
476
                verticalLine = self.scene.addLine(round(width*0.5), 0, round(width*0.5), height, pen)
477
                horizontalLine = self.scene.addLine(0, round(height*0.5), width, round(height*0.5), pen)
478

    
479
            self.GUIDELINE_ITEMS.append(verticalLine)
480
            self.GUIDELINE_ITEMS.append(horizontalLine)
481
        else:
482
            items = self.scene.items()
483
            for item in self.GUIDELINE_ITEMS:
484
                if item in items:
485
                    self.scene.removeItem(item)
486
            self.GUIDELINE_ITEMS.clear()
487

    
488
    '''
489
        @brief  drag enter event
490
        @author humkyung
491
        @date   2018.04.17
492
    '''
493
    def dragEnterEvent(self, event):
494
        event.acceptProposedAction()
495

    
496
    '''
497
        @brief      drag move event
498
        @author     humkyung
499
        @date       2018.04.17
500
        @history    humkyung 2018.08.21 highlight item under mouse
501
    '''
502
    def dragMoveEvent(self, event):
503
        scenePos = self.mapToScene(event.pos())
504
        items = [item for item in self.scene.items(scenePos) if type(item) is not QGraphicsPixmapItem]
505
        if len(items) > 0:
506
            if not hasattr(self, '_underItem') or self._underItem is not items[0]:
507
                if hasattr(self, '_underItem') and self._underItem is not None:
508
                    self._underItem.hoverLeaveEvent(event)
509

    
510
                self._underItem = items[0]
511
                self._underItem.hoverEnterEvent(event)
512
        elif hasattr(self, '_underItem') and self._underItem is not None:
513
            self._underItem.hoverLeaveEvent(event)
514
            self._underItem = None
515
        
516
        event.acceptProposedAction()
517

    
518
    '''
519
        @brief      drop event
520
        @author     humkyung
521
        @date       2018.04.17
522
        @history    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
523
                    humkyung 2018.08.21 call hoverLeaveEvent if item exists under mouse
524
    '''
525
    def dropEvent(self, event):
526
        from AppDocData import AppDocData
527
        import symbol
528
        
529
        if len(self.scene.items()) is 0:
530
            return
531
        if hasattr(self, '_underItem') and self._underItem is not None:
532
            self._underItem.hoverLeaveEvent(event)
533
            self._underItem = None
534

    
535
        scenePos = self.mapToScene(event.pos())
536
        svgFileName = event.mimeData().text()
537
        svg = self.createSymbolObject(svgFileName)
538
        self.matchSymbolToLine(svg, scenePos)
539

    
540
        if type(svg) is QEngineeringSpecBreakItem:
541
            self.command.specBreak_startPoint = [scenePos.x(), scenePos.y()]
542
            self.command.isCopy = True
543
            self.command.isSpecBreak = True
544
            self.command.symbol = svg
545
            while 0 != svg.angle:
546
                svg.rotateSymbol()
547

    
548
        event.acceptProposedAction()
549

    
550
    '''
551
        @brief  drop create Symbol
552
        @author kyouho
553
        @date   2018.07.27
554
    '''
555
    def createSymbolObject(self, svgFileName):
556
        from AppDocData import AppDocData
557
        import symbol
558
        
559
        symbol = AppDocData.instance().getSymbolByQuery('name', svgFileName)
560
        svgFilePath = os.path.join(AppDocData.instance().getCurrentProject().getSvgFilePath(), symbol.getType(), svgFileName+'.svg')
561
        svg = SymbolSvgItem.createItem(symbol.getType(), svgFilePath)
562
        connPts = None
563
        strConnPts = symbol.getConnectionPoint()
564
        if strConnPts is not None:
565
            connPts = [(float(x.split(',')[0]), float(x.split(',')[1])) if len(x.split(',')) == 2 else (x.split(',')[0], float(x.split(',')[1]), float(x.split(',')[2])) \
566
            for x in strConnPts.split('/')]
567

    
568
        svg.buildItem(svgFileName, symbol.getType(), 0, None, None, None, connPts, symbol.getBaseSymbol(), symbol.getAdditionalSymbol(), symbol.getHasInstrumentLabel())
569
        
570
        return svg
571
        
572
    '''
573
        @brief      match symbol to line
574
        @author     kyouho
575
        @date       2018.07.27
576
        @history    humkyung 2018.08.23 change scenePos to connector's center when symbol is placed on connector
577
    '''
578
    def matchSymbolToLine(self, svg, scenePos):
579
        from EngineeringConnectorItem import QEngineeringConnectorItem
580

    
581
        items = [item for item in self.scene.items(scenePos) if type(item) is not QGraphicsPixmapItem]
582
        if len(items) > 0 and type(items[0]) is QEngineeringConnectorItem:
583
            scenePos = QPointF(items[0].center()[0], items[0].center()[1])
584

    
585
        matches = [item for item in self.scene.items() if (type(item) is QEngineeringLineItem) and (item.distanceTo((scenePos.x(), scenePos.y())) < 20)]
586
        if len(matches) == 1:
587
            matches[0].insertSymbol(svg, scenePos)
588
        else:
589
            transform = QTransform()
590
            transform.translate(scenePos.x() - svg.symbolOrigin[0], scenePos.y() - svg.symbolOrigin[1])
591
            svg.setTransform(transform)
592
            svg.loc = [round(scenePos.x() - svg.symbolOrigin[0], 1), round(scenePos.y() - svg.symbolOrigin[1], 1)]
593
            svg.size = [svg.boundingRect().width(), svg.boundingRect().height()]
594
            svg.origin = [round(scenePos.x(), 1), round(scenePos.y(), 1)]
595
            self.scene.addItem(svg)
596

    
597
        svg.transfer.onRemoved.connect(self.mainWindow.itemRemoved)
598

    
599
        self.scene.clearFocus()
600
        for item in self.scene.selectedItems():
601
            item.setSelected(False)
602

    
603
        self.setFocus()
604
        svg.setSelected(True)
605
        self.scene.setFocusItem(svg)
606

    
607
    '''
608
        @brief  find item by uid (SymbolSvgItem 기반, QEngineeringConnectorItem 제외, QEngineeringLineItem 포함)
609
        @author kyouho
610
        @date   2018.07.31
611
    '''
612
    def findItemByUid(self, uid):
613
        from EngineeringConnectorItem import QEngineeringConnectorItem
614
        items = [item for item in self.scene.items() if hasattr(item, 'uid')]
615
        for item in items:
616
            if item.uid == uid:
617
                return item
618
        
619
        return None
620
            
621

    
622

    
623
if __name__ == '__main__':
624
    import sys
625
    try:
626
        from PyQt5.QtWidgets import QApplication
627
    except ImportError:
628
        try:
629
            from PyQt4.QtGui import QApplication
630
        except ImportError:
631
            raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
632
    print('Using Qt ' + QT_VERSION_STR)
633

    
634
    def handleLeftClick(x, y):
635
        row = int(y)
636
        column = int(x)
637
        print("Clicked on image pixel (row="+str(row)+", column="+str(column)+")")
638

    
639
    # Create the application.
640
    app = QApplication(sys.argv)
641

    
642
    # Create image viewer and load an image file to display.
643
    viewer = QtImageViewer(None)
644
    viewer.loadImageFromFile()  # Pops up file dialog.
645

    
646
    # Handle left mouse clicks with custom slot.
647
    viewer.leftMouseButtonPressed.connect(handleLeftClick)
648

    
649
    # Show viewer and run application.
650
    viewer.show()
651
    sys.exit(app.exec_())
클립보드 이미지 추가 (최대 크기: 500 MB)