프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

hytos / HYTOS / HYTOS / QtImageViewer.py @ d79cbac6

이력 | 보기 | 이력해설 | 다운로드 (25.4 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 EngineeringTextItem import QEngineeringTextItem
20
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
21
from SymbolSvgItem import SymbolSvgItem
22

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

    
26

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

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

    
53
    '''
54
        @history    2018.06.27  Jeongwoo    Change zoom rule (Qt.KeepAspectRatioByExpanding → Qt.KeepAspectRatio)
55
    '''
56
    def __init__(self, mainWindow = None):
57
        from QtImageViewerScene import QtImageViewerScene
58

    
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 = QtImageViewerScene(self)
65
        self.setScene(self.scene)
66
        self.scene.setBackgroundBrush(Qt.lightGray)
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
        """ Load an image from file.
192
        Without any arguments, loadImageFromFile() will popup a file dialog to choose the image file.
193
        With a fileName argument, loadImageFromFile(fileName) will attempt to load the specified image file directly.
194
        """
195
        try:
196
            if len(fileName) == 0:
197
                options = QFileDialog.Options()
198
                options |= QFileDialog.DontUseNativeDialog
199
                if QT_VERSION_STR[0] == '4':
200
                    fileName = QFileDialog.getOpenFileName(self, "Open image file", os.getcwd() if folder == '' else folder, "Image files(*.png *.jpg)", options=options)
201
                elif QT_VERSION_STR[0] == '5':
202
                    fileName, dummy = QFileDialog.getOpenFileName(self, "Open image file", os.getcwd() if folder == '' else folder, "Image files(*.png *.jpg)", options=options)
203
            if len(fileName) and os.path.isfile(fileName):
204
                image = QImage(fileName, format = None)
205
                self.setImage(image)
206
        except Exception as ex:
207
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
208

    
209
        return fileName
210

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

    
228
    def zoomImageInit(self):
229
        if self.hasImage():
230
            self.zoomStack = []
231
            self.updateViewer()
232
            self.setCursor(QCursor(Qt.ArrowCursor))
233

    
234
    '''
235
        @brief      Zoom in & out image
236
        @author     Jeongwoo
237
        @date       -
238
        @history    18.04.11    Jeongwoo    add parameter 'adjust' (@ref ResultTreeWidget.itemClickEvent(self, item, columnNo))
239
    '''
240
    def zoomImage(self, isZoomIn, event, adjust = 1):
241
        """ Zoom in & out
242
        """
243

    
244
        HALF_SIZE = 300
245
        clickPos = event.pos()
246
        scenePos1 = self.mapToScene(clickPos.x() - HALF_SIZE//adjust, clickPos.y() - HALF_SIZE//adjust)
247
        scenePos2 = self.mapToScene(clickPos.x() + HALF_SIZE//adjust, clickPos.y() + HALF_SIZE//adjust)
248
        if isZoomIn:
249
            zoomArea = QRectF(QPointF(scenePos1.x() if scenePos1.x() > 0 else 0, scenePos1.y() if scenePos1.y() > 0 else 0), QPointF(scenePos2.x(), scenePos2.y()))
250
            #self.fitInView(zoomArea, Qt.KeepAspectRatioByExpanding)
251
            viewBBox = self.zoomStack[-1] if len(self.zoomStack) else self.sceneRect()
252
            selectionBBox = zoomArea.intersected(viewBBox)
253
            self.scene.setSelectionArea(QPainterPath())  # Clear current selection area.
254
            if selectionBBox.width() > HALF_SIZE*2 and selectionBBox.height() > HALF_SIZE*2:
255
                if selectionBBox.isValid() and (selectionBBox != viewBBox):
256
                    self.zoomStack.append(selectionBBox)
257
                    self.updateViewer()
258
        else:
259
            zoomNewRect = None
260
            self.scene.setSelectionArea(QPainterPath())  # Clear current selection area.
261
            if len(self.zoomStack):
262
                self.zoomStack.pop()
263
            if len(self.zoomStack):
264
                newScenePos = self.mapToScene(clickPos.x(), clickPos.y())
265
                newPosX1 = newScenePos.x() - self.zoomStack[-1].width() / 2
266
                newPosY1 = newScenePos.y() - self.zoomStack[-1].height() / 2
267
                zoomNewPos1 = QPointF(newPosX1 if newPosX1 > 0 else 0, newPosY1 if newPosY1 > 0 else 0)
268
                newPosX2 = newScenePos.x() + self.zoomStack[-1].width() / 2
269
                newPosY2 = newScenePos.y() + self.zoomStack[-1].width() / 2
270
                zoomNewPos2 = QPointF(newPosX2, newPosY2)
271
                zoomNewRect = QRectF(zoomNewPos1, zoomNewPos2)
272
            self.updateViewer(zoomNewRect)
273

    
274
    def resizeEvent(self, event):
275
        """ Maintain current zoom on resize.
276
        """
277
        self.updateViewer()
278

    
279
    '''
280
        @brief  mouse move event
281
    '''
282
    def mouseMoveEvent(self, event):
283
        try:
284
            scenePos = self.mapToScene(event.pos())
285
            if self.command is not None:
286
                self.command.execute(['mouseMoveEvent', event, scenePos])
287
                if self.command.name == "SelectAttribute":
288
                    QGraphicsView.mouseMoveEvent(self, event)
289
                if self.command.isTreated == True: return
290
        except Exception as ex:
291
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
292

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

    
297
        QGraphicsView.mouseMoveEvent(self, event)
298

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

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

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

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

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

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

    
361
    '''
362
        @brief      key press event
363
        @author     Jeongwoo
364
        @date       2018.??.??
365
        @history    send escape key event to command
366
    
367
    def keyPressEvent(self, event):
368
        try:
369
            if event.key() == Qt.Key_Delete:
370
                for item in [item for item in self.scene.selectedItems() if hasattr(item, 'transfer')]:
371
                    item.transfer.onRemoved.emit(item)
372
            elif event.key() == Qt.Key_Escape:
373
                if self.command is not None:
374
                    self.command.execute(['keyPressEvent', event, []])
375
                    if self.command.isTreated: return
376
            else:
377
                if self.command is not None:
378
                    self.command.execute(['keyPressEvent', event, []])
379
                    if self.command.isTreated: return
380
            
381
            QGraphicsView.keyPressEvent(self, event)
382
        except Exception as ex:
383
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
384
    '''
385

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

    
395
        QGraphicsView.keyReleaseEvent(self, event)
396

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

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

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

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

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

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

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

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

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

    
509
                self._underItem = items[0]
510
                if hasattr(self._underItem, 'highlight'):
511
                    self._underItem.highlight(True)
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
        uid = event.mimeData().text()
537
        svg = self.createSymbolObject(uid)
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, uid):
556
        from AppDocData import AppDocData
557
        import symbol
558
        
559
        symbol = AppDocData.instance().getSymbolByQuery('uid', uid)
560
        svgFileName = symbol.getName()
561
        svgFilePath = os.path.join(AppDocData.instance().getCurrentProject().getSvgFilePath(), symbol.getCategory(), symbol.getType(), svgFileName+'.svg')
562
        svg = SymbolSvgItem.createItem(symbol.getType(), svgFilePath)
563
        connPts = None
564
        strConnPts = symbol.getConnectionPoint()
565
        if strConnPts is not None and strConnPts != '':
566
            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])) \
