def actionPrintSlot(self) -> None: printer = QPrinter() printer.setPageOrientation(QPageLayout.Landscape) if QPrintDialog(printer).exec_(): painter = QPainter(printer) painter.setRenderHint(QPainter.Antialiasing) view = QGraphicsView() view.setScene(self.scene) view.setSceneRect(QRectF(0, 0, 290, 200)) view.fitInView(QRectF(0, 0, 290, 200), Qt.KeepAspectRatio) view.scale(1, -1) view.render(painter) del painter # necessary, thanks Qt
def main(): app = QApplication(sys.argv) grview = QGraphicsView() scene = QGraphicsScene() scene.setSceneRect(0, 0, 680, 459) scene.addPixmap(QPixmap('../images/phototest.tif')) grview.setScene(scene) item = AreaItem(0, 0, 300, 150) item.areaColor = QColor(155, 155, 0, 75) scene.addItem(item) grview.fitInView(scene.sceneRect(), Qt.KeepAspectRatio) grview.show() sys.exit(app.exec_())
class View(QWidget): trigger_focus_event = QtCore.pyqtSignal(str) def __init__(self, buffer, view_info): super(View, self).__init__() self.buffer = buffer # Init widget attributes. self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True) self.setContentsMargins(0, 0, 0, 0) self.installEventFilter(self) # Init attributes. self.view_info = view_info (self.buffer_id, self.emacs_xid, self.x, self.y, self.width, self.height) = view_info.split(":") self.emacs_xid = int(self.emacs_xid) self.x = int(self.x) self.y = int(self.y) self.width = int(self.width) self.height = int(self.height) # Build QGraphicsView. self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) self.graphics_view = QGraphicsView(buffer, self) self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing) # Remove damn border from QGraphicsView. self.graphics_view.setFrameStyle(QFrame.NoFrame) self.layout.addWidget(self.graphics_view) # NOTE: show function must start before resize to trigger *first* resizeEvent after show. self.show() # Resize after show to trigger fit view operation. self.resize(self.width, self.height) self.buffer.aspect_ratio_change.connect(self.adjust_aspect_ratio) def resizeEvent(self, event): # Fit content to view rect just when buffer fit_to_view option is enable. if self.buffer.fit_to_view: if event.oldSize().isValid(): self.graphics_view.fitInView( self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio) QWidget.resizeEvent(self, event) def adjust_aspect_ratio(self): widget_width = self.width widget_height = self.height if self.buffer.aspect_ratio == 0: self.buffer.buffer_widget.resize(self.width, self.height) self.layout.setContentsMargins(0, 0, 0, 0) else: view_height = widget_height * ( 1 - 2 * self.buffer.vertical_padding_ratio) view_width = view_height * self.buffer.aspect_ratio horizontal_padding = (widget_width - view_width) / 2 vertical_padding = self.buffer.vertical_padding_ratio * widget_height self.buffer.buffer_widget.resize(view_width, view_height) self.layout.setContentsMargins(horizontal_padding, vertical_padding, horizontal_padding, vertical_padding) def eventFilter(self, obj, event): # Focus emacs buffer when user click view. if event.type() in [ QEvent.MouseButtonPress, QEvent.MouseButtonRelease, QEvent.MouseButtonDblClick, QEvent.Wheel ]: self.trigger_focus_event.emit(self.buffer_id) # Stop mouse event. return True return False def showEvent(self, event): # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed. self.reparent() # Make graphics view at left-top corner after show. self.graphics_view.verticalScrollBar().setValue(0) self.graphics_view.horizontalScrollBar().setValue(0) def reparent(self): qwindow = self.windowHandle() qwindow.setParent(QWindow.fromWinId(self.emacs_xid)) qwindow.setPosition(QPoint(self.x, self.y)) def destroy_view(self): self.destroy()
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 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.setFixedSize(self.width(), self.height()) self.setWindowTitle("Magic Viewer") self.setWindowIcon(QIcon(':/image/Icon.png')) 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) #菜单栏 # 将ContextMenuPolicy设置为Qt.CustomContextMenu # 否则无法使用customContextMenuRequested信号 self.setContextMenuPolicy(Qt.CustomContextMenu) # 创建QMenu信号事件 self.customContextMenuRequested.connect(self.showMenu) self.menu = QMenu(self) self.function_menu = QMenu(self.menu) self.function_menu.setTitle('功能') self.open_menu = self.menu.addAction(QIcon(':/image/open.png'), '打开 O') self.file_path_menu = self.menu.addAction( QIcon(':/image/openfolder.png'), '打开文件所在位置') self.menu.addSeparator() self.menu.addMenu(self.function_menu) self.zoom_in_menu = self.function_menu.addAction( QIcon(':/image/zoom_in.png'), '放大 Scorll Up, W', ) self.zoom_out_menu = self.function_menu.addAction( QIcon(':/image/zoom_out.png'), '缩小 Scroll Down, S') self.rotate_right_menu = self.function_menu.addAction( QIcon(':/image/rotate_right.png'), '顺转90° R') self.rotate_left_menu = self.function_menu.addAction( QIcon(':/image/rotate_left.png'), '逆转90° E') self.fitsize_menu = self.function_menu.addAction( QIcon(':/image/fitsize.png'), '适合屏幕 F') self.relsize_menu = self.function_menu.addAction( QIcon(':/image/relsize.png'), '实际尺寸 1') self.loop_menu = self.function_menu.addAction( QIcon(':/image/loop.png'), '幻灯片 L') self.about_menu = self.function_menu.addAction( QIcon(':/image/about.png'), '关于Magic Viewer') self.menu.addSeparator() self.next_menu = self.menu.addAction(QIcon(':/image/next.png'), '下一张 Right, SPACE') self.previous_menu = self.menu.addAction(QIcon(':/image/previous.png'), '上一张 Left, B') self.full_menu = self.menu.addAction(QIcon(':/image/full.png'), '全屏 F11') self.menu.addSeparator() self.close_menu = self.menu.addAction(QIcon(':/image/exit.png'), '退出') # 事件绑定 self.zoom_in_menu.triggered.connect(self.zoomIn) self.zoom_out_menu.triggered.connect(self.zoomOut) self.full_menu.triggered.connect(self.toggleFullscreen) self.rotate_right_menu.triggered.connect(lambda: self.rotateImg(-1)) self.rotate_left_menu.triggered.connect(lambda: self.rotateImg(1)) self.next_menu.triggered.connect(lambda: self.dirBrowse(1)) self.previous_menu.triggered.connect(lambda: self.dirBrowse(-1)) self.fitsize_menu.triggered.connect(self.fitView) self.relsize_menu.triggered.connect(self.zoomReset) self.open_menu.triggered.connect(lambda: self.openfile(None)) self.close_menu.triggered.connect(self.closeMainWindow) self.file_path_menu.triggered.connect(self.openfile_path) self.about_menu.triggered.connect(self.about) self.loop_menu.triggered.connect(self.loop_start) # 判断是否是幻灯片模式 self.isLoop = False def btnClicked(self): self.openfile() def openfile(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 common_file(self, path): self.key, _ = QFileDialog.getOpenFileName( self, "选择文件", path, "图片文件 (*.bmp *.jpg *.jpeg *.png *.gif)") self.openfile(file=self.key) def openfile_path(self): #获得当前路径 try: os.startfile(self.file_path) except FileNotFoundError: print("文件目录不存在!") 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 closeMainWindow(self): self.close() def toggleFullscreen(self): # 全屏 if self.isFullScreen(): if self.isLoop: self.loop_end() else: self.showNormal() elif self.btn.isEnabled(): #未全屏状态下如果任处启动界面,pass pass else: self.showFullScreen() def keyPressEvent(self, event): if self.isLoop: self.loop_end() return elif 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_O: self.btnClicked() elif event.key() == Qt.Key_L: self.loop_start() elif event.key() == Qt.Key_Escape: self.showNormal() 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) - 第%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 setBackground(self, color): #改变背景颜色 # self.color = QColor(0, 0, 0) self.setStyleSheet('QWidget{background-color:%s}' % color) def loop_end(self): #关闭幻灯片 if self.isLoop: self.timer.stop() self.setBackground('') #样式恢复默认效果 self.isLoop = False self.showNormal() def loop_start(self): #开启幻灯片 self.isLoop = True self.timer = QTimer() if self.isLoop: self.showFullScreen() self.setBackground('black') self.timer.start(5000) # 每过5秒,定时器到期,产生timeout的信号 self.timer.timeout.connect(partial(self.dirBrowse, 1)) def wheelEvent(self, event): # 鼠标滚动 moose = event.angleDelta().y() / 120 if moose > 0: self.zoomIn() elif moose < 0: self.zoomOut() def showMenu(self): # 右键菜单 if self.btn.isEnabled(): common_menu = QMenu() qconfig = QConfig() common_menu.addAction(QIcon(':/image/config.png'), '配置', qconfig.show) path1, path2, path3 = qconfig.read_config() if os.path.isdir(path1): common_menu.addAction(QIcon(':/image/common.png'), os.path.basename(path1), lambda: self.common_file(path1)) if os.path.isdir(path2): common_menu.addAction(QIcon(':/image/common.png'), os.path.basename(path2), lambda: self.common_file(path2)) if os.path.isdir(path3): common_menu.addAction(QIcon(':/image/common.png'), os.path.basename(path3), lambda: self.common_file(path3)) common_menu.exec_(QCursor.pos()) elif self.isLoop: self.loop_end() return else: self.menu.exec_(QCursor.pos()) # 在鼠标位置显示 def about(self): QMessageBox.about( self, "关于Magic Viewer", "<b>Magic Viewer</b>是一个基于PyQt5的开源图片浏览器<br>" "二次作者 : SkyZZF<br>" "原作者 : Youth Lee<br>" "版本 : Ver 0.4<br>" "网址 : <a href='https://github.com/SkyZZF/MagicViewer'>https://github.com/SkyZZF/MagicViewer</a>" )
class GameViewer(QWidget): ''' The main game viewer GUI ''' def __init__(self): super(GameViewer, self).__init__() self.cell_size = 100 # Arbitrary units self.scene = None self.game = None self.game_generator = None self.goody0 = None self.goody1 = None self.baddy = None self.ping_marker = {} self.results = defaultdict(int) self.round_timer = QTimer(interval=50, timeout=self._play) # milliseconds self.running = False self.view = QGraphicsView() self.view.scale(1, -1) # We want x to increase rightwards and y to increase upwards self.view.setMinimumSize(500, 500) self.round = QLabel() self.status = QLabel() self.goodies_win_count = QLineEdit(readOnly=True) self.draw_count = QLineEdit(readOnly=True) self.baddy_wins_count = QLineEdit(readOnly=True) self.auto_start = QCheckBox("Auto-start new game", checked=True) self.new_game_button = QPushButton("&New Game", clicked=self.new_game, enabled=False) self.step_button = QPushButton("S&tep", clicked=self.do_round, enabled=False) self.go_stop_button = QPushButton("&Go", clicked=self.toggle_running, enabled=False) stats_layout = QHBoxLayout() stats_layout.addWidget(QLabel("Goodies:")) stats_layout.addWidget(self.goodies_win_count) stats_layout.addWidget(QLabel("Draw:")) stats_layout.addWidget(self.draw_count) stats_layout.addWidget(QLabel("Baddy:")) stats_layout.addWidget(self.baddy_wins_count) info_layout = QFormLayout() info_layout.addRow("Round:", self.round) info_layout.addRow("Status:", self.status) info_layout.addRow(stats_layout) buttons_layout = QHBoxLayout() buttons_layout.addWidget(self.new_game_button) buttons_layout.addWidget(self.step_button) buttons_layout.addWidget(self.go_stop_button) layout = QVBoxLayout(self) layout.addWidget(self.view) layout.addLayout(info_layout) layout.addWidget(self.auto_start) layout.addLayout(buttons_layout) def set_game(self, game): ''' Set the Game object that should be viewed by this GUI ''' if self.running: self.toggle_running() # Alter the GUI widgets self.game = game self.scene = QGraphicsScene() self.view.setScene(self.scene) self.go_stop_button.setEnabled(True) self.step_button.setEnabled(True) height = game.maze.height width = game.maze.width cell = self.cell_size # Leave a border of cell_size units, and put (0, 0) at the bottom corner of the maze's interior self.scene.setSceneRect(-cell, -cell, (width + 2) * cell, (height + 2) * cell) self.view.fitInView(self.scene.sceneRect()) wall_brush = QBrush(QColor("black")) wall_pen = QPen(wall_brush, 0) goody_brush = QBrush(QColor("green")) goody_pen = QPen(goody_brush, 0) baddy_brush = QBrush(QColor("red")) baddy_pen = QPen(baddy_brush, 0) ping_brush = QBrush(QColor("white")) # Create the border self.scene.addRect(-cell, -cell, (width + 2) * cell, cell, pen=wall_pen, brush=wall_brush) self.scene.addRect(-cell, height * cell, (width + 2) * cell, cell, pen=wall_pen, brush=wall_brush) self.scene.addRect(-cell, 0, cell, height * cell, pen=wall_pen, brush=wall_brush) self.scene.addRect(width * cell, 0, cell, height * cell, pen=wall_pen, brush=wall_brush) # Add the obstructions: for y in xrange(width): for x in xrange(height): if game.maze[x, y] == Maze.wall: self.scene.addRect(x * cell, y * cell, cell, cell, pen=wall_pen, brush=wall_brush) # Add the players goody0_pos = game.position[game.goody0] goody1_pos = game.position[game.goody1] baddy_pos = game.position[game.baddy] self.goody0 = self.scene.addEllipse(0, 0, cell, cell, pen=goody_pen, brush=goody_brush) self.goody0.setPos(goody0_pos.x * cell, goody0_pos.y * cell) self.goody1 = self.scene.addEllipse(0, 0, cell, cell, pen=goody_pen, brush=goody_brush) self.goody1.setPos(goody1_pos.x * cell, goody1_pos.y * cell) self.baddy = self.scene.addEllipse(0, 0, cell, cell, pen=baddy_pen, brush=baddy_brush) self.baddy.setPos(baddy_pos.x * cell, baddy_pos.y * cell) # Add the ping markers for player in (game.goody0, game.goody1, game.baddy): pen = goody_pen if isinstance(player, Goody) else baddy_pen marker = self.scene.addEllipse(cell // 4, cell // 4, cell // 2, cell // 2, pen=pen, brush=ping_brush) marker.hide() marker.setZValue(-1) self.ping_marker[player] = marker # Set the info self.round.setText(str(game.round)) self.status.setText(game.status) self.running = False # Change the window title self.setWindowTitle("{} and {} vs. {}".format(type(game.goody0).__name__, type(game.goody1).__name__, type(game.baddy).__name__)) def set_game_generator(self, game_generator): ''' Set the game generator (a generator of Game instances) that the GUI can take from ''' self.game_generator = game_generator self.new_game_button.setEnabled(True) self.new_game() def new_game(self): ''' Take the next Game from the generator ''' if self.game_generator is not None: self.set_game(next(self.game_generator)) def toggle_running(self): ''' Switch between automatically stepping through the game and allowing manual "Step" clicks ''' if self.running: self.round_timer.stop() self.running = False else: self.round_timer.start() self.running = True self._update_widgets() def _play(self): ''' Private - called to do a round of turns and check if the game has ended ''' result = self.do_round() if result != Game.in_play: self.toggle_running() if not self.running and self.auto_start.isChecked(): self.new_game() self.toggle_running() def _update_widgets(self): ''' Private - Make the GUI show the current state of the Game ''' if self.running: self.go_stop_button.setText("&Stop") self.step_button.setEnabled(False) else: self.go_stop_button.setText("&Go") if self.game.status == Game.in_play: self.step_button.setEnabled(True) else: self.go_stop_button.setEnabled(False) self.step_button.setEnabled(False) self.goodies_win_count.setText(str(self.results[Game.goodies_win])) self.draw_count.setText(str(self.results[Game.draw])) self.baddy_wins_count.setText(str(self.results[Game.baddy_wins])) def do_round(self): ''' Take a round of turns ''' self.started = True game = self.game if game is None: return result = game.do_round() for graphic, player in ((self.goody0, game.goody0), (self.goody1, game.goody1), (self.baddy, game.baddy)): new_pos = game.position[player] new_x = new_pos.x * self.cell_size new_y = new_pos.y * self.cell_size graphic.setPos(new_x, new_y) if game.ping: marker = self.ping_marker[player] marker.setPos(new_x, new_y) marker.show() if result != Game.in_play: self.results[result] += 1 if not self.running: self._update_widgets() self.round.setText(str(self.game.round)) self.status.setText(self.game.status) return result
class VideoWindow(QMainWindow): def __init__(self, parent=None): super(VideoWindow, self).__init__(parent) self.setWindowTitle( "PyQt Video Player Widget Example - pythonprogramminglanguage.com") self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.camera = QCamera(0) self.cameraviewfinder = QCameraViewfinder() self.cameramode = self.camera.CaptureMode(2) self.cameraimgcap = QCameraImageCapture(self.camera) videoWidget = QVideoWidget() self.imageView = QLabel("add a image file") self.imageView.setAlignment(Qt.AlignCenter) self.playButton = QPushButton() self.playButton.setEnabled(True) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.scene1 = QGraphicsScene() self.view1 = QGraphicsView(self.scene1) # Create new action # Create exit action # Create a widget for window contents wid = QWidget(self) self.setCentralWidget(wid) # Create layouts to place inside widget # controlLayout = QHBoxLayout() # controlLayout.setContentsMargins(0, 0, 0, 0) # controlLayout.addWidget(self.playButton) # controlLayout.addWidget(self.positionSlider) videolayout = QVBoxLayout() videolayout.addWidget(videoWidget) # videolayout.addLayout(controlLayout) # Set widget to contain window contents layout = QHBoxLayout() layout.addLayout(videolayout) layout.addWidget(self.cameraviewfinder) # layout.addWidget(self.view1) wid.setLayout(layout) self.mediaPlayer.setVideoOutput(videoWidget) self.cameraviewfinder.show() self.camera.setViewfinder(self.cameraviewfinder) def exitCall(self): sys.exit(app.exec_()) def play(self): self.showFullScreen() fileName = 'D:\\桌面\\some.mp4' if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.playButton.setEnabled(True) self.cameraviewfinder.resize(640, 480) self.camera.start() self.mediaPlayer.play() camera_capture = cv2.VideoCapture(0) while True: ret, camera_frame = camera_capture.read() if ret: self.displayImage(camera_frame) else: break camera_capture.release() cv2.destroyAllWindows() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def displayImage(self, img): self.scene1.clear() pixMap = QPixmap(img) w, h = pixMap.width(), pixMap.height() self.scene1.addPixmap(pixMap) self.view1.fitInView(QRectF(0, 0, w, h), Qt.KeepAspectRatio) self.scene1.update()
class Spectrum(QWidget): """Plot the power spectrum for a specified channel. Attributes ---------- parent : instance of QMainWindow the main window. x_limit : tuple or list 2 values specifying the limit on x-axis y_limit : tuple or list 2 values specifying the limit on y-axis log : bool log-transform the data or not idx_chan : instance of QComboBox the element with the list of channel names. idx_x_min : instance of QLineEdit value with min x value idx_x_max : instance of QLineEdit value with max x value idx_y_min : instance of QLineEdit value with min y value idx_y_max : instance of QLineEdit value with max y value idx_log : instance of QCheckBox widget that defines if log should be used or not idx_fig : instance of QGraphicsView the view with the power spectrum scene : instance of QGraphicsScene the scene with GraphicsItems Notes ----- If data contains NaN, it doesn't create any spectrum (feature or bug?). """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigSpectrum(self.display_window) self.selected_chan = None self.idx_chan = None self.idx_fig = None self.scene = None self.create() def create(self): """Create empty scene for power spectrum.""" self.idx_chan = QComboBox() self.idx_chan.activated.connect(self.display_window) self.idx_fig = QGraphicsView(self) self.idx_fig.scale(1, -1) layout = QVBoxLayout() layout.addWidget(self.idx_chan) layout.addWidget(self.idx_fig) self.setLayout(layout) self.resizeEvent(None) def show_channame(self, chan_name): self.selected_chan = self.idx_chan.currentIndex() self.idx_chan.clear() self.idx_chan.addItem(chan_name) self.idx_chan.setCurrentIndex(0) def update(self): """Add channel names to the combobox.""" self.idx_chan.clear() for chan_name in self.parent.traces.chan: self.idx_chan.addItem(chan_name) if self.selected_chan is not None: self.idx_chan.setCurrentIndex(self.selected_chan) self.selected_chan = None def display_window(self): """Read the channel name from QComboBox and plot its spectrum. This function is necessary it reads the data and it sends it to self.display. When the user selects a smaller chunk of data from the visible traces, then we don't need to call this function. """ if self.idx_chan.count() == 0: self.update() chan_name = self.idx_chan.currentText() lg.info('Power spectrum for channel ' + chan_name) if chan_name: trial = 0 data = self.parent.traces.data(trial=trial, chan=chan_name) self.display(data) else: self.scene.clear() def display(self, data): """Make graphicsitem for spectrum figure. Parameters ---------- data : ndarray 1D vector containing the data only This function can be called by self.display_window (which reads the data for the selected channel) or by the mouse-events functions in traces (which read chunks of data from the user-made selection). """ value = self.config.value self.scene = QGraphicsScene(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) self.idx_fig.setScene(self.scene) self.add_grid() self.resizeEvent(None) s_freq = self.parent.traces.data.s_freq f, Pxx = welch(data, fs=s_freq, nperseg=int(min((s_freq, len(data))))) # force int freq_limit = (value['x_min'] <= f) & (f <= value['x_max']) if self.config.value['log']: Pxx_to_plot = log(Pxx[freq_limit]) else: Pxx_to_plot = Pxx[freq_limit] self.scene.addPath(Path(f[freq_limit], Pxx_to_plot), QPen(QColor(LINE_COLOR), LINE_WIDTH)) def add_grid(self): """Add axis and ticks to figure. Notes ----- I know that visvis and pyqtgraphs can do this in much simpler way, but those packages create too large a padding around the figure and this is pretty fast. """ value = self.config.value # X-AXIS # x-bottom self.scene.addLine(value['x_min'], value['y_min'], value['x_min'], value['y_max'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # at y = 0, dashed self.scene.addLine(value['x_min'], 0, value['x_max'], 0, QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DashLine)) # ticks on y-axis y_high = int(floor(value['y_max'])) y_low = int(ceil(value['y_min'])) x_length = (value['x_max'] - value['x_min']) / value['x_tick'] for y in range(y_low, y_high): self.scene.addLine(value['x_min'], y, value['x_min'] + x_length, y, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # Y-AXIS # left axis self.scene.addLine(value['x_min'], value['y_min'], value['x_max'], value['y_min'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # larger ticks on x-axis every 10 Hz x_high = int(floor(value['x_max'])) x_low = int(ceil(value['x_min'])) y_length = (value['y_max'] - value['y_min']) / value['y_tick'] for x in range(x_low, x_high, 10): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # smaller ticks on x-axis every 10 Hz y_length = (value['y_max'] - value['y_min']) / value['y_tick'] / 2 for x in range(x_low, x_high, 5): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) def resizeEvent(self, event): """Fit the whole scene in view. Parameters ---------- event : instance of Qt.Event not important """ value = self.config.value self.idx_fig.fitInView(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) def reset(self): """Reset widget as new""" self.idx_chan.clear() if self.scene is not None: self.scene.clear() self.scene = None
class IDLocator(QWidget): def __init__(self): super(IDLocator, self).__init__() # Set up the user interface from Designer. self.ui = Ui_idLocator() self.ui.setupUi(self) self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setRenderHint(QPainter.HighQualityAntialiasing) self.ui.imgLayout.addWidget(self.view) self.img = QPixmap() self.imgItem = QGraphicsPixmapItem(self.img) self.scene.addItem(self.imgItem) self.bottomRect = QGraphicsRectItem() self.brush = QBrush(QColor(0, 60, 80, 64)) self.bottomRect.setBrush(self.brush) self.topRect = QGraphicsRectItem() self.brush = QBrush(QColor(60, 0, 80, 64)) self.topRect.setBrush(self.brush) self.scene.addItem(self.bottomRect) self.scene.addItem(self.topRect) # Connect up the buttons. self.ui.goButton.clicked.connect(self.getToIt) self.ui.cancelButton.clicked.connect(self.close) self.grabFirstImage() self.setRectangles() self.ui.topSlider.valueChanged.connect(self.updateTopRect) self.ui.bottomSlider.valueChanged.connect(self.updateBottomRect) self.ui.topLayout.setAlignment(Qt.AlignHCenter) self.ui.bottomLayout.setAlignment(Qt.AlignHCenter) def grabFirstImage(self): fn = sorted( glob.glob("../scanAndGroup/readyForMarking/idgroup/*idg.png"))[0] print("Loading {}".format(fn)) self.img = QPixmap(fn) self.imgItem.setPixmap(self.img) self.imgItem.setPos(0, 0) self.scene.setSceneRect(0, 0, self.img.width(), self.img.height()) print(self.img.height(), self.img.width()) self.scene.update() self.view.fitInView(self.imgItem, Qt.KeepAspectRatio) def setRectangles(self): w = self.img.width() h = self.img.height() self.updateTopRect() self.updateBottomRect() def updateTopRect(self): v = self.ui.topSlider.value() / 100 w = self.img.width() h = self.img.height() self.topRect.setRect(0, 0, w, h * v) self.ui.topLabel.setText("{}".format(self.ui.topSlider.value())) if self.ui.topSlider.value() + self.ui.bottomSlider.value() > 100: self.ui.bottomSlider.setValue(100 - self.ui.topSlider.value()) def updateBottomRect(self): v = self.ui.bottomSlider.value() / 100 w = self.img.width() h = self.img.height() self.bottomRect.setRect(0, h * (1 - v), w, h * v) self.ui.bottomLabel.setText("{}".format(100 - self.ui.bottomSlider.value())) if self.ui.topSlider.value() + self.ui.bottomSlider.value() > 100: self.ui.topSlider.setValue(100 - self.ui.bottomSlider.value()) def getToIt(self): h = self.img.height() t = int(max(0, self.ui.topSlider.value() - 5) / 100 * h) b = int(min(100, 105 - self.ui.bottomSlider.value()) / 100 * h) print("Run ID-code on image height range {} to {}".format(t, b)) cmd = ["python3", "./readStudentID.py", str(t), str(b)] subprocess.check_call(cmd) self.close()
w = QtWidgets.QWidget() v = QGraphicsView() def quit(): print("Connection closed by server") app.quit() iface = NetworkInterface() t = QtCore.QThread() iface.moveToThread(t) t.start() QtCore.QMetaObject.invokeMethod(iface, "run", Qt.QueuedConnection) scene = QGraphicsScene(v) v.setRenderHints(QtGui.QPainter.HighQualityAntialiasing) v.setScene(scene) size = blobs.BOARD_SIZE v.fitInView(0, 0, size, size) field = GameField(size, scene) iface.dataReceived.connect(field.update, Qt.QueuedConnection) iface.connectionClosed.connect(quit) w.setLayout(QtWidgets.QHBoxLayout()) w.resize(800, 600) w.layout().addWidget(v) w.setWindowFlags(Qt.Dialog) w.show() app.exec_()
class CaptureVideoWidget(QWidget): def __init__(self, parent=None): self.converted_memory_pointer = ueye.c_mem_p() self.converted_memory_id = ueye.int() self.img_data = ImageData() self.capturing = False self.hCam = 0 self.init() ueye.is_SetColorMode(self.hCam, ueye.IS_CM_RGB8_PACKED) self.alloc(self.hCam) self.qt_image = None ueye.is_CaptureVideo(self.hCam, Wait=True) QWidget.__init__(self, parent, flags=Qt.Widget) self.graphics_scene = QGraphicsScene() self.graphics_view = QGraphicsView(self.graphics_scene) self.graphics_view.setViewportUpdateMode( QGraphicsView.FullViewportUpdate) self.start_stop_button = QPushButton("start/stop") self.event = ueye.HANDLE(int()) self.frame_event_id = ueye.IS_SET_EVENT_FRAME self.image_data_copy = None self.pil_image = None self.pix_map = None self.width = 0 self.height = 0 self.threads = [] layout = QVBoxLayout() layout.addWidget(self.start_stop_button, alignment=Qt.AlignTop) layout.addWidget(self.graphics_view) self.setLayout(layout) self.start_stop_button.clicked.connect(self.switch_capturing) def init(self): h_cam = ueye.HIDS(0 | ueye.IS_USE_DEVICE_ID) ret = ueye.is_InitCamera(h_cam, None) if ret != ueye.IS_SUCCESS: error_message = QMessageBox() result = QMessageBox.critical(error_message, 'Error', "Invalid device id!", buttons=QMessageBox.Ok) if result == QMessageBox.Ok: exit() self.hCam = h_cam return h_cam def alloc(self, h_cam): rect_aoi = ueye.IS_RECT() memory_id = ueye.int() memory_pointer = ueye.c_mem_p() bits_per_pixel = 8 ueye.is_AOI(h_cam, ueye.IS_AOI_IMAGE_GET_AOI, rect_aoi, ueye.sizeof(rect_aoi)) ueye.is_AllocImageMem(h_cam, rect_aoi.s32Width, rect_aoi.s32Height, bits_per_pixel, memory_pointer, memory_id) ueye.is_SetImageMem(h_cam, memory_pointer, memory_id) self.img_data.memory_pointer = memory_pointer self.img_data.memory_id = memory_id self.img_data.width = rect_aoi.s32Width self.img_data.height = rect_aoi.s32Height self.img_data.bits_per_pixel = bits_per_pixel ueye.is_AllocImageMem(h_cam, rect_aoi.s32Width, rect_aoi.s32Height, 24, self.converted_memory_pointer, self.converted_memory_id) def closeEvent(self, event): self.capturing = False ueye.is_DisableEvent(self.hCam, self.frame_event_id) ueye.is_ExitEvent(self.hCam, self.frame_event_id) if ueye.is_CaptureVideo(self.hCam, ueye.IS_GET_LIVE): ueye.is_StopLiveVideo(self.hCam, Wait=True) def switch_capturing(self): if self.capturing: ueye.is_StopLiveVideo(self.hCam, Wait=True) self.capturing = False else: ueye.is_CaptureVideo(self.hCam, Wait=True) self.capturing = True self.display_image() def convert_image_data(self): rect_aoi = ueye.IS_RECT() bits_per_pixel = 24 converted_image_data = ImageData() conversion_params = ueye.BUFFER_CONVERSION_PARAMS() ueye.is_AOI(self.hCam, ueye.IS_AOI_IMAGE_GET_AOI, rect_aoi, ueye.sizeof(rect_aoi)) converted_image_data.memory_pointer = self.converted_memory_pointer converted_image_data.memory_id = self.converted_memory_id converted_image_data.width = rect_aoi.s32Width converted_image_data.height = rect_aoi.s32Height converted_image_data.bits_per_pixel = bits_per_pixel conversion_params.nDestPixelFormat = ueye.IS_CM_RGB8_PACKED conversion_params.pSourceBuffer = self.img_data.memory_pointer conversion_params.pDestBuffer = converted_image_data.memory_pointer conversion_params.nDestPixelConverter = ueye.IS_CONV_MODE_SOFTWARE_3X3 conversion_params.nDestColorCorrectionMode = ueye.IS_CCOR_DISABLE conversion_params.nDestGamma = ueye.INT(100) conversion_params.nDestSaturationU = ueye.INT(100) conversion_params.nDestSaturationV = ueye.INT(100) conversion_params.nDestEdgeEnhancement = ueye.INT(0) ueye.is_Convert(self.hCam, ueye.IS_CONVERT_CMD_APPLY_PARAMS_AND_CONVERT_BUFFER, conversion_params, ueye.sizeof(conversion_params)) return converted_image_data def free_image_mem(self, mempointer, memid): ueye.is_FreeImageMem(self.hCam, mempointer, memid) def display_image(self): fps = ueye.DOUBLE() ueye.is_GetFramesPerSecond(self.hCam, fps) timeout = int((5 / fps) * 1000) h_event = None if platform.system() == 'Windows': h_event = win32event.CreateEvent(None, False, False, None) self.event = ueye.HANDLE(int(h_event)) ueye.is_InitEvent(self.hCam, self.event, self.frame_event_id) ueye.is_EnableEvent(self.hCam, self.frame_event_id) while True: ret = None if not self.capturing: break if platform.system() == 'Windows': ret = win32event.WaitForSingleObject(h_event, timeout) elif platform.system() == 'Linux': ret = ueye.is_WaitEvent(self.hCam, self.frame_event_id, timeout) if ret == 0: converted_image_data = self.convert_image_data() self.image_data_copy = ( ueye.CHAR * int(self.img_data.width * self.img_data.height * 3))() ueye.is_CopyImageMem( hCam=self.hCam, pcSource=converted_image_data.memory_pointer, nID=converted_image_data.memory_id, pcDest=self.image_data_copy) bytes_per_pixel = 3 self.image_data_copy = numpy.reshape( self.image_data_copy, (int(self.img_data.height), int( self.img_data.width), bytes_per_pixel)) self.image_data_copy = self.image_data_copy.view(numpy.uint8) self.pil_image = Image.fromarray(self.image_data_copy) self.graphics_scene.clear() self.width, self.height = self.pil_image.size self.qt_image = ImageQt.ImageQt(self.pil_image) self.pix_map = QPixmap.fromImage(self.qt_image) self.graphics_scene.addPixmap(self.pix_map) self.graphics_view.fitInView( QRectF(0, 0, self.width, self.height), Qt.KeepAspectRatio) self.graphics_scene.update() app.processEvents()
class ExamReorientWindow(QDialog): """Widget to flip page images if they happen to be upsidedown. User selects how many pages in the group, the image is then split into that number of sub-images. They can then be flipped independently. The result is then saved. """ def __init__(self, fname): QGraphicsWidget.__init__(self) self.initUI(fname) def initUI(self, fname): # Grab the image filename. self.fname = fname # Set up a QGraphicsScene and QGraphicsView self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) # Create a pixmap of the file and corresponding item self.image = QPixmap(self.fname) self.imageItem = QGraphicsPixmapItem(self.image) self.imageItem.setTransformationMode(Qt.SmoothTransformation) # Set scene dimensions to that of the image. self.scene.setSceneRect(0, 0, self.image.width(), self.image.height()) # Set the view to encompass the image. self.scene.addItem(self.imageItem) self.view.fitInView(self.imageItem, Qt.KeepAspectRatio) # Spinbox for entering the number of pages in the image self.partL = QLabel("Number of pages") self.partSB = QSpinBox() self.partSB.setValue(1) self.partSB.setRange(1, 9) # Buttons and connections to functions self.splitB = QPushButton("Split") self.splitB.clicked.connect(self.splitIt) self.acceptB = QPushButton("Accept") self.acceptB.clicked.connect(self.acceptIt) self.cancelB = QPushButton("Cancel") self.cancelB.clicked.connect(self.reject) # The void button will become a flip button for each page self.voidB = QPushButton() self.voidB.setEnabled(False) # lay out buttons etc self.grid = QGridLayout() self.grid.addWidget(self.partL, 1, 1) self.grid.addWidget(self.partSB, 1, 2) self.grid.addWidget(self.view, 1, 3, 3, 3) self.grid.addWidget(self.voidB, 5, 3, 1, 3) self.grid.addWidget(self.splitB, 2, 1, 2, 1) self.grid.addWidget(self.acceptB, 10, 2) self.grid.addWidget(self.cancelB, 10, 1) self.setLayout(self.grid) self.show() def splitIt(self): """Split the groupimage into user-selected number of pages and create individual page-flip buttons. """ self.splitB.setEnabled(False) n = self.partSB.value() self.grid.removeWidget(self.view) self.grid.addWidget(self.view, 1, 3, 3, n) # remove the voidButton and replace with a button for each page. self.grid.removeWidget(self.voidB) self.flip = {} for k in range(n): self.flip[k] = QPushButton("{}".format(k)) self.flip[k].clicked.connect(lambda: self.flipPage()) self.grid.addWidget(self.flip[k], 5, 3 + k) # remove the original image and paste in each nth portion of it. self.scene.removeItem(self.imageItem) w = self.image.width() // n h = self.image.height() # Each split image and corresponding graphicsitem self.splitImg = {} self.splitImgI = {} for k in range(n): self.splitImg[k] = self.image.copy(w * k, 0, w, h) self.splitImgI[k] = QGraphicsPixmapItem(self.splitImg[k]) self.splitImgI[k].setPos(w * k, 0) # Flip around centre. self.splitImgI[k].setTransformOriginPoint(w // 2, h // 2) # Place into the scene self.scene.addItem(self.splitImgI[k]) self.view.fitInView(0, 0, w * n, h) def flipPage(self): # rotate the relevant nth of the groupimage by 180 around its centre sender = self.sender() k = int(sender.text().replace("&", "")) if self.splitImgI[k].rotation() == 0: self.splitImgI[k].setRotation(180) else: self.splitImgI[k].setRotation(0) def acceptIt(self): # Accept the result and save. w = self.image.width() h = self.image.height() # create pixmap of scene and painter to render it. oimg = QPixmap(w, h) exporter = QPainter(oimg) self.scene.render(exporter) exporter.end() # save result to file. oimg.save(self.fname) self.accept()
class SpecifyTarget(Plugin): def __init__(self, parent=None): super(SpecifyTarget, self).__init__() self.setObjectName('specify_target') # should be plugin name # ~ self.needsGraphicsView = True self.needsEventFilter = True self.fname = '' self.image = None self.targetImg = None # declare all parameter widgets below vbox1 = QVBoxLayout() hbox1 = QHBoxLayout() self.dblNumTargets = QDoubleSpinBox(objectName='dblNumTargets') self.dblNumTargets.setMinimum(1) self.dblNumTargets.setMaximum(5) self.dblNumTargets.setValue(1) self.dblNumTargets.setSingleStep(1) self.chkSaveTarget = QCheckBox('save target.png', objectName='chkSaveTarget') hbox1.addWidget(self.dblNumTargets) hbox1.addWidget(QLabel('num targets')) hbox1.addWidget(self.chkSaveTarget) labels = ['Rectangle', 'Square', 'Ellipse', 'Circle'] groupBox1, self.bgrpShape = radio_filler('target shape', labels, 2) labels = ['opposite\ncorners', 'center\n-edge'] groupBox2, self.bgrpDrawMethod = radio_filler('draw method', labels, 2) self.lblStatus = QLabel(wordWrap=True) groupBox2.layout().addWidget(self.lblStatus, 0, 2) self.bgrpShape.button(0).setChecked(True) self.bgrpDrawMethod.button(0).setChecked(True) self.bgrpShape.buttonClicked.connect(self.radio_handler) self.targetView = QGraphicsView() scene = QGraphicsScene() self.targetView.setScene(scene) # ~ vbox1.addLayout(hbox1) # ~ vbox1.addWidget(groupBox1) vbox1.addWidget(self.targetView) vbox1.addWidget(groupBox2) vbox1.setStretch(0, 3) vbox1.setStretch(1, 1) self.setLayout(vbox1) self.chkSaveTarget.setChecked(True) # class variables self.targetShape = None self.target = None self.begin = None self.end = None self.training = False def getParams(self): params = super(SpecifyTarget, self).getParams() params['fname'] = self.fname self.Params = params return params def setParams(self, params): params = super(SpecifyTarget, self).setParams(params) self.fname = self.Params['fname'] def showImg(self, img): if len(img.shape) == 3: # ~ #img = cv.cvtColor(img, cv.COLOR_BGR2RGB) height, width, bpc = img.shape bpl = bpc * width # ~ print(subimage.data, ', ', width, ', ', height, ', ', bpl) qimg = QImage(img, width, height, bpl, QImage.Format_RGB888) else: height, width = img.shape bpc = 1 bpl = bpc * width qimg = QImage(img.data, width, height, bpl, QImage.Format_Grayscale8) self.image = QGraphicsPixmapItem(QPixmap.fromImage(qimg)) self.targetImg = img self.targetView.scene().clear() self.targetView.scene().addItem(self.image) self.targetView.fitInView(self.image.boundingRect(), Qt.KeepAspectRatio) def eventFilter(self, source, event): if event.type() == QtCore.QEvent.MouseButtonPress: print(time.time(), ' mousebuttonpress') if isinstance(source, QGraphicsView): self.mouseButtonPress(source) return True elif isinstance( source, QGraphicsView) or source.objectName() == 'MainWindowWindow': if self.training: if (event.type() == QtCore.QEvent.MouseMove and source.objectName() == 'MainWindowWindow'): if event.buttons() != QtCore.Qt.NoButton: # ~ global end self.mouseMove() return True elif (event.type() == QtCore.QEvent.MouseButtonRelease and source.objectName() == 'MainWindowWindow'): self.mouseButtonRelease() return True # this is for eventFilter. when True, stop processing events return False # this is for eventFilter. when False, keep processing events def mouseButtonPress(self, source): pos = QtGui.QCursor.pos() viewPoint = source.mapFromGlobal(pos) scenePoint = source.mapToScene(viewPoint) # ~ global graphicsView self.graphicsView = source self.begin = scenePoint self.training = True # ~ print(pos) # ~ print(self.begin) rect = QRectF(self.begin, self.begin) # ~ print(rect) # ~ self.targetShape = QGraphicsRectItem(rect) # ~ global targetShapes if self.targetShape is not None: try: print('targetShape ', self.targetShape) source.scene().removeItem(self.targetShape) except RuntimeError: pass # ~ bshape = self.bgrpShape.checkedId() bshape = 0 # ~ print('bshape ', bshape) if bshape == 0: # Rectangle self.targetShape = QGraphicsRectItem(rect) elif bshape == 1: # Square self.targetShape = QGraphicsRectItem(rect) elif bshape == 2: # Ellipse self.targetShape = QGraphicsEllipseItem(rect) elif bshape == 3: # Circle self.targetShape = QGraphicsEllipseItem(rect) self.targetShape.setZValue(1) pen = QPen(QColor(0, 255, 0), 5) self.targetShape.setPen(pen) try: source.scene().addItem(self.targetShape) except RuntimeError: pass print('mousie pressie') def mouseMove(self): pos = QtGui.QCursor.pos() viewPoint = self.graphicsView.mapFromGlobal(pos) scenePoint = self.graphicsView.mapToScene(viewPoint) self.end = scenePoint # ~ print('end :', self.end) try: # ~ bshape = self.bgrpShape.checkedId() bshape = 0 bmethod = self.bgrpDrawMethod.checkedId() if bshape == 3: # circle if bmethod == 1: # center radius circle r = QLineF(self.begin, self.end).length() cx = self.begin.x() cy = self.begin.y() # ~ x1 = self.begin.x() - r # ~ y1 = self.begin.y() - r # ~ x2 = self.begin.x() + r # ~ y2 = self.begin.y() + r elif bmethod == 0: r = QLineF(self.begin, self.end).length() / 2 # ~ center = line.center() # not available until qt > 5.8 cx = float(self.begin.x() + self.end.x()) / 2.0 cy = float(self.begin.y() + self.end.y()) / 2.0 x1 = cx - r y1 = cy - r x2 = cx + r y2 = cy + r # ~ print('begin ', self.begin, ' end ', self.end) # ~ print('r ', r, ' cx ', cx, ' cy ', cy) elif bshape == 1: # square if bmethod == 1: # center radius circle r = QLineF(self.begin, self.end).length() / np.sqrt(2) cx = self.begin.x() cy = self.begin.y() x1 = cx - r y1 = cy - r x2 = cx + r y2 = cy + r elif bmethod == 0: line = QLineF(self.begin, self.end) r = line.length() / np.sqrt(2) sx = np.sign(line.dx()) sy = np.sign(line.dy()) x1 = self.begin.x() y1 = self.begin.y() x2 = self.begin.x() + sx * r y2 = self.begin.y() + sy * r #rectangles and ellipses else: if bmethod == 0: # 2 corners rectangle x1 = self.begin.x() y1 = self.begin.y() x2 = self.end.x() y2 = self.end.y() elif bmethod == 1: # center/corner rectangle x1 = self.begin.x() - abs(self.begin.x() - self.end.x()) y1 = self.begin.y() - abs(self.begin.y() - self.end.y()) x2 = self.begin.x() + abs(self.begin.x() - self.end.x()) y2 = self.begin.y() + abs(self.begin.y() - self.end.y()) # ~ self.targetShape.setRect(QRectF(begin, end)) # ~ idx = len(self.targetShapes)-1 self.targetShape.setRect(QRectF(QPointF(x1, y1), QPointF(x2, y2))) self.lblStatus.setText('drawing target') # ~ print('x1, y1, x2, y2: ', x1, y1, x2, y2) except RuntimeError as e: # ~ pass print('RuntimeError in mouseMove. ', e) def mouseButtonRelease(self): self.training = False # time to save target image. but first we need to # check the sizes self.graphicsItems.append(self.targetShape) # only save to target.png if checkbox is checked # ~ if self.chkSaveTarget.isChecked(): try: rect = self.targetShape.rect() print('target rect ', rect) x1 = int(round(min([rect.left(), rect.right()]))) y1 = int(round(min([rect.top(), rect.bottom()]))) x2 = int(round(max([rect.left(), rect.right()]))) y2 = int(round(max([rect.top(), rect.bottom()]))) # ~ print( 'x1, x2, y1, y2: %d, %d, %d, %d' % (x1, x2, y1, y2)) # ~ print('width: ', rect.width(), '. height: ', rect.height()) # for circle and ellipse, we want width and height to be divisible # by two. so we'll add an extra pixel if necessary x2 += (x2 - x1) % 2 # remainder will be 1 for odd widths y2 += (y2 - y1) % 2 # ~ print( 'x2, y2: %d, %d' % (x2, y2)) if abs(y2 - y1) > 20: # ~ dx = x2-x1 # ~ dy = y2-y1 # use +1 because slice notation is screwy subimage = self.inputImg[y1:y2, x1:x2].copy() self.showImg(subimage) if subimage.ndim == 3: subimage = cv.cvtColor(subimage, cv.COLOR_RGB2BGR) fname = 'target_' + str(uuid4()) + '.png' # ~ print(fname) self.fname = fname cv.imwrite(fname, subimage) self.lblStatus.setText('target set') else: self.lblStatus.setText('') self.graphicsView.scene().removeItem(self.targetShape) except RuntimeError as e: print('RuntimeError in mouseButtonRelease. ', e) def mainFunc(self, playing, scriptList, row): # ~ print(self.inputImg) if self.inputImg is not None: self.outputImg = self.inputImg # here we don't even need to # make a copy. it's a straight # pass through. # ~ self.outputImg = self.inputImg.copy() # ~ print('copy') if self.image is None: if self.fname: img = cv.imread(self.fname) if img is None: self.lblStatus.setText('target file not found') else: if img.ndim == 3: img = cv.cvtColor(img, cv.COLOR_BGR2RGB) self.showImg(img) def resizeEvent(self, event=0): try: rect = self.targetView.scene().items()[0].boundingRect() self.targetView.fitInView(rect, Qt.KeepAspectRatio) except IndexError: pass def radio_handler(self): self.bgrpDrawMethod.button(1).setChecked(True)
class MapWidget(QtWidgets.QFrame): """ Custom tab widget with function for editing templates """ mapItem_delete_signal = QtCore.pyqtSignal(object) def __init__(self, parent, mainWindow): super().__init__(parent) self.mainWindow = mainWindow self.mapManager = MapManager() self.map = None self.init_bar() self.init_ui() self.mapItem_delete_signal.connect(self.item_delete_slot) def init_ui(self): """ Init map widget UI :return: """ self.setFrameShape(QtWidgets.QFrame.NoFrame) self.frameLayout = QtWidgets.QVBoxLayout(self) self.frameLayout.setObjectName("Frame layout") self.grview = QGraphicsView() self.grview.setRenderHints(self.grview.renderHints() | QPainter.Antialiasing | QPainter.SmoothPixmapTransform) self.scene = QGraphicsScene() # scene.setSceneRect(0, 0, 1500, 459) self.grview.setScene(self.scene) noMap = QPixmap('resources/icons/no_map.png') self.scene.addPixmap(noMap) self.grview.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) self.frameLayout.addWidget(self.grview) def init_bar(self) -> None: """ Init function bar, set to right side of widget :return: """ toolbar = QToolBar() toolbar.setObjectName('MapToolbar') self.mainWindow.addToolBar(Qt.RightToolBarArea, toolbar) # ------------------------------- Open map ---------------------------------- self.openMap_action = QAction(QIcon('resources/icons/openMap.png'), TR().tr('Open_map'), self.mainWindow, triggered=self.open_map_action, enabled=False) toolbar.addAction(self.openMap_action) # ------------------------------- Zoom in ---------------------------------- self.zoomIn_action = QAction(QIcon('resources/icons/zoomIn.png'), TR().tr('Zoom_in'), self.mainWindow, triggered=self.zoom_in_action, shortcut='Ctrl++', enabled=False) toolbar.addAction(self.zoomIn_action) # ------------------------------- Zoom out ---------------------------------- self.zoomOut_action = QAction(QIcon('resources/icons/zoomOut.png'), TR().tr('Zoom_out'), self.mainWindow, triggered=self.zoom_out_action, shortcut='Ctrl++', enabled=False) toolbar.addAction(self.zoomOut_action) # ------------------------------- Edit info ---------------------------------- self.info_action = QAction(QIcon('resources/icons/scroll.png'), TR().tr('Edit_info'), self.mainWindow, triggered=self.edit_info_action, shortcut='Ctrl+P', enabled=False) toolbar.addAction(self.info_action) toolbar.addSeparator() # ------------------------------- Add monster ---------------------------------- self.addMonster_action = QAction(QIcon('resources/icons/addMonster.png'), TR().tr('Add_monster'), self.mainWindow, triggered=self.add_monster_action, shortcut='Ctrl+M', enabled=False) toolbar.addAction(self.addMonster_action) # ------------------------------- Add item ---------------------------------- self.addItem_action = QAction(QIcon('resources/icons/addItem.png'), TR().tr('Add_item'), self.mainWindow, triggered=self.add_item_action, enabled=False) toolbar.addAction(self.addItem_action) # ------------------------------- Add room ---------------------------------- self.addRoom_action = QAction(QIcon('resources/icons/addRoom.png'), TR().tr('Add_room'), self.mainWindow, triggered=self.add_room_action, enabled=False) toolbar.addAction(self.addRoom_action) # ------------------------------- Add object ---------------------------------- self.addObject_action = QAction(QIcon('resources/icons/addObject.png'), TR().tr('Add_object_map'), self.mainWindow, triggered=self.add_object_action, enabled=False) toolbar.addAction(self.addObject_action) def enable_tool_bar(self) -> None: """ Enable tool bar actions """ self.openMap_action.setEnabled(True) self.zoomIn_action.setEnabled(True) self.zoomOut_action.setEnabled(True) self.info_action.setEnabled(True) self.addItem_action.setEnabled(True) self.addRoom_action.setEnabled(True) self.addMonster_action.setEnabled(True) self.addObject_action.setEnabled(True) def tree_item_doubleclick_action(self, item) -> None: """ Slot for double click on map at tree widget :param item: item in tree widget """ if self.map: self.save_map() if item: if item.data(0, 11).object_type is not ObjectType.MAP: self.mainWindow.redraw_context_widget(item.data(0, 11).object_type, item) else: self.enable_tool_bar() map = MapDAO().get(item.data(0, 11).id) if self.map and self.map.id == map.id: map = MapDAO().get(item.data(0, 11).id) self.map = map self.redraw() def item_delete_slot(self, mapItem) -> None: """ Slot for deleting map item from map. Deleted from map and updated in database :param mapItem: map item, that you want to delete :return: """ # mapItem.number self.map.mapItemDraws.remove(self.map.mapItemDraws[mapItem.number - 1]) MapItemDAO().delete(mapItem.mapItem.id) # self.redraw() def save_map(self) -> None: """ Save image of map :return: """ self.mapManager.update(self.map) self.save_map_action() def redraw(self) -> None: """ Redraw scene in widget Whole scene is cleared and new map and map items is draw """ self.scene.clear() if self.map.mapFile: pixMap = QPixmap(self.map.mapFile) sceneMap = self.scene.addPixmap(pixMap) self.map.mapPixMap = sceneMap self.grview.fitInView(self.scene.itemsBoundingRect(), Qt.KeepAspectRatio) for num, mapItem in enumerate(self.map.mapItems): mapItem.number = num + 1 item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def open_map_action(self) -> None: """ Open image with map slot, if some map is here, old one is deleted """ fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self.mainWindow, "Open File", QtCore.QDir.currentPath()) if fileName: if self.map.mapPixMap: self.scene.removeItem(self.map.mapPixMap) fileName = self.mapManager.copy_map(fileName, self.map) self.map.mapFile = fileName self.map.mapPixMap = self.scene.addPixmap(QPixmap(fileName)) self.grview.fitInView(self.scene.itemsBoundingRect(), Qt.KeepAspectRatio) def zoom_in_action(self) -> None: """ Zoom in whole map widget """ self.grview.scale(1.2, 1.2) def zoom_out_action(self) -> None: """ Zoom out whole map widget """ self.grview.scale(0.8, 0.8) def add_item_action(self) -> None: """ Add item to map :return: """ data, choice = NewMapItem.get_data() if choice: number = len(self.map.mapItemDraws) + 1 mapItem = MapItem(None, data.get('name', ''), data.get('description', ''), QPointF(), 0, number, None, self.map.id, MapItemType.ITEM) id = MapItemDAO().create(mapItem) mapItem.id = id item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def add_monster_action(self) -> None: """ Add monster to map :return: """ data, choice = NewMapItem.get_data() if choice: number = len(self.map.mapItemDraws) + 1 mapItem = MapItem(None, data.get('name', ''), data.get('description', ''), QPointF(), 0, number, None, self.map.id, MapItemType.MONSTER) id = MapItemDAO().create(mapItem) mapItem.id = id item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def add_room_action(self) -> None: """ Add room to map :return: """ data, choice = NewMapItem.get_data() if choice: number = len(self.map.mapItemDraws) + 1 mapItem = MapItem(None, data.get('name', ''), data.get('description', ''), QPointF(), 0, number, None, self.map.id, MapItemType.ROOM) id = MapItemDAO().create(mapItem) mapItem.id = id item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def add_object_action(self) -> None: """ Add object to map :return: """ data, choice = NewMapItem.get_data() if choice: number = len(self.map.mapItemDraws) + 1 mapItem = MapItem(None, data.get('name', ''), data.get('description', ''), QPointF(), 0, number, None, self.map.id, MapItemType.OBJECT) id = MapItemDAO().create(mapItem) mapItem.id = id item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def edit_info_action(self) -> None: """ Edit map info, when click on edit button """ data, choice = EditMapItem.get_data(None, self.map) if choice: self.map.name = data['name'] self.map.description = data['description'] def save_map_action(self): """ Save whole map action. This action create image from map :return: """ self.scene.clearSelection() self.scene.setSceneRect(self.scene.itemsBoundingRect()) img = QImage(self.scene.sceneRect().size().toSize(), QImage.Format_ARGB32) img.fill(Qt.transparent) painter = QPainter(img) self.scene.render(painter) name = 'resources/maps/exportedMap-{}.png'.format(self.map.id) img.save(name) del painter def drawItems(self, painter, items, options, widget=None): pass
class PeakListArea(QWidget): """ A widget containing a QGraphicsScene for rendering the drag and drop creation of the Farseer-NMR cube. When a peaklist is dropped on a PeakListLabel instance, the variables instance is updated and its position in the Farseer-NMR cube is specified. Parameters: parent (QWidget): specifies the parent widget containing the QLabel and the QSpinBox. gui_settings (dict): a dictionary carrying the settings required to correctly render the graphics based on screen resolution. Methods: .setEvents() .side_bar() .update_variables() .show_update_warning() .show_duplicate_key_warning() .update_experimental_dataset(values_dict) .check_conditions_for_tree() .update_tree() .add_connecting_line() """ variables = Variables()._vars def __init__(self, parent, gui_settings): QWidget.__init__(self, parent) self.scene = QGraphicsScene(self) self.height = gui_settings['peaklistarea_height'] self.scrollContents = QGraphicsView(self.scene, self) self.scrollContents.setRenderHint(QtGui.QPainter.Antialiasing) self.scene.setSceneRect(0, 0, width, self.height) layout = QGridLayout() self.setLayout(layout) self.layout().addWidget(self.scrollContents) self.scrollContents.setMinimumSize(gui_settings['scene_width'], gui_settings['scene_height']) self.scrollContents.setAcceptDrops(True) self.set_events() self.updateClicks = 0 def set_events(self): self.scrollContents.scene().dragEnterEvent = self._dragEnterEvent def _dragEnterEvent(self, event): event.accept() def side_bar(self): return self.parent().parent().parent().side_bar def update_variables(self): self.update_tree() def show_update_warning(self): msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Reset Experimental Series") msg.setInformativeText("Do you want to all peaklists from the " "Experimental Series and re-draw the series?") msg.setWindowTitle("Reset Experimental Series") msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) retval = msg.exec_() return retval def show_duplicate_key_warning(self, axis): msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Duplicate conditions") msg.setInformativeText("There are duplicate " "conditions on the {} axis. ".format(axis)) msg.setWindowTitle("Duplicate conditions") msg.setStandardButtons(QMessageBox.Ok) retval = msg.exec_() return retval def show_empty_condition_warning(self): msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Empty conditions") msg.setInformativeText("There are empty conditions, " "so dataset cannot be drawn.") msg.setWindowTitle("Empty conditions") msg.setStandardButtons(QMessageBox.Ok) retval = msg.exec_() return retval def update_experimental_dataset(self, values_dict): tmp_dict = {} for z in values_dict["z"]: tmp_dict[z] = {} for y in values_dict["y"]: tmp_dict[z][y] = {} for x in values_dict["x"]: tmp_dict[z][y][x] = '' if self.variables["experimental_dataset"][z][y].keys(): tmp_dict[z][y][x] = \ self.variables["experimental_dataset"][z][y][x] return tmp_dict def check_conditions_for_tree(self): self.values_dict = self.variables["conditions"] # Check if condition boxes are empty and throw warning if so. if not all(x for v in self.values_dict.values() for x in v): self.show_empty_condition_warning() return False if len(set(self.values_dict['z'])) != len(self.values_dict['z']): self.show_duplicate_key_warning('z') return False if len(set(self.values_dict['y'])) != len(self.values_dict['y']): self.show_duplicate_key_warning('y') return False if len(set(self.values_dict['x'])) != len(self.values_dict['x']): self.show_duplicate_key_warning('x') return False return True def update_tree(self): if not self.check_conditions_for_tree(): return if self.updateClicks > 0: if self.show_update_warning() == QMessageBox.Cancel: return self.peak_list_objects = [] self.peak_list_dict = {} self.show() self.side_bar().refresh_sidebar() self.scene.clear() z_conds = self.values_dict['z'] y_conds = self.values_dict['y'] x_conds = self.values_dict['x'] num_x = len(x_conds) num_y = len(y_conds) num_z = len(z_conds) total_x = num_x * num_y * num_z keys_to_remove = [ k for k in self.variables['fasta_files'].keys() if k not in y_conds ] for k in keys_to_remove: del self.variables['fasta_files'][k] if total_x > 10: self.scrollContents.setSceneRect(0, 0, width, total_x * 22) else: self.scrollContents.setSceneRect(0, 0, width, self.height) self.scrollContents.fitInView(0, 0, width, self.height, QtCore.Qt.KeepAspectRatio) if total_x < 2: x_spacing = self.scene.height() / 2 elif 2 < total_x < 10: x_spacing = self.scene.height() / (total_x + 1) else: x_spacing = 20 zz_pos = 0 yy_pos = self.scene.width() * 0.25 xx_pos = self.scene.width() * 0.5 pl_pos = self.scene.width() * 0.75 xx_vertical = x_spacing num = 0 for i, z in enumerate(z_conds): self.peak_list_dict[z] = {} y_markers = [] for j, y in enumerate(y_conds): self.peak_list_dict[z][y] = {} x_markers = [] for k, x in enumerate(x_conds): xx = ConditionLabel(str(x), [xx_pos, xx_vertical]) self.scene.addItem(xx) if z not in self.variables["experimental_dataset"].keys() \ or y not in self.variables["experimental_dataset"][z].keys() \ or x not in self.variables["experimental_dataset"][z][y].keys(): pl = PeakListLabel(self, 'Drop peaklist here', self.scene, [pl_pos, xx_vertical], x_cond=x, y_cond=y, z_cond=z) self.peak_list_dict[z][y][x] = '' elif not self.variables["experimental_dataset"][z][y][x]: pl = PeakListLabel(self, 'Drop peaklist here', self.scene, [pl_pos, xx_vertical], x_cond=x, y_cond=y, z_cond=z) self.peak_list_dict[z][y][x] = '' else: pl_name = self.variables["experimental_dataset"][z][y][ x] pl = PeakListLabel(self, pl_name, self.scene, [pl_pos, xx_vertical], x_cond=x, y_cond=y, z_cond=z, peak_list=pl_name) self.peak_list_dict[z][y][x] = pl_name self.side_bar()._raise_context_menu(pl_name) self.peak_list_objects.append(pl) self.scene.addItem(pl) self.add_connecting_line(xx, pl) x_markers.append(xx) num += 1 xx_vertical += x_spacing if len(x_markers) % 2 == 1: yy_vertical = x_markers[int(math.ceil(len(x_markers)) / 2)].y() else: yy_vertical = x_markers[int( math.ceil(len(x_markers)) / 2)].y() - (x_spacing / 2) yy = ConditionLabel(str(y), [yy_pos, yy_vertical]) y_markers.append(yy) self.scene.addItem(yy) for x_marker in x_markers: self.add_connecting_line(yy, x_marker) if len(y_markers) % 2 == 1: zz_vertical = y_markers[int(math.ceil(len(y_markers)) / 2)].y() else: zz_vertical = (y_markers[0].y() + y_markers[-1].y()) / 2 zz = ConditionLabel(str(z), [zz_pos, zz_vertical]) self.scene.addItem(zz) for x_marker in y_markers: self.add_connecting_line(zz, x_marker) self.updateClicks += 1 self.variables["experimental_dataset"] = self.peak_list_dict def add_connecting_line(self, atom1, atom2): if atom1.y() > atom2.y(): y1 = atom1.y() + (atom1.boundingRect().height() * .5) y2 = atom2.y() + (atom2.boundingRect().height() * .5) elif atom1.y() < atom2.y(): y1 = atom1.y() + (atom1.boundingRect().height() * .5) y2 = atom2.y() + (atom2.boundingRect().height() * .5) else: y1 = atom1.y() + (atom1.boundingRect().height() * 0.5) y2 = atom2.y() + (atom2.boundingRect().height() * 0.5) if atom1.x() > atom2.x(): x1 = atom1.x() x2 = atom2.x() + atom2.boundingRect().width() elif atom1.x() < atom2.x(): x1 = atom1.x() + atom1.boundingRect().width() x2 = atom2.x() else: x1 = atom1.x() + (atom1.boundingRect().width() / 2) x2 = atom2.x() + (atom1.boundingRect().width() / 2) new_line = QGraphicsLineItem(x1, y1, x2, y2) pen = QtGui.QPen() pen.setColor(QtGui.QColor("#FAFAF7")) pen.setCosmetic(True) pen.setWidth(1) new_line.setPen(pen) self.scene.addItem(new_line)
class QGameOfLife(QWidget): Games = { "Game of Life": (GameOfLife, { 'fill_rate': 0.50 }), "Bacteria": (GrayScottDiffusion, { 'coeffs': (0.16, 0.08, 0.035, 0.065) }), "Coral": (GrayScottDiffusion, { 'coeffs': (0.16, 0.08, 0.062, 0.062) }), "Fingerprint": (GrayScottDiffusion, { 'coeffs': (0.19, 0.05, 0.060, 0.062) }), "Spirals": (GrayScottDiffusion, { 'coeffs': (0.10, 0.10, 0.018, 0.050) }), "Unstable": (GrayScottDiffusion, { 'coeffs': (0.16, 0.08, 0.020, 0.055) }), "Worms": (GrayScottDiffusion, { 'coeffs': (0.16, 0.08, 0.050, 0.065) }), "Zebrafish": (GrayScottDiffusion, { 'coeffs': (0.16, 0.08, 0.035, 0.060) }), } def __init__(self, size=(400, 400)): super(QGameOfLife, self).__init__() self.size = size self.game = None self.initUI() self.show() def initUI(self): self.setWindowTitle(self.tr("Game of Life")) self.setLayout(QVBoxLayout()) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self.comboBox = QComboBox() self.comboBox.addItems(QGameOfLife.Games.keys()) self.comboBox.currentTextChanged.connect(self.select) self.layout().addWidget(self.comboBox) self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setSizePolicy( QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)) self.view.setFrameShape(QFrame.NoFrame) self.layout().addWidget(self.view) self.item = None self.timer = QTimer() self.timer.setInterval(10) self.timer.timeout.connect(self.tick) initialGame = random.choice(list(QGameOfLife.Games.keys())) self.select(initialGame) self.view.fitInView(self.item, Qt.KeepAspectRatioByExpanding) self.comboBox.setCurrentText(initialGame) def select(self, name: str): self.timer.stop() Game, args = QGameOfLife.Games[name] self.game = Game(self.size, **args) self.tick() self.timer.start() def tick(self): self.game.tick() bitmap = self.game.visualize() image = QImage(bitmap.data, bitmap.shape[1], bitmap.shape[0], QImage.Format_Grayscale8) self.scene.removeItem(self.item) pixmap = QPixmap.fromImage(image) self.item = self.scene.addPixmap(pixmap) def resizeEvent(self, event: QResizeEvent): self.view.fitInView(self.item, Qt.KeepAspectRatioByExpanding) def sizeHint(self) -> QSize: return QSize(self.size[0], self.size[1])
class View(QWidget): trigger_focus_event = QtCore.pyqtSignal(str) def __init__(self, emacs_xid, buffer, view_info): super(View, self).__init__() self.buffer = buffer self.emacs_xid = emacs_xid # Init widget attributes. self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True) self.setContentsMargins(0, 0, 0, 0) self.installEventFilter(self) # Init attributes. self.view_info = view_info (self.buffer_id, self.x, self.y, self.width, self.height) = view_info.split(":") self.x = int(self.x) self.y = int(self.y) self.width = int(self.width) self.height = int(self.height) # Build QGraphicsView. self.layout = QVBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.graphics_view = QGraphicsView(buffer, self) self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing) # Remove damn border from QGraphicsView. self.graphics_view.setFrameStyle(0) self.graphics_view.setStyleSheet( "QGraphicsView {background: transparent; border: 3px; outline: none;}" ) self.layout.addWidget(self.graphics_view) # NOTE: show function must start before resize to trigger *first* resizeEvent after show. self.show() # Resize after show to trigger fit view operation. self.resize(self.width, self.height) def resizeEvent(self, event): # Fit content to view rect just when buffer fit_to_view option is enable. if self.buffer.fit_to_view: if event.oldSize().isValid(): self.graphics_view.fitInView( self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio) QWidget.resizeEvent(self, event) def eventFilter(self, obj, event): # Focus emacs buffer when user click view. if event.type() in [ QEvent.MouseButtonPress, QEvent.MouseButtonRelease, QEvent.MouseMove, QEvent.MouseButtonDblClick, QEvent.Wheel ]: self.trigger_focus_event.emit("{0},{1}".format( event.globalX(), event.globalY())) return False def showEvent(self, event): # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed. self.reparent() # Make graphics view at left-top corner after show. self.graphics_view.verticalScrollBar().setValue(0) self.graphics_view.horizontalScrollBar().setValue(0) def reparent(self): xlib_display = get_xlib_display() view_xid = self.winId().__int__() view_xwindow = xlib_display.create_resource_object("window", view_xid) emacs_xwindow = xlib_display.create_resource_object( "window", self.emacs_xid) view_xwindow.reparent(emacs_xwindow, self.x, self.y) xlib_display.sync() def handle_destroy(self): self.destroy()
class Spectrum(QWidget): """Plot the power spectrum for a specified channel. Attributes ---------- parent : instance of QMainWindow the main window. x_limit : tuple or list 2 values specifying the limit on x-axis y_limit : tuple or list 2 values specifying the limit on y-axis log : bool log-transform the data or not idx_chan : instance of QComboBox the element with the list of channel names. idx_x_min : instance of QLineEdit value with min x value idx_x_max : instance of QLineEdit value with max x value idx_y_min : instance of QLineEdit value with min y value idx_y_max : instance of QLineEdit value with max y value idx_log : instance of QCheckBox widget that defines if log should be used or not idx_fig : instance of QGraphicsView the view with the power spectrum scene : instance of QGraphicsScene the scene with GraphicsItems Notes ----- If data contains NaN, it doesn't create any spectrum (feature or bug?). """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigSpectrum(self.display_window) self.selected_chan = None self.idx_chan = None self.idx_fig = None self.scene = None self.create() def create(self): """Create empty scene for power spectrum.""" self.idx_chan = QComboBox() self.idx_chan.activated.connect(self.display_window) self.idx_fig = QGraphicsView(self) self.idx_fig.scale(1, -1) layout = QVBoxLayout() layout.addWidget(self.idx_chan) layout.addWidget(self.idx_fig) self.setLayout(layout) self.resizeEvent(None) def show_channame(self, chan_name): self.selected_chan = self.idx_chan.currentIndex() self.idx_chan.clear() self.idx_chan.addItem(chan_name) self.idx_chan.setCurrentIndex(0) def update(self): """Add channel names to the combobox.""" self.idx_chan.clear() for chan_name in self.parent.traces.chan: self.idx_chan.addItem(chan_name) if self.selected_chan is not None: self.idx_chan.setCurrentIndex(self.selected_chan) self.selected_chan = None def display_window(self): """Read the channel name from QComboBox and plot its spectrum. This function is necessary it reads the data and it sends it to self.display. When the user selects a smaller chunk of data from the visible traces, then we don't need to call this function. """ if self.idx_chan.count() == 0: self.update() chan_name = self.idx_chan.currentText() lg.debug('Power spectrum for channel ' + chan_name) if chan_name: trial = 0 data = self.parent.traces.data(trial=trial, chan=chan_name) self.display(data) else: self.scene.clear() def display(self, data): """Make graphicsitem for spectrum figure. Parameters ---------- data : ndarray 1D vector containing the data only This function can be called by self.display_window (which reads the data for the selected channel) or by the mouse-events functions in traces (which read chunks of data from the user-made selection). """ value = self.config.value self.scene = QGraphicsScene(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) self.idx_fig.setScene(self.scene) self.add_grid() self.resizeEvent(None) s_freq = self.parent.traces.data.s_freq f, Pxx = welch(data, fs=s_freq, nperseg=int(min( (s_freq, len(data))))) # force int freq_limit = (value['x_min'] <= f) & (f <= value['x_max']) if self.config.value['log']: Pxx_to_plot = log(Pxx[freq_limit]) else: Pxx_to_plot = Pxx[freq_limit] self.scene.addPath(Path(f[freq_limit], Pxx_to_plot), QPen(QColor(LINE_COLOR), LINE_WIDTH)) def add_grid(self): """Add axis and ticks to figure. Notes ----- I know that visvis and pyqtgraphs can do this in much simpler way, but those packages create too large a padding around the figure and this is pretty fast. """ value = self.config.value # X-AXIS # x-bottom self.scene.addLine(value['x_min'], value['y_min'], value['x_min'], value['y_max'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # at y = 0, dashed self.scene.addLine(value['x_min'], 0, value['x_max'], 0, QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DashLine)) # ticks on y-axis y_high = int(floor(value['y_max'])) y_low = int(ceil(value['y_min'])) x_length = (value['x_max'] - value['x_min']) / value['x_tick'] for y in range(y_low, y_high): self.scene.addLine(value['x_min'], y, value['x_min'] + x_length, y, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # Y-AXIS # left axis self.scene.addLine(value['x_min'], value['y_min'], value['x_max'], value['y_min'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # larger ticks on x-axis every 10 Hz x_high = int(floor(value['x_max'])) x_low = int(ceil(value['x_min'])) y_length = (value['y_max'] - value['y_min']) / value['y_tick'] for x in range(x_low, x_high, 10): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # smaller ticks on x-axis every 10 Hz y_length = (value['y_max'] - value['y_min']) / value['y_tick'] / 2 for x in range(x_low, x_high, 5): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) def resizeEvent(self, event): """Fit the whole scene in view. Parameters ---------- event : instance of Qt.Event not important """ value = self.config.value self.idx_fig.fitInView(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) def reset(self): """Reset widget as new""" self.idx_chan.clear() if self.scene is not None: self.scene.clear() self.scene = None
class base_scene_reactor(reactor, qt_drawings): """ Base class for reactor using Qt graphics scene and graphics items. """ def __init__(self): self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setInteractive(False) self.view.setResizeAnchor(QGraphicsView.AnchorViewCenter) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) def widget(self): return self.view def reallocate_scene(self): self.scene = QGraphicsScene() self.view.setScene(self.scene) self.view.resetTransform() self.view.resetCachedContent() self.view.setSceneRect(QRectF()) self.view.fitInView(self.scene.sceneRect().marginsAdded(QMarginsF(10, 10, 10, 10)), Qt.KeepAspectRatio) def reset(self): self.reallocate_scene() def create_scene_tile(self, x: int, y: int, tile) -> QGraphicsItem: x, y = self.pos_to_scene(x, y) width = 2 * qt_drawings.tile_size if tile.is_horizontal else qt_drawings.tile_size height = qt_drawings.tile_size if tile.is_horizontal else 2 * qt_drawings.tile_size item = QGraphicsRectItem(0, 0, width, height) item.setPos(x, y) item.setBrush(qt_drawings.tile_to_brush(tile)) item.setPen(qt_drawings.black_pen) self.scene.addItem(item) return item @staticmethod def create_cross(): item = QGraphicsPolygonItem(qt_drawings.cross_polygon) item.setBrush(qt_drawings.red_brush) item.setPen(qt_drawings.red_pen) return item tile_rotation_angles = [[-90., 90.], [0., 180.]] @staticmethod def create_arrow(tile): item = QGraphicsPolygonItem(qt_drawings.arrow_polygon) item.setPen(qt_drawings.no_pen) if tile: item.setBrush(qt_drawings.cyan_brush if tile.is_frozen else qt_drawings.black_brush) item.setTransformOriginPoint(qt_drawings.tile_size / 2, qt_drawings.tile_size / 2) angle = base_scene_reactor.tile_rotation_angles[tile.is_horizontal][tile.is_positive] item.setRotation(angle) else: item.setBrush(qt_drawings.black_brush) return item def adjust_view_to_fit(self): viewOrigin = self.view.rect().topLeft() sceneOrigin = self.view.mapFromScene(self.scene.sceneRect().translated(-15, -15).topLeft()) if viewOrigin.x() >= sceneOrigin.x() or viewOrigin.y() >= sceneOrigin.y(): #self.view.fitInView(QRectF(0, 0, 50, 50).united(self.scene.sceneRect().marginsAdded(QMarginsF(100, 100, 100, 100))), Qt.KeepAspectRatio) self.view.fitInView(self.scene.sceneRect().marginsAdded(QMarginsF(50, 50, 50, 50)), Qt.KeepAspectRatio) def pos_to_scene(self, x: int, y: int) -> tuple: return (x * qt_drawings.tile_size, y * qt_drawings.tile_size) def middle_pos_to_scene(self, x: int, y: int, tile) -> tuple: if tile: if tile.is_horizontal: x += 0.5 else: y += 0.5 return (x * qt_drawings.tile_size, y * qt_drawings.tile_size)
class View(QWidget): trigger_focus_event = QtCore.pyqtSignal(str) def __init__(self, emacs_xid, buffer, view_info): super(View, self).__init__() self.buffer = buffer self.emacs_xid = emacs_xid # Init widget attributes. self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True) self.setContentsMargins(0, 0, 0, 0) self.installEventFilter(self) # Init attributes. self.view_info = view_info (self.buffer_id, self.x, self.y, self.width, self.height) = view_info.split(":") self.x = int(self.x) self.y = int(self.y) self.width = int(self.width) self.height = int(self.height) # Build QGraphicsView. self.layout = QVBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.graphics_view = QGraphicsView(buffer, self) self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing) # Remove damn border from QGraphicsView. self.graphics_view.setFrameStyle(0) self.graphics_view.setStyleSheet("QGraphicsView {background: transparent; border: 3px; outline: none;}") self.layout.addWidget(self.graphics_view) # NOTE: show function must start before resize to trigger *first* resizeEvent after show. self.show() # Resize after show to trigger fit view operation. self.resize(self.width, self.height) def resizeEvent(self, event): # Fit content to view rect just when buffer fit_to_view option is enable. if self.buffer.fit_to_view: if event.oldSize().isValid(): self.graphics_view.fitInView(self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio) QWidget.resizeEvent(self, event) def eventFilter(self, obj, event): # Focus emacs buffer when user click view. if event.type() in [QEvent.MouseButtonPress, QEvent.MouseButtonRelease, QEvent.MouseMove, QEvent.MouseButtonDblClick, QEvent.Wheel]: # Send mouse event to applicatin view. self.trigger_focus_event.emit("{0},{1}".format(event.globalX(), event.globalY())) # Stop mouse event. return True return False def showEvent(self, event): # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed. self.reparent() # Make graphics view at left-top corner after show. self.graphics_view.verticalScrollBar().setValue(0) self.graphics_view.horizontalScrollBar().setValue(0) def reparent(self): xlib_display = get_xlib_display() view_xid = self.winId().__int__() view_xwindow = xlib_display.create_resource_object("window", view_xid) emacs_xwindow = xlib_display.create_resource_object("window", self.emacs_xid) view_xwindow.reparent(emacs_xwindow, self.x, self.y) xlib_display.sync() def handle_destroy(self): self.destroy()
brush = QBrush(Qt.black) for oeil in yeux: oeil.setBrush(brush) smiley.setPos(rectGris.mapToScene(rectGris.rect().center())) scene.addItem(smiley) smiley.setRotation(20) smiley.setScale(1.5) smiley.setFlag(QGraphicsItem.ItemIsMovable) texte.setZValue(1) # vue principale vue = QGraphicsView(scene) vue.setRenderHints(QPainter.Antialiasing) vue.resize(800, 600) vue.centerOn(rectGris) vue.fitInView(rectGris, Qt.KeepAspectRatio) vue.show() # vues auxiliaires vues = [] for _ in range(4): vuex = QGraphicsView(scene) vues.append(vuex) vuex.setRenderHints(QPainter.Antialiasing) vuex.resize(400, 300) vuex.rotate(360. * random()) vuex.scale(4. * random(), 4. * random()) # pour éviter les déformations, remplacer l'instruction précédente par # f = 4. * random() # vuex.scale(f,f) vuex.show()
class View(QWidget): def __init__(self, buffer, view_info): super(View, self).__init__() self.buffer = buffer # Init widget attributes. if platform.system() == "Darwin": self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) else: self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True) self.setContentsMargins(0, 0, 0, 0) self.installEventFilter(self) # Init attributes. self.view_info = view_info (self.buffer_id, self.emacs_xid, self.x, self.y, self.width, self.height) = view_info.split(":") self.emacs_xid = int(self.emacs_xid) self.x = int(self.x) self.y = int(self.y) self.width = int(self.width) self.height = int(self.height) # Build QGraphicsView. self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) self.graphics_view = QGraphicsView(buffer, self) # Set background color. # When fit_to_view is True, QGraphicsView will fill color around app view. # We fill color with buffer's attribute "background_color". if hasattr(self.buffer, "background_color") and self.buffer.background_color: self.graphics_view.setBackgroundBrush( QBrush(self.buffer.background_color)) # Remove border from QGraphicsView. self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing) self.graphics_view.setFrameStyle(QFrame.NoFrame) # Add graphics view. self.layout.addWidget(self.graphics_view) # NOTE: show function must start before resize to trigger *first* resizeEvent after show. self.show() # Resize after show to trigger fit view operation. self.resize(self.width, self.height) self.buffer.aspect_ratio_change.connect(self.adjust_aspect_ratio) def resizeEvent(self, event): # Fit content to view rect just when buffer fit_to_view option is enable. if self.buffer.fit_to_view: if event.oldSize().isValid(): self.graphics_view.fitInView( self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio) QWidget.resizeEvent(self, event) def adjust_aspect_ratio(self): widget_width = self.width widget_height = self.height if self.buffer.aspect_ratio == 0: self.buffer.buffer_widget.resize(self.width, self.height) self.layout.setContentsMargins(0, 0, 0, 0) else: view_height = widget_height * ( 1 - 2 * self.buffer.vertical_padding_ratio) view_width = view_height * self.buffer.aspect_ratio horizontal_padding = (widget_width - view_width) / 2 vertical_padding = self.buffer.vertical_padding_ratio * widget_height self.buffer.buffer_widget.resize(view_width, view_height) self.layout.setContentsMargins(horizontal_padding, vertical_padding, horizontal_padding, vertical_padding) def eventFilter(self, obj, event): # import time # print(time.time(), event.type()) if event.type() in [QEvent.ShortcutOverride]: eval_in_emacs('eaf-activate-emacs-window', [self.buffer_id]) # Focus emacs buffer when user click view. event_type = [ QEvent.MouseButtonPress, QEvent.MouseButtonRelease, QEvent.MouseButtonDblClick ] if platform.system() != "Darwin": event_type += [QEvent.Wheel] if event.type() in event_type: focus_emacs_buffer(self.buffer_id) # Stop mouse event. return True return False def showEvent(self, event): # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed. self.reparent() if platform.system() in ["Windows", "Darwin"]: eval_in_emacs('eaf-activate-emacs-window', []) # Make graphics view at left-top corner after show. self.graphics_view.verticalScrollBar().setValue(0) self.graphics_view.horizontalScrollBar().setValue(0) def reparent(self): qwindow = self.windowHandle() if platform.system() != "Darwin": qwindow.setParent(QWindow.fromWinId(self.emacs_xid)) qwindow.setPosition(QPoint(self.x, self.y)) def destroy_view(self): self.destroy()
class TestWidget(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.status = 0 self.statusBar() self.scene1 = QGraphicsScene() self.scene2 = QGraphicsScene() self.view1 = QGraphicsView(self.scene1) self.view2 = QGraphicsView(self.scene2) # self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowMaximizeButtonHint) # self.setWindowFlags(self.windowFlags() | QtCore.Qt.CustomizeWindowHint) self.setWindowIcon(QIcon('download123.jpg')) self.setWindowTitle('Cut_In Event Identification') self.label = QLabel() self.label.setText("") self.label.setDisabled(True) self.label2 = QLabel() self.label2.setText("") self.label2.setDisabled(True) self.fileopen = False self.openFile = QAction(QIcon('input.jpeg'), 'Open File', self) self.openFile.setShortcut('Ctrl+O') self.openFile.setStatusTip('Open File') self.openFile.triggered.connect(self.OpenDialog) self.Play_on = False self.Play = QToolButton() self.Play.setIcon(QIcon('play.png')) self.Play.setIconSize(QSize(150, 150)) self.Play.setStyleSheet('border-radius: 4px;') self.Play.setShortcut('Space') self.Play.clicked.connect(self.Play_Action) # self.load_input = QToolButton() # self.load_input.setIcon(QIcon('icons\video_clip.png')) # self.load_input.setText("load input") # self.load_input.setIconSize(QSize(50,50)) # self.load_input.setStyleSheet("border-radius: 4px;") # self.load_input.setShortcut('Ctrl+I') # self.load_input.clicked.connect(self.load_input_video) toolbar = self.addToolBar('Quick Access') toolbar.addAction(self.openFile) self.indicator = QToolButton() self.indicator.setIcon(QIcon('go.png')) # self.indicator.setText("load output") self.indicator.setIconSize(QSize(150, 150)) self.indicator.setStyleSheet("border-radius: 4px;") self.indicator.setShortcut('Ctrl+O') #self.indicator.clicked.connect(self.indicator_action) self.indicator.setDisabled(True) #dynamic_canvas = FigureCanvas(Figure(figsize=(7, 4))) Vlayout = QVBoxLayout() Hlayout = QHBoxLayout() buttonlayout = QHBoxLayout() viewlayout = QHBoxLayout() vstacklayout = QVBoxLayout() # xlayout = QVBoxLayout() viewlayout.setAlignment(Qt.AlignCenter) buttonlayout.setAlignment(Qt.AlignCenter) #xlayout.setAlignment(Qt.AlignCenter) Hlayout.addWidget(self.indicator) Hlayout.addWidget(self.label) Hlayout.addWidget(self.Play) vstacklayout.addLayout(Hlayout) vstacklayout.addWidget(self.label2) #vstacklayout.addWidget(dynamic_canvas) vstacklayout.addStretch() viewlayout.addWidget(self.view1) viewlayout.addLayout(vstacklayout) #xlayout.addLayout(Hlayout) # xlayout.addWidget(self.Play) # viewlayout.addStretch(1) # buttonlayout.addWidget(self.load_input) Vlayout.addLayout(viewlayout) # Vlayout.addLayout(Hlayout) window = QWidget() window.setLayout(Vlayout) self.setCentralWidget(window) # self._dynamic_ax = dynamic_canvas.figure.subplots() # self._dynamic_ax.set(xlabel='frames (num)', ylabel='magnitude',title='lane plot') # self._dynamic_ax.grid() # self._timer = dynamic_canvas.new_timer(100, [(self._update_canvas, (), {})]) self.setLayout(Vlayout) def _update_canvas(self): new_th = [] for (i, t) in enumerate(self.theta_diff): new_th.append( int(t * math.sin(2 * math.pi * 10 * i / 1000) + time.time())) self._dynamic_ax.clear() self._dynamic_ax.set(xlabel='frames (num)', ylabel='magnitude', title='lane plot') self._dynamic_ax.grid(True) t = np.arange(self.total_frames) self._dynamic_ax.plot(t, new_th, 'g') self._dynamic_ax.figure.canvas.draw() def OpenDialog(self): fname = QFileDialog.getOpenFileName( self, 'Open file', '', 'Video Files (*.avi *.mp4);; Image Files (*.jpg *.png);; CSV Files (*.csv)' )[0] print(fname) lst1 = [] df = pd.read_csv( '/home/souravkc/Desktop/yolo-object-detection/1233_FINAL__newcross.csv' ) #print(df) df1 = pd.DataFrame(df) df2 = df1[df1['lxmin_y']][['frame_no']] self.dict_df = {} for i, row in df1.iterrows(): self.dict_df[row['frame_no']] = row['lxmin_y'] #print(df2) #=='True'] #df3 = pd.DataFrame(df2) #lst1.append(df3) lst1 = df2['frame_no'].values.tolist() #print(lst1) lst1 = set(lst1) lst1 = list(lst1) if ('.avi' in fname) or ('.mp4' in fname): #call a function to process video self.process_video(fname) elif ('.jpg' in fname) or ('.png' in fname): #call a function prosess image print("calling image fn") else: pass def indicator_action(self): i = 0 z = 0 while (i != 3001): #print(i) #print(lst1[z]) if (lst1[z] == i): # print(i) # print(lst1[z]) #print('1') #if self.data.lxmin_y == 'True': self.indicator.setIcon(QIcon('go.png')) self.indicator.setIconSize(QSize(150, 150)) z += 1 i = 0 else: self.indicator.setIcon(QIcon('download.png')) self.indicator.setIconSize(QSize(150, 150)) i = i + 1 # if self.status == 0: # self.indicator.setIcon(QIcon('download.png')) # self.indicator.setIconSize(QSize(64,64)) # else: # self.indicator.setIcon(QIcon('stop.png')) # self.indicator.setIconSize(QSize(64,64)) def load_output_video(self): print("output") def display_image_scene1(self, img): npimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) pil_image = Image.fromarray(npimg) self.scene1.clear() self.w, self.h = pil_image.size self.imgQ = ImageQt.ImageQt( pil_image) # we need to hold reference to imgQ, or it will crash pixMap = QPixmap.fromImage(self.imgQ) self.scene1.addPixmap(pixMap) self.view1.fitInView(QRectF(0, 0, self.w, self.h), Qt.KeepAspectRatio) self.scene1.update() def display_image_scene2(self, img): npimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) pil_image = Image.fromarray(npimg) self.scene2.clear() self.w, self.h = pil_image.size self.imgQ = ImageQt.ImageQt( pil_image) # we need to hold reference to imgQ, or it will crash pixMap = QPixmap.fromImage(self.imgQ) self.scene2.addPixmap(pixMap) self.view1.fitInView(QRectF(0, 0, self.w, self.h), Qt.KeepAspectRatio) self.scene2.update() def closeEvent(self, event): self.reply = QMessageBox.question(self, 'Confirm Exit', "Are you sure to Quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if self.reply == QMessageBox.Yes: event.accept() else: event.ignore() def Play_Action(self): if self.fileopen == True: self.Play_on = not self.Play_on if self.Play_on is True: self.Play.setStatusTip("Pause") self.Play.setIcon(QIcon('pause.jpeg')) else: self.Play.setStatusTip("Play") self.Play.setIcon(QIcon('play.png')) def Pause_video(self): self.Play_on = False self.stop.setDisabled(False) self.Play.setStatusTip("Play") self.Play.setIcon(QIcon('play.png')) def close_application(self, path): import time cap = cv2.VideoCapture(path) # Check if camera opened successfully if (cap.isOpened() == False): print("Error opening video file") # Read until video is completed while (cap.isOpened()): # Capture frame-by-frame ret, frame = cap.read() if ret is True: self.label.setDisabled(False) self.indicator.setDisabled(False) self.label2.setDisabled(False) # Display the resulting frame #cv2.imshow('Frame', frame) self.display_image_scene1(frame) # Press Q on keyboard to exit if cv2.waitKey(25) & 0xFF == ord('q'): break # Break the loop else: # print("Done Processing :) ") self.indicator.setDisabled(True) self.label.setDisabled(True) self.label2.setDisabled(True) break # When everything done, release # the video capture object cap.release() # Closes all the frames cv2.destroyAllWindows() def process_video(self, path): self.Play.setDisabled(False) cap = cv2.VideoCapture(path) import time self.reply = QMessageBox.No # video_writer_set = False self.total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # print("video file " + input_video_path) # sys.stdout.write("\r") # angle_data = [] # self.theta_diff = np.zeros(self.total_frames) # # self.theta_diff = [] oldstatus = self.status import json #print(json.dumps(self.dict_df, indent=4)) while cap.isOpened(): #self._timer.start() self.fileopen = True #ret,frame = cap.read() #framecpy = np.copy(frame) if self.Play_on == True: ret, frame = cap.read() framecpy = np.copy(frame) if ret is True: self.label.setDisabled(False) self.indicator.setDisabled(False) self.label2.setDisabled(False) # if video_writer_set is False: # out = cv2.VideoWriter("out.avi",cv2.VideoWriter_fourcc(*'DIVX'), 30, (frame.shape[1], frame.shape[0])) # video_writer_set = True present_frame = int(cap.get(cv2.CAP_PROP_POS_FRAMES)) #cap.set(cv2.CV_CAP_PROP_FPS, 30) #cv2.waitKey(100) self.display_image_scene1(frame) # cv2.waitKey(200000) try: if not self.dict_df[present_frame]: self.indicator.setIcon(QIcon('go.png')) self.indicator.setIconSize(QSize(150, 150)) self.label2.setText(" Free_From_Cut-In") #time.sleep(0.01) else: self.indicator.setIcon(QIcon('download.png')) self.indicator.setIconSize(QSize(140, 140)) self.label2.setText(" Cut-In_Car") #time.sleep(0.01) except Exception as e: #print("except") pass if cv2.waitKey(30) == ord('q'): break #cv2.waitKey(20000) #try : # colored_image,angle1,angle2,ximg = process_image(framecpy) # cnt2 += 1 # if cnt2 > 5: # self.status = 0 # self.label2.setText("FREE_LANE") # # cv2.putText(framecpy, "Not changing", (100, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255,0,0), 3, cv2.LINE_AA) # cnt = 0 # else: # pass # present_frame = int(cap.get(cv2.CAP_PROP_POS_FRAMES)) # self.theta_diff[present_frame] = angle1+angle2 # self.display_image_scene1(frame) # # self._update_canvas() # # out.write(colored_image) # #angle_data.append([present_frame,angle1,angle2,self.status]) # except TypeError: # cnt += 1 # if cnt>5: # self.status = 1 # self.label2.setText("INCOMING") # # cv2.putText(framecpy, "Changing lane", (100, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0,0,255), 3, cv2.LINE_AA) # cnt2=0 # else: # pass # present_frame = int(cap.get(cv2.CAP_PROP_POS_FRAMES)) # self.theta_diff[present_frame] = 150 # self.display_image_scene1(frame) # # self._update_canvas() # # out.write(frame) # #angle_data.append([present_frame,-75,75,self.status]) # pass # except ZeroDivisionError: # cnt += 1 # if cnt>5: # self.status = 1 # self.label2.setText("INCOMING") # # cv2.putText(framecpy, "Changing lane", (100, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0,0,255), 3, cv2.LINE_AA) # cnt2=0 # else: # pass # present_frame = int(cap.get(cv2.CAP_PROP_POS_FRAMES)) # self.theta_diff[present_frame] = 150 # self.display_image_scene1(frame) # # self._update_canvas() # # out.write(frame) # #angle_data.append([present_frame,-75,75,self.status]) # pass # # if cv2.waitKey(1) == ord('q'): # # break # else: # # print("Done Processing :) ") # self.indicator.setDisabled(True) # self.label.setDisabled(True) # self.label2.setDisabled(True) # break self.label.setText("frames: " + str(present_frame) + "\\" + str(self.total_frames)) if self.reply == QMessageBox.Yes: cap.release() #out.release() cv2.destroyAllWindows() break #if self.status is not oldstatus: # self.indicator.click() oldstatus = self.status QCoreApplication.processEvents() #csv_data = pd.DataFrame(angle_data, columns = ["frame_no","theta_left","theta_right","status"]) #csv_data.to_csv('angle_data.csv') cap.release() #out.release() cv2.destroyAllWindows()
class View(QWidget): trigger_focus_event = QtCore.pyqtSignal(str) def __init__(self, buffer, view_info): super(View, self).__init__() self.buffer = buffer # Init widget attributes. self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True) self.setContentsMargins(0, 0, 0, 0) self.installEventFilter(self) # Init attributes. self.view_info = view_info (self.buffer_id, self.emacs_xid, self.x, self.y, self.width, self.height) = view_info.split(":") self.emacs_xid = int(self.emacs_xid) self.x = int(self.x) self.y = int(self.y) self.width = int(self.width) self.height = int(self.height) # Build QGraphicsView. self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) self.graphics_view = QGraphicsView(buffer, self) # Set background color. # When fit_to_view is True, QGraphicsView will fill color around app view. # We fill color with buffer's attribute "background_color". if hasattr(self.buffer, "background_color") and self.buffer.background_color: self.graphics_view.setBackgroundBrush( QBrush(self.buffer.background_color)) # Remove border from QGraphicsView. self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing) self.graphics_view.setFrameStyle(QFrame.NoFrame) # Add graphics view. self.layout.addWidget(self.graphics_view) # NOTE: show function must start before resize to trigger *first* resizeEvent after show. self.show() # Resize after show to trigger fit view operation. self.resize(self.width, self.height) self.buffer.aspect_ratio_change.connect(self.adjust_aspect_ratio) def resizeEvent(self, event): # Fit content to view rect just when buffer fit_to_view option is enable. if self.buffer.fit_to_view: if event.oldSize().isValid(): self.graphics_view.fitInView( self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio) QWidget.resizeEvent(self, event) def adjust_aspect_ratio(self): widget_width = self.width widget_height = self.height if self.buffer.aspect_ratio == 0: self.buffer.buffer_widget.resize(self.width, self.height) self.layout.setContentsMargins(0, 0, 0, 0) else: view_height = widget_height * ( 1 - 2 * self.buffer.vertical_padding_ratio) view_width = view_height * self.buffer.aspect_ratio horizontal_padding = (widget_width - view_width) / 2 vertical_padding = self.buffer.vertical_padding_ratio * widget_height self.buffer.buffer_widget.resize(view_width, view_height) self.layout.setContentsMargins(horizontal_padding, vertical_padding, horizontal_padding, vertical_padding) def eventFilter(self, obj, event): # When we press Alt + Tab in operating system. # Emacs window cannot get the focus normally if mouse in EAF buffer area. # # So we use wmctrl activate on Emacs window after Alt + Tab operation. # # NOTE: turn off this behavior under i3 window manager. if event.type() in [QEvent.ShortcutOverride]: import os if os.environ.get("DESKTOP_SESSION") != "i3": if not activate_emacs_window(): self.buffer.message_to_emacs.emit( "You need install tool 'wmctrl' to activate Emacs window, make Emacs input correctly after Alt + Tab operation." ) # Focus emacs buffer when user click view. if event.type() in [ QEvent.MouseButtonPress, QEvent.MouseButtonRelease, QEvent.MouseButtonDblClick, QEvent.Wheel ]: self.trigger_focus_event.emit(self.buffer_id) # Stop mouse event. return True return False def showEvent(self, event): # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed. self.reparent() # Make graphics view at left-top corner after show. self.graphics_view.verticalScrollBar().setValue(0) self.graphics_view.horizontalScrollBar().setValue(0) def reparent(self): qwindow = self.windowHandle() qwindow.setParent(QWindow.fromWinId(self.emacs_xid)) qwindow.setPosition(QPoint(self.x, self.y)) def destroy_view(self): self.destroy()
from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView app = QApplication(sys.argv) rs = QRectF(0, 0, 100, 100) ro = QRectF(-1, -1, 3, 2) s = QGraphicsScene(rs) v = QGraphicsView(s) v.setGeometry(20, 20, 600, 600) v._origin_u = True v._origin_l = True print('screenGeometry():', app.desktop().screenGeometry()) print('scene rect=', s.sceneRect()) v.fitInView( rs, Qt.KeepAspectRatio ) # Qt.IgnoreAspectRatio Qt.KeepAspectRatioByExpanding Qt.KeepAspectRatio s.addRect(rs, pen=QPen(Qt.black, 0, Qt.SolidLine), brush=QBrush(Qt.yellow)) s.addRect(ro, pen=QPen(Qt.black, 0, Qt.SolidLine), brush=QBrush(Qt.red)) ruler1 = FWRuler(v, 'L') ruler2 = FWRuler(v, 'D') ruler3 = FWRuler(v, 'U') ruler4 = FWRuler(v, 'R') v.setWindowTitle("My window") v.setContentsMargins(0, 0, 0, 0) v.show() app.exec_()
class BoardGUI(QWidget): """cointain the graphical representation of the Board""" # ratio of bordersize compared to the size of one base square borderRatio = 0.8 baseRectRatio = 14/15 # 12/13 for normal ratio but looks weird stoneScale = 0.46 # siganl stoneClicked = pyqtSignal(tuple) def __init__(self, parent, game): super().__init__() self.initUI(game) def initUI(self, game): self.board = game.currentBoard self.game = game self.showCoords = True self.scene = QGraphicsScene() # grid containing coordinates for the scene self.grid = [] self.drawGrid() # initialize and set layout + view self.view = QGraphicsView(self.scene) self.view.setMouseTracking(True) self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setMouseTracking(True) box = QHBoxLayout() box.addWidget(self.view) self.setLayout(box) # stones for all positions are created and listed in self.pos dict self.createPosition() self.makeCoords() # has to be called after drawGrid! def resizeEvent(self, e): self.view.fitInView(self.view.scene().sceneRect(), Qt.KeepAspectRatio) def boardWidth(self): """returns the max width fitting into widget""" width = self.contentsRect().width()*0.95 height = self.contentsRect().height()*0.95 return min(width, height*self.baseRectRatio) def boardHeight(self): """returns the max width fitting into widget """ return self.boardWidth()*(1/self.baseRectRatio) def makeGrid(self): """ returns coords [[(x, y)]] for the Grid according to current window mesures """ # set scenesize to window size self.scene.setSceneRect(0, 0, self.boardWidth(), self.boardHeight()) denom = self.board.size + 2*self.borderRatio baseWidth = self.boardWidth() / denom baseHeight = self.boardHeight() / denom leftOffset = 0.5*baseWidth # (self.contentsRect().width()-self.boardWidth())/2 topOffset = 0 # (self.contentsRect().height()-self.boardHeight())/2 partionWidth = [leftOffset+(self.borderRatio+x)*baseWidth for x in range(self.board.size)] partionHeight = [topOffset+(self.borderRatio+x)*baseHeight for x in range(self.board.size)] grid = [[(x, y) for x in partionWidth] for y in partionHeight] self.grid = grid self.baseWidth = baseWidth def drawGrid(self): """draws the background grid""" self.makeGrid() for line in self.grid: self.scene.addLine(*line[0], *line[-1]) for (pointT, pointB) in zip(self.grid[0], self.grid[-1]): self.scene.addLine(*pointT, *pointB) self.drawHoshis() def makeCoords(self): """ draws Coordinates """ xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ" yLabels = list(range(1, 26)) botGrid = [] leftGrid = [] # generate pixel coordinates grids for n in range(self.board.size): (xBot, yBot) = self.grid[self.board.size-1][n] yBot += self.baseWidth*0.4/self.baseRectRatio xBot -= self.baseWidth*0.1 botGrid.append((xBot, yBot)) (xLeft, yLeft) = self.grid[n][0] xLeft -= self.baseWidth*1.2 yLeft -= self.baseWidth*0.3/self.baseRectRatio leftGrid.append((xLeft, yLeft)) # generate Text items and add them to group self.coordGroup = QGraphicsItemGroup() for n in range(self.board.size): leftText = QGraphicsSimpleTextItem(str(yLabels[n])) leftText.setPos(*leftGrid[n]) self.coordGroup.addToGroup(leftText) bottomText = QGraphicsSimpleTextItem(xLabels[n]) bottomText.setPos(*botGrid[n]) self.coordGroup.addToGroup(bottomText) # draw coordinates and update visibility according to self.showCoords self.scene.addItem(self.coordGroup) self.updateCoords() def updateCoords(self): """ slot that updates the visibility os the coordiantes. """ self.coordGroup.setVisible(self.showCoords) def setCoordVis(self, visibility): """ set the self.showCoords boolean """ self.showCoords = visibility self.updateCoords() def drawHoshis(self): """ Draws Hoshi dots""" hoshis = [] rad = self.baseWidth*0.15 for (x, y) in self.board.getHoshis(): hoshis.append(self.grid[x][y]) for point in hoshis: (x, y) = point self.scene.addEllipse(x-rad, y-rad, rad*2.0, rad*2.0, QPen(), QBrush(Qt.SolidPattern)) def updatePosition(self): """ sets the colors for all stones in self.pos according to the status in self.board """ for (x, y) in self.pos: color = self.game.currentBoard.getPosition(x, y) self.pos[(x, y)].setMark(None) self.pos[(x, y)].setColor(color) lastMove = self.game.currentBoard.lastMove if lastMove: self.pos[lastMove].setMark(GoMarks.circel) ko = self.game.currentBoard.ko if ko: self.pos[ko].setMark(GoMarks.square) def createPosition(self): """ Creates the self.pos dictionary containing all possible stones on the board initialized as empty stones also connects a signal form each stone to ??? """ self.pos = {} radius = self.stoneScale*self.baseWidth for row in range(self.board.size): for col in range(self.board.size): (x, y) = self.grid[row][col] newStone = Stone(x, y, radius) self.pos[(row, col)] = newStone self.scene.addItem(newStone) self.updatePosition() self.connecting() def connecting(self): for key in self.pos: self.pos[key].clicked.connect(lambda key=key: self.resend(key)) def resend(self, pos): """ emits the captured signal again, with (int, in) parameter for stone clicked """ self.stoneClicked.emit(pos)
class QGameOfLife(QWidget): games = { "Game of Life": lambda size: GameOfLife(size=size), "Bacteria": lambda size: GrayScottDiffusion(size=size, coeffs=(0.16, 0.08, 0.035, 0.065)), "Coral": lambda size: GrayScottDiffusion(size=size, coeffs=(0.16, 0.08, 0.062, 0.062)), "Fingerprint": lambda size: GrayScottDiffusion(size=size, coeffs=(0.19, 0.05, 0.060, 0.062)), "Spirals": lambda size: GrayScottDiffusion(size=size, coeffs=(0.10, 0.10, 0.018, 0.050)), "Unstable": lambda size: GrayScottDiffusion(size=size, coeffs=(0.16, 0.08, 0.020, 0.055)), "Worms": lambda size: GrayScottDiffusion(size=size, coeffs=(0.16, 0.08, 0.050, 0.065)), "Zebrafish": lambda size: GrayScottDiffusion(size=size, coeffs=(0.16, 0.08, 0.035, 0.060)), } def __init__(self, size=(400, 400)): super(QGameOfLife, self).__init__() self.game = None self.size = size self.initUI() self.show() def initUI(self): self.setWindowTitle(self.tr("Game of Life")) self.setLayout(QVBoxLayout()) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self.comboBox = QComboBox() self.comboBox.addItems(self.games.keys()) self.comboBox.currentTextChanged.connect(self.gameEvent) self.layout().addWidget(self.comboBox) self.scene = QGraphicsScene() self.item = None self.view = QGraphicsView(self.scene) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setSizePolicy( QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)) self.view.setFrameShape(QFrame.NoFrame) self.layout().addWidget(self.view) self.tickEvent(QImage()) self.view.fitInView(self.item, Qt.KeepAspectRatioByExpanding) self.comboBox.setCurrentText(random.choice(list(self.games.keys()))) def gameEvent(self, name): if self.game is not None: self.game.stop() constructor = self.games[name] self.game = constructor(self.size) self.game.delegate = self self.game.start() def tickEvent(self, image): self.scene.removeItem(self.item) pixmap = QPixmap.fromImage(image) self.item = self.scene.addPixmap(pixmap) def resizeEvent(self, QResizeEvent): self.view.fitInView(self.item, Qt.KeepAspectRatioByExpanding) def sizeHint(self): return QSize(self.size[0], self.size[1])