def on_item_changed(self, current, previous): if not current: return crc, goodname, path, fname = current.data(Qt.UserRole) title = QPixmap(os.path.join( self.user_data_path, "title", "%s.png") % crc) snapshot = QPixmap(os.path.join( self.user_data_path, "snapshot", "%s.png") % crc) if title.isNull(): title = QPixmap(":/title/%s.jpg" % crc) if snapshot.isNull(): snapshot = QPixmap(":/snapshot/%s.jpg" % crc) if title.isNull(): title = QPixmap(":/images/default.png") if snapshot.isNull(): snapshot = QPixmap(":/images/default.png") if previous is not None: self.titleView.scene().removeItem(self.title_item) self.snapshotView.scene().removeItem(self.snapshot_item) title_pixmap = title.scaled( self.titleView.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) snapshot_pixmap = snapshot.scaled( self.snapshotView.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) title_item = QGraphicsPixmapItem(title_pixmap) snapshot_item = QGraphicsPixmapItem(snapshot_pixmap) self.titleView.scene().addItem(title_item) self.snapshotView.scene().addItem(snapshot_item) self.title_item = title_item self.snapshot_item = snapshot_item
def on_imagesTree_currentItemChanged(self, current, previous): """ Private slot to show a preview of the selected image. @param current current image entry (QTreeWidgetItem) @param previous old current entry (QTreeWidgetItem) """ if current is None: return imageUrl = QUrl(current.text(1)) if not imageUrl.host(): imageUrl.setHost(QUrl(self.siteAddressLabel.text()).host()) imageUrl.setScheme(QUrl(self.siteAddressLabel.text()).scheme()) import Helpviewer.HelpWindow cache = Helpviewer.HelpWindow.HelpWindow.networkAccessManager().cache() if cache: cacheData = cache.data(imageUrl) else: cacheData = None pixmap = QPixmap() invalidPixmap = False scene = QGraphicsScene(self.imagePreview) if not cacheData: invalidPixmap = True else: pixmap.loadFromData(cacheData.readAll()) if pixmap.isNull(): invalidPixmap = True if invalidPixmap: scene.addText(self.tr("Preview not available.")) else: scene.addPixmap(pixmap) self.imagePreview.setScene(scene)
def set_background(self, data): img = QImage() img.loadFromData(data) pixmap = QPixmap(img) if pixmap.isNull(): return None return pixmap
def loadImageDropped(self, urlin): pix = QPixmap(urlin.toLocalFile()) if pix.isNull(): QMessageBox.critical(self, 'Error', 'An error occured while loading image') return False self.setPixmap(pix) return pix
def findIconHelper(self, size = int, themeName = str, iconName = str): pixmap = QPixmap() if iconName == '' or self.themeName == '': return pixmap if themeName == '': themeName = self.themeName if themeName == self.themeName: index = self.themeIndex else: index = self.readThemeIndex(themeName) subDirs = filter(lambda x:x[0] == str(size), index.dirList) for iconDir in self.iconDirs: if path.exists(path.join(iconDir, themeName)): for theme in subDirs: fileName = path.join(iconDir, themeName, theme[1], '%s.png' % str(iconName)) fileName_svg = path.join(iconDir, themeName, theme[1], '%s.svg' % str(iconName)) logging.debug('Looking for : %s' % fileName) if path.exists(fileName): pixmap.load(fileName) logging.debug('Icon: %s found in theme %s' % \ (iconName, themeName)) return pixmap elif path.exists(fileName_svg): pixmap.load(fileName_svg) logging.debug('Icon: %s found in %s' % (iconName, iconDir)) return pixmap for iconDir in self.extraIcons: fileName = path.join(iconDir, '%s.png' % str(iconName)) fileName_svg = path.join(iconDir, '{}.svg'.format(str(iconName))) if path.exists(fileName): pixmap.load(fileName) #print "pixmap ->{}".format(fileName) logging.debug('Icon: %s found in %s' % (iconName, iconDir)) return pixmap elif path.exists(fileName_svg): image=QImage(size, size, QImage.Format_RGB32) reader=QImageReader(fileName) reader.read(image) pixmap.convertFromImage(image) logging.debug('Icon: %s found in %s' % (iconName, iconDir)) #print "pixmap ->{}".format(fileName) return pixmap if len(self._themes) > 0: self._themes.pop(0) if not len(self._themes) == 0 and pixmap.isNull(): pixmap = self.findIconHelper(size, self._themes[0], iconName) return pixmap
def set_img(self, future): content = future.result() img = QImage() img.loadFromData(content) pixmap = QPixmap(img) if pixmap.isNull(): return None self.img_label.setPixmap( pixmap.scaledToWidth(self.img_label.width(), mode=Qt.SmoothTransformation))
def loadImage(self): filein, _ = QFileDialog.getOpenFileName(self, 'Open image', '', 'Images (*.png *.jpg *.gif *.bmp)') if not filein: return False pix = QPixmap(filein) if pix.isNull(): QMessageBox.critical(self, 'Error', 'An error occured while loading image') return False self.setPixmap(pix) return pix
def fillImage(self, pixmap, painter, roi, param, source): """Draw image in roi. """ x, y, w, h = roi fillPixmap = QPixmap(param.fillPath) if not fillPixmap.isNull(): fillPixmap = fillPixmap.scaled(w, h, QtCore.Qt.IgnoreAspectRatio) mask = self.getMask(pixmap, x, y, w, h, param.shape, None, QtCore.Qt.white, QtCore.Qt.black) painter.setClipRegion(QtGui.QRegion(QtGui.QBitmap(mask))) painter.drawPixmap(x, y, fillPixmap) painter.setClipping(False)
def __init__(self, parent, collection, item): QWidget.__init__(self, parent) self.setupUi(self) self.parent = parent self.item = item self.collection = collection self.header.setText(collection.title) self.description.setText(collection.description) icon = QPixmap(":/gui/pics/%s" % collection.icon) if icon.isNull(): icon = QPixmap(":/gui/pics/systemsettings.png") self.icon.setPixmap(icon)
class RoundRectItem(QGraphicsObject): def __init__(self, bounds, color, parent=None): super(RoundRectItem, self).__init__(parent) self.fillRect = False self.bounds = QRectF(bounds) self.pix = QPixmap() self.gradient = QLinearGradient() self.gradient.setStart(self.bounds.topLeft()) self.gradient.setFinalStop(self.bounds.bottomRight()) self.gradient.setColorAt(0, color) self.gradient.setColorAt(1, color.darker(200)) self.setCacheMode(QGraphicsItem.ItemCoordinateCache) def setFill(self, fill): self.fillRect = fill self.update() def fill(self): return self.fillRect fill = pyqtProperty(bool, fill, setFill) def paint(self, painter, option, widget): painter.setPen(Qt.NoPen) painter.setBrush(QColor(0, 0, 0, 64)) painter.drawRoundedRect(self.bounds.translated(2, 2), 25.0, 25.0) if self.fillRect: painter.setBrush(QApplication.palette().brush(QPalette.Window)) else: painter.setBrush(self.gradient) painter.setPen(QPen(Qt.black, 1)) painter.drawRoundedRect(self.bounds, 25.0, 25.0) if not self.pix.isNull(): painter.scale(1.95, 1.95) painter.drawPixmap(-self.pix.width() / 2, -self.pix.height() / 2, self.pix) def boundingRect(self): return self.bounds.adjusted(0, 0, 2, 2) def pixmap(self): return QPixmap(self.pix) def setPixmap(self, pixmap): self.pix = QPixmap(pixmap) self.update()
def pixmap_from_url(self, url, callback=None): # FIXME: only neteasemusic img url accept the params data = {'param': '{0}y{0}'.format(self.width())} res = self.request.get(url, data) if res is None: return None img = QImage() img.loadFromData(res.content) pixmap = QPixmap(img) if pixmap.isNull(): return None if callback is not None: callback(pixmap) return pixmap
def _init_icon(): """Initialize the icon of qutebrowser.""" icon = QIcon() fallback_icon = QIcon() for size in [16, 24, 32, 48, 64, 96, 128, 256, 512]: filename = ':/icons/qutebrowser-{}x{}.png'.format(size, size) pixmap = QPixmap(filename) if pixmap.isNull(): log.init.warning("Failed to load {}".format(filename)) else: fallback_icon.addPixmap(pixmap) icon = QIcon.fromTheme('qutebrowser', fallback_icon) if icon.isNull(): log.init.warning("Failed to load icon") else: qApp.setWindowIcon(icon)
def drawBackground(self, pixmap): """Draw background in pixmap. """ w, h = pixmap.width(), pixmap.height() mode = self.__bgModes[self.bgCBox.currentIndex()] source = QPixmap(pixmap) painter = QtGui.QPainter(pixmap) if mode == self.BG_COLOR: painter.fillRect(0, 0, w, h, self.bgColor) if mode == self.BG_TRANSPARENT or mode == self.BG_IMAGE or mode == self.BG_INPUT: painter.drawPixmap(0, 0, common.checkerboard(pixmap.size())) if mode == self.BG_IMAGE and self.bgPath: bgPixmap = QPixmap(self.bgPath) if not bgPixmap.isNull(): bgPixmap = bgPixmap.scaled(w, h, QtCore.Qt.IgnoreAspectRatio) painter.drawPixmap(0, 0, bgPixmap) if mode == self.BG_INPUT: painter.drawPixmap(0, 0, source)
def findIconHelper(self, size = int, themeName = str, iconName = str): pixmap = QPixmap() if iconName == '' or self.themeName == '': return pixmap if themeName == '': themeName = self.themeName if themeName == self.themeName: index = self.themeIndex else: index = self.readThemeIndex(themeName) subDirs = filter(lambda x:x[0] == str(size), index.dirList) for iconDir in self.iconDirs: if path.exists(path.join(iconDir, themeName)): for theme in subDirs: fileName = path.join(iconDir, themeName, theme[1], '%s.png' % str(iconName)) logging.debug('Looking for : %s' % fileName) if path.exists(fileName): pixmap.load(fileName) logging.debug('Icon: %s found in theme %s' % \ (iconName, themeName)) return pixmap for iconDir in self.extraIcons: fileName = path.join(iconDir, '%s.png' % str(iconName)) if path.exists(fileName): pixmap.load(fileName) logging.debug('Icon: %s found in %s' % (iconName, iconDir)) return pixmap if len(self._themes) > 0: self._themes.pop(0) if not len(self._themes) == 0 and pixmap.isNull(): pixmap = self.findIconHelper(size, self._themes[0], iconName) return pixmap
def set_paragraph(self, h2='', h3='', text='', img=None): if h2 != '': lbl_h2 = QLabel(h2, self.inner) fnt = lbl_h2.font() fnt.setPointSize(self.H2_FONT_SIZE) lbl_h2.setFont(fnt) lbl_h2.setFixedHeight(self.H2_HEIGHT) lbl_h2.setAlignment(Qt.AlignBottom) lbl_h2.setMargin(self.SIDE_MARGIN) self.vbox.addWidget(lbl_h2) frm = QFrame(self.inner) frm.setFrameShape(QFrame.HLine) frm.setContentsMargins(self.SIDE_MARGIN, 0, self.SIDE_MARGIN, 0) plt = frm.palette() plt.setColor(QPalette.WindowText, Qt.darkGray) frm.setPalette(plt) self.vbox.addWidget(frm) if text != '': lbl_txt = QLabel(text, self.inner) lbl_txt.setWordWrap(True) fnt = lbl_txt.font() fnt.setPointSize(self.TEXT_FONT_SIZE) lbl_txt.setFont(fnt) lbl_txt.setMargin(self.SIDE_MARGIN) self.vbox.addWidget(lbl_txt) if img is not None: if self.params.lang == 'en': img += '_en.png' else: img += '_jp.png' pixmap = QPixmap(img) if not pixmap.isNull(): lbl_img = QLabel(self.inner) lbl_img.setPixmap(pixmap) self.lbl_img_list.append(lbl_img) self.pixmap_list.append(pixmap.scaledToWidth(pixmap.width())) self.vbox.addWidget(lbl_img) self.inner.setLayout(self.vbox)
class RobotHead(RobotPart): def __init__(self, parent=None): super(RobotHead, self).__init__(parent) self.pixmap = QPixmap() def boundingRect(self): return QRectF(-15, -50, 30, 50) def paint(self, painter, option, widget=None): if self.pixmap.isNull(): painter.setBrush(self.color.lighter(130) if self.dragOver else self.color) painter.drawRoundedRect(-10, -30, 20, 30, 25, 25, Qt.RelativeSize) painter.setBrush(Qt.white) painter.drawEllipse(-7, -3 - 20, 7, 7) painter.drawEllipse(0, -3 - 20, 7, 7) painter.setBrush(Qt.black) painter.drawEllipse(-5, -1 - 20, 2, 2) painter.drawEllipse(2, -1 - 20, 2, 2) painter.setPen(QPen(Qt.black, 2)) painter.setBrush(Qt.NoBrush) painter.drawArc(-6, -2 - 20, 12, 15, 190 * 16, 160 * 16) else: painter.scale(0.2272, 0.2824) painter.drawPixmap(QPointF(-15 * 4.4, -50 * 3.54), self.pixmap) def dragEnterEvent(self, event): if event.mimeData().hasImage(): event.setAccepted(True) self.dragOver = True self.update() else: super(RobotHead, self).dragEnterEvent(event) def dropEvent(self, event): if event.mimeData().hasImage(): self.dragOver = False self.pixmap = QPixmap(event.mimeData().imageData()) self.update() else: super(RobotHead, self).dropEvent(event)
def getPixmap(self, key): """ Public method to retrieve a pixmap. @param key name of the wanted pixmap (string) @return the requested pixmap (QPixmap) """ if key: try: return self.pixmapCache[key] except KeyError: if not os.path.isabs(key): for path in self.searchPath: pm = QPixmap(path + "/" + key) if not pm.isNull(): break else: pm = QPixmap() else: pm = QPixmap(key) self.pixmapCache[key] = pm return self.pixmapCache[key] return QPixmap()
class Dialog(QDialog): """A Dialog with basic layout features: a main widget, an icon or pixmap, a separator, buttons (provided by a QDialogButtonBox) """ def __init__(self, parent = None, message = "", title = "", icon = None, iconSize = QSize(64, 64), pixmap = None, separator = True, buttonOrientation = Qt.Horizontal, buttons = ('ok', 'cancel'), help = None, **kwargs): """Initializes the dialog. parent = a parent widget or None. The following keyword arguments are recognized: - message: the text to display in the message label - title: the window title - icon or pixmap: shown in the left area - iconSize: size of the icon in the left (QSize, default: 64x64) - separator: draw a separator line or not (default: True) - buttonOrientation: Qt.Horizontal (default) or Qt.Vertical - buttons: which buttons to use (default: Ok, Cancel) - help: function to call when a help button is clicked. Other keyword arguments are passed to QDialog. """ super(Dialog, self).__init__(parent, **kwargs) self._icon = QIcon() self._separatorWidget = Separator() self._mainWidget = QWidget() self._pixmap = QPixmap() self._pixmapLabel = QLabel(self) self._messageLabel = QLabel(self) self._buttonBox = b = QDialogButtonBox(self) b.accepted.connect(self.accept) b.rejected.connect(self.reject) layout = QGridLayout() layout.setSpacing(10) self.setLayout(layout) # handle keyword args self._buttonOrientation = buttonOrientation self._iconSize = iconSize self._separator = separator if title: self.setWindowTitle(title) self.setMessage(message) if icon: self.setIcon(icon) elif pixmap: self.setPixmap(pixmap) b.helpRequested.connect(help or self.helpRequest) self.setStandardButtons(buttons) self.reLayout() def helpRequest(self): """Called when a help button is clicked.""" pass def setButtonOrientation(self, orientation): """Sets the button orientation. Qt.Horizontal (default) puts the buttons at the bottom of the dialog in a horizontal row, Qt.Vertical puts the buttons at the right in a vertical column. """ if orientation != self._buttonOrientation: self._buttonOrientation = orientation self._buttonBox.setOrientation(orientation) self.reLayout() def buttonOrientation(self): """Returns the button orientation.""" return self._buttonOrientation def setIcon(self, icon): """Sets the icon to display in the left area. May be: - None or QIcon() - one of 'info', 'warning', 'critical', 'question' - a QStyle.StandardPixmap - a QIcon. """ if icon in standardicons: icon = standardicons[icon] if isinstance(icon, QStyle.StandardPixmap): icon = self.style().standardIcon(icon) if icon is None: icon = QIcon() self._icon = icon self.setPixmap(icon.pixmap(self._iconSize)) def icon(self): """Returns the currently set icon as a QIcon.""" return self._icon def setIconSize(self, size): """Sets the icon size (QSize or int).""" if isinstance(size, int): size = QSize(size, size) changed = size != self._iconSize self._iconSize = size if changed and not self._icon.isNull(): self.setPixmap(self._icon.pixmap(size)) def iconSize(self): """Returns the icon size (QSize).""" return self._iconSize def setPixmap(self, pixmap): """Sets the pixmap to display in the left area.""" changed = self._pixmap.isNull() != pixmap.isNull() self._pixmap = pixmap self._pixmapLabel.setPixmap(pixmap) if not pixmap.isNull(): self._pixmapLabel.setFixedSize(pixmap.size()) if changed: self.reLayout() def pixmap(self): """Returns the currently set pixmap.""" return self._pixmap def setMessage(self, text): """Sets the main text in the dialog.""" self._messageLabel.setText(text) def message(self): """Returns the main text.""" return self._messageLabel.text() def messageLabel(self): """Returns the QLabel displaying the message text.""" return self._messageLabel def buttonBox(self): """Returns our QDialogButtonBox instance.""" return self._buttonBox def setStandardButtons(self, buttons): """Convenience method to set standard buttons in the button box. Accepts a sequence of string names from the standardbuttons constant, or a QDialogButtonBox.StandardButtons value. """ if isinstance(buttons, (set, tuple, list)): buttons = functools.reduce(operator.or_, map(standardbuttons.get, buttons), QDialogButtonBox.StandardButtons()) self._buttonBox.setStandardButtons(buttons) def button(self, button): """Returns the given button. May be a QDialogButtonBox.StandardButton or a key from standardbuttons. """ if button in standardbuttons: button = standardbuttons[button] return self._buttonBox.button(button) def setSeparator(self, enabled): """Sets whether to show a line between contents and buttons.""" changed = self._separator != enabled self._separator = enabled if changed: self.reLayout() def hasSeparator(self): """Returns whether a separator line is shown.""" return self._separator def setMainWidget(self, widget): """Sets the specified widget as our main widget.""" old = self._mainWidget if old: old.setParent(None) self._mainWidget = widget self.reLayout() def mainWidget(self): """Returns the current main widget (an empty QWidget by default).""" return self._mainWidget def reLayout(self): """(Internal) Lays out all items in this dialog.""" layout = self.layout() while layout.takeAt(0): pass if not self._pixmap.isNull(): col = 1 layout.addWidget(self._pixmapLabel, 0, 0, 2, 1) else: layout.setColumnStretch(1, 0) col = 0 layout.setColumnStretch(col, 1) self._pixmapLabel.setVisible(not self._pixmap.isNull()) layout.addWidget(self._messageLabel, 0, col) layout.addWidget(self._mainWidget, 1, col) if self._buttonOrientation == Qt.Horizontal: if self._separator: layout.addWidget(self._separatorWidget, 2, 0, 1, col+1) layout.addWidget(self._buttonBox, 3, 0, 1, col+1) else: if self._separator: layout.addWidget(self._separatorWidget, 0, col+1, 2, 1) layout.addWidget(self._buttonBox, 0, col+2, 2, 1) self._separatorWidget.setVisible(self._separator)
class Canvas(QWidget): def __init__(self, **kwargs): super(Canvas, self).__init__(**kwargs) self.pixmap = QPixmap() self.filenamePrefix = "" self.scale = DEFAULT_SCALE self.scaleMax = MAX_SCALE self.scaleMin = MIN_SCALE self.scaleIncrement = ZOOM_INCREMENT self.painter = QPainter() self.setMouseTracking(True) self.color = QColor(CANVAS_DEFAULT_COLOR) self.parentCenterX = 0 self.parentCenterY = 0 self.canvasCenterX = self.pixmap.width() // 2 self.canvasCenterY = self.pixmap.height() // 2 self.canvasWidth = int(self.pixmap.width() * self.scale) self.canvasHeight = int(self.pixmap.height() * self.scale) self.canvasGlobalLeft = 0 self.canvasGlobalRight = 0 self.canvasGlobalTop = 0 self.canvasGlobalBottom = 0 self.controlOpacity = CONTROL_OPACITY self.polygons = [] self.mouseHeld = False self.middleClickHeld = False self.mouseDownPos = QPoint() self.mousePos = QPoint() self.previousMousePos = QPoint() self.highlightedControl = None self.clickedControl = None self.selectedPolygon = None self.freeDrawPolygon = None self.closestLine = None self.controlOffset = QPoint() self.copyOfSelectedPolygon = None self.hideControls = False self.vBarPos = 0 self.hBarPos = 0 self.hBar = None self.vBar = None self.state = MOVE_CONTROLS self.update() self.updateCanvasGlobalParameters() def showEvent(self, event): ''' Used for making sure the correct width/height of the screen is used Inside __init__(), parent.size = (1280, 720) (doesn't take into account margins, incorrect mouse positions) When running, parent.size = (1278, 667) (Does take into account margins, correct mouse positions) ''' parent = self.parent().window() self.hBar = parent.scrollArea.horizontalScrollBar() self.vBar = parent.scrollArea.verticalScrollBar() self.updateCanvasGlobalParameters() def paintEvent(self, event): if (not self.pixmap.isNull()): self.painter.begin(self) self.setPainterQuality() self.painter.scale(self.scale, self.scale) self.painter.translate(self.offsetToCenter()) self.drawImage() self.drawPolygons() if (self.closestLine is not None and self.selectedPolygon is not None and type(self.highlightedControl) is not Control): self.drawClosestLineControls() if (self.state == DRAW_POLYGON): self.drawMouseTargets() self.painter.end() def sizeHint(self): return self.minimumSizeHint() def minimumSizeHint(self): if self.pixmap: return self.scale * self.pixmap.size() return super(Canvas, self).minimumSizeHint() def drawImage(self): self.painter.setOpacity(1) self.painter.drawPixmap(0, 0, self.pixmap) def drawPolygons(self): for poly in self.polygons: self.painter.setOpacity(CONTROL_OPACITY) if (not self.hideControls): self.drawControls(poly.controls) elif (poly == self.selectedPolygon): self.drawControls(poly.controls) elif (poly == self.freeDrawPolygon): self.drawControls(poly.controls) self.painter.setBrush(poly.color) if (poly == self.selectedPolygon and poly == self.highlightedControl): self.painter.setOpacity(HIGHLIGHTED_OPACITY) self.painter.setPen(QColor(CONTROL_HIGHLIGHT_COLOR)) elif (poly == self.selectedPolygon): self.painter.setPen(QColor(CONTROL_HIGHLIGHT_COLOR)) self.painter.setOpacity(SELECTED_OPACITY) elif (poly == self.highlightedControl): self.painter.setOpacity(HIGHLIGHTED_OPACITY) else: self.painter.setPen(Qt.NoPen) self.painter.drawPolygon(poly.toQPointList()) def drawControls(self, controls): for control in controls: self.painter.setBrush(control.color) if (control == self.highlightedControl): self.painter.setOpacity(HIGHLIGHTED_OPACITY) else: self.painter.setPen(Qt.NoPen) self.painter.setOpacity(CONTROL_OPACITY) self.painter.drawEllipse(control.position, control.radius, control.radius) def drawClosestLineControls(self): scaledPos = self.scaleMousePos() self.painter.setPen(QColor(CLOSEST_LINE_COLOR)) line = self.closestLine start = self.selectedPolygon.controls[line[0]].position end = self.selectedPolygon.controls[line[1]].position self.painter.drawLine(start.x(), start.y(), end.x(), end.y()) self.painter.setBrush(self.selectedPolygon.color) self.painter.drawEllipse(self.getClosestLineIntersection(), CONTROL_RADIUS / self.scale, CONTROL_RADIUS / self.scale) def drawMouseTargets(self): scaledPos = self.scaleMousePos() self.painter.setPen(Qt.black) self.painter.pen().setWidth(MOUSE_TARGET_THICKNESS) self.painter.drawLine(0, scaledPos.y(), self.pixmap.width(), scaledPos.y()) self.painter.drawLine(scaledPos.x(), 0, scaledPos.x(), self.pixmap.height()) def mousePressEvent(self, event): if (not self.pixmap.isNull()): self.mouseHeld = True self.mouseDownPos = self.scaleMousePos() self.previousMousePos = self.mouseDownPos if (event.button() == Qt.LeftButton): self.handleLeftClick(event) elif (event.button() == Qt.MiddleButton): self.handleMiddleClick(event) elif (event.button() == Qt.RightButton): self.handleRightClick(event) def mouseMoveEvent(self, event): if (not self.pixmap.isNull()): self.mousePos = event.pos() scaledPos = self.scaleMousePos() self.closestLine = None if (self.middleClickHeld): self.scrollWindow(scaledPos) else: self.moveControls(scaledPos) self.parent().window().labelCoordinates.setText( f"X: {scaledPos.x()}; Y: {scaledPos.y()}") self.update() def scrollWindow(self, scaledPos): move = (scaledPos - self.previousMousePos) * SCROLL_SCALE self.hBar.setValue(self.hBar.value() - move.x()) self.vBar.setValue(self.vBar.value() - move.y()) self.previousMousePos = scaledPos def moveControls(self, scaledPos): if (self.clickedControl is not None): newPos = scaledPos validPos = True if (type(self.clickedControl) is Polygon): prevPos = self.clickedControl.center newPos += self.controlOffset self.clickedControl.move(newPos) for control in self.clickedControl.controls: if (control.position.x() < 0): validPos = False newPos.setX(prevPos.x()) elif (control.position.x() > self.pixmap.width()): validPos = False newPos.setX(prevPos.x()) if (control.position.y() < 0): validPos = False newPos.setY(prevPos.y()) elif (control.position.y() >= self.pixmap.height()): validPos = False newPos.setY(prevPos.y()) if (not validPos): self.clickedControl.move(newPos) else: self.clickedControl.move(newPos) self.parent().window().saved = False elif (self.state is not DRAW_POLYGON): self.highlightedControl = self.checkIfHoveringOverControl( scaledPos) if (self.selectedPolygon is not None and type(self.selectedPolygon)) is Polygon and type( self.highlightedControl) is not Control: distance, indexes = getClosestLine(self.scaleMousePos(), self.selectedPolygon) if (distance < CONTROL_MIN_LINE_DISTANCE): self.closestLine = indexes self.state = ADD_CONTROL elif (self.state is not DRAW_POLYGON): self.state = MOVE_CONTROLS else: self.closestLine = None if (self.state is not DRAW_POLYGON): self.state = MOVE_CONTROLS def mouseReleaseEvent(self, event): self.clickedControl = None self.mouseHeld = False self.middleClickHeld = False def wheelEvent(self, event): if (event.angleDelta().y() >= 0): self.scale += self.scaleIncrement else: self.scale -= self.scaleIncrement self.scale = clamp(self.scale, self.scaleMin, self.scaleMax) self.hBar.setValue(self.hBar.value()) self.vBar.setValue(self.vBar.value()) self.updateControlRadius() self.updateCanvasGlobalParameters() self.update() self.adjustSize() def handleLeftClick(self, event): self.mouseDownPos = event.pos() scaledPos = self.scaleMousePos() if (self.state == MOVE_CONTROLS): if (self.highlightedControl is not None): self.clickedControl = self.highlightedControl if (type(self.clickedControl) is Polygon): self.controlOffset = self.clickedControl.center - scaledPos self.updateSelectedPolygon() elif (self.state == ADD_CONTROL): index = self.closestLine[1] self.selectedPolygon.addControlAtIndex(index, scaledPos) self.selectedPolygon.updateParameters() self.updateControlRadius() self.state = MOVE_CONTROLS elif (self.state == DRAW_POLYGON): if (self.freeDrawPolygon is None): poly = Polygon(color=self.color) poly.controls = [] poly.addControlAtPosition(self.scaleMousePos()) poly.computeBoundingBox() self.polygons.append(poly) self.freeDrawPolygon = poly self.updateControlRadius() self.update() else: self.freeDrawPolygon.addControlAtPosition(self.scaleMousePos()) self.freeDrawPolygon.updateParameters() self.updateControlRadius() self.update() def handleMiddleClick(self, event): self.middleClickHeld = True def deleteControl(self): control = self.highlightedControl control.parent.deleteControl(control) control.parent.updateParameters() def handleRightClick(self, event): pos = event.pos() scaledPos = self.scaleMousePos() menu = QMenu(self) menu.setStyleSheet(STYLE_SHEET) changeColorAciton = menu.addAction("Change Color") menu.addSeparator() copyAction = menu.addAction(COPY_TEXT) pasteAction = menu.addAction(PASTE_TEXT) menu.addSeparator() deleteControlAction = menu.addAction(DELETE_CONTROL_TEXT) deletePolygonAction = menu.addAction(DELETE_POLYGON_TEXT) if (self.highlightedControl is None): changeColorAciton.setDisabled(True) copyAction.setDisabled(True) deletePolygonAction.setDisabled(True) deleteControlAction.setDisabled(True) elif (self.selectedPolygon is None): changeColorAciton.setDisabled(True) if (type(self.highlightedControl) is Polygon): deleteControlAction.setDisabled(True) elif (type(self.highlightedControl) is Control): deletePolygonAction.setDisabled(True) copyAction.setDisabled(True) selectedAction = menu.exec_(self.mapToGlobal(event.pos())) if (selectedAction == changeColorAciton): self.askForColorChange() elif (selectedAction == copyAction): self.copyPolygon() elif (selectedAction == pasteAction): self.pastePolygon() elif (selectedAction == deleteControlAction): self.deleteControl() elif (selectedAction == deletePolygonAction): self.deletePolygon() elif (selectedAction == None): self.highlightedControl = None self.update() def updateSelectedPolygon(self): if (type(self.clickedControl) == Control): self.selectedPolygon = self.clickedControl.parent elif (type(self.clickedControl) == Polygon): self.selectedPolygon = self.clickedControl else: self.selectedPolygon = None def updateControlRadius(self): for control in Control.instances: control.radius = control._radius / self.scale def checkIfClickedOnControl(self): scaledMousePos = self.scaleMousePos() for control in Control.instances: if (control.checkClicked(scaledMousePos)): return control return None def checkIfHoveringOverControl(self, scaledPos): if (self.hideControls): if (self.selectedPolygon is not None): for control in self.selectedPolygon.controls: if (control.checkClicked(scaledPos)): return control else: for control in Control.instances: if (control.checkClicked(scaledPos)): return control for poly in self.polygons: if (pointInsidePolygon(scaledPos, poly.toList())): return poly return None def setPainterQuality(self): self.painter.setRenderHint(QPainter.Antialiasing, True) self.painter.setRenderHint(QPainter.HighQualityAntialiasing) self.painter.setRenderHint(QPainter.SmoothPixmapTransform) self.painter.setPen(Qt.NoPen) def sizeHint(self): if (self.pixmap): return self.scale * self.pixmap.size() def offsetToCenter(self): #https://github.com/tzutalin/labelImg/blob/master/libs/canvas.py self.scale area = super(Canvas, self).size() w = self.pixmap.width() * self.scale h = self.pixmap.height() * self.scale aw = area.width() ah = area.height() x = (aw - w) / (2 * self.scale) y = (ah - h) / (2 * self.scale) return QPointF(x, y) def resizedParent(self): self.updateCanvasGlobalParameters() def scaleMousePos(self): offset = self.getCanvasStartPosition() mouseX = self.mousePos.x() mouseY = self.mousePos.y() scaledX = scale(mouseX, self.canvasGlobalLeft, self.canvasGlobalRight, 0, self.pixmap.width()) scaledY = scale(mouseY, self.canvasGlobalTop, self.canvasGlobalBottom, 0, self.pixmap.height()) scaledX = clamp(scaledX, 0, self.pixmap.width()) scaledY = clamp(scaledY, 0, self.pixmap.height()) return QPoint(scaledX, scaledY) def getCanvasStartPosition(self): parentCenterX = self.parent().size().width() // 2 parentCenterY = self.parent().size().height() // 2 startX = (parentCenterX - (self.canvasWidth // 2)) - self.hBar.value() startY = (parentCenterY - (self.canvasHeight // 2)) - self.vBar.value() return QPoint(startX, startY) def updateCanvasGlobalParameters(self): self.parentCenterX = self.parent().size().width() // 2 self.parentCenterY = self.parent().size().height() // 2 self.canvasCenterX = self.pixmap.width() // 2 self.canvasCenterY = self.pixmap.height() // 2 self.canvasWidth = int(self.pixmap.width() * self.scale) self.canvasHeight = int(self.pixmap.height() * self.scale) self.canvasGlobalLeft = self.parentCenterX - (self.canvasWidth // 2) self.canvasGlobalTop = self.parentCenterY - (self.canvasHeight // 2) if (self.canvasGlobalLeft < 0): self.canvasGlobalLeft = 0 if (self.canvasGlobalTop < 0): self.canvasGlobalTop = 0 self.canvasGlobalRight = self.canvasGlobalLeft + self.canvasWidth self.canvasGlobalBottom = self.canvasGlobalTop + self.canvasHeight def addPolygon(self, color): if (not self.pixmap.isNull()): polyColor = None if (type(color) is str): polyColor = QColor(int(color, 0)) elif (type(color) is QColor): polyColor = color poly = Polygon(color=polyColor, center=QPoint(self.canvasCenterX, self.canvasCenterY)) poly.computeBoundingBox() self.polygons.append(poly) self.updateControlRadius() self.update() else: QMessageBox.information(self, NO_IMAGE_TITLE, NO_IMAGE_TEXT) def deletePolygon(self): if (self.selectedPolygon is not None): try: index = self.polygons.index(self.selectedPolygon) self.polygons.pop(index) self.selectedPolygon = None self.update() except ValueError: pass def addControlToSelectedPolygon(self): if (self.selectedPolygon is not None): self.selectedPolygon.addControl() self.update() self.updateControlRadius() def deleteControlFromSelectedPolygon(self): if (self.selectedPolygon is not None): self.selectedPolygon.deleteLastControl() if (len(self.selectedPolygon.controls) <= 0): index = self.polygons.index(self.selectedPolygon) self.polygons.pop(index) self.selectedPolygon = None self.update() def resetCanvas(self): Control.deleteAllControls() self.highlightedControl = None self.selectedPolygon = None self.clickedControl = None self.polygons = [] def loadImage(self, filename, copyPolygons=False): self.pixmap.load(filename) self.filenamePrefix = filename[:-4] pickleFilename = f"{self.filenamePrefix}{POLYGON_SUFFIX}" if (os.path.exists(pickleFilename)): self.resetCanvas() with open(pickleFilename, 'rb') as polyPickle: polygons = pickle.load(polyPickle) for polygon in polygons: color = polygon['color'] newPolygon = Polygon( color=QColor(color[0], color[1], color[2])) newPolygon.setFromListOfCotnrolPositions( polygon['controls']) newPolygon.updateParameters() newPolygon.updateOffsets() self.polygons.append(newPolygon) elif (copyPolygons is False): self.resetCanvas() self.updateControlRadius() self.updateCanvasGlobalParameters() self.update() def saveImage(self): if (not self.pixmap.isNull()): image = np.zeros((self.pixmap.height(), self.pixmap.width(), 3), dtype=np.uint8) polygons = [] for polygon in self.polygons: polyToDraw = np.array(polygon.toList()) color = polygon.colorToCV() image = cv2.fillPoly(image, [polyToDraw], color) polyObj = {'color': color, 'controls': polyToDraw} polygons.append(polyObj) #Deals with openCV using BGR instead of RGB image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) cv2.imwrite(f"{self.filenamePrefix}{SEGMENTATION_SUFFIX}", image) with open(f"{self.filenamePrefix}{POLYGON_SUFFIX}", 'wb+') as polyPickle: pickle.dump(polygons, polyPickle) def setState(self, state): self.state = state if (state == DRAW_POLYGON): self.freeDrawPolygon = None self.highlightedControl = None self.closestLine = None self.selectedPolygon = None else: self.freeDrawPolygon = None if (not self.pixmap.isNull()): self.update() def setColor(self, color): if (type(color) == str): self.color = QColor(color) elif (type(color) == QColor): self.color = color def getClosestLineIntersection(self): pos1 = self.selectedPolygon.controls[self.closestLine[0]].position pos2 = self.selectedPolygon.controls[self.closestLine[1]].position line = [pos1.x(), pos1.y(), pos2.x(), pos2.y()] mPos = self.scaleMousePos() vLine = [ mPos.x(), mPos.y() + MOUSE_SEARCH_AREA, mPos.x(), mPos.y() - MOUSE_SEARCH_AREA ] hLine = [ mPos.x() - MOUSE_SEARCH_AREA, mPos.y(), mPos.x() + MOUSE_SEARCH_AREA, mPos.y() ] intersectionV = linesIntersect(line, vLine) intersectionH = linesIntersect(line, hLine) intersection = intersectionV if (intersectionV is not None and intersectionH is not None): vDistance = distance([intersectionV['x'], intersectionV['y']], [mPos.x(), mPos.y()]) hDistance = distance([intersectionH['x'], intersectionH['y']], [mPos.x(), mPos.y()]) if (vDistance < hDistance): intersection = intersectionV else: intersection = intersectionH elif (intersectionV is None): intersection = intersectionH if (intersection is not None): return QPoint(intersection['x'], intersection['y']) else: return QPoint(OFFSCREEN, OFFSCREEN) def copyPolygon(self): if (self.selectedPolygon is not None): self.copyOfSelectedPolygon = self.selectedPolygon def pastePolygon(self): if (self.copyOfSelectedPolygon is not None): import time startTime = time.time() c = self.copyOfSelectedPolygon newPolygon = Polygon(color=QColor(c.color)) newPolygon.copyControls(c.controls, offset=COPY_OFFSET) newPolygon.updateParameters() self.polygons.append(newPolygon) self.updateControlRadius() self.update() def askForColorChange(self): if (self.selectedPolygon is not None): color = QColorDialog.getColor() if (QColor.isValid(color)): self.setColor(color) self.selectedPolygon.setColor(color) def changeHideControlsState(self, state): if (state > 0): self.hideControls = True else: self.hideControls = False self.update()
class FLCodBar(object): barcode = {} p = None pError = None def __init__(self, value=None, type_=BARCODE_128, margin=10, scale=1.0, cut=1.0, rotation=0, text_flag=False, fg=QtCore.Qt.black, bg=QtCore.Qt.white, res=72): dict_ = {"barcode": "python-barcode"} from pineboolib.utils import checkDependencies checkDependencies(dict_) self.pError = "Not Implemented" self.barcode["value"] = "" if value in [None, 0]: self.p = None self.pError = QPixmap() self.readingStdout = False self.writingStdout = False self.fillDefault(self.barcode) else: if isinstance(value, str): self.p = None self.pError = QPixmap() self.readingStdout = False self.writingStdout = False self.barcode["value"] = value self.barcode["type"] = type_ self.barcode["margin"] = margin self.barcode["scale"] = scale self.barcode["cut"] = cut self.barcode["rotation"] = rotation self.barcode["text"] = text_flag self.barcode["fg"] = fg self.barcode["bg"] = bg self.barcode["valid"] = False self.barcode["res"] = res else: self._copyBarCode(value, self.barcode) def pixmap(self): self._createBarcode() if not self.p: self.barcode["valid"] = False return self.p def pixmapError(self): return self.pError def value(self): return self.barcode["value"] def type_(self): return self.barcode["type"] def margin(self): return self.barcode["margin"] def scale(self): return self.barcode["scale"] def cut(self): return self.barcode["cut"] def text(self): return self.barcode["text"] def rotation(self): return self.barcode["rotation"] def fg(self): return self.barcode["fg"] def bg(self): return self.barcode["bg"] def setData(self, d): self.barcode = d def validBarcode(self): return self.barcode["valid"] def setCaption(self, caption): self.barcode["caption"] = caption def caption(self): return self.barcode["caption"] def setValue(self, value): self.barcode["value"] = value def setType(self, type_): self.barcode["type"] = type_ def setMargin(self, margin): self.barcode["margin"] = margin def setScale(self, scale): self.barcode["scale"] = scale def setCut(self, cut): self.barcode["cut"] = cut def setText(self, text): self.barcode["text"] = text def setRotation(self, rotation): self.barcode["rotation"] = rotation def setFg(self, fg): self.barcode["fg"] = fg def setBg(self, bg): self.barcode["bg"] = bg def setRes(self, res): self.barcode["res"] = res def data(self): return self.barcode def fillDefault(self, data): data["bg"] = "white" data["fg"] = "black" data["margin"] = 10 data["text"] = True data["value"] = "1234567890" data["type"] = BARCODE_39 data["scale"] = 1.0 data["cut"] = 1.0 data["rotation"] = 0 data["caption"] = "Static" data["valid"] = False data["res"] = 72 def cleanUp(self): self.p.resize(0, 0) self.pError.resize(0, 0) def nameToType(self, name): n = name.lower() if n == "any": return BARCODE_ANY elif n == "ean": return BARCODE_EAN elif n == "ean-8": return BARCODE_EAN_8 elif n == "ean-13": return BARCODE_EAN_13 elif n == "ean-14": return BARCODE_EAN_14 elif n == "upc": return BARCODE_UPC elif n == "upc-a": return BARCODE_UPC_A elif n == "jan": return BARCODE_JAN elif n == "isbn": return BARCODE_ISBN elif n == "isbn-10": return BARCODE_ISBN_10 elif n == "isbn-13": return BARCODE_ISBN_13 elif n == "issn": return BARCODE_ISSN elif n == "code39": return BARCODE_39 elif n == "code128": return BARCODE_128 elif n == "pzn": return BARCODE_PZN elif n == "itf": return BARCODE_ITF elif n == "gs1": return BARCODE_GS1 elif n == "gtin": return BARCODE_GTIN else: logger.warning("Formato no soportado (%s)\nSoportados: %s." % (n, barcode.PROVIDED_BARCODES)) return BARCODE_ANY def typeToName(self, type_): if type_ == BARCODE_ANY: return "ANY" elif type_ == BARCODE_EAN: return "EAN" elif type_ == BARCODE_EAN_8: return "EAN-8" elif type_ == BARCODE_EAN_13: return "EAN-13" elif type_ == BARCODE_EAN_14: return "EAN-14" elif type_ == BARCODE_UPC: return "UPC" elif type_ == BARCODE_UPC_A: return "UPC-A" elif type_ == BARCODE_JAN: return "JAN" elif type_ == BARCODE_ISBN: return "ISBN" elif type_ == BARCODE_ISBN_10: return "ISBN-10" elif type_ == BARCODE_ISBN_13: return "ISBN-13" elif type_ == BARCODE_ISSN: return "ISSN" elif type_ == BARCODE_39: return "Code39" elif type_ == BARCODE_128: return "Code128" elif type_ == BARCODE_PZN: return "PZN" elif type_ == BARCODE_ITF: return "ITF" elif type_ == BARCODE_GS1: return "GS1" elif type_ == BARCODE_GTIN: return "GTIN" else: return "ANY" def _createBarcode(self): if self.barcode["value"] == "": return if self.barcode["type"] == BARCODE_ANY: logger.warning("Usando %s por defecto" % self.typeToName(BARCODE_128)) self.barcode["type"] = BARCODE_128 type_ = self.typeToName(self.barcode["type"]) value_ = self.barcode["value"] bg_ = self.barcode["bg"] fg_ = self.barcode["fg"] if not isinstance(self.barcode["bg"], str): bg_ = QColor(self.barcode["bg"]).name() if not isinstance(self.barcode["fg"], str): fg_ = QColor(self.barcode["fg"]).name() margin_ = self.barcode["margin"] / 10 render_options = {} render_options['module_width'] = 0.6 render_options['module_height'] = 10 render_options['background'] = bg_.lower() render_options['foreground'] = fg_.lower() render_options['font_size'] = 8 render_options['write_text'] = self.barcode["text"] render_options['text_distance'] = 35 render_options['quiet_zone'] = margin_ if self.barcode["text"]: render_options['text'] = value_ else: render_options['text'] = " " import barcode from barcode.writer import ImageWriter from PyQt5.QtSvg import QSvgRenderer barC = barcode.get_barcode_class(type_.lower()) try: bar_ = barC(u'%s' % value_) except Exception: bar_ = barC('000000000000') svg = bar_.render(render_options) xml_svg = load2xml(svg.decode("utf-8")) svg_w = (3.779 * float(xml_svg.get("width")[0:6])) svg_h = (3.779 * float(xml_svg.get("height")[0:6])) self.p = QPixmap(svg_w, svg_h) render = QSvgRenderer(svg) self.p.fill(QtCore.Qt.transparent) painter = Qt.QPainter(self.p) render.render(painter, QRectF(0,0,svg_w * 3.4 , svg_h * 3.4)) if self.p.isNull(): self.barcode["valid"] = False else: if self.barcode["scale"] != 1.0: wS_ = self.barcode["x"] * self.barcode["scale"] hS_ = self.barcode["y"] * self.barcode["scale"] self.p = self.p.scaled(wS_, hS_) self.barcode["x"] = self.p.width() self.barcode["y"] = self.p.height() self.barcode["valid"] = True def _copyBarCode(self, source, dest): dest["value"] = source["value"] dest["type"] = source["type"] dest["margin"] = source["margin"] dest["scale"] = source["scale"] dest["cut"] = source["cut"] dest["rotation"] = source["rotation"] dest["text"] = source["text"] dest["caption"] = source["caption"] dest["valid"] = source["valid"] dest["fg"] = source["fg"] dest["bg"] = source["bg"] dest["x"] = source["x"] dest["y"] = source["y"] dest["res"] = source["res"]
def getWidget(self, media, scale): """ _________________________________________ | Icon | Title | |______|__________________________________| """ title_layout = QHBoxLayout() title_layout.setAlignment(Qt.AlignLeft) # space between the three grids title_layout.setSpacing(10) # margin around the widget title_layout.setContentsMargins(0, 0, 0, 0) widget = QWidget() widget.setLayout(title_layout) # # existing showing # ____________________________________________________________________________ # # icon.png icon.png # # card.ini: # iconkey + # media + # categpry media-{collector/storage}-{media}-{categry}-{iconkey}.png # # card.ini: # iconkey media-{collector/storage}-{iconkey}.png # # card.ini: # media + # categpry media-{collector/storage}-{media}-{categry}.png # # # Icon # pixmap = None pathToFile = media.getPathOfIcon() if pathToFile: pixmap = QPixmap(pathToFile) if not pixmap: #media-(collector/storage) iconFileName = TITLE_ICON_PREFIX + "-" + media.getFolderType() # media-(collector/storage)-{iconKey} if media.control.getIconKey(): iconFileName += "-" + media.control.getIconKey() # media-(collector/storage)-{media} elif media.control.getMedia() and not media.control.getCategory(): iconFileName += "-" + media.control.getMedia() # media-(collector/storage)-{media}-{category} elif media.control.getMedia() and media.control.getCategory(): iconFileName += ("-" + media.control.getMedia() if media.control.getMedia() else "") + ("-" + media.control.getCategory() if media.control.getCategory() else "") iconFileName += "." + TITLE_ICON_EXTENSION pathToFile = resource_filename( __name__, os.path.join(TITLE_ICON_FOLDER, iconFileName)) pixmap = QPixmap(pathToFile) if pixmap.isNull(): smaller_pixmap = QPixmap(TITLE_ICON_HEIGHT * scale, TITLE_ICON_HEIGHT * scale) smaller_pixmap.fill(QColor(media.getBackgroundColor())) else: if pixmap.width() >= pixmap.height(): smaller_pixmap = pixmap.scaledToWidth(TITLE_ICON_HEIGHT * scale) else: smaller_pixmap = pixmap.scaledToHeight(TITLE_ICON_HEIGHT * scale) iconWidget = QLabel() iconWidget.setPixmap(smaller_pixmap) title_layout.addWidget(iconWidget) # # Title # titleWidget = QLabel(self.getFormattedTitle(media)) titleWidget.setFont( QFont(PANEL_FONT_TYPE, PANEL_FONT_SIZE * scale * 1.8, weight=QFont.Bold)) title_layout.addWidget(titleWidget) return widget
class ImageViewer(QMainWindow): def __init__(self): super().__init__() self.formats = ('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.pbm', '.pgm', '.ppm', '.xbm', '.xpm') self.rotval = 0 # 旋转方向 self.rotvals = (0, -90, -180, -270) self.file_path = QDir.currentPath() # 获取当前文件路径 self.resize(1000, 800) self.setWindowTitle("Magic Viewer") self.btn = QPushButton("打开图片", self) self.btn.resize(200, 80) self.btn.move((self.width() - self.btn.width()) / 2, (self.height() - self.btn.height()) / 2) self.btn.setFont(QFont("", 20, QFont.Bold)) self.btn.clicked.connect(self.btnClicked) self.show() def btnClicked(self): self.open() def open(self, file=None): if file is None: self.chooseFile() else: self.key = file.replace("\\", "/") # 获取图像列表 if self.key: self.btn.setEnabled(False) # 选择了文件按钮消失 self.imgfiles = [] # 如果选择了文件则则重新获取图像列表 self.file_path = os.path.dirname(self.key) # 获取文件路径 try: for file in os.listdir(self.file_path): if os.path.splitext(file)[1].lower() in self.formats: self.imgfiles.append(self.file_path + "/" + file) self.count = len(self.imgfiles) # 图像列表总数量 self.index = self.imgfiles.index(self.key) # 当前图像在图像列表中位置 except FileNotFoundError: print("文件目录不存在!") self.showImage() def chooseFile(self): # 选择图片文件 self.key, _ = QFileDialog.getOpenFileName( self, "选择文件", self.file_path, "图片文件 (*.bmp *.jpg *.jpeg *.png *.gif)") def showImage(self): if self.key: self.img = QPixmap(self.key) if self.img.isNull(): QMessageBox.information(self, "Magic Viewer", "不能打开文件:%s!" % self.key) return self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setDragMode(QGraphicsView.ScrollHandDrag) # self.view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) # self.view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.scene.clear() self.view.resetTransform() self.scene.addPixmap(self.img) self.zoom = 1 # 缩放系数 self.rotate = 0 # 旋转系数 # 如果图片尺寸>窗口尺寸,计算缩放系数进行缩放 if self.img.width() > self.width() or self.img.height( ) > self.height(): self.zoom = min(self.width() / self.img.width(), self.height() / self.img.height()) * 0.995 width = self.img.width() height = self.img.height() # self.scene.setSceneRect(0, 0, width - 2, height - 2) self.view.resize(width, height) self.setCentralWidget(self.view) self.updateView() self.show() # 获取文件大小 def fileSize(self, file): size = QFileInfo(file).size() if size < 1024: return str(size), "B" elif 1024 <= size < 1024 * 1024: return str(round(size / 1024, 2)), "KB" else: return str(round(size / 1024 / 1024, 2)), "MB" # 全屏 def toggleFullscreen(self): if self.isFullScreen(): self.showNormal() else: self.showFullScreen() def keyPressEvent(self, event): if event.key() == Qt.Key_F11: self.toggleFullscreen() elif event.key() == Qt.Key_Up or event.key() == Qt.Key_W: self.zoomIn() elif event.key() == Qt.Key_Down or event.key() == Qt.Key_S: self.zoomOut() elif event.key() == Qt.Key_1: self.zoomReset() elif event.key() == Qt.Key_E: self.rotateImg(-1) elif event.key() == Qt.Key_R: self.rotateImg(1) elif event.key() == Qt.Key_F: self.fitView() elif event.key() == Qt.Key_Right or event.key() == Qt.Key_Space: self.dirBrowse(1) elif event.key() == Qt.Key_Left or event.key() == Qt.Key_B: self.dirBrowse(-1) elif event.key() == Qt.Key_Q or event.key() == Qt.Key_Escape: self.close() elif event.key() == Qt.Key_O: self.btnClicked() def mouseDoubleClickEvent(self, event): self.toggleFullscreen() def zoomIn(self): self.zoom *= 1.05 self.updateView() def zoomOut(self): self.zoom /= 1.05 self.updateView() def zoomReset(self): self.zoom = 1 self.updateView() def rotateImg(self, clock): self.rotval += clock if self.rotval == 4: self.rotval = 0 elif self.rotval < 0: self.rotval = 3 self.rotate = self.rotvals[self.rotval] self.updateView() def fitView(self): self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) if self.rotate == 0: self.zoom = self.view.transform().m11() elif self.rotate == -90: self.zoom = (self.view.transform().m12()) * -1 elif self.rotate == -180: self.zoom = (self.view.transform().m11()) * -1 else: self.zoom = self.view.transform().m12() def updateView(self): self.view.setTransform(QTransform().scale(self.zoom, self.zoom).rotate( self.rotate)) # 更新标题信息 self.title = os.path.basename(self.key) size = self.fileSize(self.key) self.setWindowTitle( "%s(%sx%s,%s %s) - Magic Viewer - 第%s/%s张 %.2f%%" % (self.title, self.img.width(), self.img.height(), size[0], size[1], self.index + 1, self.count, self.zoom * 100)) def dirBrowse(self, direc): if self.count > 1: self.index += direc # 最后一张后跳到第一张,第一张前跳到最后一张 if self.index > self.count - 1: self.index = 0 elif self.index < 0: self.index = self.count - 1 self.key = self.imgfiles[self.index] self.showImage() def wheelEvent(self, event): # 鼠标滚动 moose = event.angleDelta().y() / 120 if moose > 0: self.zoomIn() elif moose < 0: self.zoomOut() def contextMenuEvent(self, event): # 右键菜单 menu = QMenu() menu.addAction(QIcon('image\\zoom_in.png'), '放大 Scorll Up, W', self.zoomIn) menu.addAction(QIcon('image\\zoom_out.png'), '缩小 Scroll Down, S', self.zoomOut) menu.addAction(QIcon('image\\full.png'), '全屏 F11', self.toggleFullscreen) menu.addAction(QIcon('image\\rotate_right.png'), '右转90° R', partial(self.rotateImg, 1)) menu.addAction(QIcon('image\\rotate_left.png'), '左转90° E', partial(self.rotateImg, -1)) menu.addAction(QIcon('image\\next.png'), '下一张 Right, SPACE', partial(self.dirBrowse, 1)) menu.addAction(QIcon('image\\previous.png'), '上一张 Left, B', partial(self.dirBrowse, -1)) menu.addAction('适合屏幕 F', self.fitView) menu.addAction('实际尺寸 1', self.zoomReset) menu.addSeparator() menu.addAction('打开 O', self.open) menu.addAction('退出 Q, ESC', self.close) menu.addSeparator() menu.addAction('关于Magic Viewer', self.about) menu.exec_(event.globalPos()) def about(self): QMessageBox.about( self, "关于Magic Viewer", "<b>Magic Viewer</b>是一个基于PyQt5的开源图片浏览器<br>" "作者 : Youth Lee<br>" "版本 : Ver 0.3<br>" "网址 : <a href='https://github.com/createnewli/Magic-Viewer'>https://github.com/createnewli/Magic-Viewer</a>" )
class MyWinMap(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.initWidget() # 初始化组件 self.initLayout() # 初始化布局 self.initWindow(800, 700) # 初始化窗口 self.initMap() # 初始化地图 self.initSerial(STR_COM) # 初始化串口 self.show() '''----------------------------------------------''' def initWidget(self): '''地图显示控件''' self.gscene_map = QGraphicsScene() self.gview_map = QGraphicsView(self.gscene_map) '''设定节点及阈值区''' self.chb_mark = QCheckBox('进入标记模式') self.chb_mark.toggle() self.sp_thre = QSpinBox() self.sp_thre.setRange(0, 10) # 设置上界和下界 '''数据显示区''' def initLayout(self): '''箱组声明''' self.gpbx_map = QGroupBox('地图', self) self.gpbx_mark_and_thre = QGroupBox('设定节点及阈值', self) self.gpbx_data = QGroupBox('数据', self) '''箱组布局类型''' self.lot_v_map = QVBoxLayout() self.lot_g_mark_and_thre = QGridLayout() self.lot_g_data = QGridLayout() self.lot_v_all = QVBoxLayout() '''箱组map布局设置''' self.lot_v_map.addWidget(self.gview_map, alignment=Qt.AlignHCenter) self.gpbx_map.setLayout(self.lot_v_map) '''箱组mark and thre布局设置''' # _ __ __ _ _ # |_|__|__|_|_| self.lot_g_mark_and_thre.addWidget(self.chb_mark, 0, 1, 1, 1, Qt.AlignCenter) self.lot_g_mark_and_thre.addWidget(self.sp_thre, 0, 3, 1, 1, Qt.AlignCenter) self.lot_g_mark_and_thre.setColumnStretch(0, 1) self.lot_g_mark_and_thre.setColumnStretch(1, 2) self.lot_g_mark_and_thre.setColumnStretch(2, 2) self.lot_g_mark_and_thre.setColumnStretch(3, 1) self.lot_g_mark_and_thre.setColumnStretch(4, 1) self.gpbx_mark_and_thre.setLayout(self.lot_g_mark_and_thre) '''箱组data布局设置''' for i in range(NODE_NUM): # 数据框 le_temp = QLineEdit('*') le_temp.setReadOnly(True) le_temp.setAlignment(Qt.AlignHCenter) self.lot_g_data.addWidget(le_temp, 0, i) for i in range(NODE_NUM): # 节点号框 lb_temp = QLabel('<div style="color:#d648ac;"><b>' + str(i + 1) + '</b></div>') lb_temp.setAlignment(Qt.AlignCenter) self.lot_g_data.addWidget(lb_temp, 1, i) self.gpbx_data.setLayout(self.lot_g_data) '''总布局设置''' self.lot_v_all.addWidget(self.gpbx_map) self.lot_v_all.addWidget(self.gpbx_mark_and_thre) self.lot_v_all.addWidget(self.gpbx_data) self.setLayout(self.lot_v_all) def initWindow(self, w, h): '''获取屏幕居中点信息''' center_point = QDesktopWidget().availableGeometry().center() self.center_point_x = center_point.x() self.center_point_y = center_point.y() '''窗口初始化''' self.setGeometry(0, 0, w, h) self.max_w = (self.center_point_x - 10) * 2 # 窗口允许的最大宽 self.max_h = (self.center_point_y - 20) * 2 # 窗口允许的最大高 self.setMaximumSize(self.max_w, self.max_h) # 防止窗口尺寸过大 self.moveToCenter(w, h) self.win_name = GUI_NAME # 窗口标题 self.setWindowTitle(self.win_name) def moveToCenter(self, w, h): '''窗口过大则先进行调整''' if (w > self.max_w) or (h > self.max_h): self.adjustSize() '''窗口居中''' topleft_point_x = (int)(self.center_point_x - w / 2) topleft_point_y = (int)(self.center_point_y - h / 2) self.move(topleft_point_x, topleft_point_y) def initMap(self): try: # 地图加载部分 self.pixmap_map = QPixmap('平面图_走廊_房间.png') if self.pixmap_map.isNull(): # 空图处理 self.initMapErrorHandle() return self.pixmap_map = self.pixmap_map.scaled(700, 600, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.gscene_map.addPixmap(self.pixmap_map) # 固定边界以禁用滑动条 self.f_pixmap_map_x = float(self.pixmap_map.rect().x()) self.f_pixmap_map_y = float(self.pixmap_map.rect().y()) self.f_pixmap_map_w = float(self.pixmap_map.rect().width()) self.f_pixmap_map_h = float(self.pixmap_map.rect().height()) self.gview_map.setSceneRect(self.f_pixmap_map_x, self.f_pixmap_map_y, self.f_pixmap_map_w, self.f_pixmap_map_h) # 地图加载成功的标志位 self.b_map_loaded = True # 复选框信号连接 self.chb_mark.stateChanged.connect(self.updateMap) # view视图鼠标响应 self.gview_map.mousePressEvent = self.markMap w = self.width() h = self.height() self.moveToCenter(w, h) # 节点相关部分 self.node_list = [] # 存储节点的坐标及邻域信息 except Exception as e: print(e) self.initMapErrorHandle() def initMapErrorHandle(self): self.b_map_loaded = False self.text_warning = '<div style="font:20px;\ color:red;\ text-align:center;">\ <b>⚠ WARNING ⚠</b><br /><br />\ 地图加载出错啦<br /><br />\ ::>﹏<::\ </div>' self.gtext_warning = QGraphicsTextItem() self.gtext_warning.setHtml(self.text_warning) self.gscene_map.addItem(self.gtext_warning) def markMap(self, event): if self.b_map_loaded: if self.chb_mark.isChecked(): self.node_pos = self.gview_map.mapToScene(event.pos()) # 左键创建标记 if event.button() == Qt.LeftButton: if len(self.node_list) < NODE_NUM: _is_near_init = False # 标记模式下,初始化无近邻rssi _append_iter = [self.node_pos, _is_near_init] # 用list存储复合信息 self.node_list.append(_append_iter) # 绘图部分 self.drawNode(len(self.node_list), _append_iter[0], _append_iter[1]) # 右键回退标记 if event.button() == Qt.RightButton: if len(self.node_list) > 0: self.node_list.pop() self.gscene_map.clear() # 清空scene self.gscene_map.addPixmap(self.pixmap_map) # 重新加载地图 for i in range(len(self.node_list)): self.drawNode(i + 1, self.node_list[i][0], self.node_list[i][1]) def updateMap(self): if self.b_map_loaded: if not self.chb_mark.isChecked(): self.timer_map_refresh = QTimer(self) # 设定地图刷新定时器 self.timer_map_refresh.timeout.connect(self.redrawMap) self.timer_map_refresh.start(REFRESH_TIME_MS) # 设置刷新时间为100毫秒 def redrawMap(self): self.gscene_map.clear() # 清空scene self.gscene_map.addPixmap(self.pixmap_map) # 重新加载地图 for i in range(len(self.node_list)): self.drawNode(i + 1, self.node_list[i][0], self.node_list[i][1]) '''----------------------------------------------''' def drawNode(self, index, node_pos, is_near): # 样式设置 node_draw_r = 15 node_draw_x = node_pos.x() - node_draw_r node_draw_y = node_pos.y() - node_draw_r # node_draw_pos = QPointF(node_draw_x, node_draw_y) node_draw_pen = QPen(QColor(204, 47, 105), 3, Qt.SolidLine) node_draw_brush = QBrush(QColor(255, 110, 151), Qt.SolidPattern) # 正式画圆 self.gellipse_node = self.gscene_map.addEllipse( node_draw_x, node_draw_y, 2 * node_draw_r, 2 * node_draw_r, node_draw_pen, node_draw_brush) # 索引号 self.text_index = '<div style=\"font:26px;color:black;font-weight:900;\">' + \ str(index) + '</div>' self.gtext_index = QGraphicsTextItem() self.gtext_index.setHtml(self.text_index) self.gtext_index.setParentItem(self.gellipse_node) self.gtext_index.setPos(node_draw_x + 4, node_draw_y - 2) if is_near: # 若附近rssi判断有效 node_draw_r = 20 node_draw_x = node_pos.x() - node_draw_r node_draw_y = node_pos.y() - node_draw_r node_draw_pen = QPen(QColor(245, 229, 143), 10, Qt.DashLine) self.gscene_map.addEllipse(node_draw_x, node_draw_y, 2 * node_draw_r, 2 * node_draw_r, node_draw_pen) '''----------------------------------------------''' def initSerial(self, str_com): self.data_zigbee_list = [] # 初始化串口 self.ser_data = QSerialPort(STR_COM, baudRate=QSerialPort.Baud115200, readyRead=self.receive) self.ser_data.open(QIODevice.ReadWrite) if self.ser_data.isOpen(): print('串口开启成功!') else: print('串口打开失败……') @pyqtSlot() def receive(self): _data = self.ser_data.readLine().data() # 读取数据 if _data != b'': self.data_zigbee_list = [] # 清空数据 self.data = _data[0:2 * NODE_NUM].decode("gbk") # 存储数据 for i in range(len(self.data) // 2): # 每两位存储,用tuple存储,只读 data_iter = (self.data[2 * i:2 * i + 1], self.data[2 * i + 1:2 * i + 2]) self.data_zigbee_list.append(data_iter) # print('data_zigbee_list:', self.data_zigbee_list) self.updateSerial() else: print('串口接收内容为空!') def updateSerial(self): if not self.chb_mark.isChecked(): for i in range(NODE_NUM): if i < len(self.node_list): value_update = self.data_zigbee_list[i][1] # 更新节点列表 self.node_list[i][1] = (True if value_update == '1' else False) else: value_update = '*' self.lot_g_data.itemAt(i).widget().setText(value_update)
class CAvatar(QWidget): Circle = 0 # 圆圈 Rectangle = 1 # 圆角矩形 SizeLarge = QSize(128, 128) SizeMedium = QSize(64, 64) SizeSmall = QSize(32, 32) StartAngle = 0 # 起始旋转角度 EndAngle = 360 # 结束旋转角度 clicked = pyqtSignal(bool) def __init__(self, *args, shape=0, url='', cacheDir=False, size=QSize(64, 64), animation=False, **kwargs): super(CAvatar, self).__init__(*args, **kwargs) self.url = '' self._angle = 0 # 角度 self.pradius = 0 # 加载进度条半径 self.animation = animation # 是否使用动画 self._movie = None # 动态图 self._pixmap = QPixmap() # 图片对象 self.pixmap = QPixmap() # 被绘制的对象 self.isGif = url.endswith('.gif') # 进度动画定时器 self.loadingTimer = QTimer(self, timeout=self.onLoading) # 旋转动画 self.rotateAnimation = QPropertyAnimation(self, b'angle', self, loopCount=1) self.setShape(shape) self.setCacheDir(cacheDir) self.setSize(size) self.setUrl(url) def paintEvent(self, event): super(CAvatar, self).paintEvent(event) # 画笔 painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.HighQualityAntialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, True) # 绘制 path = QPainterPath() diameter = min(self.width(), self.height()) if self.shape == self.Circle: radius = int(diameter / 2) elif self.shape == self.Rectangle: radius = 4 halfW = self.width() / 2 halfH = self.height() / 2 painter.translate(halfW, halfH) path.addRoundedRect(QRectF(-halfW, -halfH, diameter, diameter), radius, radius) painter.setClipPath(path) # 如果是动画效果 if self.rotateAnimation.state() == QPropertyAnimation.Running: painter.rotate(self._angle) # 旋转 painter.drawPixmap( QPointF(-self.pixmap.width() / 2, -self.pixmap.height() / 2), self.pixmap) else: painter.drawPixmap(-int(halfW), -int(halfH), self.pixmap) # 如果在加载 if self.loadingTimer.isActive(): diameter = 2 * self.pradius painter.setBrush( QColor(45, 140, 240, (1 - self.pradius / 10) * 255)) painter.setPen(Qt.NoPen) painter.drawRoundedRect( QRectF(-self.pradius, -self.pradius, diameter, diameter), self.pradius, self.pradius) def enterEvent(self, event): """鼠标进入动画 :param event: """ if not (self.animation and not self.isGif): return self.rotateAnimation.stop() cv = self.rotateAnimation.currentValue() or self.StartAngle self.rotateAnimation.setDuration(540 if cv == 0 else int(cv / self.EndAngle * 540)) self.rotateAnimation.setStartValue(cv) self.rotateAnimation.setEndValue(self.EndAngle) self.rotateAnimation.start() def leaveEvent(self, event): """鼠标离开动画 :param event: """ if not (self.animation and not self.isGif): return self.rotateAnimation.stop() cv = self.rotateAnimation.currentValue() or self.EndAngle self.rotateAnimation.setDuration(int(cv / self.EndAngle * 540)) self.rotateAnimation.setStartValue(cv) self.rotateAnimation.setEndValue(self.StartAngle) self.rotateAnimation.start() def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: self.clicked.emit(True) def onLoading(self): """更新进度动画 """ if self.loadingTimer.isActive(): if self.pradius > 9: self.pradius = 0 self.pradius += 1 else: self.pradius = 0 self.update() def onFinished(self): """图片下载完成 """ self.loadingTimer.stop() self.pradius = 0 reply = self.sender() if self.isGif: self._movie = QMovie(reply, b'gif', self) if self._movie.isValid(): self._movie.frameChanged.connect(self._resizeGifPixmap) self._movie.start() else: data = reply.readAll().data() reply.deleteLater() del reply self._pixmap.loadFromData(data) if self._pixmap.isNull(): self._pixmap = QPixmap(self.size()) self._pixmap.fill(QColor(204, 204, 204)) self._resizePixmap() def onError(self, code): """下载出错了 :param code: """ self._pixmap = QPixmap(self.size()) self._pixmap.fill(QColor(204, 204, 204)) self._resizePixmap() def refresh(self): """强制刷新 """ self._get(self.url) def isLoading(self): """判断是否正在加载 """ return self.loadingTimer.isActive() def setShape(self, shape): """设置形状 :param shape: 0=圆形, 1=圆角矩形 """ self.shape = shape def setUrl(self, url): """设置url,可以是本地路径,也可以是网络地址 :param url: """ self.url = url # print('设置头像', url) self._get(url) def setCacheDir(self, cacheDir=''): """设置本地缓存路径 :param cacheDir: """ self.cacheDir = cacheDir self._initNetWork() def setSize(self, size): """设置固定尺寸 :param size: """ if not isinstance(size, QSize): size = self.SizeMedium self.setMinimumSize(size) self.setMaximumSize(size) self._resizePixmap() @pyqtProperty(int) def angle(self): return self._angle @angle.setter def angle(self, value): self._angle = value self.update() def _resizePixmap(self): """缩放图片 """ if not self._pixmap.isNull(): self.pixmap = self._pixmap.scaled(self.width(), self.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) self.update() def _resizeGifPixmap(self, _): """缩放动画图片 """ if self._movie: self.pixmap = self._movie.currentPixmap().scaled( self.width(), self.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) self.update() def _initNetWork(self): """初始化异步网络库 """ if not hasattr(qApp, '_network'): network = QNetworkAccessManager(self.window()) setattr(qApp, '_network', network) # 是否需要设置缓存 if self.cacheDir and not qApp._network.cache(): cache = QNetworkDiskCache(self.window()) cache.setCacheDirectory(self.cacheDir) qApp._network.setCache(cache) def _get(self, url): """设置图片或者请求网络图片 :param url: """ if not url: self.onError('') return if url.startswith('http') and not self.loadingTimer.isActive(): url = QUrl(url) request = QNetworkRequest(url) # request.setHeader(QNetworkRequest.UserAgentHeader, b'CAvatar') # request.setRawHeader(b'Author', b'Irony') request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True) if qApp._network.cache(): request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.PreferNetwork) request.setAttribute(QNetworkRequest.CacheSaveControlAttribute, True) reply = qApp._network.get(request) self.pradius = 0 self.loadingTimer.start(50) # 显示进度动画 reply.finished.connect(self.onFinished) reply.error.connect(self.onError) return self.pradius = 0 if os.path.exists(url) and os.path.isfile(url): if self.isGif: self._movie = QMovie(url, parent=self) if self._movie.isValid(): self._movie.frameChanged.connect(self._resizeGifPixmap) self._movie.start() else: self._pixmap = QPixmap(url) self._resizePixmap() else: self.onError('')
class Viewer(QtMainWindow): jobAdded = Signal() jobFinished = Signal() def __init__(self, weboob, parent=None): super(Viewer, self).__init__(parent) self.ui = Ui_Viewer() self.ui.setupUi(self) self.ui.prevButton.clicked.connect(self.prev) self.ui.nextButton.clicked.connect(self.next) self.ui.firstButton.clicked.connect(self.first) self.ui.lastButton.clicked.connect(self.last) self.ui.actionZoomIn.triggered.connect(self.zoomIn) self.ui.actionZoomOut.triggered.connect(self.zoomOut) self.ui.actionFullSize.triggered.connect(self.zoomFullSize) self.ui.actionFitWindow.triggered.connect(self.zoomFit) self.ui.actionSaveImage.setShortcut(QKeySequence.Save) self.ui.actionSaveImage.triggered.connect(self.saveImage) self.ui.actionClose.setShortcut(QKeySequence.Close) self.ui.actionClose.triggered.connect(self.close) self.model = None self.current = None self.total = 0 self.zoomFactor = 1 self.zoomMode = ZOOM_FACTOR self.weboob = weboob def setData(self, model, qidx): self.model = model self.current = QPersistentModelIndex(qidx) self.model.rowsInserted.connect(self.updatePos) self.model.rowsRemoved.connect(self.updatePos) self.model.rowsInserted.connect(self.updateNavButtons) self.model.rowsRemoved.connect(self.updateNavButtons) self.model.dataChanged.connect(self._dataChanged) self.model.modelReset.connect(self.disable) self.updateImage() @Slot() def disable(self): self.setEnabled(False) def updateNavButtons(self): prev = self.current.row() > 0 self.ui.prevButton.setEnabled(prev) self.ui.firstButton.setEnabled(prev) next = self.current.row() < self.total - 1 self.ui.nextButton.setEnabled(next) self.ui.lastButton.setEnabled(next) def updatePos(self): self.total = self.model.rowCount(self.current.parent()) self.ui.posLabel.setText('%d / %d' % (self.current.row() + 1, self.total)) def updateImage(self): self.updatePos() self.updateNavButtons() obj = self.current.data(ResultModel.RoleObject) if obj.data is NotLoaded: self.model.fillObj(obj, ['data'], QModelIndex(self.current)) self.pixmap = None elif obj.data: self.pixmap = QPixmap(QImage.fromData(obj.data)) else: self.pixmap = QPixmap() self._rebuildImage() @Slot(QModelIndex) def _dataChanged(self, qidx): if qidx == self.current: obj = qidx.data(ResultModel.RoleObject) if obj.data: self.pixmap = QPixmap(QImage.fromData(obj.data)) else: self.pixmap = QPixmap() self._rebuildImage() @Slot() def next(self): new = self.current.sibling(self.current.row() + 1, 0) if not new.isValid(): return self.current = QPersistentModelIndex(new) self.updateImage() @Slot() def prev(self): if self.current.row() == 0: return self.current = QPersistentModelIndex(self.current.sibling(self.current.row() - 1, 0)) self.updateImage() @Slot() def first(self): self.current = QPersistentModelIndex(self.current.sibling(0, 0)) self.updateImage() @Slot() def last(self): self.current = QPersistentModelIndex(self.current.sibling(self.total - 1, 0)) self.updateImage() @Slot() def zoomIn(self): self.zoomFactor *= 1.25 self.zoomMode = ZOOM_FACTOR self._rebuildImage() @Slot() def zoomOut(self): self.zoomFactor *= 0.75 self.zoomMode = ZOOM_FACTOR self._rebuildImage() @Slot() def zoomFullSize(self): self.zoomFactor = 1 self.zoomMode = ZOOM_FACTOR self._rebuildImage() @Slot() def zoomFit(self): self.zoomMode = ZOOM_FIT self._rebuildImage() def resizeEvent(self, ev): super(Viewer, self).resizeEvent(ev) if self.zoomMode == ZOOM_FIT: self._rebuildImage() def _rebuildZoom(self): if self.zoomMode == ZOOM_FACTOR: new_width = int(self.pixmap.width() * self.zoomFactor) pixmap = self.pixmap.scaledToWidth(new_width, Qt.SmoothTransformation) else: new_size = self.ui.scrollArea.viewport().size() pixmap = self.pixmap.scaled(new_size, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.zoomFactor = pixmap.width() / float(self.pixmap.width()) return pixmap def _rebuildImage(self): if self.pixmap is None: self.ui.view.setText('Loading...') return elif self.pixmap.isNull(): self.ui.view.setText('Image could not be loaded') return pixmap = self._rebuildZoom() self.ui.view.setPixmap(pixmap) @Slot() def saveImage(self): def ext_for_filter(s): return re.match(r'(?:[A-Z]+) \(\*\.([a-z]+)\)$', s).group(1) if not self.pixmap: return filters = ['PNG (*.png)', 'JPEG (*.jpg)', 'GIF (*.gif)'] obj = self.current.data(ResultModel.RoleObject) name = '%s.%s' % (obj.title or obj.id or u'', obj.ext or 'png') default = filters[0] for f in filters: if name.endswith(ext_for_filter(f)): default = f filters = ';;'.join(filters) target = os.path.join(self.parent().lastSaveDir, name) out, filter = QFileDialog.getSaveFileName(self, 'Save image', target, filters, default) if not out: return ext = ext_for_filter(filter) self.parent().lastSaveDir = os.path.dirname(out) if not os.path.splitext(out)[1]: out = '%s.%s' % (out, ext) if os.path.exists(out): q = self.tr('%s already exists, are you sure you want to replace it?') % out reply = QMessageBox.question(self, self.tr('Overwrite?'), q) if reply == QMessageBox.No: return self.saveImage() self.pixmap.save(out, ext.upper())
class ImageWidget(QLabel): def __init__(self, parent): super(QLabel, self).__init__(parent) self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.setMouseTracking(True) self.setCursor(Qt.CrossCursor) self.thread = RenderThread() self.pixmap = QPixmap() self.thread.renderedImage.connect(self.updatePixmap) self.thread.render() # https://stackoverflow.com/questions/7829829/pyqt4-mousemove-event-without-mousepress self.state = make_default_state() self.thread.load_image( "/Users/jonathan/Desktop/scanned on 20180605/Scan.jpeg") def mouseMoveEvent(self, event): mouse_x = event.pos().x() mouse_y = event.pos().y() # boxes = self.state.bounding_boxes # for box in boxes: # box.selected = self.is_point_in_box(mouse_x, mouse_y, box) # self.thread.render(self.state) self.state = self.state._replace( mouse_pos=[event.pos().x(), event.pos().y()]) self.thread.render(self.state) def mousePressEvent(self, event): mouse_x = event.pos().x() mouse_y = event.pos().y() # event.buttons() => bitmask of ALL buttons - i.e we can perform multi click etc. if event.buttons() & Qt.LeftButton: boxes = self.state.bounding_boxes for box in boxes: box.selected = box.xy_in_bounds(mouse_x, mouse_y) self.thread.render(self.state) self.state = self.state._replace(bounding_boxes=boxes) self.state = self.state._replace( drag_start_pos=[mouse_x, mouse_y], dragging=True, ) def mouseReleaseEvent(self, event): # event.button() (lack of 's') => button that caused the event. if event.button() == Qt.LeftButton: if self.state.dragging: self.state = self.state._replace( drag_end_pos=[event.pos().x(), event.pos().y()], dragging=False) bounding_boxes = self.state.bounding_boxes x1 = self.state.drag_start_pos[0] x2 = self.state.drag_end_pos[0] y1 = self.state.drag_start_pos[1] y2 = self.state.drag_end_pos[1] # Normalize coordinates (remove difference between start corner and end corner): # top left, bottom right => x,y,w,h min_x = min(x1, x2) min_y = min(y1, y2) max_x = max(x1, x2) max_y = max(y1, y2) x = min_x y = min_y w = max_x - min_x h = max_y - min_y box = BoundingBox(x=x, y=y, w=w, h=h, selected=True) if box.get_area() > 20: bounding_boxes.append(box) self.state = self.state._replace(bounding_boxes=bounding_boxes) def paintEvent(self, event): painter = QPainter(self) painter.fillRect(self.rect(), Qt.black) if self.pixmap.isNull(): painter.setPen(Qt.white) painter.drawText(self.rect(), Qt.AlignCenter, "No image loaded...") return painter.drawPixmap(QPoint(), self.pixmap) def updatePixmap(self, image): self.pixmap = QPixmap.fromImage(image) self.update()
class Dialog(QDialog): """A Dialog with basic layout features: a main widget, an icon or pixmap, a separator, buttons (provided by a QDialogButtonBox) """ def __init__(self, parent=None, message="", title="", icon=None, iconSize=QSize(64, 64), pixmap=None, separator=True, buttonOrientation=Qt.Horizontal, buttons=('ok', 'cancel'), help=None, **kwargs): """Initializes the dialog. parent = a parent widget or None. The following keyword arguments are recognized: - message: the text to display in the message label - title: the window title - icon or pixmap: shown in the left area - iconSize: size of the icon in the left (QSize, default: 64x64) - separator: draw a separator line or not (default: True) - buttonOrientation: Qt.Horizontal (default) or Qt.Vertical - buttons: which buttons to use (default: Ok, Cancel) - help: function to call when a help button is clicked. Other keyword arguments are passed to QDialog. """ super(Dialog, self).__init__(parent, **kwargs) self._icon = QIcon() self._separatorWidget = Separator() self._mainWidget = QWidget() self._pixmap = QPixmap() self._pixmapLabel = QLabel(self) self._messageLabel = QLabel(self) self._buttonBox = b = QDialogButtonBox(self) b.accepted.connect(self.accept) b.rejected.connect(self.reject) layout = QGridLayout() layout.setSpacing(10) self.setLayout(layout) # handle keyword args self._buttonOrientation = buttonOrientation self._iconSize = iconSize self._separator = separator if title: self.setWindowTitle(title) self.setMessage(message) if icon: self.setIcon(icon) elif pixmap: self.setPixmap(pixmap) b.helpRequested.connect(help or self.helpRequest) self.setStandardButtons(buttons) self.reLayout() def helpRequest(self): """Called when a help button is clicked.""" pass def setButtonOrientation(self, orientation): """Sets the button orientation. Qt.Horizontal (default) puts the buttons at the bottom of the dialog in a horizontal row, Qt.Vertical puts the buttons at the right in a vertical column. """ if orientation != self._buttonOrientation: self._buttonOrientation = orientation self._buttonBox.setOrientation(orientation) self.reLayout() def buttonOrientation(self): """Returns the button orientation.""" return self._buttonOrientation def setIcon(self, icon): """Sets the icon to display in the left area. May be: - None or QIcon() - one of 'info', 'warning', 'critical', 'question' - a QStyle.StandardPixmap - a QIcon. """ if icon in standardicons: icon = standardicons[icon] if isinstance(icon, QStyle.StandardPixmap): icon = self.style().standardIcon(icon) if icon is None: icon = QIcon() self._icon = icon self.setPixmap(icon.pixmap(self._iconSize)) def icon(self): """Returns the currently set icon as a QIcon.""" return self._icon def setIconSize(self, size): """Sets the icon size (QSize or int).""" if isinstance(size, int): size = QSize(size, size) changed = size != self._iconSize self._iconSize = size if changed and not self._icon.isNull(): self.setPixmap(self._icon.pixmap(size)) def iconSize(self): """Returns the icon size (QSize).""" return self._iconSize def setPixmap(self, pixmap): """Sets the pixmap to display in the left area.""" changed = self._pixmap.isNull() != pixmap.isNull() self._pixmap = pixmap self._pixmapLabel.setPixmap(pixmap) if not pixmap.isNull(): self._pixmapLabel.setFixedSize(pixmap.size()) if changed: self.reLayout() def pixmap(self): """Returns the currently set pixmap.""" return self._pixmap def setMessage(self, text): """Sets the main text in the dialog.""" self._messageLabel.setText(text) def message(self): """Returns the main text.""" return self._messageLabel.text() def messageLabel(self): """Returns the QLabel displaying the message text.""" return self._messageLabel def buttonBox(self): """Returns our QDialogButtonBox instance.""" return self._buttonBox def setStandardButtons(self, buttons): """Convenience method to set standard buttons in the button box. Accepts a sequence of string names from the standardbuttons constant, or a QDialogButtonBox.StandardButtons value. """ if isinstance(buttons, (set, tuple, list)): buttons = functools.reduce(operator.or_, map(standardbuttons.get, buttons), QDialogButtonBox.StandardButtons()) self._buttonBox.setStandardButtons(buttons) def button(self, button): """Returns the given button. May be a QDialogButtonBox.StandardButton or a key from standardbuttons. """ if button in standardbuttons: button = standardbuttons[button] return self._buttonBox.button(button) def setSeparator(self, enabled): """Sets whether to show a line between contents and buttons.""" changed = self._separator != enabled self._separator = enabled if changed: self.reLayout() def hasSeparator(self): """Returns whether a separator line is shown.""" return self._separator def setMainWidget(self, widget): """Sets the specified widget as our main widget.""" old = self._mainWidget if old: old.setParent(None) self._mainWidget = widget self.reLayout() def mainWidget(self): """Returns the current main widget (an empty QWidget by default).""" return self._mainWidget def reLayout(self): """(Internal) Lays out all items in this dialog.""" layout = self.layout() while layout.takeAt(0): pass if not self._pixmap.isNull(): col = 1 layout.addWidget(self._pixmapLabel, 0, 0, 2, 1) else: layout.setColumnStretch(1, 0) col = 0 layout.setColumnStretch(col, 1) self._pixmapLabel.setVisible(not self._pixmap.isNull()) layout.addWidget(self._messageLabel, 0, col) layout.addWidget(self._mainWidget, 1, col) if self._buttonOrientation == Qt.Horizontal: if self._separator: layout.addWidget(self._separatorWidget, 2, 0, 1, col + 1) layout.addWidget(self._buttonBox, 3, 0, 1, col + 1) else: if self._separator: layout.addWidget(self._separatorWidget, 0, col + 1, 2, 1) layout.addWidget(self._buttonBox, 0, col + 2, 2, 1) self._separatorWidget.setVisible(self._separator)
class SnapWidget(QWidget, Ui_SnapWidget): """ Class implementing the snapshot widget. """ ModeFullscreen = 0 ModeScreen = 1 ModeRectangle = 2 ModeFreehand = 3 ModeEllipse = 4 def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget (QWidget) """ super(SnapWidget, self).__init__(parent) self.setupUi(self) self.saveButton.setIcon(UI.PixmapCache.getIcon("fileSaveAs.png")) self.takeButton.setIcon(UI.PixmapCache.getIcon("cameraPhoto.png")) self.copyButton.setIcon(UI.PixmapCache.getIcon("editCopy.png")) self.copyPreviewButton.setIcon(UI.PixmapCache.getIcon("editCopy.png")) self.setWindowIcon(UI.PixmapCache.getIcon("ericSnap.png")) self.modeCombo.addItem(self.tr("Fullscreen"), SnapWidget.ModeFullscreen) self.modeCombo.addItem(self.tr("Rectangular Selection"), SnapWidget.ModeRectangle) self.modeCombo.addItem(self.tr("Ellipical Selection"), SnapWidget.ModeEllipse) self.modeCombo.addItem(self.tr("Freehand Selection"), SnapWidget.ModeFreehand) if QApplication.desktop().screenCount() > 1: self.modeCombo.addItem(self.tr("Current Screen"), SnapWidget.ModeScreen) self.__mode = int(Preferences.Prefs.settings.value("Snapshot/Mode", 0)) index = self.modeCombo.findData(self.__mode) if index == -1: index = 0 self.modeCombo.setCurrentIndex(index) self.__delay = int( Preferences.Prefs.settings.value("Snapshot/Delay", 0)) self.delaySpin.setValue(self.__delay) if PYQT_VERSION_STR >= "5.0.0": from PyQt5.QtCore import QStandardPaths picturesLocation = QStandardPaths.writableLocation( QStandardPaths.PicturesLocation) else: from PyQt5.QtGui import QDesktopServices picturesLocation = QDesktopServices.storageLocation( QDesktopServices.PicturesLocation) self.__filename = Preferences.Prefs.settings.value( "Snapshot/Filename", os.path.join(picturesLocation, self.tr("snapshot") + "1.png")) self.__grabber = None self.__snapshot = QPixmap() self.__savedPosition = QPoint() self.__modified = False self.__locale = QLocale() self.__grabberWidget = QWidget(None, Qt.X11BypassWindowManagerHint) self.__grabberWidget.move(-10000, -10000) self.__grabberWidget.installEventFilter(self) self.__initFileFilters() self.__initShortcuts() self.preview.startDrag.connect(self.__dragSnapshot) from .SnapshotTimer import SnapshotTimer self.__grabTimer = SnapshotTimer() self.__grabTimer.timeout.connect(self.__grabTimerTimeout) self.__updateTimer = QTimer() self.__updateTimer.setSingleShot(True) self.__updateTimer.timeout.connect(self.__updatePreview) self.__updateCaption() self.takeButton.setFocus() def __initFileFilters(self): """ Private method to define the supported image file filters. """ filters = { 'bmp': self.tr("Windows Bitmap File (*.bmp)"), 'gif': self.tr("Graphic Interchange Format File (*.gif)"), 'ico': self.tr("Windows Icon File (*.ico)"), 'jpg': self.tr("JPEG File (*.jpg)"), 'mng': self.tr("Multiple-Image Network Graphics File (*.mng)"), 'pbm': self.tr("Portable Bitmap File (*.pbm)"), 'pcx': self.tr("Paintbrush Bitmap File (*.pcx)"), 'pgm': self.tr("Portable Graymap File (*.pgm)"), 'png': self.tr("Portable Network Graphics File (*.png)"), 'ppm': self.tr("Portable Pixmap File (*.ppm)"), 'sgi': self.tr("Silicon Graphics Image File (*.sgi)"), 'svg': self.tr("Scalable Vector Graphics File (*.svg)"), 'tga': self.tr("Targa Graphic File (*.tga)"), 'tif': self.tr("TIFF File (*.tif)"), 'xbm': self.tr("X11 Bitmap File (*.xbm)"), 'xpm': self.tr("X11 Pixmap File (*.xpm)"), } outputFormats = [] writeFormats = QImageWriter.supportedImageFormats() for writeFormat in writeFormats: try: outputFormats.append(filters[bytes(writeFormat).decode()]) except KeyError: pass outputFormats.sort() self.__outputFilter = ';;'.join(outputFormats) self.__defaultFilter = filters['png'] def __initShortcuts(self): """ Private method to initialize the keyboard shortcuts. """ self.__quitShortcut = QShortcut( QKeySequence(QKeySequence.Quit), self, self.close) self.__copyShortcut = QShortcut( QKeySequence(QKeySequence.Copy), self, self.copyButton.animateClick) self.__quickSaveShortcut = QShortcut( QKeySequence(Qt.Key_Q), self, self.__quickSave) self.__save1Shortcut = QShortcut( QKeySequence(QKeySequence.Save), self, self.saveButton.animateClick) self.__save2Shortcut = QShortcut( QKeySequence(Qt.Key_S), self, self.saveButton.animateClick) self.__grab1Shortcut = QShortcut( QKeySequence(QKeySequence.New), self, self.takeButton.animateClick) self.__grab2Shortcut = QShortcut( QKeySequence(Qt.Key_N), self, self.takeButton.animateClick) self.__grab3Shortcut = QShortcut( QKeySequence(Qt.Key_Space), self, self.takeButton.animateClick) def __quickSave(self): """ Private slot to save the snapshot bypassing the file selection dialog. """ if not self.__snapshot.isNull(): while os.path.exists(self.__filename): self.__autoIncFilename() if self.__saveImage(self.__filename): self.__modified = False self.__autoIncFilename() self.__updateCaption() @pyqtSlot() def on_saveButton_clicked(self): """ Private slot to save the snapshot. """ if not self.__snapshot.isNull(): while os.path.exists(self.__filename): self.__autoIncFilename() fileName, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( self, self.tr("Save Snapshot"), self.__filename, self.__outputFilter, self.__defaultFilter, E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) if not fileName: return ext = QFileInfo(fileName).suffix() if not ext: ex = selectedFilter.split("(*")[1].split(")")[0] if ex: fileName += ex if self.__saveImage(fileName): self.__modified = False self.__filename = fileName self.__autoIncFilename() self.__updateCaption() def __saveImage(self, fileName): """ Private method to save the snapshot. @param fileName name of the file to save to (string) @return flag indicating success (boolean) """ if QFileInfo(fileName).exists(): res = E5MessageBox.yesNo( self, self.tr("Save Snapshot"), self.tr("<p>The file <b>{0}</b> already exists." " Overwrite it?</p>").format(fileName), icon=E5MessageBox.Warning) if not res: return False file = QFile(fileName) if not file.open(QFile.WriteOnly): E5MessageBox.warning( self, self.tr("Save Snapshot"), self.tr("Cannot write file '{0}:\n{1}.") .format(fileName, file.errorString())) return False ok = self.__snapshot.save(file) file.close() if not ok: E5MessageBox.warning( self, self.tr("Save Snapshot"), self.tr("Cannot write file '{0}:\n{1}.") .format(fileName, file.errorString())) return ok def __autoIncFilename(self): """ Private method to auto-increment the file name. """ # Extract the file name name = os.path.basename(self.__filename) # If the name contains a number, then increment it. numSearch = QRegExp("(^|[^\\d])(\\d+)") # We want to match as far left as possible, and when the number is # at the start of the name. # Does it have a number? start = numSearch.lastIndexIn(name) if start != -1: # It has a number, increment it. start = numSearch.pos(2) # Only the second group is of interest. numAsStr = numSearch.capturedTexts()[2] number = "{0:0{width}d}".format( int(numAsStr) + 1, width=len(numAsStr)) name = name[:start] + number + name[start + len(numAsStr):] else: # no number start = name.rfind('.') if start != -1: # has a '.' somewhere, e.g. it has an extension name = name[:start] + '1' + name[start:] else: # no extension, just tack it on to the end name += '1' self.__filename = os.path.join(os.path.dirname(self.__filename), name) self.__updateCaption() @pyqtSlot() def on_takeButton_clicked(self): """ Private slot to take a snapshot. """ self.__mode = self.modeCombo.itemData(self.modeCombo.currentIndex()) self.__delay = self.delaySpin.value() self.__savedPosition = self.pos() self.hide() if self.__delay: self.__grabTimer.start(self.__delay) else: QTimer.singleShot(200, self.__startUndelayedGrab) def __grabTimerTimeout(self): """ Private slot to perform a delayed grab operation. """ if self.__mode == SnapWidget.ModeRectangle: self.__grabRectangle() elif self.__mode == SnapWidget.ModeEllipse: self.__grabEllipse() elif self.__mode == SnapWidget.ModeFreehand: self.__grabFreehand() else: self.__performGrab() def __startUndelayedGrab(self): """ Private slot to perform an undelayed grab operation. """ if self.__mode == SnapWidget.ModeRectangle: self.__grabRectangle() elif self.__mode == SnapWidget.ModeEllipse: self.__grabEllipse() elif self.__mode == SnapWidget.ModeFreehand: self.__grabFreehand() else: if Globals.isMacPlatform(): self.__performGrab() else: self.__grabberWidget.show() self.__grabberWidget.grabMouse(Qt.CrossCursor) def __grabRectangle(self): """ Private method to grab a rectangular screen region. """ from .SnapshotRegionGrabber import SnapshotRegionGrabber self.__grabber = SnapshotRegionGrabber( mode=SnapshotRegionGrabber.Rectangle) self.__grabber.grabbed.connect(self.__captured) def __grabEllipse(self): """ Private method to grab an elliptical screen region. """ from .SnapshotRegionGrabber import SnapshotRegionGrabber self.__grabber = SnapshotRegionGrabber( mode=SnapshotRegionGrabber.Ellipse) self.__grabber.grabbed.connect(self.__captured) def __grabFreehand(self): """ Private method to grab a non-rectangular screen region. """ from .SnapshotFreehandGrabber import SnapshotFreehandGrabber self.__grabber = SnapshotFreehandGrabber() self.__grabber.grabbed.connect(self.__captured) def __performGrab(self): """ Private method to perform a screen grab other than a selected region. """ self.__grabberWidget.releaseMouse() self.__grabberWidget.hide() self.__grabTimer.stop() if self.__mode == SnapWidget.ModeFullscreen: desktop = QApplication.desktop() if qVersion() >= "5.0.0": self.__snapshot = QApplication.screens()[0].grabWindow( desktop.winId(), desktop.x(), desktop.y(), desktop.width(), desktop.height()) else: self.__snapshot = QPixmap.grabWindow( desktop.winId(), desktop.x(), desktop.y(), desktop.width(), desktop.height()) elif self.__mode == SnapWidget.ModeScreen: desktop = QApplication.desktop() screenId = desktop.screenNumber(QCursor.pos()) geom = desktop.screenGeometry(screenId) x = geom.x() y = geom.y() if qVersion() >= "5.0.0": self.__snapshot = QApplication.screens()[0].grabWindow( desktop.winId(), x, y, geom.width(), geom.height()) else: self.__snapshot = QPixmap.grabWindow( desktop.winId(), x, y, geom.width(), geom.height()) else: self.__snapshot = QPixmap() self.__redisplay() self.__modified = True self.__updateCaption() def __redisplay(self): """ Private method to redisplay the window. """ self.__updatePreview() QApplication.restoreOverrideCursor() if not self.__savedPosition.isNull(): self.move(self.__savedPosition) self.show() self.raise_() self.saveButton.setEnabled(not self.__snapshot.isNull()) self.copyButton.setEnabled(not self.__snapshot.isNull()) self.copyPreviewButton.setEnabled(not self.__snapshot.isNull()) @pyqtSlot() def on_copyButton_clicked(self): """ Private slot to copy the snapshot to the clipboard. """ if not self.__snapshot.isNull(): QApplication.clipboard().setPixmap(QPixmap(self.__snapshot)) @pyqtSlot() def on_copyPreviewButton_clicked(self): """ Private slot to copy the snapshot preview to the clipboard. """ QApplication.clipboard().setPixmap(self.preview.pixmap()) def __captured(self, pixmap): """ Private slot to show a preview of the snapshot. @param pixmap pixmap of the snapshot (QPixmap) """ self.__grabber.close() self.__snapshot = QPixmap(pixmap) self.__grabber.grabbed.disconnect(self.__captured) self.__grabber = None self.__redisplay() self.__modified = True self.__updateCaption() def __updatePreview(self): """ Private slot to update the preview picture. """ self.preview.setToolTip(self.tr( "Preview of the snapshot image ({0} x {1})").format( self.__locale.toString(self.__snapshot.width()), self.__locale.toString(self.__snapshot.height())) ) self.preview.setPreview(self.__snapshot) self.preview.adjustSize() def resizeEvent(self, evt): """ Protected method handling a resizing of the window. @param evt resize event (QResizeEvent) """ self.__updateTimer.start(200) def __dragSnapshot(self): """ Private slot handling the dragging of the preview picture. """ drag = QDrag(self) mimeData = QMimeData() mimeData.setImageData(self.__snapshot) drag.setMimeData(mimeData) drag.setPixmap(self.preview.pixmap()) drag.exec_(Qt.CopyAction) def eventFilter(self, obj, evt): """ Public method to handle event for other objects. @param obj reference to the object (QObject) @param evt reference to the event (QEvent) @return flag indicating that the event should be filtered out (boolean) """ if obj == self.__grabberWidget and \ evt.type() == QEvent.MouseButtonPress: if QWidget.mouseGrabber() != self.__grabberWidget: return False if evt.button() == Qt.LeftButton: self.__performGrab() return False def closeEvent(self, evt): """ Protected method handling the close event. @param evt close event (QCloseEvent) """ if self.__modified: res = E5MessageBox.question( self, self.tr("eric6 Snapshot"), self.tr( """The application contains an unsaved snapshot."""), E5MessageBox.StandardButtons( E5MessageBox.Abort | E5MessageBox.Discard | E5MessageBox.Save)) if res == E5MessageBox.Abort: evt.ignore() return elif res == E5MessageBox.Save: self.on_saveButton_clicked() Preferences.Prefs.settings.setValue( "Snapshot/Delay", self.delaySpin.value()) Preferences.Prefs.settings.setValue( "Snapshot/Mode", self.modeCombo.itemData(self.modeCombo.currentIndex())) Preferences.Prefs.settings.setValue( "Snapshot/Filename", self.__filename) Preferences.Prefs.settings.sync() def __updateCaption(self): """ Private method to update the window caption. """ self.setWindowTitle("{0}[*] - {1}".format( os.path.basename(self.__filename), self.tr("eric6 Snapshot"))) self.setWindowModified(self.__modified) self.pathNameEdit.setText(os.path.dirname(self.__filename))
class ImgWatch(QWidget): def __init__(self, loader, history): super().__init__() self.screen_mode = ScreenMode(self) self.image_loader = loader self.mpos = QPoint() self.pixmap = QPixmap() self.setWindowTitle('QImgWatch') self.resize(1280, 720) self.setStyleSheet("background-color: black;") if history: self.pixmap_history = collections.deque(maxlen=history) else: self.pixmap_history = None self.pixmap_idx = None self.setMouseTracking(True) def update_pixmap(self, data): if not self.pixmap.isNull() and self.pixmap_history is not None: self.pixmap_history.append(self.pixmap) self.pixmap = QPixmap() image = QImage.fromData(data) self.pixmap = QPixmap.fromImage(image) def keyPressEvent(self, ev): if ev.key() == Qt.Key_F11 or ev.key() == Qt.Key_F: self.screen_mode.fullscreen_toggle() elif ev.key() == Qt.Key_Escape: if self.screen_mode.is_fullscreen(): self.window() elif ev.key() == Qt.Key_Q: self.close() def mouseDoubleClickEvent(self, ev): self.screen_mode.fullscreen_toggle() def mousePressEvent(self, ev): self.mpos = ev.pos() def mouseMoveEvent(self, ev): if ev.buttons() & Qt.LeftButton: diff = ev.pos() - self.mpos newpos = self.pos() + diff self.move(newpos) if self.pixmap_history is not None: if ev.pos().y() > self.height() - 200: w = self.width() // self.pixmap_history.maxlen idx = ev.pos().x() // w idx = max(0, min(idx, self.pixmap_history.maxlen)) if self.pixmap_idx != idx: self.pixmap_idx = idx self.repaint() else: self.pixmap_idx = None def paintEvent(self, ev): if self.pixmap.isNull(): return painter = QPainter(self) painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) if self.pixmap_idx is None or self.pixmap_history is None: pixmap = self.pixmap else: if 0 <= self.pixmap_idx < len(self.pixmap_history): pixmap = self.pixmap_history[self.pixmap_idx] else: pixmap = self.pixmap sap = pixmap.width() / pixmap.height() tap = self.width() / self.height() if sap > tap: th = self.width() / sap painter.drawPixmap(0, self.height() // 2 - th // 2, self.width(), th, pixmap, 0, 0, pixmap.width(), pixmap.height()) else: tw = sap * self.height() painter.drawPixmap(self.width() // 2 - tw // 2, 0, tw, self.height(), pixmap, 0, 0, pixmap.width(), pixmap.height()) if self.pixmap_history is not None: for x, pixmap in enumerate(self.pixmap_history): thumb_w = self.width() // self.pixmap_history.maxlen thumb_h = 150 # pixmap.height() * thumb_w // self.pixmap.width() * 3 painter.drawPixmap(x * thumb_w, self.height() - thumb_h, thumb_w, thumb_h, pixmap, 0, 0, pixmap.width(), pixmap.height())
class RoundRectItem(QGraphicsObject): """Base class for most graphic objects in our scene""" def __init__(self, bounds, color=None, parent=None): """ Args: bounds - QRectF, geometry of object color - QColor or None parent - widget to contain this graphic item or None """ super(RoundRectItem, self).__init__(parent) self._fillRect = False self._bounds = QRectF(bounds) self._pix = QPixmap() self._color = color self.setCacheMode(QGraphicsItem.ItemCoordinateCache) def setFill(self, fill: bool): """ Changes the property of how the cell is filled. Args: fill: bool """ self._fillRect = fill self.update() @property def _gradient(self): gradient = QLinearGradient() gradient.setStart( (self._bounds.topLeft() + self._bounds.topRight()) / 2) gradient.setFinalStop( (self._bounds.bottomLeft() + self._bounds.bottomRight()) / 2) gradient.setColorAt(0, self._color) gradient.setColorAt(1, self._color.darker(200)) return gradient def paint(self, painter, option, widget): """Standard Qt paint event.""" if self._color: painter.setPen(Qt.NoPen) painter.setBrush(QColor(0, 0, 0, 64)) painter.drawRoundedRect(self._bounds.translated(2, 2), 25.0, 25.0) if self._fillRect: painter.setBrush(QApplication.palette().brush(QPalette.Window)) else: painter.setBrush(self._gradient) painter.setPen(QPen(Qt.black, 1)) painter.drawRoundedRect(self._bounds, 25.0, 25.0) if not self._pix.isNull(): if self._rounded_pixmap: painter.setRenderHint(QPainter.Antialiasing, True) brush = QBrush( self._pix.scaled(self._bounds.width(), self._bounds.height())) painter.setBrush(brush) painter.drawRoundedRect(self._bounds, 25.0, 25.0) else: painter.scale(self._bounds.width() / self._pix.width(), self._bounds.height() / self._pix.height()) painter.drawPixmap(-self._pix.width() / 2, -self._pix.height() / 2, self._pix) def boundingRect(self): """returns bounding rectangle""" return self._bounds.adjusted(0, 0, 2, 2) def setPixmap(self, pixmap_path: str, rounded_pixmap=False): """ Sets new pixmap for this graphic object. Args: pixmap_path: path to image for pixmap rounded_pixmap: make the picture rounded (used, e.g., for lava in the cells) """ self._rounded_pixmap = rounded_pixmap self._pix = QPixmap(pixmap_path) self.update()
class TrafficUi(QMainWindow): def __init__(self): QMainWindow.__init__(self) naming = "no file selected" self.setMinimumSize(QSize(1015, 1000)) self.setWindowTitle("Traffic Management") centralWidget = QWidget(self) self.setCentralWidget(centralWidget) oImage = QImage("b.png") sImage = oImage.scaled(QSize(1015, 1000)) palette = QPalette() palette.setBrush(10, QBrush(sImage)) newfont = QFont('Roboto', 12, QFont.Bold) self.setPalette(palette) self.run_btn = QPushButton('Start', self) self.run_btn.resize(100, 40) self.run_btn.move(10, 10) self.run_btn.clicked.connect(self.runMethod) self.east_label = QLabel("east", self) self.east_label.resize(200, 40) self.east_label.move(780, 380) self.east_label.setFont(newfont) self.south_label = QLabel("south", self) self.south_label.resize(200, 40) self.south_label.move(400, 825) self.south_label.setFont(newfont) self.west_label = QLabel("west", self) self.west_label.resize(200, 40) self.west_label.move(160, 380) self.west_label.setFont(newfont) self.north_label = QLabel("north", self) self.north_label.resize(200, 40) self.north_label.move(400, 175) self.north_label.setFont(newfont) self.east_density = QLabel("low", self) self.east_density.resize(200, 40) self.east_density.move(780, 600) self.east_density.setFont(newfont) self.east_density.setStyleSheet('color : white;') self.south_density = QLabel("low", self) self.south_density.resize(200, 40) self.south_density.move(600, 825) self.south_density.setFont(newfont) self.south_density.setStyleSheet('color : white;') self.west_density = QLabel("low", self) self.west_density.resize(200, 40) self.west_density.move(160, 600) self.west_density.setFont(newfont) self.west_density.setStyleSheet('color : white;') self.north_density = QLabel("low", self) self.north_density.resize(200, 40) self.north_density.move(600, 175) self.north_density.setFont(newfont) self.north_density.setStyleSheet('color : white;') self.traffic_h = QLabel(self) self.traffic_h_pixmap = QPixmap('traffic_lamp2.png') self.traffic_h_pixmap = self.traffic_h_pixmap.scaled(150, 60) self.traffic_h.setPixmap(self.traffic_h_pixmap) self.traffic_h.resize(150, 60) self.traffic_h.move(425, 780) self.traffic_h.hide() self.traffic_h.setStyleSheet( 'border-style: solid; border-width: 0px 3px 0px 3px; border-color: white;' ) self.traffic_h2 = QLabel(self) self.traffic_h2_pixmap = QPixmap('traffic_lamp2.png') self.traffic_h2_pixmap = self.traffic_h2_pixmap.scaled(150, 60) self.traffic_h2.setPixmap(self.traffic_h2_pixmap) self.traffic_h2.resize(150, 60) self.traffic_h2.move(425, 160) self.traffic_h2.hide() self.traffic_h2.setStyleSheet( 'border-style: solid; border-width: 0px 3px 0px 3px; border-color: white;' ) self.traffic_v = QLabel(self) self.traffic_v_pixmap = QPixmap('traffic_lamp.png') self.traffic_v_pixmap = self.traffic_v_pixmap.scaled(60, 150) self.traffic_v.setPixmap(self.traffic_v_pixmap) self.traffic_v.resize(60, 150) self.traffic_v.move(780, 425) self.traffic_v.hide() self.traffic_v.setStyleSheet( 'border-style: solid; border-width: 3px 0px 3px 0px; border-color: white;' ) self.traffic_v2 = QLabel(self) self.traffic_v2_pixmap = QPixmap('traffic_lamp.png') self.traffic_v2_pixmap = self.traffic_v2_pixmap.scaled(60, 150) self.traffic_v2.setPixmap(self.traffic_v2_pixmap) self.traffic_v2.resize(60, 150) self.traffic_v2.move(160, 425) self.traffic_v2.hide() self.traffic_v2.setStyleSheet( 'border-style: solid; border-width: 3px 0px 3px 0px; border-color: white;' ) self.red_label = QLabel(self) self.red_pixmap = QPixmap('red.png') self.red_pixmap = self.red_pixmap.scaled(50, 50) self.red_label.setPixmap(self.red_pixmap) self.red_label.resize(50, 50) self.red_label.move(785, 428) self.red_label2 = QLabel(self) self.red_pixmap2 = QPixmap('red.png') self.red_pixmap2 = self.red_pixmap2.scaled(50, 50) self.red_label2.setPixmap(self.red_pixmap2) self.red_label2.resize(50, 50) self.red_label2.move(431, 785) self.red_label3 = QLabel(self) self.red_pixmap3 = QPixmap('red.png') self.red_pixmap3 = self.red_pixmap3.scaled(50, 50) self.red_label3.setPixmap(self.red_pixmap3) self.red_label3.resize(50, 50) self.red_label3.move(166, 428) self.red_label4 = QLabel(self) self.red_pixmap4 = QPixmap('red.png') self.red_pixmap4 = self.red_pixmap4.scaled(50, 50) self.red_label4.setPixmap(self.red_pixmap4) self.red_label4.resize(50, 50) self.red_label4.move(431, 166) self.yellow_label = QLabel(self) self.yellow_pixmap = QPixmap('yellow.png') self.yellow_pixmap = self.yellow_pixmap.scaled(50, 50) self.yellow_label.setPixmap(self.yellow_pixmap) self.yellow_label.resize(50, 50) self.yellow_label.move(785, 475) self.yellow_label2 = QLabel(self) self.yellow_pixmap2 = QPixmap('yellow.png') self.yellow_pixmap2 = self.yellow_pixmap2.scaled(50, 50) self.yellow_label2.setPixmap(self.yellow_pixmap2) self.yellow_label2.resize(50, 50) self.yellow_label2.move(478, 785) self.yellow_label3 = QLabel(self) self.yellow_pixmap3 = QPixmap('yellow.png') self.yellow_pixmap3 = self.yellow_pixmap3.scaled(50, 50) self.yellow_label3.setPixmap(self.yellow_pixmap3) self.yellow_label3.resize(50, 50) self.yellow_label3.move(166, 475) self.yellow_label4 = QLabel(self) self.yellow_pixmap4 = QPixmap('yellow.png') self.yellow_pixmap4 = self.yellow_pixmap4.scaled(50, 50) self.yellow_label4.setPixmap(self.yellow_pixmap4) self.yellow_label4.resize(50, 50) self.yellow_label4.move(478, 166) self.green_label = QLabel(self) self.green_pixmap = QPixmap('green.png') self.green_pixmap = self.green_pixmap.scaled(50, 50) self.green_label.setPixmap(self.green_pixmap) self.green_label.resize(50, 50) self.green_label.move(785, 522) self.green_label2 = QLabel(self) self.green_pixmap2 = QPixmap('green.png') self.green_pixmap2 = self.green_pixmap2.scaled(50, 50) self.green_label2.setPixmap(self.green_pixmap2) self.green_label2.resize(50, 50) self.green_label2.move(525, 785) self.green_label3 = QLabel(self) self.green_pixmap3 = QPixmap('green.png') self.green_pixmap3 = self.green_pixmap3.scaled(50, 50) self.green_label3.setPixmap(self.green_pixmap3) self.green_label3.resize(50, 50) self.green_label3.move(166, 522) self.green_label4 = QLabel(self) self.green_pixmap4 = QPixmap('green.png') self.green_pixmap4 = self.green_pixmap4.scaled(50, 50) self.green_label4.setPixmap(self.green_pixmap4) self.green_label4.resize(50, 50) self.green_label4.move(525, 166) self.east_road = QLabel(self) self.east_road_pixmap = QPixmap('./Test/images/east.png') self.east_road_pixmap = self.east_road_pixmap.scaled(150, 150) self.east_road.setPixmap(self.east_road_pixmap) self.east_road.resize(150, 150) self.east_road.move(10, -250) self.east_road.setStyleSheet( 'border-style: solid; border-width: 3px; border-color: white;') self.east_road_bbox = QLabel(self) self.east_road_bbox_pixmap = QPixmap('./Test/images/east_bbox.png') self.east_road_bbox_pixmap = self.east_road_bbox_pixmap.scaled( 150, 150) self.east_road_bbox.setPixmap(self.east_road_bbox_pixmap) self.east_road_bbox.resize(150, 150) self.east_road_bbox.move(10, -250) self.east_road_bbox.setStyleSheet( 'border-style: solid; border-width: 3px; border-color: white;') self.south_road = QLabel(self) self.south_road_pixmap = QPixmap('./Test/images/south.png') self.south_road_pixmap = self.south_road_pixmap.scaled(150, 150) self.south_road.setPixmap(self.south_road_pixmap) self.south_road.resize(150, 150) self.south_road.move(10, -250) self.south_road.setStyleSheet( 'border-style: solid; border-width: 3px; border-color: white;') self.south_road_bbox = QLabel(self) self.south_road_bbox_pixmap = QPixmap('./Test/images/south_bbox.png') self.south_road_bbox_pixmap = self.south_road_bbox_pixmap.scaled( 150, 150) self.south_road_bbox.setPixmap(self.south_road_bbox_pixmap) self.south_road_bbox.resize(150, 150) self.south_road_bbox.move(10, -250) self.south_road_bbox.setStyleSheet( 'border-style: solid; border-width: 3px; border-color: white;') self.west_road = QLabel(self) self.west_road_pixmap = QPixmap('./Test/images/west.png') self.west_road_pixmap = self.west_road_pixmap.scaled(150, 150) self.west_road.setPixmap(self.west_road_pixmap) self.west_road.resize(150, 150) self.west_road.move(10, -250) self.west_road.setStyleSheet( 'border-style: solid; border-width: 3px; border-color: white;') self.west_road_bbox = QLabel(self) self.west_road_bbox_pixmap = QPixmap('./Test/images/west_bbox.png') self.west_road_bbox_pixmap = self.west_road_bbox_pixmap.scaled( 150, 150) self.west_road_bbox.setPixmap(self.west_road_bbox_pixmap) self.west_road_bbox.resize(150, 150) self.west_road_bbox.move(10, -250) self.west_road_bbox.setStyleSheet( 'border-style: solid; border-width: 3px; border-color: white;') self.north_road = QLabel(self) self.north_road_pixmap = QPixmap('./Test/images/north.png') self.north_road_pixmap = self.north_road_pixmap.scaled(150, 150) self.north_road.setPixmap(self.north_road_pixmap) self.north_road.resize(150, 150) self.north_road.move(10, -250) self.north_road.setStyleSheet( 'border-style: solid; border-width: 3px; border-color: white;') self.north_road_bbox = QLabel(self) self.north_road_bbox_pixmap = QPixmap('./Test/images/north_bbox.png') self.north_road_bbox_pixmap = self.north_road_bbox_pixmap.scaled( 150, 150) self.north_road_bbox.setPixmap(self.north_road_bbox_pixmap) self.north_road_bbox.resize(150, 150) self.north_road_bbox.move(10, -250) self.north_road_bbox.setStyleSheet( 'border-style: solid; border-width: 3px; border-color: white;') def runMethod(self): t2 = threading.Thread(target=self.print_images) t2.start() self.runMethod_() def runMethod_(self): self.run_btn.hide() QApplication.processEvents() self.east = 30 self.south = 60 self.west = 90 self.north = 120 self.cur = "east" self.east_status = "low" self.south_status = "low" self.west_status = "low" self.north_status = "low" self.traffic_v2.show() self.traffic_v.show() self.traffic_h.show() self.traffic_h2.show() while (True): if self.cur == "east": self.east_label.setText(str(self.east)) self.south_label.setText(str(self.south - 30)) self.west_label.setText(str(self.west - 30)) self.north_label.setText(str(self.north - 30)) if self.cur == "south": self.east_label.setText(str(self.east - 30)) self.south_label.setText(str(self.south)) self.west_label.setText(str(self.west - 30)) self.north_label.setText(str(self.north - 30)) if self.cur == "west": self.east_label.setText(str(self.east - 30)) self.south_label.setText(str(self.south - 30)) self.west_label.setText(str(self.west)) self.north_label.setText(str(self.north - 30)) if self.cur == "north": self.east_label.setText(str(self.east - 30)) self.south_label.setText(str(self.south - 30)) self.west_label.setText(str(self.west - 30)) self.north_label.setText(str(self.north)) QApplication.processEvents() self.file = open('val.txt', 'r+') self.cont = self.file.read() self.cont = self.cont[1:-2] self.cont = self.cont.replace(',', '') self.east_st, self.south_st, self.west_st, self.north_st = self.cont.split( ' ') print(self.east_st, self.south_st, self.west_st, self.north_st) if float(self.east_st) > 40: self.east_status = "High" elif float(self.east_st) > 30: self.east_status = "Mod" else: self.east_status = "low" if float(self.south_st) > 40: self.south_status = "High" elif float(self.south_st) > 30: self.south_status = "Mod" else: self.south_status = "low" if float(self.west_st) > 40: self.west_status = "High" elif float(self.west_st) > 30: self.west_status = "Mod" else: self.west_status = "low" if float(self.north_st) > 40: self.north_status = "High" elif float(self.north_st) > 30: self.north_status = "Mod" else: self.north_status = "low" print(self.east_status, self.south_status, self.west_status, self.north_status) time.sleep(0.9) self.east -= 1 self.south -= 1 self.west -= 1 self.north -= 1 if self.east == 0: self.east = 120 self.south = 30 self.west = 60 self.north = 90 self.cur = "south" if self.south == 0: self.east = 90 self.south = 120 self.west = 30 self.north = 60 self.cur = "west" if self.west == 0: self.east = 60 self.south = 90 self.west = 120 self.north = 30 self.cur = "north" if self.north == 0: self.east = 30 self.south = 60 self.west = 90 self.north = 120 self.cur = "east" if self.east > 35: self.east_label.setStyleSheet('color: red') self.red_label.show() self.yellow_label.hide() self.green_label.hide() elif self.east > 30: self.east_label.setStyleSheet('color: yellow') self.red_label.hide() self.yellow_label.show() self.green_label.hide() else: self.east_label.setStyleSheet('color: green') self.red_label.hide() self.yellow_label.hide() self.green_label.show() if self.south > 35: self.south_label.setStyleSheet('color: red') self.red_label2.show() self.yellow_label2.hide() self.green_label2.hide() elif self.south > 30: self.south_label.setStyleSheet('color: yellow') self.red_label2.hide() self.yellow_label2.show() self.green_label2.hide() else: self.south_label.setStyleSheet('color: green') self.red_label2.hide() self.yellow_label2.hide() self.green_label2.show() if self.west > 35: self.west_label.setStyleSheet('color: red') self.red_label3.show() self.yellow_label3.hide() self.green_label3.hide() elif self.west > 30: self.west_label.setStyleSheet('color: yellow') self.red_label3.hide() self.yellow_label3.show() self.green_label3.hide() else: self.west_label.setStyleSheet('color: green') self.red_label3.hide() self.yellow_label3.hide() self.green_label3.show() if self.north > 35: self.north_label.setStyleSheet('color: red') self.red_label4.show() self.yellow_label4.hide() self.green_label4.hide() elif self.north > 30: self.north_label.setStyleSheet('color: yellow') self.red_label4.hide() self.yellow_label4.show() self.green_label4.hide() else: self.north_label.setStyleSheet('color: green') self.red_label4.hide() self.yellow_label4.hide() self.green_label4.show() if self.east_status == "High": if self.cur != "east": if (self.cur == "west" and self.west > 10) and self.west_status != 'High': self.east = 70 self.south = 100 self.west = 10 self.north = 40 elif (self.cur == "north" and self.north > 10) and self.north_status != 'High': self.east = 40 self.south = 70 self.west = 100 self.north = 10 elif (self.cur == "south" and self.south > 10) and self.south_status != 'High': self.east = 100 self.south = 10 self.west = 40 self.north = 70 #self.east_status = "low" elif self.south_status == "High": if self.cur != "south": if (self.cur == "west" and self.west > 10) and self.west_status != 'High': self.east = 70 self.south = 100 self.west = 10 self.north = 40 elif (self.cur == "north" and self.north > 10) and self.north_status != 'High': self.east = 40 self.south = 70 self.west = 100 self.north = 10 elif (self.cur == "east" and self.east > 10) and self.east_status != 'High': self.east = 10 self.south = 40 self.west = 70 self.north = 100 #self.south_status = "low" elif self.west_status == "High": if self.cur != "west": if (self.cur == "east" and self.east > 10) and self.east_status != 'High': self.east = 10 self.south = 40 self.west = 70 self.north = 100 elif (self.cur == "south" and self.south > 10) and self.south_status != 'High': self.east = 100 self.south = 10 self.west = 40 self.north = 70 elif (self.cur == "north" and self.north > 10) and self.north_status != 'High': self.east = 40 self.south = 70 self.west = 100 self.north = 10 #self.west_status = "low" elif self.north_status == "High": if self.cur != "north": if (self.cur == "east" and self.east > 10) and self.east_status != 'High': self.east = 10 self.south = 40 self.west = 70 self.north = 100 elif (self.cur == "south" and self.south > 10) and self.south_status != 'High': self.east = 100 self.south = 10 self.west = 40 self.north = 70 elif (self.cur == "west" and self.west > 10) and self.west_status != 'High': self.east = 70 self.south = 100 self.west = 10 self.north = 40 #self.north_status = "low" elif self.east_status == "Mod": if self.cur != "east": if (self.cur == "west" and self.west > 15) and self.west_status == 'low': self.east = 75 self.south = 105 self.west = 15 self.north = 45 elif (self.cur == "north" and self.north > 15) and self.north_status == 'low': self.east = 45 self.south = 75 self.west = 105 self.north = 15 elif (self.cur == "south" and self.south > 15) and self.south_status == 'low': self.east = 105 self.south = 15 self.west = 45 self.north = 75 #self.east_status = "low" elif self.south_status == "Mod": if self.cur != "south": if (self.cur == "west" and self.west > 15) and self.west_status == 'low': self.east = 75 self.south = 105 self.west = 15 self.north = 45 elif (self.cur == "north" and self.north > 15) and self.north_status == 'low': self.east = 45 self.south = 75 self.west = 105 self.north = 15 elif (self.cur == "east" and self.east > 15) and self.east_status == 'low': self.east = 15 self.south = 45 self.west = 75 self.north = 105 #self.south_status = "low" elif self.west_status == "Mod": if self.cur != "west": if (self.cur == "east" and self.east > 15) and self.east_status == 'low': self.east = 15 self.south = 45 self.west = 75 self.north = 105 elif (self.cur == "south" and self.south > 15) and self.south_status == 'low': self.east = 105 self.south = 15 self.west = 45 self.north = 75 elif (self.cur == "north" and self.north > 15) and self.north_status == 'low': self.east = 45 self.south = 75 self.west = 105 self.north = 15 #self.west_status = "low" elif self.north_status == "Mod": if self.cur != "north": if (self.cur == "east" and self.east > 15) and self.east_status == 'low': self.east = 15 self.south = 45 self.west = 75 self.north = 105 elif (self.cur == "south" and self.south > 15) and self.south_status == 'low': self.east = 105 self.south = 15 self.west = 45 self.north = 75 elif (self.cur == "west" and self.west > 15) and self.west_status == 'low': self.east = 75 self.south = 105 self.west = 15 self.north = 45 #self.north_status = "low" self.east_density.setText(self.east_status) self.south_density.setText(self.south_status) self.west_density.setText(self.west_status) self.north_density.setText(self.north_status) print(self.east, self.south, self.west, self.north) print(self.east_status, self.south_status, self.west_status, self.north_status) def print_images(self): while True: self.east_road_pixmap = QPixmap('./Test/images/east.png') if not self.east_road_pixmap.isNull(): self.east_road_pixmap = self.east_road_pixmap.scaled(150, 150) self.east_road.setPixmap(self.east_road_pixmap) self.east_road.resize(150, 150) self.east_road.move(630, 425) self.east_road_bbox_pixmap = QPixmap('./Test/images/east_bbox.png') if not self.east_road_bbox_pixmap.isNull(): self.east_road_bbox_pixmap = self.east_road_bbox_pixmap.scaled( 150, 150) self.east_road_bbox.setPixmap(self.east_road_bbox_pixmap) self.east_road_bbox.resize(150, 150) self.east_road_bbox.move(840, 425) self.south_road_pixmap = QPixmap('./Test/images/south.png') if not self.south_road_pixmap.isNull(): self.south_road_pixmap = self.south_road_pixmap.scaled( 150, 150) self.south_road.setPixmap(self.south_road_pixmap) self.south_road.resize(150, 150) self.south_road.move(425, 630) self.south_road_bbox_pixmap = QPixmap( './Test/images/south_bbox.png') if not self.south_road_bbox_pixmap.isNull(): self.south_road_bbox_pixmap = self.south_road_bbox_pixmap.scaled( 150, 150) self.south_road_bbox.setPixmap(self.south_road_bbox_pixmap) self.south_road_bbox.move(425, 840) self.west_road_pixmap = QPixmap('./Test/images/west.png') if not self.west_road_pixmap.isNull(): self.west_road_pixmap = self.west_road_pixmap.scaled(150, 150) self.west_road.setPixmap(self.west_road_pixmap) self.west_road.move(220, 425) self.west_road_bbox_pixmap = QPixmap('./Test/images/west_bbox.png') if not self.west_road_bbox_pixmap.isNull(): self.west_road_bbox_pixmap = self.west_road_bbox_pixmap.scaled( 150, 150) self.west_road_bbox.setPixmap(self.west_road_bbox_pixmap) self.west_road_bbox.move(10, 425) self.north_road_pixmap = QPixmap('./Test/images/north.png') if not self.north_road_pixmap.isNull(): self.north_road_pixmap = self.north_road_pixmap.scaled( 150, 150) self.north_road.setPixmap(self.north_road_pixmap) self.north_road.resize(150, 150) self.north_road.move(425, 220) self.north_road_bbox_pixmap = QPixmap( './Test/images/north_bbox.png') if not self.north_road_bbox_pixmap.isNull(): self.north_road_bbox_pixmap = self.north_road_bbox_pixmap.scaled( 150, 150) self.north_road_bbox.setPixmap(self.north_road_bbox_pixmap) self.north_road_bbox.resize(150, 150) self.north_road_bbox.move(425, 10) time.sleep(0.3)
class MandelbrotWidget(QWidget): def __init__(self, parent=None): super(MandelbrotWidget, self).__init__(parent) self.thread = RenderThread() self.pixmap = QPixmap() self.pixmapOffset = QPoint() self.lastDragPos = QPoint() self.centerX = DefaultCenterX self.centerY = DefaultCenterY self.pixmapScale = DefaultScale self.curScale = DefaultScale self.thread.renderedImage.connect(self.updatePixmap) self.setWindowTitle("Mandelbrot") self.setCursor(Qt.CrossCursor) self.resize(550, 400) def paintEvent(self, event): painter = QPainter(self) painter.fillRect(self.rect(), Qt.black) if self.pixmap.isNull(): painter.setPen(Qt.white) painter.drawText(self.rect(), Qt.AlignCenter, "Rendering initial image, please wait...") return if self.curScale == self.pixmapScale: painter.drawPixmap(self.pixmapOffset, self.pixmap) else: scaleFactor = self.pixmapScale / self.curScale newWidth = int(self.pixmap.width() * scaleFactor) newHeight = int(self.pixmap.height() * scaleFactor) newX = self.pixmapOffset.x() + (self.pixmap.width() - newWidth) / 2 newY = self.pixmapOffset.y() + (self.pixmap.height() - newHeight) / 2 painter.save() painter.translate(newX, newY) painter.scale(scaleFactor, scaleFactor) exposed, _ = painter.matrix().inverted() exposed = exposed.mapRect(self.rect()).adjusted(-1, -1, 1, 1) painter.drawPixmap(exposed, self.pixmap, exposed) painter.restore() text = "Use mouse wheel or the '+' and '-' keys to zoom. Press and " \ "hold left mouse button to scroll." metrics = painter.fontMetrics() textWidth = metrics.width(text) painter.setPen(Qt.NoPen) painter.setBrush(QColor(0, 0, 0, 127)) painter.drawRect((self.width() - textWidth) / 2 - 5, 0, textWidth + 10, metrics.lineSpacing() + 5) painter.setPen(Qt.white) painter.drawText((self.width() - textWidth) / 2, metrics.leading() + metrics.ascent(), text) def resizeEvent(self, event): self.thread.render(self.centerX, self.centerY, self.curScale, self.size()) def keyPressEvent(self, event): if event.key() == Qt.Key_Plus: self.zoom(ZoomInFactor) elif event.key() == Qt.Key_Minus: self.zoom(ZoomOutFactor) elif event.key() == Qt.Key_Left: self.scroll(-ScrollStep, 0) elif event.key() == Qt.Key_Right: self.scroll(+ScrollStep, 0) elif event.key() == Qt.Key_Down: self.scroll(0, -ScrollStep) elif event.key() == Qt.Key_Up: self.scroll(0, +ScrollStep) else: super(MandelbrotWidget, self).keyPressEvent(event) def wheelEvent(self, event): numDegrees = event.angleDelta().y() / 8 numSteps = numDegrees / 15.0 self.zoom(pow(ZoomInFactor, numSteps)) def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: self.lastDragPos = QPoint(event.pos()) def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: self.pixmapOffset += event.pos() - self.lastDragPos self.lastDragPos = QPoint(event.pos()) self.update() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.pixmapOffset += event.pos() - self.lastDragPos self.lastDragPos = QPoint() deltaX = (self.width() - self.pixmap.width()) / 2 - self.pixmapOffset.x() deltaY = (self.height() - self.pixmap.height()) / 2 - self.pixmapOffset.y() self.scroll(deltaX, deltaY) def updatePixmap(self, image, scaleFactor): if not self.lastDragPos.isNull(): return self.pixmap = QPixmap.fromImage(image) self.pixmapOffset = QPoint() self.lastDragPosition = QPoint() self.pixmapScale = scaleFactor self.update() def zoom(self, zoomFactor): self.curScale *= zoomFactor self.update() self.thread.render(self.centerX, self.centerY, self.curScale, self.size()) def scroll(self, deltaX, deltaY): self.centerX += deltaX * self.curScale self.centerY += deltaY * self.curScale self.update() self.thread.render(self.centerX, self.centerY, self.curScale, self.size())
class eventedLabel(QLabel): def __init__(self, parent_dim): """ This class inherits the QLabel class and handles events internally. It handles all the intra-image events. I keep an unmodified version of the original image in the background. :param parent_dim: Tuple. The dimensions of the parent window """ super().__init__() self.mouse_held = False self.press_location = (None, None) self.scale_factor = (1, 1) self.parent_height = parent_dim[0] self.parent_width = parent_dim[1] self.existing_rects = [] def mousePressEvent(self, event): super().mousePressEvent(event) self.mouse_held = True self.press_location = (event.pos().x(), event.pos().y()) def mouseReleaseEvent(self, event): super().mouseReleaseEvent(event) self.appendRect( *self.press_location, event.pos().x() - self.press_location[0], event.pos().y() - self.press_location[1] ) self.drawExistingRects() self.mouse_held = False def appendRect(self, x, y, w, h): """ If the user drags upwards or leftwards, the w,h of the rectangle could be negaive. :return: Tuple. (x, y, w, h) corrected so that x,y always describe the upper=left corner. """ if w < 0: x = x + w w = abs(w) if h < 0: y = y + h h = abs(h) self.existing_rects.append([x, y, w, h]) return x, y, w, h def mouseMoveEvent(self, event): super().mouseMoveEvent(event) self.drawTempRect( *self.press_location, event.pos().x() - self.press_location[0], event.pos().y() - self.press_location[1], Qt.red ) def drawRect(self, x, y, w, h, c): self.painter = QPainter(self.pixmap) pen = QPen(c, 3) self.painter.setPen(pen) self.painter.drawRect(x, y, w, h) self.painter.end() self.setScaledPixmap() def drawTempRect(self, x, y, w, h, c): """ This function draw a rectangle and clears it right up again. It is needed so that we dont start painting with rectangles on the image. :param c: QT constant. Color. :return: """ self.drawExistingRects() self.drawRect(x, y, w, h, c) self.pixmap = self.static_pixmap.copy() def drawExistingRects(self): self.setScaledPixmap() for rect in self.existing_rects: self.drawRect(*rect, Qt.blue) def setImage(self, path, annotations): """ Sets an image within the label and handle its annotations. :param path: Str. Path to the image file :param annotations: List of Lists. Bounding Box annotations of head location. [[x1,y1,w1,h1], [x2,y2,w2,h2]] :return: True if image loaded correctly. False otherwise. """ self.existing_rects = [] self.scale_factor = (1, 1) self.path = path self.pixmap = QPixmap( str( path ) ) if self.pixmap.isNull(): print(f'Cannot load image {str(path)}') return False self.setScaledPixmap() self.static_pixmap = self.pixmap.copy() if len(annotations) > 0: self.existing_rects = self.useAnnotations(annotations) self.drawExistingRects() return True def setScaledPixmap(self): if self.pixmap.height() > self.parent_height or self.pixmap.width() > self.parent_width: original_size = self.pixmap.height(), self.pixmap.width() self.pixmap = self.pixmap.scaled(self.parent_width, self.parent_height, Qt.KeepAspectRatio) self.scale_factor = (original_size[0] / self.pixmap.height(), original_size[1] / self.pixmap.width()) self.setPixmap(self.pixmap) def labelToImageCoordinates(self, x, y, w, h): """ Translate between label coordinates (possibly scaled to fit the screen) and image coordinates. :return: xywh in image coordinates """ x *= self.scale_factor[0] y *= self.scale_factor[1] w *= self.scale_factor[0] h *= self.scale_factor[1] return x, y, w, h def imageToLabelCoordinates(self, x, y, w, h): """ Translate between image coordinates and label coordinates (possibly scaled to fit the screen). :return: xywh in label coordinates """ x /= self.scale_factor[0] y /= self.scale_factor[1] w /= self.scale_factor[0] h /= self.scale_factor[1] return x, y, w, h def getAnnotations(self): """ Parse annotations to the activating class. :return: Annotaions in image coordinates. """ return [list(map(round, self.labelToImageCoordinates(*coords))) for coords in self.existing_rects] def useAnnotations(self, annotations): """ Parse annotations from file. :param annotations: List of lists. :return: List of lists. """ return [self.imageToLabelCoordinates(*coords) for coords in annotations] def deleteAndUpdate(self): self.existing_rects = self.existing_rects[:-1] self.setImage(self.path, self.getAnnotations()) self.drawExistingRects()
def createUI(self): """ Set up the window for the VLC viewer """ self.widget = QWidget(self) self.setCentralWidget(self.widget) # In this widget, the video will be drawn if sys.platform == "darwin": # for MacOS from PyQt5.QtWidgets import QMacCocoaViewContainer self.videoframe = QMacCocoaViewContainer(0) else: self.videoframe = QFrame() self.palette = self.videoframe.palette() self.palette.setColor (QPalette.Window, QColor(0,0,0)) self.videoframe.setPalette(self.palette) self.videoframe.setAutoFillBackground(True) self.hbuttonbox = QHBoxLayout() self.playbutton = QPushButton("Run my program") self.hbuttonbox.addWidget(self.playbutton) self.playbutton.clicked.connect(partial(self.drone_vision.run_user_code, self.playbutton)) self.landbutton = QPushButton("Land NOW") self.hbuttonbox.addWidget(self.landbutton) self.landbutton.clicked.connect(self.drone_vision.land) self.stopbutton = QPushButton("Quit") self.hbuttonbox.addWidget(self.stopbutton) self.stopbutton.clicked.connect(self.drone_vision.close_exit) self.vboxlayout = QVBoxLayout() self.vboxlayout.addWidget(self.videoframe) if (self.drone_vision.user_draw_window_fn is not None): self.userWindow = QLabel() fullPath = inspect.getfile(DroneVisionGUI) shortPathIndex = fullPath.rfind("/") if (shortPathIndex == -1): # handle Windows paths shortPathIndex = fullPath.rfind("\\") print(shortPathIndex) shortPath = fullPath[0:shortPathIndex] pixmap = QPixmap('%s/demo_user_image.png' % shortPath) print(pixmap) print(pixmap.isNull()) self.userWindow.setPixmap(pixmap) self.vboxlayout.addWidget(self.userWindow) self.vboxlayout.addLayout(self.hbuttonbox) self.widget.setLayout(self.vboxlayout) # the media player has to be 'connected' to the QFrame # (otherwise a video would be displayed in it's own window) # this is platform specific! # you have to give the id of the QFrame (or similar object) to # vlc, different platforms have different functions for this if sys.platform.startswith('linux'): # for Linux using the X Server self.mediaplayer.set_xwindow(self.videoframe.winId()) elif sys.platform == "win32": # for Windows self.mediaplayer.set_hwnd(self.videoframe.winId()) elif sys.platform == "darwin": # for MacOS self.mediaplayer.set_nsobject(int(self.videoframe.winId()))
class SnapWidget(QWidget, Ui_SnapWidget): """ Class implementing the snapshot widget. """ ModeFullscreen = 0 ModeScreen = 1 ModeRectangle = 2 ModeFreehand = 3 ModeEllipse = 4 def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget (QWidget) """ super(SnapWidget, self).__init__(parent) self.setupUi(self) self.saveButton.setIcon(UI.PixmapCache.getIcon("fileSaveAs.png")) self.takeButton.setIcon(UI.PixmapCache.getIcon("cameraPhoto.png")) self.copyButton.setIcon(UI.PixmapCache.getIcon("editCopy.png")) self.copyPreviewButton.setIcon(UI.PixmapCache.getIcon("editCopy.png")) self.setWindowIcon(UI.PixmapCache.getIcon("ericSnap.png")) self.modeCombo.addItem(self.tr("Fullscreen"), SnapWidget.ModeFullscreen) self.modeCombo.addItem(self.tr("Rectangular Selection"), SnapWidget.ModeRectangle) self.modeCombo.addItem(self.tr("Ellipical Selection"), SnapWidget.ModeEllipse) self.modeCombo.addItem(self.tr("Freehand Selection"), SnapWidget.ModeFreehand) if QApplication.desktop().screenCount() > 1: self.modeCombo.addItem(self.tr("Current Screen"), SnapWidget.ModeScreen) self.__mode = int(Preferences.Prefs.settings.value("Snapshot/Mode", 0)) index = self.modeCombo.findData(self.__mode) if index == -1: index = 0 self.modeCombo.setCurrentIndex(index) self.__delay = int( Preferences.Prefs.settings.value("Snapshot/Delay", 0)) self.delaySpin.setValue(self.__delay) if PYQT_VERSION_STR >= "5.0.0": from PyQt5.QtCore import QStandardPaths picturesLocation = QStandardPaths.writableLocation( QStandardPaths.PicturesLocation) else: from PyQt5.QtGui import QDesktopServices picturesLocation = QDesktopServices.storageLocation( QDesktopServices.PicturesLocation) self.__filename = Preferences.Prefs.settings.value( "Snapshot/Filename", os.path.join(picturesLocation, self.tr("snapshot") + "1.png")) self.__grabber = None self.__snapshot = QPixmap() self.__savedPosition = QPoint() self.__modified = False self.__locale = QLocale() self.__grabberWidget = QWidget(None, Qt.X11BypassWindowManagerHint) self.__grabberWidget.move(-10000, -10000) self.__grabberWidget.installEventFilter(self) self.__initFileFilters() self.__initShortcuts() self.preview.startDrag.connect(self.__dragSnapshot) from .SnapshotTimer import SnapshotTimer self.__grabTimer = SnapshotTimer() self.__grabTimer.timeout.connect(self.__grabTimerTimeout) self.__updateTimer = QTimer() self.__updateTimer.setSingleShot(True) self.__updateTimer.timeout.connect(self.__updatePreview) self.__updateCaption() self.takeButton.setFocus() def __initFileFilters(self): """ Private method to define the supported image file filters. """ filters = { 'bmp': self.tr("Windows Bitmap File (*.bmp)"), 'gif': self.tr("Graphic Interchange Format File (*.gif)"), 'ico': self.tr("Windows Icon File (*.ico)"), 'jpg': self.tr("JPEG File (*.jpg)"), 'mng': self.tr("Multiple-Image Network Graphics File (*.mng)"), 'pbm': self.tr("Portable Bitmap File (*.pbm)"), 'pcx': self.tr("Paintbrush Bitmap File (*.pcx)"), 'pgm': self.tr("Portable Graymap File (*.pgm)"), 'png': self.tr("Portable Network Graphics File (*.png)"), 'ppm': self.tr("Portable Pixmap File (*.ppm)"), 'sgi': self.tr("Silicon Graphics Image File (*.sgi)"), 'svg': self.tr("Scalable Vector Graphics File (*.svg)"), 'tga': self.tr("Targa Graphic File (*.tga)"), 'tif': self.tr("TIFF File (*.tif)"), 'xbm': self.tr("X11 Bitmap File (*.xbm)"), 'xpm': self.tr("X11 Pixmap File (*.xpm)"), } outputFormats = [] writeFormats = QImageWriter.supportedImageFormats() for writeFormat in writeFormats: try: outputFormats.append(filters[bytes(writeFormat).decode()]) except KeyError: pass outputFormats.sort() self.__outputFilter = ';;'.join(outputFormats) self.__defaultFilter = filters['png'] def __initShortcuts(self): """ Private method to initialize the keyboard shortcuts. """ self.__quitShortcut = QShortcut(QKeySequence(QKeySequence.Quit), self, self.close) self.__copyShortcut = QShortcut(QKeySequence(QKeySequence.Copy), self, self.copyButton.animateClick) self.__quickSaveShortcut = QShortcut(QKeySequence(Qt.Key_Q), self, self.__quickSave) self.__save1Shortcut = QShortcut(QKeySequence(QKeySequence.Save), self, self.saveButton.animateClick) self.__save2Shortcut = QShortcut(QKeySequence(Qt.Key_S), self, self.saveButton.animateClick) self.__grab1Shortcut = QShortcut(QKeySequence(QKeySequence.New), self, self.takeButton.animateClick) self.__grab2Shortcut = QShortcut(QKeySequence(Qt.Key_N), self, self.takeButton.animateClick) self.__grab3Shortcut = QShortcut(QKeySequence(Qt.Key_Space), self, self.takeButton.animateClick) def __quickSave(self): """ Private slot to save the snapshot bypassing the file selection dialog. """ if not self.__snapshot.isNull(): while os.path.exists(self.__filename): self.__autoIncFilename() if self.__saveImage(self.__filename): self.__modified = False self.__autoIncFilename() self.__updateCaption() @pyqtSlot() def on_saveButton_clicked(self): """ Private slot to save the snapshot. """ if not self.__snapshot.isNull(): while os.path.exists(self.__filename): self.__autoIncFilename() fileName, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( self, self.tr("Save Snapshot"), self.__filename, self.__outputFilter, self.__defaultFilter, E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) if not fileName: return ext = QFileInfo(fileName).suffix() if not ext: ex = selectedFilter.split("(*")[1].split(")")[0] if ex: fileName += ex if self.__saveImage(fileName): self.__modified = False self.__filename = fileName self.__autoIncFilename() self.__updateCaption() def __saveImage(self, fileName): """ Private method to save the snapshot. @param fileName name of the file to save to (string) @return flag indicating success (boolean) """ if QFileInfo(fileName).exists(): res = E5MessageBox.yesNo( self, self.tr("Save Snapshot"), self.tr("<p>The file <b>{0}</b> already exists." " Overwrite it?</p>").format(fileName), icon=E5MessageBox.Warning) if not res: return False file = QFile(fileName) if not file.open(QFile.WriteOnly): E5MessageBox.warning( self, self.tr("Save Snapshot"), self.tr("Cannot write file '{0}:\n{1}.").format( fileName, file.errorString())) return False ok = self.__snapshot.save(file) file.close() if not ok: E5MessageBox.warning( self, self.tr("Save Snapshot"), self.tr("Cannot write file '{0}:\n{1}.").format( fileName, file.errorString())) return ok def __autoIncFilename(self): """ Private method to auto-increment the file name. """ # Extract the file name name = os.path.basename(self.__filename) # If the name contains a number, then increment it. numSearch = QRegExp("(^|[^\\d])(\\d+)") # We want to match as far left as possible, and when the number is # at the start of the name. # Does it have a number? start = numSearch.lastIndexIn(name) if start != -1: # It has a number, increment it. start = numSearch.pos(2) # Only the second group is of interest. numAsStr = numSearch.capturedTexts()[2] number = "{0:0{width}d}".format(int(numAsStr) + 1, width=len(numAsStr)) name = name[:start] + number + name[start + len(numAsStr):] else: # no number start = name.rfind('.') if start != -1: # has a '.' somewhere, e.g. it has an extension name = name[:start] + '1' + name[start:] else: # no extension, just tack it on to the end name += '1' self.__filename = os.path.join(os.path.dirname(self.__filename), name) self.__updateCaption() @pyqtSlot() def on_takeButton_clicked(self): """ Private slot to take a snapshot. """ self.__mode = self.modeCombo.itemData(self.modeCombo.currentIndex()) self.__delay = self.delaySpin.value() self.__savedPosition = self.pos() self.hide() if self.__delay: self.__grabTimer.start(self.__delay) else: QTimer.singleShot(200, self.__startUndelayedGrab) def __grabTimerTimeout(self): """ Private slot to perform a delayed grab operation. """ if self.__mode == SnapWidget.ModeRectangle: self.__grabRectangle() elif self.__mode == SnapWidget.ModeEllipse: self.__grabEllipse() elif self.__mode == SnapWidget.ModeFreehand: self.__grabFreehand() else: self.__performGrab() def __startUndelayedGrab(self): """ Private slot to perform an undelayed grab operation. """ if self.__mode == SnapWidget.ModeRectangle: self.__grabRectangle() elif self.__mode == SnapWidget.ModeEllipse: self.__grabEllipse() elif self.__mode == SnapWidget.ModeFreehand: self.__grabFreehand() else: if Globals.isMacPlatform(): self.__performGrab() else: self.__grabberWidget.show() self.__grabberWidget.grabMouse(Qt.CrossCursor) def __grabRectangle(self): """ Private method to grab a rectangular screen region. """ from .SnapshotRegionGrabber import SnapshotRegionGrabber self.__grabber = SnapshotRegionGrabber( mode=SnapshotRegionGrabber.Rectangle) self.__grabber.grabbed.connect(self.__captured) def __grabEllipse(self): """ Private method to grab an elliptical screen region. """ from .SnapshotRegionGrabber import SnapshotRegionGrabber self.__grabber = SnapshotRegionGrabber( mode=SnapshotRegionGrabber.Ellipse) self.__grabber.grabbed.connect(self.__captured) def __grabFreehand(self): """ Private method to grab a non-rectangular screen region. """ from .SnapshotFreehandGrabber import SnapshotFreehandGrabber self.__grabber = SnapshotFreehandGrabber() self.__grabber.grabbed.connect(self.__captured) def __performGrab(self): """ Private method to perform a screen grab other than a selected region. """ self.__grabberWidget.releaseMouse() self.__grabberWidget.hide() self.__grabTimer.stop() if self.__mode == SnapWidget.ModeFullscreen: desktop = QApplication.desktop() if qVersion() >= "5.0.0": self.__snapshot = QApplication.screens()[0].grabWindow( desktop.winId(), desktop.x(), desktop.y(), desktop.width(), desktop.height()) else: self.__snapshot = QPixmap.grabWindow(desktop.winId(), desktop.x(), desktop.y(), desktop.width(), desktop.height()) elif self.__mode == SnapWidget.ModeScreen: desktop = QApplication.desktop() screenId = desktop.screenNumber(QCursor.pos()) geom = desktop.screenGeometry(screenId) x = geom.x() y = geom.y() if qVersion() >= "5.0.0": self.__snapshot = QApplication.screens()[0].grabWindow( desktop.winId(), x, y, geom.width(), geom.height()) else: self.__snapshot = QPixmap.grabWindow(desktop.winId(), x, y, geom.width(), geom.height()) else: self.__snapshot = QPixmap() self.__redisplay() self.__modified = True self.__updateCaption() def __redisplay(self): """ Private method to redisplay the window. """ self.__updatePreview() QApplication.restoreOverrideCursor() if not self.__savedPosition.isNull(): self.move(self.__savedPosition) self.show() self.raise_() self.saveButton.setEnabled(not self.__snapshot.isNull()) self.copyButton.setEnabled(not self.__snapshot.isNull()) self.copyPreviewButton.setEnabled(not self.__snapshot.isNull()) @pyqtSlot() def on_copyButton_clicked(self): """ Private slot to copy the snapshot to the clipboard. """ if not self.__snapshot.isNull(): QApplication.clipboard().setPixmap(QPixmap(self.__snapshot)) @pyqtSlot() def on_copyPreviewButton_clicked(self): """ Private slot to copy the snapshot preview to the clipboard. """ QApplication.clipboard().setPixmap(self.preview.pixmap()) def __captured(self, pixmap): """ Private slot to show a preview of the snapshot. @param pixmap pixmap of the snapshot (QPixmap) """ self.__grabber.close() self.__snapshot = QPixmap(pixmap) self.__grabber.grabbed.disconnect(self.__captured) self.__grabber = None self.__redisplay() self.__modified = True self.__updateCaption() def __updatePreview(self): """ Private slot to update the preview picture. """ self.preview.setToolTip( self.tr("Preview of the snapshot image ({0} x {1})").format( self.__locale.toString(self.__snapshot.width()), self.__locale.toString(self.__snapshot.height()))) self.preview.setPreview(self.__snapshot) self.preview.adjustSize() def resizeEvent(self, evt): """ Protected method handling a resizing of the window. @param evt resize event (QResizeEvent) """ self.__updateTimer.start(200) def __dragSnapshot(self): """ Private slot handling the dragging of the preview picture. """ drag = QDrag(self) mimeData = QMimeData() mimeData.setImageData(self.__snapshot) drag.setMimeData(mimeData) drag.setPixmap(self.preview.pixmap()) drag.exec_(Qt.CopyAction) def eventFilter(self, obj, evt): """ Public method to handle event for other objects. @param obj reference to the object (QObject) @param evt reference to the event (QEvent) @return flag indicating that the event should be filtered out (boolean) """ if obj == self.__grabberWidget and \ evt.type() == QEvent.MouseButtonPress: if QWidget.mouseGrabber() != self.__grabberWidget: return False if evt.button() == Qt.LeftButton: self.__performGrab() return False def closeEvent(self, evt): """ Protected method handling the close event. @param evt close event (QCloseEvent) """ if self.__modified: res = E5MessageBox.question( self, self.tr("Pymakr Snapshot"), self.tr("""The application contains an unsaved snapshot."""), E5MessageBox.StandardButtons(E5MessageBox.Abort | E5MessageBox.Discard | E5MessageBox.Save)) if res == E5MessageBox.Abort: evt.ignore() return elif res == E5MessageBox.Save: self.on_saveButton_clicked() Preferences.Prefs.settings.setValue("Snapshot/Delay", self.delaySpin.value()) Preferences.Prefs.settings.setValue( "Snapshot/Mode", self.modeCombo.itemData(self.modeCombo.currentIndex())) Preferences.Prefs.settings.setValue("Snapshot/Filename", self.__filename) Preferences.Prefs.settings.sync() def __updateCaption(self): """ Private method to update the window caption. """ self.setWindowTitle("{0}[*] - {1}".format( os.path.basename(self.__filename), self.tr("Pymakr Snapshot"))) self.setWindowModified(self.__modified) self.pathNameEdit.setText(os.path.dirname(self.__filename))
class ImageLayer(Layer): ## # Constructor. ## def __init__(self, name, x, y, width, height): super().__init__(Layer.ImageLayerType, name, x, y, width, height) self.mImage = QPixmap() self.mTransparentColor = QColor() self.mImageSource = QString() ## # Destructor. ## def __del__(self): pass def usedTilesets(self): return QSet() def referencesTileset(self, arg1): return False def replaceReferencesToTileset(self, arg1, arg2): pass def canMergeWith(self, arg1): return False def mergedWith(self, arg1): return None ## # Returns the transparent color, or an invalid color if no transparent # color is used. ## def transparentColor(self): return QColor(self.mTransparentColor) ## # Sets the transparent color. Pixels with this color will be masked out # when loadFromImage() is called. ## def setTransparentColor(self, c): self.mTransparentColor = c ## # Sets image source file name ## def setSource(self, source): self.mImageSource = source ## # Returns the file name of the layer image. ## def imageSource(self): return self.mImageSource ## # Returns the image of this layer. ## def image(self): return QPixmap(self.mImage) ## # Sets the image of this layer. ## def setImage(self, image): self.mImage = image ## # Resets layer image. ## def resetImage(self): self.mImage = QPixmap() self.mImageSource = '' ## # Load this layer from the given \a image. This will replace the existing # image. The \a fileName becomes the new imageSource, regardless of # whether the image could be loaded. # # @param image the image to load the layer from # @param fileName the file name of the image, which will be remembered # as the image source of this layer. # @return <code>true</code> if loading was successful, otherwise # returns <code>false</code> ## def loadFromImage(self, image, fileName): self.mImageSource = fileName if (image.isNull()): self.mImage = QPixmap() return False self.mImage = QPixmap.fromImage(image) if (self.mTransparentColor.isValid()): mask = image.createMaskFromColor(self.mTransparentColor.rgb()) self.mImage.setMask(QBitmap.fromImage(mask)) return True ## # Returns True if no image source has been set. ## def isEmpty(self): return self.mImage.isNull() def clone(self): return self.initializeClone(ImageLayer(self.mName, self.mX, self.mY, self.mWidth, self.mHeight)) def initializeClone(self, clone): super().initializeClone(clone) clone.mImageSource = self.mImageSource clone.mTransparentColor = self.mTransparentColor clone.mImage = self.mImage return clone