def main(): app = QApplication(sys.argv) grview = QGraphicsView() scene = QGraphicsScene() scene.setSceneRect(0, 0, 680, 459) scene.addPixmap(QPixmap('01.png')) grview.setScene(scene) item = GraphicsRectItem(0, 0, 300, 150) scene.addItem(item) grview.fitInView(scene.sceneRect(), Qt.KeepAspectRatio) grview.show() sys.exit(app.exec_())
class ImagesPreviewer(foundations.ui.common.QWidgetFactory(uiFile=UI_FILE)): """ | This class provides the Application images previewer. | It defines methods to navigate through the list of given images ( List of images paths ), zoom in / out and fit the displayed image, etc... """ def __init__(self, parent, paths=None, *args, **kwargs): """ This method initializes the class. :param parent: Object parent. ( QObject ) :param paths: Images paths. ( Tuple / List ) :param \*args: Arguments. ( \* ) :param \*\*kwargs: Keywords arguments. ( \*\* ) """ LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__)) super(ImagesPreviewer, self).__init__(parent, *args, **kwargs) # --- Setting class attributes. --- self.__container = parent self.__paths = None self.paths = paths self.__uiResourcesDirectory = "resources" self.__uiResourcesDirectory = os.path.join(os.path.dirname(__file__), self.__uiResourcesDirectory) self.__uiPreviousImage = "Previous.png" self.__uiNextImage = "Next.png" self.__uiZoomOutImage = "Zoom_Out.png" self.__uiZoomInImage = "Zoom_In.png" # Ensure the ui object is destroyed on close to avoid memory leaks. self.setAttribute(Qt.WA_DeleteOnClose) self.__graphicsSceneBackgroundColor = QColor(32, 32, 32) self.__minimumZoomFactor = 0.05 self.__maximumZoomFactor = 25 self.__displayGraphicsItemMargin = 32 self.__graphicsSceneWidth = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).width() * (1 / self.__minimumZoomFactor * 1.75) self.__graphicsSceneHeight = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).height() * (1 / self.__minimumZoomFactor * 1.75) self.__wheelZoomFactor = 350.0 self.__keyZoomFactor = 1.20 self.__graphicsView = None self.__graphicsScene = None self.__displayGraphicsItem = None ImagesPreviewer.__initializeUi(self) self.loadImage() #****************************************************************************************************************** #*** Attributes properties. #****************************************************************************************************************** @property def container(self): """ This method is the property for **self.__container** attribute. :return: self.__container. ( QObject ) """ return self.__container @container.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def container(self, value): """ This method is the setter method for **self.__container** attribute. :param value: Attribute value. ( QObject ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "container")) @container.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def container(self): """ This method is the deleter method for **self.__container** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "container")) @property def paths(self): """ This method is the property for **self.__paths** attribute. :return: self.__paths. ( Tuple / List ) """ return self.__paths @paths.setter @foundations.exceptions.handleExceptions(AssertionError) def paths(self, value): """ This method is the setter method for **self.__paths** attribute. :param value: Attribute value. ( Tuple / List ) """ if value is not None: assert type(value) in (tuple, list), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format("paths", value) for element in value: assert type(element) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "paths", element) self.__paths = value @paths.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def paths(self): """ This method is the deleter method for **self.__paths** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "paths")) @property def uiResourcesDirectory(self): """ This method is the property for **self.__uiResourcesDirectory** attribute. :return: self.__uiResourcesDirectory. ( String ) """ return self.__uiResourcesDirectory @uiResourcesDirectory.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiResourcesDirectory(self, value): """ This method is the setter method for **self.__uiResourcesDirectory** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiResourcesDirectory")) @uiResourcesDirectory.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiResourcesDirectory(self): """ This method is the deleter method for **self.__uiResourcesDirectory** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiResourcesDirectory")) @property def uiPreviousImage(self): """ This method is the property for **self.__uiPreviousImage** attribute. :return: self.__uiPreviousImage. ( String ) """ return self.__uiPreviousImage @uiPreviousImage.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiPreviousImage(self, value): """ This method is the setter method for **self.__uiPreviousImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiPreviousImage")) @uiPreviousImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiPreviousImage(self): """ This method is the deleter method for **self.__uiPreviousImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiPreviousImage")) @property def uiNextImage(self): """ This method is the property for **self.__uiNextImage** attribute. :return: self.__uiNextImage. ( String ) """ return self.__uiNextImage @uiNextImage.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiNextImage(self, value): """ This method is the setter method for **self.__uiNextImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiNextImage")) @uiNextImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiNextImage(self): """ This method is the deleter method for **self.__uiNextImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiNextImage")) @property def uiZoomOutImage(self): """ This method is the property for **self.__uiZoomOutImage** attribute. :return: self.__uiZoomOutImage. ( String ) """ return self.__uiZoomOutImage @uiZoomOutImage.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiZoomOutImage(self, value): """ This method is the setter method for **self.__uiZoomOutImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiZoomOutImage")) @uiZoomOutImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiZoomOutImage(self): """ This method is the deleter method for **self.__uiZoomOutImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiZoomOutImage")) @property def uiZoomInImage(self): """ This method is the property for **self.__uiZoomInImage** attribute. :return: self.__uiZoomInImage. ( String ) """ return self.__uiZoomInImage @uiZoomInImage.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiZoomInImage(self, value): """ This method is the setter method for **self.__uiZoomInImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiZoomInImage")) @uiZoomInImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiZoomInImage(self): """ This method is the deleter method for **self.__uiZoomInImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiZoomInImage")) @property def graphicsSceneBackgroundColor(self): """ This method is the property for **self.__graphicsSceneBackgroundColor** attribute. :return: self.__graphicsSceneBackgroundColor. ( QColors ) """ return self.__graphicsSceneBackgroundColor @graphicsSceneBackgroundColor.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsSceneBackgroundColor(self, value): """ This method is the setter method for **self.__graphicsSceneBackgroundColor** attribute. :param value: Attribute value. ( QColors ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsSceneBackgroundColor")) @graphicsSceneBackgroundColor.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsSceneBackgroundColor(self): """ This method is the deleter method for **self.__graphicsSceneBackgroundColor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsSceneBackgroundColor")) @property def graphicsSceneWidth(self): """ This method is the property for **self.__graphicsSceneWidth** attribute. :return: self.__graphicsSceneWidth. ( Integer ) """ return self.__graphicsSceneWidth @graphicsSceneWidth.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsSceneWidth(self, value): """ This method is the setter method for **self.__graphicsSceneWidth** attribute. :param value: Attribute value. ( Integer ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsSceneWidth")) @graphicsSceneWidth.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsSceneWidth(self): """ This method is the deleter method for **self.__graphicsSceneWidth** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsSceneWidth")) @property def graphicsSceneHeight(self): """ This method is the property for **self.__graphicsSceneHeight** attribute. :return: self.__graphicsSceneHeight. ( Object ) """ return self.__graphicsSceneHeight @graphicsSceneHeight.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsSceneHeight(self, value): """ This method is the setter method for **self.__graphicsSceneHeight** attribute. :param value: Attribute value. ( Object ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsSceneHeight")) @graphicsSceneHeight.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsSceneHeight(self): """ This method is the deleter method for **self.__graphicsSceneHeight** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsSceneHeight")) @property def minimumZoomFactor(self): """ This method is the property for **self.__minimumZoomFactor** attribute. :return: self.__minimumZoomFactor. ( Float ) """ return self.__minimumZoomFactor @minimumZoomFactor.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def minimumZoomFactor(self, value): """ This method is the setter method for **self.__minimumZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "minimumZoomFactor")) @minimumZoomFactor.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def minimumZoomFactor(self): """ This method is the deleter method for **self.__minimumZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "minimumZoomFactor")) @property def maximumZoomFactor(self): """ This method is the property for **self.__maximumZoomFactor** attribute. :return: self.__maximumZoomFactor. ( Float ) """ return self.__maximumZoomFactor @maximumZoomFactor.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def maximumZoomFactor(self, value): """ This method is the setter method for **self.__maximumZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "maximumZoomFactor")) @maximumZoomFactor.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def maximumZoomFactor(self): """ This method is the deleter method for **self.__maximumZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "maximumZoomFactor")) @property def wheelZoomFactor(self): """ This method is the property for **self.__wheelZoomFactor** attribute. :return: self.__wheelZoomFactor. ( Float ) """ return self.__wheelZoomFactor @wheelZoomFactor.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def wheelZoomFactor(self, value): """ This method is the setter method for **self.__wheelZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "wheelZoomFactor")) @wheelZoomFactor.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def wheelZoomFactor(self): """ This method is the deleter method for **self.__wheelZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "wheelZoomFactor")) @property def keyZoomFactor(self): """ This method is the property for **self.__keyZoomFactor** attribute. :return: self.__keyZoomFactor. ( Float ) """ return self.__keyZoomFactor @keyZoomFactor.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def keyZoomFactor(self, value): """ This method is the setter method for **self.__keyZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "keyZoomFactor")) @keyZoomFactor.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def keyZoomFactor(self): """ This method is the deleter method for **self.__keyZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "keyZoomFactor")) @property def graphicsView(self): """ This method is the property for **self.__graphicsView** attribute. :return: self.__graphicsView. ( QGraphicsView ) """ return self.__graphicsView @graphicsView.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsView(self, value): """ This method is the setter method for **self.__graphicsView** attribute. :param value: Attribute value. ( QGraphicsView ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsView")) @graphicsView.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsView(self): """ This method is the deleter method for **self.__graphicsView** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsView")) @property def graphicsScene(self): """ This method is the property for **self.__graphicsScene** attribute. :return: self.__graphicsScene. ( QGraphicsScene ) """ return self.__graphicsScene @graphicsScene.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsScene(self, value): """ This method is the setter method for **self.__graphicsScene** attribute. :param value: Attribute value. ( QGraphicsScene ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsScene")) @graphicsScene.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def graphicsScene(self): """ This method is the deleter method for **self.__graphicsScene** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsScene")) @property def displayGraphicsItem(self): """ This method is the property for **self.__displayGraphicsItem** attribute. :return: self.__displayGraphicsItem. ( QGraphicsItem ) """ return self.__displayGraphicsItem @displayGraphicsItem.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def displayGraphicsItem(self, value): """ This method is the setter method for **self.__displayGraphicsItem** attribute. :param value: Attribute value. ( QGraphicsItem ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "displayGraphicsItem")) @displayGraphicsItem.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def displayGraphicsItem(self): """ This method is the deleter method for **self.__displayGraphicsItem** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "displayGraphicsItem")) #****************************************************************************************************************** #*** Class methods. #****************************************************************************************************************** def show(self): """ This method reimplements the :meth:`QWidget.show` method. """ super(ImagesPreviewer, self).show() foundations.ui.common.centerWidgetOnScreen(self) def closeEvent(self, event): """ This method reimplements the :meth:`QWidget.closeEvent` method. :param event: QEvent ( QEvent ) """ LOGGER.debug("> Removing '{0}' from Images Previewers list.".format(self)) self.__container.imagesPreviewers.remove(self) event.accept() def wheelEvent(self, event): """ This method reimplements the :meth:`QWidget.wheelEvent` method. :param event: QEvent ( QEvent ) """ self.scaleView(pow(1.5, event.delta() / self.__wheelZoomFactor)) def keyPressEvent(self, event): """ This method reimplements the :meth:`QWidget.keyPressEvent` method. :param event: QEvent ( QEvent ) """ key = event.key() if key == Qt.Key_Plus: self.scaleView(self.__keyZoomFactor) elif key == Qt.Key_Minus: self.scaleView(1 / self.__keyZoomFactor) else: super(ImagesPreviewer, self).keyPressEvent(event) def __initializeUi(self): """ This method initializes the Widget ui. """ LOGGER.debug("> Initializing '{0}' ui.".format(self.__class__.__name__)) self.Previous_Image_pushButton.setIcon(QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiPreviousImage))) self.Next_Image_pushButton.setIcon(QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiNextImage))) self.Zoom_In_pushButton.setIcon(QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiZoomInImage))) self.Zoom_Out_pushButton.setIcon(QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiZoomOutImage))) len(self.__paths) <= 1 and self.Navigation_frame.hide() LOGGER.debug("> Initializing graphics View.") self.__graphicsView = QGraphicsView() self.__graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__graphicsView.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.__graphicsView.setDragMode(QGraphicsView.ScrollHandDrag) # Reimplementing QGraphicsView wheelEvent method. self.__graphicsView.wheelEvent = self.wheelEvent LOGGER.debug("> Initializing graphics scene.") self.__graphicsScene = QGraphicsScene(self.__graphicsView) self.__graphicsScene.setItemIndexMethod(QGraphicsScene.NoIndex) self.__graphicsScene.setSceneRect(-(float(self.__graphicsSceneWidth)) / 2, - (float(self.__graphicsSceneHeight)) / 2, float(self.__graphicsSceneWidth), float(self.__graphicsSceneHeight)) self.__graphicsView.setScene(self.__graphicsScene) self.__graphicsView.setBackgroundBrush(QBrush(self.__graphicsSceneBackgroundColor)) self.Images_Previewer_frame_gridLayout.addWidget(self.__graphicsView) # Signals / Slots. self.__container.engine.imagesCaches.QImage.contentAdded.connect(self.__engine_imagesCaches_QImage__contentAdded) self.Previous_Image_pushButton.clicked.connect(self.__Previous_Image_pushButton__clicked) self.Next_Image_pushButton.clicked.connect(self.__Next_Image_pushButton__clicked) self.Zoom_Out_pushButton.clicked.connect(self.__Zoom_Out_pushButton__clicked) self.Zoom_In_pushButton.clicked.connect(self.__Zoom_In_pushButton__clicked) self.Zoom_Fit_pushButton.clicked.connect(self.__Zoom_Fit_pushButton__clicked) def __Images_Informations_label_setUi(self): """ This method sets the **Images_Informations_label** Widget ui. """ if not self.__displayGraphicsItem: return image = self.__displayGraphicsItem.image self.Images_Informations_label.setText("{0} - {1}x{2} px - {3} bit".format(os.path.basename(image.data.path), image.data.width, image.data.height, image.data.bpp / 4)) def __engine_imagesCaches_QImage__contentAdded(self, content): """ This method is triggered by the Application **QImage** images cache when content has been added. :param content: Cache added content. ( List ) """ if not self.__paths: return path = foundations.common.getFirstItem(content) if not path in self.__paths: return image = self.__container.engine.imagesCaches.QImage.getContent(path) self.__setDisplayGraphicsItem(image) def __Previous_Image_pushButton__clicked(self, checked): """ This method is triggered when **Previous_Image_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.loopThroughImages(True) def __Next_Image_pushButton__clicked(self, checked): """ This method is triggered when **Next_Image_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.loopThroughImages() def __Zoom_In_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_In_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.scaleView(self.__keyZoomFactor) def __Zoom_Out_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_Out_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.scaleView(1 / self.__keyZoomFactor) def __Zoom_Fit_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_Fit_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.fitImage() def __clearGraphicsScene(self): """ This method clears the View. """ for graphicsItem in self.__graphicsScene.items(): self.__graphicsScene.removeItem(graphicsItem) def __setDisplayGraphicsItem(self, image): """ This method sets the View using given image. :param image: Image to display. ( Qimage ) """ self.__clearGraphicsScene() LOGGER.debug("> Initializing graphics item.") self.__displayGraphicsItem = Image_QGraphicsItem(image=image) self.__graphicsScene.addItem(self.__displayGraphicsItem) self.__Images_Informations_label_setUi() def loadImage(self, index=0): """ This method loads the display image in the View. :param index: Index to load. ( Integer ) :return: Method success. ( Boolean ) """ if not self.__paths: return False image = sibl_gui.ui.common.getImage(self.__paths[index]) self.__setDisplayGraphicsItem(image) return True def scaleView(self, scaleFactor): """ This method scales the Previewer view. :param scaleFactor: Float ( Float ) :return: Method success. ( Boolean ) """ graphicsView = self.findChild(QGraphicsView) factor = graphicsView.matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width() if factor < self.__minimumZoomFactor or factor > self.__maximumZoomFactor: return False graphicsView.scale(scaleFactor, scaleFactor) return True def fitWindow(self): """ This method fits the View window. :return: Method success. ( Boolean ) """ if not self.__displayGraphicsItem: return False desktopWidth = QApplication.desktop().screenGeometry(QApplication.desktop().primaryScreen()).width() desktopHeight = QApplication.desktop().screenGeometry(QApplication.desktop().primaryScreen()).height() width = min(desktopWidth * 0.80, self.__displayGraphicsItem.width) height = min(desktopHeight * 0.80, self.__displayGraphicsItem.height) self.resize(width, height) foundations.ui.common.centerWidgetOnScreen(self) return True def fitImage(self): """ This method fits the image to the View. :return: Method success. ( Boolean ) """ if not self.__displayGraphicsItem: return False self.__graphicsView.fitInView( QRectF(-(self.__displayGraphicsItem.width / 2) - (self.__displayGraphicsItemMargin / 2), - (self.__displayGraphicsItem.height / 2) - (self.__displayGraphicsItemMargin / 2), self.__displayGraphicsItem.width + self.__displayGraphicsItemMargin, self.__displayGraphicsItem.height + self.__displayGraphicsItemMargin), Qt.KeepAspectRatio) return True def loopThroughImages(self, backward=False): """ This method loops through View images. :param backward: Looping backward. ( Boolean ) :return: Method success. ( Boolean ) """ index = self.__paths.index(self.__displayGraphicsItem.image.data.path) index += not backward and 1 or -1 if index < 0: index = len(self.__paths) - 1 elif index > len(self.__paths) - 1: index = 0 self.loadImage(index) return True
class ImagesPreviewer(foundations.ui.common.QWidgetFactory(uiFile=UI_FILE)): """ | This class provides the Application images previewer. | It defines methods to navigate through the list of given images ( List of images paths ), zoom in / out and fit the displayed image, etc... """ def __init__(self, parent, paths=None, *args, **kwargs): """ This method initializes the class. :param parent: Object parent. ( QObject ) :param paths: Images paths. ( Tuple / List ) :param \*args: Arguments. ( \* ) :param \*\*kwargs: Keywords arguments. ( \*\* ) """ LOGGER.debug("> Initializing '{0}()' class.".format( self.__class__.__name__)) super(ImagesPreviewer, self).__init__(parent, *args, **kwargs) # --- Setting class attributes. --- self.__container = parent self.__paths = None self.paths = paths self.__uiResourcesDirectory = "resources" self.__uiResourcesDirectory = os.path.join(os.path.dirname(__file__), self.__uiResourcesDirectory) self.__uiPreviousImage = "Previous.png" self.__uiNextImage = "Next.png" self.__uiZoomOutImage = "Zoom_Out.png" self.__uiZoomInImage = "Zoom_In.png" # Ensure the ui object is destroyed on close to avoid memory leaks. self.setAttribute(Qt.WA_DeleteOnClose) self.__graphicsSceneBackgroundColor = QColor(32, 32, 32) self.__minimumZoomFactor = 0.05 self.__maximumZoomFactor = 25 self.__displayGraphicsItemMargin = 32 self.__graphicsSceneWidth = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).width() * ( 1 / self.__minimumZoomFactor * 1.75) self.__graphicsSceneHeight = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).height() * ( 1 / self.__minimumZoomFactor * 1.75) self.__wheelZoomFactor = 350.0 self.__keyZoomFactor = 1.20 self.__graphicsView = None self.__graphicsScene = None self.__displayGraphicsItem = None ImagesPreviewer.__initializeUi(self) self.loadImage() #****************************************************************************************************************** #*** Attributes properties. #****************************************************************************************************************** @property def container(self): """ This method is the property for **self.__container** attribute. :return: self.__container. ( QObject ) """ return self.__container @container.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def container(self, value): """ This method is the setter method for **self.__container** attribute. :param value: Attribute value. ( QObject ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "container")) @container.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def container(self): """ This method is the deleter method for **self.__container** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "container")) @property def paths(self): """ This method is the property for **self.__paths** attribute. :return: self.__paths. ( Tuple / List ) """ return self.__paths @paths.setter @foundations.exceptions.handleExceptions(AssertionError) def paths(self, value): """ This method is the setter method for **self.__paths** attribute. :param value: Attribute value. ( Tuple / List ) """ if value is not None: assert type(value) in ( tuple, list ), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format( "paths", value) for element in value: assert type( element ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "paths", element) self.__paths = value @paths.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def paths(self): """ This method is the deleter method for **self.__paths** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "paths")) @property def uiResourcesDirectory(self): """ This method is the property for **self.__uiResourcesDirectory** attribute. :return: self.__uiResourcesDirectory. ( String ) """ return self.__uiResourcesDirectory @uiResourcesDirectory.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiResourcesDirectory(self, value): """ This method is the setter method for **self.__uiResourcesDirectory** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiResourcesDirectory")) @uiResourcesDirectory.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiResourcesDirectory(self): """ This method is the deleter method for **self.__uiResourcesDirectory** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiResourcesDirectory")) @property def uiPreviousImage(self): """ This method is the property for **self.__uiPreviousImage** attribute. :return: self.__uiPreviousImage. ( String ) """ return self.__uiPreviousImage @uiPreviousImage.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiPreviousImage(self, value): """ This method is the setter method for **self.__uiPreviousImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiPreviousImage")) @uiPreviousImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiPreviousImage(self): """ This method is the deleter method for **self.__uiPreviousImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiPreviousImage")) @property def uiNextImage(self): """ This method is the property for **self.__uiNextImage** attribute. :return: self.__uiNextImage. ( String ) """ return self.__uiNextImage @uiNextImage.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiNextImage(self, value): """ This method is the setter method for **self.__uiNextImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiNextImage")) @uiNextImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiNextImage(self): """ This method is the deleter method for **self.__uiNextImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiNextImage")) @property def uiZoomOutImage(self): """ This method is the property for **self.__uiZoomOutImage** attribute. :return: self.__uiZoomOutImage. ( String ) """ return self.__uiZoomOutImage @uiZoomOutImage.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiZoomOutImage(self, value): """ This method is the setter method for **self.__uiZoomOutImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiZoomOutImage")) @uiZoomOutImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiZoomOutImage(self): """ This method is the deleter method for **self.__uiZoomOutImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiZoomOutImage")) @property def uiZoomInImage(self): """ This method is the property for **self.__uiZoomInImage** attribute. :return: self.__uiZoomInImage. ( String ) """ return self.__uiZoomInImage @uiZoomInImage.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiZoomInImage(self, value): """ This method is the setter method for **self.__uiZoomInImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiZoomInImage")) @uiZoomInImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiZoomInImage(self): """ This method is the deleter method for **self.__uiZoomInImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiZoomInImage")) @property def graphicsSceneBackgroundColor(self): """ This method is the property for **self.__graphicsSceneBackgroundColor** attribute. :return: self.__graphicsSceneBackgroundColor. ( QColors ) """ return self.__graphicsSceneBackgroundColor @graphicsSceneBackgroundColor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneBackgroundColor(self, value): """ This method is the setter method for **self.__graphicsSceneBackgroundColor** attribute. :param value: Attribute value. ( QColors ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsSceneBackgroundColor")) @graphicsSceneBackgroundColor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneBackgroundColor(self): """ This method is the deleter method for **self.__graphicsSceneBackgroundColor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsSceneBackgroundColor")) @property def graphicsSceneWidth(self): """ This method is the property for **self.__graphicsSceneWidth** attribute. :return: self.__graphicsSceneWidth. ( Integer ) """ return self.__graphicsSceneWidth @graphicsSceneWidth.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneWidth(self, value): """ This method is the setter method for **self.__graphicsSceneWidth** attribute. :param value: Attribute value. ( Integer ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsSceneWidth")) @graphicsSceneWidth.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneWidth(self): """ This method is the deleter method for **self.__graphicsSceneWidth** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsSceneWidth")) @property def graphicsSceneHeight(self): """ This method is the property for **self.__graphicsSceneHeight** attribute. :return: self.__graphicsSceneHeight. ( Object ) """ return self.__graphicsSceneHeight @graphicsSceneHeight.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneHeight(self, value): """ This method is the setter method for **self.__graphicsSceneHeight** attribute. :param value: Attribute value. ( Object ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsSceneHeight")) @graphicsSceneHeight.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneHeight(self): """ This method is the deleter method for **self.__graphicsSceneHeight** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsSceneHeight")) @property def minimumZoomFactor(self): """ This method is the property for **self.__minimumZoomFactor** attribute. :return: self.__minimumZoomFactor. ( Float ) """ return self.__minimumZoomFactor @minimumZoomFactor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def minimumZoomFactor(self, value): """ This method is the setter method for **self.__minimumZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "minimumZoomFactor")) @minimumZoomFactor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def minimumZoomFactor(self): """ This method is the deleter method for **self.__minimumZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "minimumZoomFactor")) @property def maximumZoomFactor(self): """ This method is the property for **self.__maximumZoomFactor** attribute. :return: self.__maximumZoomFactor. ( Float ) """ return self.__maximumZoomFactor @maximumZoomFactor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def maximumZoomFactor(self, value): """ This method is the setter method for **self.__maximumZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "maximumZoomFactor")) @maximumZoomFactor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def maximumZoomFactor(self): """ This method is the deleter method for **self.__maximumZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "maximumZoomFactor")) @property def wheelZoomFactor(self): """ This method is the property for **self.__wheelZoomFactor** attribute. :return: self.__wheelZoomFactor. ( Float ) """ return self.__wheelZoomFactor @wheelZoomFactor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def wheelZoomFactor(self, value): """ This method is the setter method for **self.__wheelZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "wheelZoomFactor")) @wheelZoomFactor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def wheelZoomFactor(self): """ This method is the deleter method for **self.__wheelZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "wheelZoomFactor")) @property def keyZoomFactor(self): """ This method is the property for **self.__keyZoomFactor** attribute. :return: self.__keyZoomFactor. ( Float ) """ return self.__keyZoomFactor @keyZoomFactor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def keyZoomFactor(self, value): """ This method is the setter method for **self.__keyZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "keyZoomFactor")) @keyZoomFactor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def keyZoomFactor(self): """ This method is the deleter method for **self.__keyZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "keyZoomFactor")) @property def graphicsView(self): """ This method is the property for **self.__graphicsView** attribute. :return: self.__graphicsView. ( QGraphicsView ) """ return self.__graphicsView @graphicsView.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsView(self, value): """ This method is the setter method for **self.__graphicsView** attribute. :param value: Attribute value. ( QGraphicsView ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsView")) @graphicsView.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsView(self): """ This method is the deleter method for **self.__graphicsView** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsView")) @property def graphicsScene(self): """ This method is the property for **self.__graphicsScene** attribute. :return: self.__graphicsScene. ( QGraphicsScene ) """ return self.__graphicsScene @graphicsScene.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsScene(self, value): """ This method is the setter method for **self.__graphicsScene** attribute. :param value: Attribute value. ( QGraphicsScene ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsScene")) @graphicsScene.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsScene(self): """ This method is the deleter method for **self.__graphicsScene** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsScene")) @property def displayGraphicsItem(self): """ This method is the property for **self.__displayGraphicsItem** attribute. :return: self.__displayGraphicsItem. ( QGraphicsItem ) """ return self.__displayGraphicsItem @displayGraphicsItem.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def displayGraphicsItem(self, value): """ This method is the setter method for **self.__displayGraphicsItem** attribute. :param value: Attribute value. ( QGraphicsItem ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "displayGraphicsItem")) @displayGraphicsItem.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def displayGraphicsItem(self): """ This method is the deleter method for **self.__displayGraphicsItem** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "displayGraphicsItem")) #****************************************************************************************************************** #*** Class methods. #****************************************************************************************************************** def show(self): """ This method reimplements the :meth:`QWidget.show` method. """ super(ImagesPreviewer, self).show() foundations.ui.common.centerWidgetOnScreen(self) def closeEvent(self, event): """ This method reimplements the :meth:`QWidget.closeEvent` method. :param event: QEvent ( QEvent ) """ LOGGER.debug( "> Removing '{0}' from Images Previewers list.".format(self)) self.__container.imagesPreviewers.remove(self) event.accept() def wheelEvent(self, event): """ This method reimplements the :meth:`QWidget.wheelEvent` method. :param event: QEvent ( QEvent ) """ self.scaleView(pow(1.5, event.delta() / self.__wheelZoomFactor)) def keyPressEvent(self, event): """ This method reimplements the :meth:`QWidget.keyPressEvent` method. :param event: QEvent ( QEvent ) """ key = event.key() if key == Qt.Key_Plus: self.scaleView(self.__keyZoomFactor) elif key == Qt.Key_Minus: self.scaleView(1 / self.__keyZoomFactor) else: super(ImagesPreviewer, self).keyPressEvent(event) def __initializeUi(self): """ This method initializes the Widget ui. """ LOGGER.debug("> Initializing '{0}' ui.".format( self.__class__.__name__)) self.Previous_Image_pushButton.setIcon( QIcon( os.path.join(self.__uiResourcesDirectory, self.__uiPreviousImage))) self.Next_Image_pushButton.setIcon( QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiNextImage))) self.Zoom_In_pushButton.setIcon( QIcon( os.path.join(self.__uiResourcesDirectory, self.__uiZoomInImage))) self.Zoom_Out_pushButton.setIcon( QIcon( os.path.join(self.__uiResourcesDirectory, self.__uiZoomOutImage))) len(self.__paths) <= 1 and self.Navigation_frame.hide() LOGGER.debug("> Initializing graphics View.") self.__graphicsView = QGraphicsView() self.__graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__graphicsView.setTransformationAnchor( QGraphicsView.AnchorUnderMouse) self.__graphicsView.setDragMode(QGraphicsView.ScrollHandDrag) # Reimplementing QGraphicsView wheelEvent method. self.__graphicsView.wheelEvent = self.wheelEvent LOGGER.debug("> Initializing graphics scene.") self.__graphicsScene = QGraphicsScene(self.__graphicsView) self.__graphicsScene.setItemIndexMethod(QGraphicsScene.NoIndex) self.__graphicsScene.setSceneRect( -(float(self.__graphicsSceneWidth)) / 2, -(float(self.__graphicsSceneHeight)) / 2, float(self.__graphicsSceneWidth), float(self.__graphicsSceneHeight)) self.__graphicsView.setScene(self.__graphicsScene) self.__graphicsView.setBackgroundBrush( QBrush(self.__graphicsSceneBackgroundColor)) self.Images_Previewer_frame_gridLayout.addWidget(self.__graphicsView) # Signals / Slots. self.__container.engine.imagesCaches.QImage.contentAdded.connect( self.__engine_imagesCaches_QImage__contentAdded) self.Previous_Image_pushButton.clicked.connect( self.__Previous_Image_pushButton__clicked) self.Next_Image_pushButton.clicked.connect( self.__Next_Image_pushButton__clicked) self.Zoom_Out_pushButton.clicked.connect( self.__Zoom_Out_pushButton__clicked) self.Zoom_In_pushButton.clicked.connect( self.__Zoom_In_pushButton__clicked) self.Zoom_Fit_pushButton.clicked.connect( self.__Zoom_Fit_pushButton__clicked) def __Images_Informations_label_setUi(self): """ This method sets the **Images_Informations_label** Widget ui. """ if not self.__displayGraphicsItem: return image = self.__displayGraphicsItem.image self.Images_Informations_label.setText( "{0} - {1}x{2} px - {3} bit".format( os.path.basename(image.data.path), image.data.width, image.data.height, image.data.bpp / 4)) def __engine_imagesCaches_QImage__contentAdded(self, content): """ This method is triggered by the Application **QImage** images cache when content has been added. :param content: Cache added content. ( List ) """ if not self.__paths: return path = foundations.common.getFirstItem(content) if not path in self.__paths: return image = self.__container.engine.imagesCaches.QImage.getContent(path) self.__setDisplayGraphicsItem(image) def __Previous_Image_pushButton__clicked(self, checked): """ This method is triggered when **Previous_Image_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.loopThroughImages(True) def __Next_Image_pushButton__clicked(self, checked): """ This method is triggered when **Next_Image_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.loopThroughImages() def __Zoom_In_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_In_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.scaleView(self.__keyZoomFactor) def __Zoom_Out_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_Out_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.scaleView(1 / self.__keyZoomFactor) def __Zoom_Fit_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_Fit_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.fitImage() def __clearGraphicsScene(self): """ This method clears the View. """ for graphicsItem in self.__graphicsScene.items(): self.__graphicsScene.removeItem(graphicsItem) def __setDisplayGraphicsItem(self, image): """ This method sets the View using given image. :param image: Image to display. ( Qimage ) """ self.__clearGraphicsScene() LOGGER.debug("> Initializing graphics item.") self.__displayGraphicsItem = Image_QGraphicsItem(image=image) self.__graphicsScene.addItem(self.__displayGraphicsItem) self.__Images_Informations_label_setUi() def loadImage(self, index=0): """ This method loads the display image in the View. :param index: Index to load. ( Integer ) :return: Method success. ( Boolean ) """ if not self.__paths: return False image = sibl_gui.ui.common.getImage(self.__paths[index]) self.__setDisplayGraphicsItem(image) return True def scaleView(self, scaleFactor): """ This method scales the Previewer view. :param scaleFactor: Float ( Float ) :return: Method success. ( Boolean ) """ graphicsView = self.findChild(QGraphicsView) factor = graphicsView.matrix().scale(scaleFactor, scaleFactor).mapRect( QRectF(0, 0, 1, 1)).width() if factor < self.__minimumZoomFactor or factor > self.__maximumZoomFactor: return False graphicsView.scale(scaleFactor, scaleFactor) return True def fitWindow(self): """ This method fits the View window. :return: Method success. ( Boolean ) """ if not self.__displayGraphicsItem: return False desktopWidth = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).width() desktopHeight = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).height() width = min(desktopWidth * 0.80, self.__displayGraphicsItem.width) height = min(desktopHeight * 0.80, self.__displayGraphicsItem.height) self.resize(width, height) foundations.ui.common.centerWidgetOnScreen(self) return True def fitImage(self): """ This method fits the image to the View. :return: Method success. ( Boolean ) """ if not self.__displayGraphicsItem: return False self.__graphicsView.fitInView( QRectF( -(self.__displayGraphicsItem.width / 2) - (self.__displayGraphicsItemMargin / 2), -(self.__displayGraphicsItem.height / 2) - (self.__displayGraphicsItemMargin / 2), self.__displayGraphicsItem.width + self.__displayGraphicsItemMargin, self.__displayGraphicsItem.height + self.__displayGraphicsItemMargin), Qt.KeepAspectRatio) return True def loopThroughImages(self, backward=False): """ This method loops through View images. :param backward: Looping backward. ( Boolean ) :return: Method success. ( Boolean ) """ index = self.__paths.index(self.__displayGraphicsItem.image.data.path) index += not backward and 1 or -1 if index < 0: index = len(self.__paths) - 1 elif index > len(self.__paths) - 1: index = 0 self.loadImage(index) return True
class Nexus(QMainWindow): """ Die Hauptklasse des Programms. In dieser Klasse wird die GUI gesteuert und die Würfelwürfe aufgerufen. """ dicePoolChanged = pyqtSignal(int) xAgainChanged = pyqtSignal(int) cursed = pyqtSignal(bool) def __init__(self, parent=None): """ Konstruktor """ self.translator_app = QTranslator() self.translator_qt = QTranslator() QApplication.installTranslator( self.translator_app ) QApplication.installTranslator( self.translator_qt ) QWidget.__init__(self, parent) QCoreApplication.setOrganizationName("Caern") QCoreApplication.setOrganizationDomain("www.caern.de") QCoreApplication.setApplicationName("DiceRoller WoD") QCoreApplication.setApplicationVersion(QString.number(PROGRAM_VERSION_MAJOR) + "." + QString.number(PROGRAM_VERSION_MINOR) + "." + QString.number(PROGRAM_VERSION_CHANGE) ) QApplication.setWindowIcon(QIcon(":/icons/logo/WoD.png")) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.createInfo() #self.createLanguageMenu() self.instantRoll = InstantRoll() self.extendedRoll = ExtendedRoll() # Dieser Zähler bestimmt, wie der rollende Würfel angezeigt wird. self.timerDice = QTimer() # Verzögert die tatsächliche Ausführung des Würfelwurfs. self.timerRoll = QTimer() self.populateUi() self.createConnections() self.initializing() self.setWindowTitle(QCoreApplication.applicationName()) #self.retranslateUi() ## Die von der letzten Benutzung gespeicherte Größe und Position auf dem Bildschirm laden. #self.readSettings() #def closeEvent(self, event): #""" #Diese Funktion wird aufgerufen, wann immer das Programm geschlossen wird. #Die Idee dahinter ist, vor dem Beenden, Größe und Position des Fensters zu speichern. #""" #self.writeSettings() #event.accept() def createInfo(self): """ Erzeugt Tooltips und Hilfe für die einzelnen Teile des Programms. """ self.ui.action_houserules.setStatusTip(self.ui.action_houserules.toolTip()) #def createLanguageMenu(self): #""" #Erzeugt das Menü zum Umschalten zwischen den möglichen Sprachen. #""" #self.menu_language = QMenu( self.tr("&Language") ) #self.actionGroup_language = QActionGroup(self) #self.langPath = getPath() + "/" + PROGRAM_LANGUAGE_PATH #self.dir_qm = QDir( self.langPath ); #self.fileNames = self.dir_qm.entryList( QStringList( "DiceRoller-WoD_*.qm" )); ## Englisch hat keine qm-Datei, also muß es von Hand hinzugefügt werden. #self.action = QAction( "&1 English", self.actionGroup_language ) #self.action.setCheckable( True ) #self.action.setData( "en" ) #self.action.setChecked( True ) #self.menu_language.addAction( self.action ) #self.actionGroup_language.addAction( self.action ) #iter = 0 #for i in self.fileNames: #self.trFilename = unicode(i) #self.locale = unicode(i) #self.locale = self.locale[(self.locale.find( "_" )+1):(self.locale.find( "." ))] #self.translator = QTranslator() #self.translator.load( self.trFilename, self.dir_qm.absolutePath() ) #self.language = self.translator.translate( "MainWindow", "English" ) #self.action = QAction( "&" + QString.number(iter + 2) + " " + self.language, self.actionGroup_language ) #self.action.setCheckable( True ) #self.action.setData( self.locale ) #self.menu_language.addAction ( self.action ) #self.actionGroup_language.addAction ( self.action ) #iter += 1 #self.actionGroup_language.triggered.connect(self.switchLanguage) #self.ui.menuBar.insertMenu(self.ui.menuHelp.menuAction(), self.menu_language) #def switchLanguage( self, action ): #""" #Schaltet zwischen den einzelnen Sprachen um. #""" #self.locale = action.data().toString(); #self.qmPath = getPath() + "/" + PROGRAM_LANGUAGE_PATH ##if self.translator_app.load( "DiceRoller-WoD_" + self.locale, self.qmPath ): ##qDebug("Hat DiceRoller-WoD_" + self.locale + " geladen.") ##if self.translator_qt.load( "qt_" + self.locale, QLibraryInfo.location ( QLibraryInfo.TranslationsPath ) ): ##qDebug("Hat qt_" + self.locale + " geladen.") ## Alle Texte neu setzen #self.retranslateUi() ## Seltsamerweise ist retranslate in Ui_MainWindow leer. Ich weiß nicht, wieso das der Fall ist. #self.ui.retranslateUi(self.ui) #def retranslateUi(self): #""" #Diese Funktion übersetzt alle Texte, welche nicht in der .ui-Datei festgelegt sind, sondern im Quellcode (hier) geschrieben wurden. #""" #self.menu_language.setTitle( self.tr( "&Language" ) ) #self.reset() def populateUi(self): self.svgRenderer = QSvgRenderer(":/icons/W10.svg") self.scene = QGraphicsScene() self.view = QGraphicsView() self.view.setFrameShape(QFrame.NoFrame) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.view.setStyleSheet("background-color: transparent;"); self.view.setScene(self.scene) self.ui.horizontalLayout_dice.insertWidget(1, self.view) def createConnections(self): """ Erstelle die Verbindungen zwischen den verschiedenen Klassen und Elementen des Programms. """ self.ui.action_about.triggered.connect(self.aboutApp) self.ui.action_aboutQt.triggered.connect(QApplication.aboutQt) self.ui.action_houserules.toggled.connect(self.setHouserules) self.ui.pushButton_roll.clicked.connect(self.roll) self.ui.spinBox_pool.valueChanged.connect(self.calcDicePool) self.ui.spinBox_pool.valueChanged.connect(self.reset) self.ui.spinBox_modifier.valueChanged.connect(self.calcDicePoolMod) self.ui.spinBox_modifier.valueChanged.connect(self.reset) self.ui.checkBox_rote.toggled.connect(self.instantRoll.setRote) self.ui.checkBox_rote.toggled.connect(self.extendedRoll.setRote) self.ui.checkBox_rote.toggled.connect(self.reset) self.ui.comboBox_xAgain.activated.connect(self.setXAgainThreshold) self.ui.comboBox_xAgain.activated.connect(self.reset) self.ui.groupBox_extended.toggled.connect(self.changeText) self.ui.radioButton_target.toggled.connect(self.changeText) self.ui.radioButton_maxRolls.toggled.connect(self.changeText) self.ui.groupBox_extended.toggled.connect(self.reset) self.ui.radioButton_target.toggled.connect(self.setExtendedMode) self.ui.spinBox_target.valueChanged.connect(self.extendedRoll.setTarget) self.ui.spinBox_target.valueChanged.connect(self.reset) self.ui.spinBox_maxRolls.valueChanged.connect(self.extendedRoll.setMaxRolls) self.ui.spinBox_maxRolls.valueChanged.connect(self.reset) self.ui.checkBox_rollsLimited.toggled.connect(self.extendedRoll.setLimited) self.ui.checkBox_rollsLimited.toggled.connect(self.reset) self.xAgainChanged.connect(self.instantRoll.setThreshold) self.xAgainChanged.connect(self.extendedRoll.setThreshold) self.cursed.connect(self.instantRoll.setCurse) self.cursed.connect(self.extendedRoll.setCurse) self.instantRoll.rolled.connect(self.setResultSuccesses) self.extendedRoll.rolled.connect(self.setResultSuccesses) self.extendedRoll.rollsNeeded.connect(self.setResultRolls) self.instantRoll.rollFinished.connect(self.setResult) self.extendedRoll.rollFinished.connect(self.setResult) self.dicePoolChanged.connect(self.changeDiceDisplay) self.timerDice.timeout.connect(self.displayDice) self.timerRoll.timeout.connect(self._executeRoll) def initializing(self): """ Initialisiert das Programm mit den Startwerten. """ self.ui.action_quit.setIcon(QIcon(":/icons/actions/exit.png")) self.ui.action_about.setIcon(QIcon(":/icons/logo/WoD.png")) self.ui.pushButton_quit.setIcon(self.ui.action_quit.icon()) self.ui.pushButton_roll.setIcon(QIcon(":icons/W10_0.svg")) self.ui.action_quit.setMenuRole(QAction.QuitRole) self.ui.action_about.setText(self.tr("About %1...").arg(QApplication.applicationName())) self.ui.action_about.setMenuRole(QAction.AboutRole) self.ui.spinBox_pool.setValue(2) self.ui.checkBox_rote.setChecked(False) self.ui.comboBox_xAgain.setCurrentIndex(0) self.ui.spinBox_target.setValue(1) self.changeText() self.ui.radioButton_target.setChecked(True) self.ui.groupBox_extended.setChecked(False) self.ui.checkBox_rollsLimited.setChecked(True) self.dice = [] for i in xrange(10): self.W10_x = QGraphicsSvgItem() self.W10_x.setSharedRenderer(self.svgRenderer) self.W10_x.setElementId("layer" + str(i)) #self.W10_x.setVisible(False) # Ich lege diese Liste an, da ich auf die Liste in self.scene irgendwie nicht zugreifen kann. self.dice.append(self.W10_x) #self.scene.addItem(self.W10_x) def displayDice(self, value=None): """ @todo Der Würfel kann mehrmals in Folge das selbe Ergebnis anzeigen, was dazu führt, daß der Bildablauf zu stocken scheint. """ if (value == None): dieValue = Random.random(10)-1 else: dieValue = value for item in self.scene.items(): self.scene.removeItem(item) self.scene.addItem(self.dice[dieValue]) self.view.setSceneRect(self.scene.itemsBoundingRect()) self.view.fitInView(self.dice[dieValue]) def changeDiceDisplay(self, number): """ Diese Funktion bestimmt, wieviele Würfel angezeigt werden. """ pass #if (self.ui.horizontalLayout_dice.count > 2): #pass #randomValue = Random.random(10)-1 #for die in xrange(number): #self.__W10_scene = QGraphicsScene() #self.__W10_scene.addItem(self.dice[randomValue]) #self.__W10_view = QGraphicsView() #self.__W10_view.setScene(self.__W10_scene) #self.__W10_view.setSceneRect(self.scene.itemsBoundingRect()) #self.__W10_view.fitInView(self.dice[randomValue]) #self.ui.horizontalLayout_dice.insertWidget(1, self.__W10_view) def aboutApp(self): """ Zeigt die Info-Nachricht an. """ self.appText = self.tr(""" <h1>%1</h1> <h2>Version: %2</h2> <p>Copyright (C) 2011 by Victor von Rhein<br> EMail: [email protected]</p> """).arg(QCoreApplication.applicationName()).arg(QCoreApplication.applicationVersion()) self.gnuText = self.tr(""" <h2>GNU General Public License</h2> <p>This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</p> <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p> <p>You should have received a copy of the GNU General Public License along with this program. If not, see <a>http://www.gnu.org/licenses/</a>.</p> """) self.wodText = self.tr(""" <h2>%1</h2> <p>%1, %2, the %3 and all referring terms and symbols are copyrighted by %4</p> """).arg("World of Darkness").arg("White Wolf").arg("White Wolf-Logo").arg("White Wolf Inc.") self.aboutText = self.appText + self.gnuText + self.wodText QMessageBox.about(self, "About " + QCoreApplication.applicationName(), self.aboutText ) def roll(self): """ Der Wurf wird durchgeführt. Der tatsächliche Wurf wird aber von den Timern angestoßen. """ # Es wird ein rollender Würfel angezeigt. self.timerDice.start(DICEROLL_TIMER_INTERVAL) self.timerRoll.start(DICEROLL_TIMER_DELAY) def _executeRoll(self): """ Entscheidet vor dem eigentlichen Würfelwurf, ob ein normaler oder ein erweiterter Wurf notwendig ist und führt diesen aus. """ if self.ui.groupBox_extended.isChecked(): #qDebug("Checked") self.extendedRoll.roll() else: #qDebug("Not Checked") self.instantRoll.roll() # Die Anzeige des rollenden Würfels wird angehalten self.timerDice.stop() self.timerRoll.stop() def calcDicePool(self, value): """ Berechnet die Größe des zur Verfügung stehenden Würfelpools, welcher von den Würfeln und den Modifikatoren abhängt. """ self.instantRoll.poolSize = value + self.ui.spinBox_modifier.value() self.extendedRoll.poolSize = self.instantRoll.poolSize self.extendedRoll.limit = value self.dicePoolChanged.emit(self.instantRoll.poolSize) def calcDicePoolMod(self, value): """ Berechnet wie schon calcDicePool() die Größe des Würfelvorrats, allerdings werden dieser Funktion andere Argumente übergeben. """ self.instantRoll.poolSize = value + self.ui.spinBox_pool.value() self.extendedRoll.poolSize = value + self.ui.spinBox_pool.value() def setHouserules(self, value): #qDebug("Test" + str(value)) self.extendedRoll.isHouserules = value def setXAgainThreshold(self, value): """ Legt fest, bei welchem Ergebnis weitergewürfelt werden kann und wann dies überhaupt nicht der Fall sein sollte oder gar Erfolge abgezogen werden können. """ self.__threshold = 0 if (value < 3): self.__threshold = 10 - value # Index 0 entspricht 10 again, 1 entspricht 9 again etc. else: self.__threshold = 11 # Index 3 entspricht "no reroll" self.xAgainChanged.emit(self.__threshold) if (value > 3): self.cursed.emit(True) # Kein reroll und 1er werden Abgezogen. else: self.cursed.emit(False) # 1er werden nicht abgezogen. def setExtendedMode(self, sw): """ Legt den Modus fest, mit welchem der erweiterte Wurf durchgeführt wird. Entweder wird auf ein Ergebnishingewürfelt, oder nach einer bestimmten Anzahl würde die Anzahl der Erfolge gezählt. """ if (sw): self.extendedRoll.isResultInRolls = False else: self.extendedRoll.isResultInRolls = True def setResult(self, value): """ Schreibt das Ergebnis des Wurfs in die GUI. Dabei wird auch je nach Erfolgsqualität bei dem dargestellten Würfel eine andere Augenzahl gezeigt. """ self.ui.statusBar.showMessage(self.tr("Result of diceroll is displayed.")) if (value == DieResult.dramaticFailure): self.ui.label_resultText.setText(self.tr("Dramatic Failure")); self.ui.label_result.setPixmap(QPixmap(":/icons/actions/cnrdelete-all1.png")); self.displayDice(1) elif (value == DieResult.failure): self.ui.label_resultText.setText(self.tr("Failure")); self.ui.label_result.setPixmap(QPixmap(":/icons/actions/fileclose.png")); self.displayDice(Random.random(2, 7)) elif (value == DieResult.success): self.ui.label_resultText.setText(self.tr("Success")); self.ui.label_result.setPixmap(QPixmap(":/icons/actions/ok.png")); self.displayDice(Random.random(8, 9)) else: self.ui.label_resultText.setText(self.tr("Exceptional Success")); self.ui.label_result.setPixmap(QPixmap(":/icons/actions/bookmark.png")); self.displayDice(0) def setResultRolls(self, value): """ Zeigt in der GUI an, wieviele Würfe nötig waren. """ if (self.ui.groupBox_extended.isChecked() and self.ui.radioButton_target.isChecked()): self.ui.lcdNumber_successes.display(value) def setResultSuccesses(self, value): """ Zeigt in der GUI an, wieviele Erfolge erzielt wurden. """ if (not self.ui.groupBox_extended.isChecked() or not self.ui.radioButton_target.isChecked()): self.ui.lcdNumber_successes.display(value) def changeText(self): """ Verändert den Text in der Statuszeile. """ if (self.ui.groupBox_extended.isChecked() and self.ui.radioButton_target.isChecked()): self.ui.label_successes.setText(self.tr("Number of rolls needed:")) else: self.ui.label_successes.setText(self.tr("Number of successes:")) def reset(self): """ Setzt das Programm auf einen definierten Startwert zurück. """ self.ui.label_result.setPixmap(QPixmap(":/icons/actions/fileclose.png")) self.ui.label_resultText.setText(self.tr("No result yet!")) self.ui.lcdNumber_successes.display(0) self.ui.statusBar.showMessage(self.tr("Press the Button to roll the dice!"))