Beispiel #1
0
class Container(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent)

        self._border_radius = 10
        self.label = QLabel('...', self)
        self._size_grip = QSizeGrip(self)
        self._size_grip.setFixedWidth(self._border_radius * 2)

        font = self.font()
        font.setPointSize(24)
        self.label.setFont(font)
        self.label.setAlignment(Qt.AlignBaseline | Qt.AlignVCenter
                                | Qt.AlignHCenter)
        self.label.setWordWrap(False)

        self._layout = QHBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self._layout.addSpacing(self._border_radius * 2)
        self._layout.addWidget(self.label)
        self._layout.addWidget(self._size_grip)
        self._layout.setAlignment(self._size_grip, Qt.AlignBottom)

    def paintEvent(self, e):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.palette().color(QPalette.Window))
        painter.drawRoundedRect(self.rect(), self._border_radius,
                                self._border_radius)
        painter.save()
        painter.setPen(QColor('white'))
        option = QTextOption()
        option.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        rect = QRect(self.mapToParent(self._size_grip.pos()),
                     self._size_grip.size())
        painter.drawText(QRectF(rect), '●', option)
        painter.restore()

    def show_color_dialog(self, bg=True):
        def set_color(color):
            palette = self.palette()
            if bg:
                palette.setColor(QPalette.Active, QPalette.Window, color)
                palette.setColor(QPalette.Active, QPalette.Base, color)
                palette.setColor(QPalette.Inactive, QPalette.Window, color)
                palette.setColor(QPalette.Inactive, QPalette.Base, color)
            else:
                palette.setColor(QPalette.Active, QPalette.WindowText, color)
                palette.setColor(QPalette.Active, QPalette.Text, color)
                palette.setColor(QPalette.Inactive, QPalette.WindowText, color)
                palette.setColor(QPalette.Inactive, QPalette.Text, color)
            self.label.setPalette(palette)
            self.setPalette(palette)

        dialog = QColorDialog(self)
        dialog.currentColorChanged.connect(set_color)
        dialog.colorSelected.connect(set_color)
        dialog.setOption(QColorDialog.ShowAlphaChannel, True)
        dialog.exec()

    def show_font_dialog(self):
        dialog = QFontDialog(self.label.font(), self)
        dialog.currentFontChanged.connect(self.label.setFont)
        dialog.fontSelected.connect(self.label.setFont)
        dialog.exec()

    def contextMenuEvent(self, e):
        menu = QMenu()
        bg_color_action = QAction('背景颜色', menu)
        fg_color_action = QAction('文字颜色', menu)
        font_action = QAction('字体', menu)
        menu.addAction(bg_color_action)
        menu.addAction(fg_color_action)
        menu.addSeparator()
        menu.addAction(font_action)
        bg_color_action.triggered.connect(
            lambda: self.show_color_dialog(bg=True))
        fg_color_action.triggered.connect(
            lambda: self.show_color_dialog(bg=False))
        font_action.triggered.connect(self.show_font_dialog)
        menu.exec(e.globalPos())
Beispiel #2
0
class ResizableFramelessContainer(QWidget):
    """A resizable frameless container

    ResizableFramelessContainer can be moved and resized by mouse.
    Call `attach_widget` to attach an inner widget and `detach` to
    detach the inner widget.

    NOTE: this is mainly designed for picture in picture mode currently.
    """
    def __init__(self, ):
        super().__init__(parent=None)

        self._widget = None
        self._timer = QTimer(self)
        self._old_pos = None
        self._widget = None
        self._size_grip = QSizeGrip(self)
        self._timer.timeout.connect(self.__on_timeout)

        # setup window layout
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
        self._size_grip.setFixedSize(20, 20)
        self._layout = QVBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self._layout.addWidget(self._size_grip)
        self._layout.setAlignment(self._size_grip,
                                  Qt.AlignBottom | Qt.AlignRight)

        self.setMouseTracking(True)

    def attach_widget(self, widget):
        """set inner widget"""
        self._widget = widget
        self._widget.setSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        self._layout.insertWidget(0, self._widget)

    def detach(self):
        self._layout.removeWidget(self._widget)
        self._widget = None

    def paintEvent(self, e):
        painter = QPainter(self)
        if self._size_grip.isVisible():
            painter.save()
            painter.setPen(QColor('white'))
            option = QTextOption()
            option.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
            rect = QRect(self._size_grip.pos(), self._size_grip.size())
            painter.drawText(QRectF(rect), '●', option)
            painter.restore()

    def mousePressEvent(self, e):
        self._old_pos = e.globalPos()

    def mouseMoveEvent(self, e):
        # NOTE: e.button() == Qt.LeftButton don't work on Windows
        # on Windows, even I drag with LeftButton, the e.button() return 0,
        # which means no button
        if self._old_pos is not None:
            delta = e.globalPos() - self._old_pos
            self.move(self.x() + delta.x(), self.y() + delta.y())
            self._old_pos = e.globalPos()

    def mouseReleaseEvent(self, e):
        self._old_pos = None

    def enterEvent(self, e):
        super().enterEvent(e)
        if not self._size_grip.isVisible():
            self.resize(self.width(), self.height() + 20)
            self._size_grip.show()
        self._timer.stop()

    def leaveEvent(self, e):
        super().leaveEvent(e)
        self._timer.start(2000)

    def resizeEvent(self, e):
        super().resizeEvent(e)

    def __on_timeout(self):
        if self._size_grip.isVisible():
            self._size_grip.hide()
            self.resize(self.width(), self.height() - 20)