567
            for x in strConnPts.split('/')]
568

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

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

    
586
        transform = QTransform()
587
        transform.translate(scenePos.x() - svg.symbolOrigin[0], scenePos.y() - svg.symbolOrigin[1])
588
        svg.setTransform(transform)
589
        svg.loc = [round(scenePos.x() - svg.symbolOrigin[0], 1), round(scenePos.y() - svg.symbolOrigin[1], 1)]
590
        svg.size = [svg.boundingRect().width(), svg.boundingRect().height()]
591
        svg.origin = [round(scenePos.x(), 1), round(scenePos.y(), 1)]
592
        self.scene.addItem(svg)
593

    
594
        svg.transfer.onRemoved.connect(self.mainWindow.itemRemoved)
595

    
596
        for conn in svg.connectors:
597
            conn.sceneConnectPoint = (conn.sceneBoundingRect().center().x(), conn.sceneBoundingRect().center().y())
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

    
615
        items = [item for item in self.scene.items() if hasattr(item, 'uid') and str(item.uid) == str(uid)]
616
        return items[0] if items else None
617

    
618
if __name__ == '__main__':
619
    import sys
620
    try:
621
        from PyQt5.QtWidgets import QApplication
622
    except ImportError:
623
        try:
624
            from PyQt4.QtGui import QApplication
625
        except ImportError:
626
            raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
627
    print('Using Qt ' + QT_VERSION_STR)
628

    
629
    def handleLeftClick(x, y):
630
        row = int(y)
631
        column = int(x)
632
        print("Clicked on image pixel (row="+str(row)+", column="+str(column)+")")
633

    
634
    # Create the application.
635
    app = QApplication(sys.argv)
636

    
637
    # Create image viewer and load an image file to display.
638
    viewer = QtImageViewer(None)
639
    viewer.loadImageFromFile()  # Pops up file dialog.
640

    
641
    # Handle left mouse clicks with custom slot.
642
    viewer.leftMouseButtonPressed.connect(handleLeftClick)
643

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