class TContainer(QWidget): """ allow to move and resize by user""" menu = None mode = Mode.NONE position = None inFocus = Signal(bool) outFocus = Signal(bool) newGeometry = Signal(QRect) def __init__(self, parent, p): super().__init__(parent=parent) self.menu = QMenu(parent=self, title='menu') self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) self.setVisible(True) self.setAutoFillBackground(False) self.setMouseTracking(True) self.setFocusPolicy(QtCore.Qt.ClickFocus) self.setFocus() self.move(p) self.vLayout = QVBoxLayout(self) self.m_infocus = True self.m_showMenu = False self.m_isEditing = True self.installEventFilter(parent) def setChildWidget(self, cWidget): if cWidget: self.childWidget = cWidget self.childWidget.setAttribute( QtCore.Qt.WA_TransparentForMouseEvents, True) self.childWidget.setParent(self) self.childWidget.releaseMouse() self.vLayout.addWidget(cWidget) self.vLayout.setContentsMargins(0, 0, 0, 0) def popupShow(self, pt: QPoint): if self.menu.isEmpty: return global_ = self.mapToGlobal(pt) self.m_showMenu = True self.menu.exec(global_) self.m_showMenu = False def focusInEvent(self, a0: QtGui.QFocusEvent): self.m_infocus = True p = self.parentWidget() p.installEventFilter(self) p.repaint() self.inFocus.emit(True) def focusOutEvent(self, a0: QtGui.QFocusEvent): if not self.m_isEditing: return if self.m_showMenu: return self.mode = Mode.NONE self.outFocus.emit(False) self.m_infocus = False def paintEvent(self, e: QtGui.QPaintEvent): painter = QtGui.QPainter(self) color = (r, g, b, a) = (255, 0, 0, 16) painter.fillRect(e.rect(), QColor(r, g, b, a)) if self.m_infocus: rect = e.rect() rect.adjust(0, 0, -1, -1) painter.setPen(QColor(r, g, b)) painter.drawRect(rect) def mousePressEvent(self, e: QtGui.QMouseEvent): self.position = QPoint(e.globalX() - self.geometry().x(), e.globalY() - self.geometry().y()) if not self.m_isEditing: return if not self.m_infocus: return if not e.buttons() and QtCore.Qt.LeftButton: self.setCursorShape(e.pos()) return if e.button() == QtCore.Qt.RightButton: self.popupShow(e.pos()) e.accept() def keyPressEvent(self, e: QtGui.QKeyEvent): if not self.m_isEditing: return if e.key() == QtCore.Qt.Key_Delete: self.deleteLater() # Moving container with arrows if QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: newPos = QPoint(self.x(), self.y()) if e.key() == QtCore.Qt.Key_Up: newPos.setY(newPos.y() - 1) if e.key() == QtCore.Qt.Key_Down: newPos.setY(newPos.y() + 1) if e.key() == QtCore.Qt.Key_Left: newPos.setX(newPos.x() - 1) if e.key() == QtCore.Qt.Key_Right: newPos.setX(newPos.x() + 1) self.move(newPos) if QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier: if e.key() == QtCore.Qt.Key_Up: self.resize(self.width(), self.height() - 1) if e.key() == QtCore.Qt.Key_Down: self.resize(self.width(), self.height() + 1) if e.key() == QtCore.Qt.Key_Left: self.resize(self.width() - 1, self.height()) if e.key() == QtCore.Qt.Key_Right: self.resize(self.width() + 1, self.height()) self.newGeometry.emit(self.geometry()) def setCursorShape(self, e_pos: QPoint): diff = 3 # Left - Bottom if (((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() < self.x() + diff)) or # Left # Right-Bottom ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() > self.x() + self.width() - diff)) or # Right # Left-Top ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() < self.x() + diff)) or # Left # Right-Top (e_pos.y() < self.y() + diff) and # Top (e_pos.x() > self.x() + self.width() - diff)): # Right # Left - Bottom if ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() < self.x() + diff)): # Left self.mode = Mode.RESIZEBL self.setCursor(QCursor(QtCore.Qt.SizeBDiagCursor)) # Right - Bottom if ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() > self.x() + self.width() - diff)): # Right self.mode = Mode.RESIZEBR self.setCursor(QCursor(QtCore.Qt.SizeFDiagCursor)) # Left - Top if ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() < self.x() + diff)): # Left self.mode = Mode.RESIZETL self.setCursor(QCursor(QtCore.Qt.SizeFDiagCursor)) # Right - Top if ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() > self.x() + self.width() - diff)): # Right self.mode = Mode.RESIZETR self.setCursor(QCursor(QtCore.Qt.SizeBDiagCursor)) # check cursor horizontal position elif ((e_pos.x() < self.x() + diff) or # Left (e_pos.x() > self.x() + self.width() - diff)): # Right if e_pos.x() < self.x() + diff: # Left self.setCursor(QCursor(QtCore.Qt.SizeHorCursor)) self.mode = Mode.RESIZEL else: # Right self.setCursor(QCursor(QtCore.Qt.SizeHorCursor)) self.mode = Mode.RESIZER # check cursor vertical position elif ((e_pos.y() > self.y() + self.height() - diff) or # Bottom (e_pos.y() < self.y() + diff)): # Top if e_pos.y() < self.y() + diff: # Top self.setCursor(QCursor(QtCore.Qt.SizeVerCursor)) self.mode = Mode.RESIZET else: # Bottom self.setCursor(QCursor(QtCore.Qt.SizeVerCursor)) self.mode = Mode.RESIZEB else: self.setCursor(QCursor(QtCore.Qt.ArrowCursor)) self.mode = Mode.MOVE def mouseReleaseEvent(self, e: QtGui.QMouseEvent): QWidget.mouseReleaseEvent(self, e) def mouseMoveEvent(self, e: QtGui.QMouseEvent): QWidget.mouseMoveEvent(self, e) if not self.m_isEditing: return if not self.m_infocus: return if not e.buttons() and QtCore.Qt.LeftButton: p = QPoint(e.x() + self.geometry().x(), e.y() + self.geometry().y()) self.setCursorShape(p) return if (self.mode == Mode.MOVE or self.mode == Mode.NONE) and e.buttons() and QtCore.Qt.LeftButton: toMove = e.globalPos() - self.position if toMove.x() < 0: return if toMove.y() < 0: return if toMove.x() > self.parentWidget().width() - self.width(): return self.move(toMove) self.newGeometry.emit(self.geometry()) self.parentWidget().repaint() return if (self.mode != Mode.MOVE) and e.buttons() and QtCore.Qt.LeftButton: if self.mode == Mode.RESIZETL: # Left - Top newwidth = e.globalX() - self.position.x() - self.geometry().x( ) newheight = e.globalY() - self.position.y() - self.geometry( ).y() toMove = e.globalPos() - self.position self.resize(self.geometry().width() - newwidth, self.geometry().height() - newheight) self.move(toMove.x(), toMove.y()) elif self.mode == Mode.RESIZETR: # Right - Top newheight = e.globalY() - self.position.y() - self.geometry( ).y() toMove = e.globalPos() - self.position self.resize(e.x(), self.geometry().height() - newheight) self.move(self.x(), toMove.y()) elif self.mode == Mode.RESIZEBL: # Left - Bottom newwidth = e.globalX() - self.position.x() - self.geometry().x( ) toMove = e.globalPos() - self.position self.resize(self.geometry().width() - newwidth, e.y()) self.move(toMove.x(), self.y()) elif self.mode == Mode.RESIZEB: # Bottom self.resize(self.width(), e.y()) elif self.mode == Mode.RESIZEL: # Left newwidth = e.globalX() - self.position.x() - self.geometry().x( ) toMove = e.globalPos() - self.position self.resize(self.geometry().width() - newwidth, self.height()) self.move(toMove.x(), self.y()) elif self.mode == Mode.RESIZET: # Top newheight = e.globalY() - self.position.y() - self.geometry( ).y() toMove = e.globalPos() - self.position self.resize(self.width(), self.geometry().height() - newheight) self.move(self.x(), toMove.y()) elif self.mode == Mode.RESIZER: # Right self.resize(e.x(), self.height()) elif self.mode == Mode.RESIZEBR: # Right - Bottom self.resize(e.x(), e.y()) self.parentWidget().repaint() self.newGeometry.emit(self.geometry()) # class MainWindow(QMainWindow): # def __init__(self): # super().__init__() # self.showMaximized() # lab1 = QLabel("Label1") # lab2 = QLabel("Label2") # con1 = TContainer(self, QPoint(10,10), lab1) # con2 = TContainer(self, QPoint(20,50), lab2) # if __name__ == '__main__': # app = QApplication(sys.argv) # ex = MainWindow() # sys.exit(app.exec_())
class Viewer(QDockWidget): pix_is_ready = Signal() def __init__(self, parent=None): super().__init__('Viewer', parent) self.setAllowedAreas(Qt.NoDockWidgetArea) self.image_list = [] self.index = 0 self.filters = [] self.init_filters() self.image_viewer = ImageViewer() self.image_viewer.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.scroll_area = QScrollArea() self.scroll_area.setWidget(self.image_viewer) self.setWidget(self.scroll_area) self.hide() self.setFloating(True) self.context_menu = QMenu(self) self.pix_is_ready.connect(self.image_viewer.show) def init_filters(self): formats = QImageReader.supportedImageFormats() for f in formats: self.filters.append('*.' + f.data().decode('utf-8')) def contextMenuEvent(self, event): self.context_menu.exec(event.globalPos()) def setup(self): if not self.image_list: self.open_directory() if not self.image_viewer.pixmap(): self.set_image(0) self.show() def open_directory(self, path=''): if not path: path = QFileDialog.getExistingDirectory(self, 'Open Directory', '.', QFileDialog.ShowDirsOnly) if not path: return directory = QDir(path) directory.setNameFilters(self.filters) self.image_list = [] image_files = directory.entryList() for file in image_files: self.add_item(directory.absolutePath() + '/' + file) def set_reference(self): self.open_directory() self.set_image(0) def add_item(self, path=''): if path: self.image_list.append(path) def set_image(self, index): if index < 0 or index >= len(self.image_list): return None self.image_viewer.set_image(self.image_list[index]) self.index = index self.pix_is_ready.emit() self.setWindowTitle(self.image_list[index]) self.parent().update_actions() def next(self): self.set_image(self.index + 1) self.image_viewer.scale_image_by_factor(self.image_viewer.factor) def previous(self): self.set_image(self.index - 1) self.image_viewer.scale_image_by_factor(self.image_viewer.factor) def zoom_in(self): self.image_viewer.scale_image_by_rate(1.25) def zoom_out(self): self.image_viewer.scale_image_by_rate(0.8) def normal_size(self): self.image_viewer.adjustSize() self.image_viewer.factor = 1.0 def fit_to_window(self): if self.parent().viewer_act[6].isChecked(): self.image_viewer.aspect_fit(self.scroll_area.size()) def show(self): if not self.image_viewer.pixmap(): if self.image_list: self.set_image(0) else: self.open_directory() self.set_image(0) self.image_viewer.adjustSize() self.setVisible(True) def close(self): self.hide() def resizeEvent(self, event): self.fit_to_window() super().resizeEvent(event) def isReady(self): if self.image_viewer.pixmap(): return True else: return False