class JonahWindow(QMainWindow): def __init__(self): super().__init__() self.setAttribute(Qt.WA_DeleteOnClose) self.setAcceptDrops(True)#mainwindow是否接收拖动 pathList = QStandardPaths.standardLocations(QStandardPaths.PicturesLocation)# type:tuple(list,str) self.workPath = pathList[-1] if len(pathList)>0 else QDir.currentPath() self.zoomIdx = 3 self.zoomList = [0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0] self.originSize = QSize(0, 0) self.originSize1 = QSize(0, 0) self.penColor = QColor(0, 170, 255)#初始化颜色 self.opendFile = '' self.opendFile1 = '' self.initUI() screenInfo = QApplication.desktop() screenIdx = screenInfo.screenNumber()#current screen index screenRect = screenInfo.screenGeometry(screenIdx) self.setGeometry((screenRect.width()-1280)/2, (screenRect.height()-720)/2, 1280, 720) self.__setTitle() def initUI(self): fileMenu = self.menuBar().addMenu('&File') self.menuBar().setStyleSheet('QMenuBar{background:rgb(128,128,128)}QMenuBar::item:selected{background:rgb(128,128,128)}QMenu{background:rgb(128,128,128)}QMenu::item:selected{background-color:#654321;}') openFilesAction = QAction('Open files', self) exitAction = QAction('Exit', self) closeAction = QAction('Close', self) fileMenu.addAction(openFilesAction) fileMenu.addAction(closeAction) fileMenu.addAction(exitAction) openFilesAction.triggered.connect(self.onOpenFileAction) closeAction.triggered.connect(self.onCloseAction) exitAction.triggered.connect(self.onQuit) zoomMenu = self.menuBar().addMenu('&Zoom') zoomInAction = QAction('zoom in', self) zoomOutAction = QAction('zoom out', self) zoomMenu.addAction(zoomInAction) zoomMenu.addAction(zoomOutAction) zoomInAction.triggered.connect(self.zoomIn) zoomOutAction.triggered.connect(self.zoomOut) zoomInAction.setShortcut(QKeySequence(QKeySequence.ZoomIn)) zoomOutAction.setShortcut(QKeySequence(QKeySequence.ZoomOut)) viewMenu = self.menuBar().addMenu('&View') dockWidgetMenu = QMenu('dock widget', self) dockWidgetMenu.setStyleSheet('QMenu{background:rgb(128,128,128)}QMenu::item:selected{background-color:#654321;}') viewMenu.addMenu(dockWidgetMenu) self.penBoxAction = QAction('pen box', self) self.colorGamutAction = QAction('color gamut', self) dockWidgetMenu.addAction(self.penBoxAction) self.penBoxAction.setCheckable(True) self.penBoxAction.setChecked(True) dockWidgetMenu.addAction(self.colorGamutAction) self.colorGamutAction.setCheckable(True) self.colorGamutAction.setChecked(True) aboutMenu = self.menuBar().addMenu('&About') aboutQtAction = QAction('About Qt', self) aboutQtAction.triggered.connect(self.aboutQt_) aboutThisAction = QAction('About this', self) aboutThisAction.triggered.connect(self.aboutThis) aboutMenu.addAction(aboutQtAction) aboutMenu.addAction(aboutThisAction) self.mainWidget = QFrame() self.mainWidget.setFrameStyle(QFrame.Box|QFrame.Sunken) scrollAreaLayout = QHBoxLayout() self.mainWidget.setLayout(scrollAreaLayout) self.scrollArea = QScrollArea() self.imageLabel = ImageLabel(self.penColor, 2, 'rect') self.imageLabel.setText('drag image file to here!') self.imageLabel.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter) self.imageLabel.setScaledContents(True) self.scrollArea.setWidget(self.imageLabel) self.scrollArea.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter) self.scrollArea1 = QScrollArea() self.imageLabel1 = ImageLabel(self.penColor, 2, 'rect') self.imageLabel1.setText('drag image file to here!') self.imageLabel1.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter) self.imageLabel1.setScaledContents(True) self.scrollArea1.setWidget(self.imageLabel1) self.scrollArea1.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter) scrollAreaLayout.addWidget(self.scrollArea) scrollAreaLayout.addWidget(self.scrollArea1) self.setCentralWidget(self.mainWidget) self.createDockWidget() self.paintType_line_btn.toggled.connect(self.__setPaintType_line) self.paintType_rect_btn.toggled.connect(self.__setPaintType_rect) self.lineWidth_box.currentIndexChanged[str].connect(self.__setPenWidth) self.colorBtn.clicked.connect(self.__selectColor) self.paintOk.clicked.connect(self.__handleInputPaintPos) self.paintOk1.clicked.connect(self.__handleInputPaintPos1) self.syncRight.clicked.connect(self.__syncRightPos) self.syncLeft.clicked.connect(self.__syncLeftPos) self.createDockWidget_1() self.toolBoxWidget.installEventFilter(self)#拦截消息,关闭dock widget实际是隐藏 self.plotDockWgt.installEventFilter(self) self.plot_rgb_contourf_line.clicked.connect(self.plot_rgb_contourf_line_func) self.plot_rgb_hist.clicked.connect(self.plot_rgb_hist_func) self.imageLabel.inform_real_Pos.connect(self.__flushPaintPosEdit) self.imageLabel1.inform_real_Pos.connect(self.__flushPaintPosEdit1) self.scrollArea.horizontalScrollBar().valueChanged.connect(self.__syncScrollArea1_horScBarVal) self.scrollArea.verticalScrollBar().valueChanged.connect(self.__syncScrollArea1_verScBarVal) self.scrollArea1.horizontalScrollBar().valueChanged.connect(self.__syncScrollArea_horScBarVal) self.scrollArea1.verticalScrollBar().valueChanged.connect(self.__syncScrollArea_verScBarVal) self.penBoxAction.toggled.connect(self.__toggleToolBoxDockWgt) self.colorGamutAction.toggled.connect(self.__toggleColorGamutWgt) def __syncScrollArea1_horScBarVal(self, value:int): ''' 同步两个图像区域的滚动条位置 ''' if not self.scrollArea.horizontalScrollBar().isVisible(): return if not self.scrollArea1.horizontalScrollBar().isVisible(): return try: pos_ratio = value/self.scrollArea.horizontalScrollBar().maximum() target_val = int(pos_ratio*self.scrollArea1.horizontalScrollBar().maximum()+0.5) self.scrollArea1.horizontalScrollBar().setValue(target_val) except ZeroDivisionError: return def __syncScrollArea1_verScBarVal(self, value:int): ''' 同步两个图像区域的滚动条位置 ''' if not self.scrollArea.verticalScrollBar().isVisible(): return if not self.scrollArea1.verticalScrollBar().isVisible(): return try: pos_ratio = value/self.scrollArea.verticalScrollBar().maximum() target_val = int(pos_ratio*self.scrollArea1.verticalScrollBar().maximum()+0.5) self.scrollArea1.verticalScrollBar().setValue(target_val) except ZeroDivisionError: return def __syncScrollArea_horScBarVal(self, value:int): ''' 同步两个图像区域的滚动条位置 ''' if not self.scrollArea.horizontalScrollBar().isVisible(): return if not self.scrollArea1.horizontalScrollBar().isVisible(): return try: pos_ratio = value/self.scrollArea1.horizontalScrollBar().maximum() target_val = int(pos_ratio*self.scrollArea.horizontalScrollBar().maximum()+0.5) self.scrollArea.horizontalScrollBar().setValue(target_val) except ZeroDivisionError: return def __syncScrollArea_verScBarVal(self, value:int): ''' 同步两个图像区域的滚动条位置 ''' if not self.scrollArea.verticalScrollBar().isVisible(): return if not self.scrollArea1.verticalScrollBar().isVisible(): return try: pos_ratio = value/self.scrollArea1.verticalScrollBar().maximum() target_val = int(pos_ratio*self.scrollArea.verticalScrollBar().maximum()+0.5) self.scrollArea.verticalScrollBar().setValue(target_val) except ZeroDivisionError: return def __setPaintType_line(self): ''' 设置绘图类型为直线 ''' self.imageLabel.setPaintType_Line() self.imageLabel1.setPaintType_Line() def __setPaintType_rect(self): ''' 设置绘图类型为矩形 ''' self.imageLabel.setPaintType_Rect() self.imageLabel1.setPaintType_Rect() def __setPenWidth(self, width:str): ''' 设置绘图线宽 ''' self.imageLabel.setPenWidth(width) self.imageLabel1.setPenWidth(width) def __toggleToolBoxDockWgt(self, checked:bool): ''' 菜单切换dock widget显示 ''' if checked: self.toolBoxWidget.show() else: self.toolBoxWidget.close() def __toggleColorGamutWgt(self, checked:bool): ''' 菜单切换dock widget显示 ''' if checked: self.plotDockWgt.show() else: self.plotDockWgt.close() def __syncRightPos(self): ''' 当点击面板上的sync按钮后,同步左右两侧的绘图坐标 ''' self.start_x_edit1.setText(self.start_x_edit.text()) self.start_y_edit1.setText(self.start_y_edit.text()) self.end_x_edit1.setText(self.end_x_edit.text()) self.end_y_edit1.setText(self.end_y_edit.text()) def __syncLeftPos(self): ''' 当点击面板上的sync按钮后,同步左右两侧的绘图坐标 ''' self.start_x_edit.setText(self.start_x_edit1.text()) self.start_y_edit.setText(self.start_y_edit1.text()) self.end_x_edit.setText(self.end_x_edit1.text()) self.end_y_edit.setText(self.end_y_edit1.text()) def createDockWidget(self): ''' 创建面板---绘图工具箱 ''' self.toolBoxWidget = QDockWidget(self) self.toolBoxWidget.setWindowTitle('pen box') self.toolBoxWidget.setAllowedAreas(Qt.LeftDockWidgetArea|Qt.RightDockWidgetArea) toolBoxContainer = QWidget() vlayout = QVBoxLayout() toolBoxContainer.setLayout(vlayout) self.toolBoxWidget.setWidget(toolBoxContainer) toolBoxContainer.setStyleSheet('QPushButton{background-color:rgb(156,156,156)}QComboBox{border:1px solid gray}') penGroup = QButtonGroup() penLayout = QHBoxLayout() self.paintType_line_btn = QRadioButton('line') self.paintType_rect_btn = QRadioButton('rect') self.paintType_rect_btn.setChecked(True)#初始形状 矩形 penGroup.addButton(self.paintType_line_btn) penGroup.addButton(self.paintType_rect_btn) penLayout.addWidget(self.paintType_line_btn, 1) penLayout.addWidget(self.paintType_rect_btn, 1) penLayout.addStretch(1) lineWidth_layout = QHBoxLayout() lineWidth_text = QLabel('line width:') self.lineWidth_box = QComboBox() self.lineWidth_box.addItems(['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '12', '14', '16', '18', '20', '24', '28', '32']) self.lineWidth_box.setCurrentIndex(1) lineWidth_layout.addWidget(lineWidth_text, 1) lineWidth_layout.addWidget(self.lineWidth_box, 1) lineWidth_layout.addStretch(1) colorLayout = QHBoxLayout() colorText = QLabel('color:') self.colorBtn = QPushButton('') colorLayout.addWidget(colorText, 1) colorLayout.addWidget(self.colorBtn, 1) colorLayout.addStretch(1) hline = QFrame() hline.setFrameShape(QFrame.HLine) imageSizeValidator = QIntValidator(0, 10000) paintPosLayout0 = QGridLayout() start_x_text = QLabel('start x:') self.start_x_edit = QLineEdit() self.start_x_edit.setMaximumWidth(55) self.start_x_edit.setValidator(imageSizeValidator) start_y_text = QLabel('y:') self.start_y_edit = QLineEdit() self.start_y_edit.setMaximumWidth(55) self.start_y_edit.setValidator(imageSizeValidator) paintPosLayout0.addWidget(start_x_text, 0, 0, 1, 1) paintPosLayout0.addWidget(self.start_x_edit, 0, 1, 1, 1) paintPosLayout0.addWidget(start_y_text, 1, 0, 1, 1) paintPosLayout0.addWidget(self.start_y_edit, 1, 1, 1, 1) end_x_text = QLabel('end x:') self.end_x_edit = QLineEdit() self.end_x_edit.setMaximumWidth(55) self.end_x_edit.setValidator(imageSizeValidator) end_y_text = QLabel('y:') self.end_y_edit = QLineEdit() self.end_y_edit.setMaximumWidth(55) self.end_y_edit.setValidator(imageSizeValidator) paintPosLayout0.addWidget(end_x_text, 2, 0, 1, 1) paintPosLayout0.addWidget(self.end_x_edit, 2, 1, 1, 1) paintPosLayout0.addWidget(end_y_text, 3, 0, 1, 1) paintPosLayout0.addWidget(self.end_y_edit, 3, 1, 1, 1) self.paintOk = QPushButton('ok') paintPosLayout0.addWidget(self.paintOk, 4, 1, 1, 1) vline1 = QFrame() vline1.setFrameShape(QFrame.VLine) syncLayout = QVBoxLayout() self.syncRight = QPushButton('--->') self.syncLeft = QPushButton('<---') syncLayout.addWidget(self.syncRight) syncLayout.addWidget(self.syncLeft) vline2 = QFrame() vline2.setFrameShape(QFrame.VLine) paintPosLayout1 = QGridLayout() start_x_text1 = QLabel('start x:') self.start_x_edit1 = QLineEdit() self.start_x_edit1.setMaximumWidth(55) self.start_x_edit1.setValidator(imageSizeValidator) start_y_text1 = QLabel('y:') self.start_y_edit1 = QLineEdit() self.start_y_edit1.setMaximumWidth(55) self.start_y_edit1.setValidator(imageSizeValidator) paintPosLayout1.addWidget(start_x_text1, 0, 0, 1, 1) paintPosLayout1.addWidget(self.start_x_edit1, 0, 1, 1, 1) paintPosLayout1.addWidget(start_y_text1, 1, 0, 1, 1) paintPosLayout1.addWidget(self.start_y_edit1, 1, 1, 1, 1) end_x_text1 = QLabel('end x:') self.end_x_edit1 = QLineEdit() self.end_x_edit1.setMaximumWidth(55) self.end_x_edit1.setValidator(imageSizeValidator) end_y_text1 = QLabel('y:') self.end_y_edit1 = QLineEdit() self.end_y_edit1.setMaximumWidth(55) self.end_y_edit1.setValidator(imageSizeValidator) paintPosLayout1.addWidget(end_x_text1, 2, 0, 1, 1) paintPosLayout1.addWidget(self.end_x_edit1, 2, 1, 1, 1) paintPosLayout1.addWidget(end_y_text1, 3, 0, 1, 1) paintPosLayout1.addWidget(self.end_y_edit1, 3, 1, 1, 1) self.paintOk1 = QPushButton('ok') paintPosLayout1.addWidget(self.paintOk1, 4, 1, 1, 1) paintPosLayout = QHBoxLayout() paintPosLayout.addLayout(paintPosLayout0) paintPosLayout.addWidget(vline1) paintPosLayout.addLayout(syncLayout) paintPosLayout.addWidget(vline2) paintPosLayout.addLayout(paintPosLayout1) vlayout.addLayout(penLayout) vlayout.addLayout(lineWidth_layout) vlayout.addLayout(colorLayout) vlayout.addWidget(hline) vlayout.addLayout(paintPosLayout) vlayout.addStretch(1) self.addDockWidget(Qt.LeftDockWidgetArea, self.toolBoxWidget) self.__setPenBtnColor() def __flushPaintPosEdit(self, startPt:QPointF, endPt:QPointF): ''' 接收的坐标是imagelabel的绘图坐标,需要根据当前的zoom计算出真实的图片坐标,并显示在面板上 ''' realStartPt = (startPt/self.zoomList[self.zoomIdx]).toPoint() realEndPt = (endPt/self.zoomList[self.zoomIdx]).toPoint() self.start_x_edit.setText(str(realStartPt.x())) self.start_y_edit.setText(str(realStartPt.y())) self.end_x_edit.setText(str(realEndPt.x())) self.end_y_edit.setText(str(realEndPt.y())) def __flushPaintPosEdit1(self, startPt:QPointF, endPt:QPointF): ''' 接收的坐标是imagelabel的绘图坐标,需要根据当前的zoom计算出真实的图片坐标 ''' realStartPt = (startPt/self.zoomList[self.zoomIdx]).toPoint() realEndPt = (endPt/self.zoomList[self.zoomIdx]).toPoint() self.start_x_edit1.setText(str(realStartPt.x())) self.start_y_edit1.setText(str(realStartPt.y())) self.end_x_edit1.setText(str(realEndPt.x())) self.end_y_edit1.setText(str(realEndPt.y())) def __handleInputPaintPos(self): try: if self.imageLabel.pixmap()==None: return else: maxWidth = self.imageLabel.pixmap().width() maxHeight = self.imageLabel.pixmap().height() start_x = int(self.start_x_edit.text()) start_x = maxWidth if start_x>=maxWidth else start_x start_y = int(self.start_y_edit.text()) start_y = maxHeight if start_y>=maxHeight else start_y end_x = int(self.end_x_edit.text()) end_x = maxWidth if end_x>=maxWidth else end_x end_y = int(self.end_y_edit.text()) end_y = maxHeight if end_y>=maxHeight else end_y scale_ratio = self.zoomList[self.zoomIdx] self.imageLabel.paintCoordinates[0] = QPointF(float(start_x)*scale_ratio, float(start_y)*scale_ratio) self.imageLabel.paintCoordinates[1] = QPointF(float(end_x)*scale_ratio, float(end_y)*scale_ratio) self.imageLabel.paintEnd = True self.imageLabel.repaint() except ValueError: pass def __handleInputPaintPos1(self): try: if self.imageLabel1.pixmap()==None: return else: maxWidth = self.imageLabel1.pixmap().width() maxHeight = self.imageLabel1.pixmap().height() start_x = int(self.start_x_edit.text()) start_x = maxWidth if start_x>=maxWidth else start_x start_y = int(self.start_y_edit.text()) start_y = maxHeight if start_y>=maxHeight else start_y end_x = int(self.end_x_edit.text()) end_x = maxWidth if end_x>=maxWidth else end_x end_y = int(self.end_y_edit.text()) end_y = maxHeight if end_y>=maxHeight else end_y scale_ratio = self.zoomList[self.zoomIdx] self.imageLabel1.paintCoordinates[0] = QPointF(float(start_x)*scale_ratio, float(start_y)*scale_ratio) self.imageLabel1.paintCoordinates[1] = QPointF(float(end_x)*scale_ratio, float(end_y)*scale_ratio) self.imageLabel1.paintEnd = True self.imageLabel1.repaint() except ValueError: pass def createDockWidget_1(self): ''' 创建绘图工具箱,包含绘图类型,线宽,颜色,坐标值 ''' self.plotDockWgt = QDockWidget(self) self.plotDockWgt.setAllowedAreas(Qt.LeftDockWidgetArea|Qt.RightDockWidgetArea) self.plotDockWgt.setWindowTitle('color gamut type') #self.plotDockWgt.setFeatures(QDockWidget.DockWidgetClosable|QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetFloatable|QDockWidget.DockWidgetVerticalTitleBar) pltWgtContainer = QWidget() vlayout = QVBoxLayout() pltWgtContainer.setLayout(vlayout) self.plotDockWgt.setWidget(pltWgtContainer) pltWgtContainer.setStyleSheet('QPushButton{background-color:rgb(156,156,156)}') plot_btn_layout = QGridLayout() self.plot_rgb_contourf_line = QPushButton('rgb contour/line') self.plot_rgb_hist = QPushButton('rgb hist') self.plot_yuv_contourf_line = QPushButton('yuv contour/line') self.plot_yuv_hist = QPushButton('yuv hist') self.plot_hsv_contourf_line = QPushButton('hsv contour/line') self.plot_hsv_hist = QPushButton('hsv hist') plot_btn_layout.addWidget(self.plot_rgb_contourf_line, 0, 0, 1, 1) plot_btn_layout.addWidget(self.plot_rgb_hist, 0, 1, 1, 1) plot_btn_layout.addWidget(self.plot_yuv_contourf_line, 1, 0, 1, 1) plot_btn_layout.addWidget(self.plot_yuv_hist, 1, 1, 1, 1) plot_btn_layout.addWidget(self.plot_hsv_contourf_line, 2, 0, 1, 1) plot_btn_layout.addWidget(self.plot_hsv_hist, 2, 1, 1, 1) vlayout.addLayout(plot_btn_layout) rgb2yuv_mat_layout = QGridLayout() rgb2yuv_mat_label = QLabel('rgb2yuv:') rgb2yuv_mat_layout.addWidget(rgb2yuv_mat_label, 0, 0, 1, 1) validtor = QDoubleValidator(-5.0, 5.0, 10) self.rgb2yuv_mat_0 = QLineEdit('0.299') self.rgb2yuv_mat_0.setMaximumWidth(55) self.rgb2yuv_mat_0.setValidator(validtor) self.rgb2yuv_mat_1 = QLineEdit('0.587') self.rgb2yuv_mat_1.setMaximumWidth(55) self.rgb2yuv_mat_1.setValidator(validtor) self.rgb2yuv_mat_2 = QLineEdit('0.114') self.rgb2yuv_mat_2.setMaximumWidth(55) self.rgb2yuv_mat_2.setValidator(validtor) self.rgb2yuv_mat_3 = QLineEdit('-0.147') self.rgb2yuv_mat_3.setMaximumWidth(55) self.rgb2yuv_mat_3.setValidator(validtor) self.rgb2yuv_mat_4 = QLineEdit('-0.289') self.rgb2yuv_mat_4.setMaximumWidth(55) self.rgb2yuv_mat_4.setValidator(validtor) self.rgb2yuv_mat_5 = QLineEdit('0.436') self.rgb2yuv_mat_5.setMaximumWidth(55) self.rgb2yuv_mat_5.setValidator(validtor) self.rgb2yuv_mat_6 = QLineEdit('0.615') self.rgb2yuv_mat_6.setMaximumWidth(55) self.rgb2yuv_mat_6.setValidator(validtor) self.rgb2yuv_mat_7 = QLineEdit('-0.515') self.rgb2yuv_mat_7.setMaximumWidth(55) self.rgb2yuv_mat_7.setValidator(validtor) self.rgb2yuv_mat_8 = QLineEdit('-0.100') self.rgb2yuv_mat_8.setMaximumWidth(55) self.rgb2yuv_mat_8.setValidator(validtor) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_0, 1, 0, 1, 1) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_1, 1, 1, 1, 1) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_2, 1, 2, 1, 1) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_3, 2, 0, 1, 1) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_4, 2, 1, 1, 1) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_5, 2, 2, 1, 1) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_6, 3, 0, 1, 1) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_7, 3, 1, 1, 1) rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_8, 3, 2, 1, 1) rgb2yuv_mat_layout.setColumnMinimumWidth(0, 20) rgb2yuv_mat_layout.setColumnMinimumWidth(1, 20) rgb2yuv_mat_layout.setColumnMinimumWidth(2, 20) vlayout.addLayout(rgb2yuv_mat_layout) vlayout.addStretch(1) self.addDockWidget(Qt.LeftDockWidgetArea, self.plotDockWgt) def plot_rgb_contourf_line_func(self): f = self.__plot_rgb_contourf_line(self.imageLabel, self.opendFile, 0) f1 = self.__plot_rgb_contourf_line(self.imageLabel1, self.opendFile1, 1) if f is None and f1 is None: return else: plt.show() def __plot_rgb_contourf_line(self, label:ImageLabel, file:str, figCnt:int): if label.paintEnd==True and label.pixmap()!=None: pos_0, pos_1 = QPointF(label.paintCoordinates[0])/self.zoomList[self.zoomIdx], QPointF(label.paintCoordinates[1])/self.zoomList[self.zoomIdx] x_0, x_1, y_0, y_1 = pos_0.x(), pos_1.x(), pos_0.y(), pos_1.y() if x_0!=x_1 and y_0!=y_1 and self.paintType_rect_btn.isChecked(): if x_0 > x_1: x_0, x_1 = x_1, x_0 if y_0 > y_1: y_0, y_1 = y_1, y_0 if file.endswith(('.jpg', '.jpeg', 'JPG', 'JPEG')): reader = decompress_jpeg.jpeg_reader(bytes(file, encoding='utf-8')) rgb_data, out_rgb = reader.get_rgb_data() if rgb_data is None: QMessageBox.information(self, 'information', 'can not open image', QMessageBox.Ok) return None data = rgb_data.reshape((out_rgb.image_height, out_rgb.image_width, 3)).copy() del rgb_data reader.releaseBuffer() data = data[:, :, ::-1]# rgb->bgr else: data = cv.imread(file) if data is None: QMessageBox.information(self, 'information', 'can not open image', QMessageBox.Ok) return None data_r = data[int(y_0):int(y_1), int(x_0):int(x_1), 2] data_g = data[int(y_0):int(y_1), int(x_0):int(x_1), 1] data_b = data[int(y_0):int(y_1), int(x_0):int(x_1), 0] data_max = np.max([data_r.max(), data_g.max(), data_b.max()]) data_min = np.min([data_r.min(), data_g.min(), data_b.min()]) X = np.arange(data_r.shape[1]) Y = np.arange(data_r.shape[0]) X, Y = np.meshgrid(X, Y) fig = plt.figure(figCnt, figsize=(4, 9)) ax1 = fig.add_subplot(311) surf1 = ax1.contourf(X, Y, data_r, np.linspace(data_min-5, data_max+5, 11), cmap=cm.get_cmap('coolwarm')) ax1.set_ylim([data_r.shape[0], 0]) ax1.set_title('r contour') fig.colorbar(surf1) ax2 = fig.add_subplot(312) surf2 = ax2.contourf(X, Y, data_g, np.linspace(data_min-5, data_max+5, 11), cmap=cm.get_cmap('coolwarm')) ax2.set_ylim([data_g.shape[0], 0]) ax2.set_title('g contour') fig.colorbar(surf2) ax3 = fig.add_subplot(313) surf3 = ax3.contourf(X, Y, data_b, np.linspace(data_min-5, data_max+5, 11), cmap=cm.get_cmap('coolwarm')) ax3.set_ylim([data_b.shape[0], 0]) ax3.set_title('b contour') fig.colorbar(surf3) fig.tight_layout() return fig elif self.paintType_line_btn.isChecked() and not(x_0==x_1 and y_0==y_1): if x_0 > x_1: x_0, x_1 = x_1, x_0 y_0, y_1 = y_1, y_0 data = cv.imread(file) if data is None: QMessageBox.information(self, 'information', 'can not open image %s'%self.opendFile, QMessageBox.Ok) return None if x_0==x_1: if y_0<y_1: data_r = data[y_0:y_1, x_0, 2] data_g = data[y_0:y_1, x_0, 1] data_b = data[y_0:y_1, x_0, 0] else: data_r = data[y_0:y_1:-1, x_0, 2] data_g = data[y_0:y_1:-1, x_0, 1] data_b = data[y_0:y_1:-1, x_0, 0] elif y_0==y_1: data_r = data[y_0, x_0:x_1, 2] data_g = data[y_0, x_0:x_1, 1] data_b = data[y_0, x_0:x_1, 0] else: length = math.sqrt((x_1-x_0)*(x_1-x_0) + (y_1-y_0)*(y_1-y_0)) data_r = np.zeros((int(length), ), np.uint8) data_g = np.zeros((int(length), ), np.uint8) data_b = np.zeros((int(length), ), np.uint8) k = (y_1-y_0)/(x_1-x_0) for l in range(int(length)): delt_x = math.sqrt((l*l)/(1+k*k)) delt_y = k*delt_x data_r[l] = data[int(y_0+delt_y+0.5), int(x_0+delt_x+0.5), 2] data_g[l] = data[int(y_0+delt_y+0.5), int(x_0+delt_x+0.5), 1] data_b[l] = data[int(y_0+delt_y+0.5), int(x_0+delt_x+0.5), 0] fig = plt.figure(figCnt, figsize=(6, 4)) ax = fig.add_subplot(111) ax.plot(data_r, 'r-', data_g, 'g-', data_b, 'b-') return fig else: return None else: return None def eventFilter(self, obj:QObject, event:QEvent): if obj is self.toolBoxWidget and event.type()==QEvent.Close: self.penBoxAction.setChecked(False) return True if obj is self.plotDockWgt and event.type()==QEvent.Close: self.colorGamutAction.setChecked(False) return True return super().eventFilter(obj, event) def plot_rgb_hist_func(self): fig, fig1 = None, None if self.imageLabel.paintEnd==True and self.imageLabel.pixmap()!=None: pos_0, pos_1 = QPointF(self.imageLabel.paintCoordinates[0])/self.zoomList[self.zoomIdx], QPointF(self.imageLabel.paintCoordinates[1])/self.zoomList[self.zoomIdx] x_0, x_1, y_0, y_1 = pos_0.x(), pos_1.x(), pos_0.y(), pos_1.y() if x_0 > x_1: x_0, x_1 = x_1, x_0 if y_0 > y_1: y_0, y_1 = y_1, y_0 data = cv.imread(self.opendFile) if data is None: QMessageBox.information(self, 'information', 'can not open image %s'%self.opendFile, QMessageBox.Ok) return data_r = data[int(y_0):int(y_1), int(x_0):int(x_1), 2].flatten() data_g = data[int(y_0):int(y_1), int(x_0):int(x_1), 1].flatten() data_b = data[int(y_0):int(y_1), int(x_0):int(x_1), 0].flatten() n_bins = 64 fig = plt.figure(0, figsize=(4, 6)) ax1 = fig.add_subplot(311) N1, bins1, pathch1 = ax1.hist(data_r, n_bins, histtype='bar', color='r') ax1.set_title('r0 hist') ax2 = fig.add_subplot(312) N2, bins2, pathch2 = ax2.hist(data_g, n_bins, histtype='bar', color='g') ax2.set_title('g0 hist') ax3 = fig.add_subplot(313) N3, bins3, pathch3 = ax3.hist(data_b, n_bins, histtype='bar', color='b') ax3.set_title('b0 hist') N_max_0 = np.max([N1.max(), N2.max(), N3.max()]) ax1.set_ylim([0, N_max_0]) ax1.set_xlim([0, 255]) ax2.set_ylim([0, N_max_0]) ax2.set_xlim([0, 255]) ax3.set_ylim([0, N_max_0]) ax3.set_xlim([0, 255]) fig.tight_layout() if self.imageLabel1.paintEnd==True and self.imageLabel1.pixmap()!=None: pos_1_0, pos_1_1 = QPointF(self.imageLabel1.paintCoordinates[0])/self.zoomList[self.zoomIdx], QPointF(self.imageLabel1.paintCoordinates[1])/self.zoomList[self.zoomIdx] x_1_0, x_1_1, y_1_0, y_1_1 = pos_1_0.x(), pos_1_1.x(), pos_1_0.y(), pos_1_1.y() if x_1_0 > x_1_1: x_1_0, x_1_1 = x_1_1, x_1_0 if y_1_0 > y_1_1: y_1_0, y_1_1 = y_1_1, y_1_0 data1 = cv.imread(self.opendFile1) if data1 is None: QMessageBox.information(self, 'information', 'can not open image %s'%self.opendFile1, QMessageBox.Ok) return data1_r = data1[int(y_1_0):int(y_1_1), int(x_1_0):int(x_1_1), 2].flatten() data1_g = data1[int(y_1_0):int(y_1_1), int(x_1_0):int(x_1_1), 1].flatten() data1_b = data1[int(y_1_0):int(y_1_1), int(x_1_0):int(x_1_1), 0].flatten() fig1 = plt.figure(1, figsize=(4, 6)) ax1_1 = fig1.add_subplot(311) N1_1, bins1_1, pathch1_1 = ax1_1.hist(data1_r, n_bins, histtype='bar', color='r') ax1_1.set_title('r0 hist') ax1_2 = fig1.add_subplot(312) N1_2, bins1_2, pathch1_2 = ax1_2.hist(data1_g, n_bins, histtype='bar', color='g') ax1_2.set_title('g0 hist') ax1_3 = fig1.add_subplot(313) N1_3, bins1_3, pathch1_3 = ax1_3.hist(data1_b, n_bins, histtype='bar', color='b') ax1_3.set_title('b0 hist') N_max_1 = np.max([N1_1.max(), N1_2.max(), N1_3.max()]) ax1_1.set_ylim([0, N_max_1]) ax1_1.set_xlim([0, 255]) ax1_2.set_ylim([0, N_max_1]) ax1_2.set_xlim([0, 255]) ax1_3.set_ylim([0, N_max_1]) ax1_3.set_xlim([0, 255]) fig1.tight_layout() if fig is None and fig1 is None: return plt.show() def __setPenBtnColor(self): self.colorBtn.setStyleSheet('QPushButton{background:rgb(%d,%d,%d);border:none;}'%(self.penColor.red(), self.penColor.green(), self.penColor.blue())) def __selectColor(self): dlg = QColorDialog(self.penColor, self.toolBoxWidget) reply = dlg.exec_() if reply == QColorDialog.Accepted: self.penColor = dlg.selectedColor() self.__setPenBtnColor() self.imageLabel.setPaintPenColor(self.penColor) self.imageLabel1.setPaintPenColor(self.penColor) def closeEvent(self, event): reply = QMessageBox.question(self, 'question', 'are you sure to quit?', QMessageBox.Yes|QMessageBox.No) if reply == QMessageBox.Yes: super().closeEvent(event) else: event.ignore() def onQuit(self): self.close() def onCloseAction(self): if self.imageLabel.pixmap()==None and self.imageLabel1.pixmap()==None: return self.imageLabel.clear() self.imageLabel.setText('drag image file to here!') self.imageLabel.adjustSize() self.imageLabel.paintBegin = False self.imageLabel.paintEnd = False self.imageLabel1.clear() self.imageLabel1.setText('drag image file to here!') self.imageLabel1.adjustSize() self.imageLabel1.paintBegin = False self.imageLabel1.paintEnd = False self.opendFile = '' self.opendFile1 = '' self.__setTitle() self.start_x_edit.setText('') self.start_y_edit.setText('') self.end_x_edit.setText('') self.end_y_edit.setText('') self.start_x_edit1.setText('') self.start_y_edit1.setText('') self.end_x_edit1.setText('') self.end_y_edit1.setText('') def onOpenFileAction(self): fileList = QFileDialog.getOpenFileNames(self, 'open', self.workPath, 'Images(*.jpg *.jpeg *.png *.bmp);;All file(*.*)')# type:list[str] if len(fileList)<=0 or len(fileList[0])<=0: return reader = QImageReader(fileList[0][0]) reader.setAutoTransform(True) img = reader.read() if img.isNull(): QMessageBox.information(self, 'error', 'can not open %s as image!'%fileList[0][0], QMessageBox.Ok) return self.opendFile = fileList[0][0] self.__setImage(img, self.zoomList[self.zoomIdx]) if len(fileList[0])>=2: reader1 =QImageReader(fileList[0][1]) reader1.setAutoTransform(True) img1 = reader1.read() if img1.isNull(): QMessageBox.information(self, 'error', 'can not open %s as image!'%fileList[0][0], QMessageBox.Ok) return self.__setImage1(img1, self.zoomList[self.zoomIdx]) self.opendFile1 = fileList[0][1] self.__setTitle() def __setTitle(self): if self.opendFile=='' and self.opendFile1=='': self.setWindowTitle('raw_image_data_visual') elif self.opendFile=='' or self.opendFile1=='': self.setWindowTitle(self.opendFile + self.opendFile1) else: self.setWindowTitle(self.opendFile +'<--->'+ self.opendFile1) def __setImage(self, image:QImage, factor:float): pixMap = QPixmap.fromImage(image) self.originSize = pixMap.size() self.imageLabel.paintBegin = False self.imageLabel.paintEnd = False self.imageLabel.setPixmap(pixMap) self.__adjustImgLabelSize_scrollbarPos() def __setImage1(self, image:QImage, factor:float): pixMap = QPixmap.fromImage(image) self.originSize1 = pixMap.size() self.imageLabel1.paintBegin = False self.imageLabel1.paintEnd = False self.imageLabel1.setPixmap(pixMap) self.__adjustImgLabelSize_scrollbarPos1() def zoomIn(self): if self.imageLabel.pixmap() == None or self.originSize == QSize(0, 0): return if(self.zoomIdx < len(self.zoomList)-1): self.zoomIdx = self.zoomIdx + 1 else: return scale_ratio = self.zoomList[self.zoomIdx] if self.imageLabel.paintEnd == True: self.imageLabel.paintCoordinates[0] = QPointF(float(self.start_x_edit.text())*scale_ratio, float(self.start_y_edit.text())*scale_ratio) self.imageLabel.paintCoordinates[1] = QPointF(float(self.end_x_edit.text())*scale_ratio, float(self.end_y_edit.text())*scale_ratio) self.__adjustImgLabelSize_scrollbarPos()#缩放image label if self.imageLabel1.paintEnd == True: self.imageLabel1.paintCoordinates[0] = QPointF(float(self.start_x_edit1.text())*scale_ratio, float(self.start_y_edit1.text())*scale_ratio) self.imageLabel1.paintCoordinates[1] = QPointF(float(self.end_x_edit1.text())*scale_ratio, float(self.end_y_edit1.text())*scale_ratio) self.__adjustImgLabelSize_scrollbarPos1()#因为已经关联了另一个scrollbar,会自动调整 def zoomOut(self): if self.imageLabel.pixmap() == None or self.originSize == QSize(0, 0): return if self.zoomIdx > 0: self.zoomIdx = self.zoomIdx - 1 else: return scale_ratio = self.zoomList[self.zoomIdx]/self.zoomList[self.zoomIdx+1] if self.imageLabel.paintEnd == True: self.imageLabel.paintCoordinates[0] = self.imageLabel.paintCoordinates[0]*scale_ratio self.imageLabel.paintCoordinates[1] = self.imageLabel.paintCoordinates[1]*scale_ratio self.__adjustImgLabelSize_scrollbarPos() if self.imageLabel1.paintEnd == True: self.imageLabel1.paintCoordinates[0] = self.imageLabel1.paintCoordinates[0]*scale_ratio self.imageLabel1.paintCoordinates[1] = self.imageLabel1.paintCoordinates[1]*scale_ratio #缩放绘图 self.__adjustImgLabelSize_scrollbarPos1()#缩放image label def __adjustImgLabelSize_scrollbarPos(self): self.imageLabel.resize(self.originSize*self.zoomList[self.zoomIdx]) if self.scrollArea.horizontalScrollBar().maximum() - self.scrollArea.horizontalScrollBar().minimum() > 0: self.scrollArea.horizontalScrollBar().setValue((self.scrollArea.horizontalScrollBar().maximum() - self.scrollArea.horizontalScrollBar().minimum())//2) if self.scrollArea.verticalScrollBar().maximum() - self.scrollArea.verticalScrollBar().minimum() > 0: self.scrollArea.verticalScrollBar().setValue((self.scrollArea.verticalScrollBar().maximum() - self.scrollArea.verticalScrollBar().minimum())//2) def __adjustImgLabelSize_scrollbarPos1(self): self.imageLabel1.resize(self.originSize1*self.zoomList[self.zoomIdx]) if self.scrollArea1.horizontalScrollBar().maximum() - self.scrollArea1.horizontalScrollBar().minimum() > 0: self.scrollArea1.horizontalScrollBar().setValue((self.scrollArea1.horizontalScrollBar().maximum() - self.scrollArea1.horizontalScrollBar().minimum())//2) if self.scrollArea1.verticalScrollBar().maximum() - self.scrollArea1.verticalScrollBar().minimum() > 0: self.scrollArea1.verticalScrollBar().setValue((self.scrollArea1.verticalScrollBar().maximum() - self.scrollArea1.verticalScrollBar().minimum())//2) def dragEnterEvent(self, event:QDragEnterEvent): if event.mimeData().hasUrls(): event.acceptProposedAction() else: event.ignore() def dropEvent(self, event:QDropEvent): mainWidget_rect = self.mainWidget.geometry() dropPt = event.pos() if dropPt.x()<mainWidget_rect.left() or dropPt.x()>mainWidget_rect.right() or dropPt.y()<mainWidget_rect.top() or dropPt.y()>mainWidget_rect.bottom(): return mData = event.mimeData() if not mData.hasUrls(): return urlList = mData.urls() if len(urlList)==1: scrollArea_rect = self.scrollArea.geometry().translated(mainWidget_rect.topLeft()) scrollArea1_rect = self.scrollArea1.geometry().translated(mainWidget_rect.topLeft()) if dropPt.x()>scrollArea_rect.left() and dropPt.x()<scrollArea_rect.right(): fileName = urlList[0].toLocalFile() if len(fileName)<=0 or fileName==None: return if fileName.endswith(('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.bmp', '.BMP')): reader = QImageReader(fileName) reader.setAutoTransform(True) img = reader.read() if img.isNull(): QMessageBox.information(self, 'error', 'can not open %s as image!'%fileName, QMessageBox.Ok) return self.opendFile = fileName self.__setTitle() self.__setImage(img, self.zoomList[self.zoomIdx]) elif dropPt.x()>scrollArea1_rect.left() and dropPt.x()<scrollArea1_rect.right(): fileName = urlList[0].toLocalFile() if len(fileName)<=0 or fileName==None: return if fileName.endswith(('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.bmp', '.BMP')): reader = QImageReader(fileName) reader.setAutoTransform(True) img = reader.read() if img.isNull(): QMessageBox.information(self, 'error', 'can not open %s as image!'%fileName, QMessageBox.Ok) return self.opendFile1 = fileName self.__setTitle() self.__setImage1(img, self.zoomList[self.zoomIdx]) else: pass elif len(urlList)>=2: fileName = urlList[0].toLocalFile() fileName1 = urlList[1].toLocalFile() if len(fileName)<=0 or fileName==None or len(fileName1)<=0 or fileName1==None: return if fileName.endswith(('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.bmp', '.BMP')) and fileName1.endswith(('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.bmp', '.BMP')): reader = QImageReader(fileName) reader.setAutoTransform(True) img = reader.read() reader1 = QImageReader(fileName1) reader1.setAutoTransform(True) img1 = reader1.read() if img.isNull() or img1.isNull(): QMessageBox.information(self, 'error', 'can not open %s %sas image!'%(fileName, fileName1), QMessageBox.Ok) return self.opendFile = fileName self.opendFile1 = fileName1 self.__setTitle() self.__setImage(img, self.zoomList[self.zoomIdx]) self.__setImage1(img1, self.zoomList[self.zoomIdx]) else: pass def aboutQt_(self): QApplication.instance().aboutQt() def aboutThis(self): dlg = aboutDlg(self) dlg.exec_()
class main_class(QWidget): def __init__(self): super().__init__() self.thread_subs = QThread() self.obj = thread_subtitles() self.obj.update_subtitles.connect(self.render_subtitles) self.obj.moveToThread(self.thread_subs) self.thread_subs.started.connect(self.obj.main) self.thread_subs.start() self.thread_translations = QThread() self.obj2 = thread_translations() self.obj2.get_translations.connect(self.render_popup) self.obj2.moveToThread(self.thread_translations) self.thread_translations.started.connect(self.obj2.main) self.thread_translations.start() # start the forms self.subtitles_base() self.subtitles_base2() self.popup_base() def clearLayout(self, layout): if layout == 'subs': layout = self.subtitles_vbox self.subtitles.hide() elif layout == 'subs2': layout = self.subtitles_vbox2 self.subtitles2.hide() elif layout == 'popup': layout = self.popup_vbox self.popup.hide() if layout is not None: while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.deleteLater() else: self.clearLayout(item.layout()) def subtitles_base(self): self.subtitles = QFrame() self.subtitles.setAttribute(Qt.WA_TranslucentBackground) self.subtitles.setWindowFlags(Qt.X11BypassWindowManagerHint) self.subtitles.setStyleSheet(config.style_subs) self.subtitles_vbox = QVBoxLayout(self.subtitles) self.subtitles_vbox.setSpacing(config.subs_padding_between_lines) self.subtitles_vbox.setContentsMargins(0, 0, 0, 0) def subtitles_base2(self): self.subtitles2 = QFrame() self.subtitles2.setAttribute(Qt.WA_TranslucentBackground) self.subtitles2.setWindowFlags(Qt.X11BypassWindowManagerHint) self.subtitles2.setStyleSheet(config.style_subs) self.subtitles_vbox2 = QVBoxLayout(self.subtitles2) self.subtitles_vbox2.setSpacing(config.subs_padding_between_lines) self.subtitles_vbox2.setContentsMargins(0, 0, 0, 0) if config.pause_during_translation_B: self.subtitles2.enterEvent = lambda event: [ mpv_pause(), setattr(config, 'block_popup', False) ][0] self.subtitles2.leaveEvent = lambda event: [ mpv_resume(), setattr(config, 'block_popup', True) ][0] if not config.avoid_resuming else [ setattr(config, 'avoid_resuming', False), setattr(config, 'block_popup', True) ][0] def popup_base(self): self.popup = QFrame() self.popup.setAttribute(Qt.WA_TranslucentBackground) self.popup.setWindowFlags(Qt.X11BypassWindowManagerHint) self.popup.setStyleSheet(config.style_popup) self.popup_inner = QFrame() outer_box = QVBoxLayout(self.popup) outer_box.addWidget(self.popup_inner) self.popup_vbox = QVBoxLayout(self.popup_inner) self.popup_vbox.setSpacing(0) def render_subtitles(self, hide=False, redraw=False): if hide or not len(subs): try: self.subtitles.hide() self.subtitles2.hide() finally: return if redraw: self.subtitles.setStyleSheet(config.style_subs) self.subtitles2.setStyleSheet(config.style_subs) else: self.clearLayout('subs') self.clearLayout('subs2') if hasattr(self, 'popup'): self.popup.hide() # if subtitle consists of one overly long line - split into two if config.split_long_lines_B and len( subs.split('\n')) == 1 and len(subs.split( ' ')) > config.split_long_lines_words_min - 1: subs2 = split_long_lines(subs) else: subs2 = subs subs2 = re.sub(' +', ' ', subs2).strip() ############################## for line in subs2.split('\n'): line2 = ' %s ' % line.strip() ll = drawing_layer(line2, subs2) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(0) hbox.addStretch() hbox.addWidget(ll) hbox.addStretch() self.subtitles_vbox.addLayout(hbox) #################################### hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(0) hbox.addStretch() if config.R2L_from_B: line2 = line2[::-1] line2 += '\00' word = '' for smbl in line2: if smbl.isalpha(): word += smbl else: if len(word): if config.R2L_from_B: word = word[::-1] ll = events_class(word, subs2) ll.mouseHover.connect(self.render_popup) ll.redraw.connect(self.render_subtitles) hbox.addWidget(ll) word = '' if smbl != '\00': ll = events_class(smbl, subs2, skip=True) hbox.addWidget(ll) hbox.addStretch() self.subtitles_vbox2.addLayout(hbox) self.subtitles.adjustSize() self.subtitles2.adjustSize() w = self.subtitles.geometry().width() h = self.subtitles.height = self.subtitles.geometry().height() x = (config.screen_width / 2) - (w / 2) if config.subs_top_placement_B: y = config.subs_screen_edge_padding else: y = config.screen_height - config.subs_screen_edge_padding - h self.subtitles.setGeometry(int(x), int(y), 0, 0) self.subtitles.show() self.subtitles2.setGeometry(int(x), int(y), 0, 0) self.subtitles2.show() def render_popup(self, text, x_cursor_pos, is_line): if text == '': if hasattr(self, 'popup'): self.popup.hide() return self.clearLayout('popup') if is_line: QApplication.setOverrideCursor(Qt.WaitCursor) line = globals()[config.translation_function_name_full_sentence]( text) if config.translation_function_name_full_sentence == 'google': try: line = line[0][0][0].strip() except: line = 'Google translation failed.' if config.split_long_lines_B and len( line.split('\n')) == 1 and len(line.split( ' ')) > config.split_long_lines_words_min - 1: line = split_long_lines(line) ll = QLabel(line) ll.setObjectName("first_line") self.popup_vbox.addWidget(ll) else: word = text for translation_function_name_i, translation_function_name in enumerate( config.translation_function_names): pairs, word_descr = globals()[translation_function_name](word) if not len(pairs): pairs = [['', '[Not found]']] #return # ~pairs = [ [ str(i) + ' ' + pair[0], pair[1] ] for i, pair in enumerate(pairs) ] if word in config.scroll: if len(pairs[config.scroll[word]:] ) > config.number_of_translations: pairs = pairs[config.scroll[word]:] else: pairs = pairs[-config.number_of_translations:] if len(config.translation_function_names) == 1: config.scroll[word] -= 1 for i1, pair in enumerate(pairs): if i1 == config.number_of_translations: break if config.split_long_lines_in_popup_B: pair[0] = split_long_lines( pair[0], max_symbols_per_line=config. split_long_lines_in_popup_symbols_min) pair[1] = split_long_lines( pair[1], max_symbols_per_line=config. split_long_lines_in_popup_symbols_min) if pair[0] == '-': pair[0] = '' if pair[1] == '-': pair[1] = '' # ~if config.R2L_from_B: # ~pair[0] = pair[0][::-1] # ~if config.R2L_to_B: # ~pair[1] = pair[1][::-1] if pair[0] != '': # to emphasize the exact form of the word # to ignore case on input and match it on output chnks = re.split(word, pair[0], flags=re.I) exct_words = re.findall(word, pair[0], flags=re.I) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) for i2, chnk in enumerate(chnks): if len(chnk): ll = QLabel(chnk) ll.setObjectName("first_line") hbox.addWidget(ll) if i2 + 1 < len(chnks): ll = QLabel(exct_words[i2]) ll.setObjectName("first_line_emphasize_word") hbox.addWidget(ll) # filling the rest of the line with empty bg ll = QLabel() ll.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) hbox.addWidget(ll) self.popup_vbox.addLayout(hbox) if pair[1] != '': ll = QLabel(pair[1]) ll.setObjectName("second_line") self.popup_vbox.addWidget(ll) # padding ll = QLabel() ll.setStyleSheet("font-size: 6px;") self.popup_vbox.addWidget(ll) if len(word_descr[0]): ll = QLabel(word_descr[0]) ll.setProperty("morphology", word_descr[1]) ll.setAlignment(Qt.AlignRight) self.popup_vbox.addWidget(ll) # delimiter between dictionaries if translation_function_name_i + 1 < len( config.translation_function_names): ll = QLabel() ll.setObjectName("delimiter") self.popup_vbox.addWidget(ll) self.popup_inner.adjustSize() self.popup.adjustSize() w = self.popup.geometry().width() h = self.popup.geometry().height() if w > config.screen_width: w = config.screen_width - 20 if not is_line: if w < config.screen_width / 3: w = config.screen_width / 3 if x_cursor_pos == -1: x = (config.screen_width / 2) - (w / 2) else: x = x_cursor_pos - w / 5 if x + w > config.screen_width: x = config.screen_width - w if config.subs_top_placement_B: y = self.subtitles.height + config.subs_screen_edge_padding else: y = config.screen_height - config.subs_screen_edge_padding - self.subtitles.height - h self.popup.setGeometry(int(x), int(y), int(w), 0) self.popup.show() QApplication.restoreOverrideCursor()
class MWindow(QFrame, MHierarchicalElement): def __init__(self, content, title): super().__init__() # if not (type(content) is MContainer): # raise TypeError("Expected type %s, got %s" % (str(MContainer), type(content))) self.content = content content.setMouseTracking(True) self.setObjectName("main_m_window_frame") # Construct top-level window elements self.main_layout = QVBoxLayout() self.main_layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.main_layout) self.header_frame = MHeaderBar(self) self.header_frame.setTitle(title) self.main_layout.addWidget(self.header_frame) self.main_layout.addStretch(0) self.main_layout.addWidget(self.content) self.main_layout.setStretchFactor(self.content, 1) self.show() self.setStyleSheet( self.styleSheet() + "QFrame#main_m_window_frame{border: 2px solid black}\r\n" "QFrame#main_m_window_frame{background-color:rgb(120,120,130)}") self.drop_region_top_frame = QFrame(self) self.drop_region_left_frame = QFrame(self) self.drop_region_right_frame = QFrame(self) self.drop_region_bottom_frame = QFrame(self) self.drop_region_onto_frame = QFrame(self) self.drop_region_stylesheet = "background-color: rgba(50, 50, 150, 0);" self.drop_region_focused_stylesheet = "background-color: rgba(50, 50, 80, 100);" \ "border: 2px solid grey" self.drop_region_top_frame.setStyleSheet(self.drop_region_stylesheet) self.drop_region_left_frame.setStyleSheet(self.drop_region_stylesheet) self.drop_region_right_frame.setStyleSheet(self.drop_region_stylesheet) self.drop_region_bottom_frame.setStyleSheet( self.drop_region_stylesheet) self.drop_region_onto_frame.setStyleSheet(self.drop_region_stylesheet) self.drop_regions = { "top": self.drop_region_top_frame, "left": self.drop_region_left_frame, "right": self.drop_region_right_frame, "bottom": self.drop_region_bottom_frame, "onto": self.drop_region_onto_frame } self.setMinimumHeight(24) self.setMinimumWidth(128) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.uid = None def get_content(self): return self.content def set_title(self, title): self.header_frame.setTitle(title) def get_title(self): return self.header_frame.getTitle() def show_drop_regions(self): window_geometry = self.geometry() self.drop_region_top_frame.setGeometry(0, 0, window_geometry.width(), window_geometry.height() / 5) self.drop_region_left_frame.setGeometry(0, 0, window_geometry.width() / 5, window_geometry.height()) self.drop_region_right_frame.setGeometry( 4 * window_geometry.width() / 5, 0, window_geometry.width() / 5, window_geometry.height()) self.drop_region_bottom_frame.setGeometry( 0, 4 * window_geometry.height() / 5, window_geometry.width(), window_geometry.height() / 5) self.drop_region_onto_frame.setGeometry( 1 * window_geometry.width() / 3, 1 * window_geometry.height() / 3, window_geometry.width() / 3, window_geometry.height() / 3) self.drop_region_top_frame.show() self.drop_region_left_frame.show() self.drop_region_right_frame.show() self.drop_region_bottom_frame.show() self.drop_region_onto_frame.show() self.drop_region_top_frame.raise_() self.drop_region_top_frame.updateGeometry() def hide_drop_regions(self): #print("hiding drop regions of", str(self)) for child in self.child_containers: child.hide_drop_regions() self.drop_region_top_frame.hide() self.drop_region_left_frame.hide() self.drop_region_right_frame.hide() self.drop_region_bottom_frame.hide() self.drop_region_onto_frame.hide() def over_drop_regions(self, pos): if self.drop_region_top_frame.geometry().contains( self.mapFromGlobal(pos)): return self.drop_region_top_frame elif self.drop_region_left_frame.geometry().contains( self.mapFromGlobal(pos)): return self.drop_region_left_frame elif self.drop_region_right_frame.geometry().contains( self.mapFromGlobal(pos)): return self.drop_region_right_frame elif self.drop_region_bottom_frame.geometry().contains( self.mapFromGlobal(pos)): return self.drop_region_bottom_frame elif self.drop_region_onto_frame.geometry().contains( self.mapFromGlobal(pos)): return self.drop_region_onto_frame else: return None def focus_drop_region(self, pos): active_region = self.over_drop_regions(pos) for drop_region in self.drop_regions.values(): if drop_region is active_region: drop_region.setStyleSheet(self.drop_region_focused_stylesheet) else: drop_region.setStyleSheet(self.drop_region_stylesheet) def get_drop_region(self, key): return self.drop_regions[key] def __str__(self): return self.get_title()