Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将小部件旋转一定程度_Python_Pyqt - Fatal编程技术网

Python 将小部件旋转一定程度

Python 将小部件旋转一定程度,python,pyqt,Python,Pyqt,我是pyqt的新手,需要帮助旋转标签。我很困惑,无法理解如何以特定角度旋转整个小部件。不是小部件的内容,而是小部件本身。我正在搜索解决方案,但找不到任何东西。QWidget不支持旋转,但解决方法是将小部件插入QGraphicsProxyWidget并将其添加到QGraphicsCene,然后旋转QGraphicsProxyWidget,该小部件在视觉上产生相同的小部件旋转效果 从PyQt5导入QtCore、QtGui、qtwidget def main(): 导入系统 app=qtwidts.Q

我是pyqt的新手,需要帮助旋转标签。我很困惑,无法理解如何以特定角度旋转整个小部件。不是小部件的内容,而是小部件本身。我正在搜索解决方案,但找不到任何东西。

QWidget不支持旋转,但解决方法是将小部件插入QGraphicsProxyWidget并将其添加到QGraphicsCene,然后旋转QGraphicsProxyWidget,该小部件在视觉上产生相同的小部件旋转效果

从PyQt5导入QtCore、QtGui、qtwidget
def main():
导入系统
app=qtwidts.QApplication(sys.argv)
label=qtwidts.QLabel(“堆栈溢出”,alignment=QtCore.Qt.AlignCenter)
graphicsview=QtWidgets.QGraphicsView()
场景=qtwidts.qgraphicscene(graphicsview)
graphicsview.setScene(场景)
proxy=qtwidts.QGraphicsProxyWidget()
proxy.setWidget(标签)
proxy.setTransformOriginPoint(proxy.boundingRect().center())
场景.附加项(代理)
滑块=qtwidts.QSlider(最小值=0,最大值=359,方向=QtCore.Qt.Horizontal)
slider.valueChanged.connect(proxy.setRotation)
label_text=qtwidts.QLabel(
“{}°”.format(slider.value()),alignment=QtCore.Qt.AlignCenter
)
slider.valueChanged.connect(
lambda值:label_text.setText(“{}°”.format(slider.value()))
)
滑块设置值(45)
w=qtwidts.QWidget()
lay=qtwidts.QVBoxLayout(w)
lay.addWidget(graphicsview)
lay.addWidget(滑块)
lay.addWidget(标签\文本)
w、 调整大小(640480)
w、 show()
sys.exit(app.exec_())
如果名称=“\uuuuu main\uuuuuuuu”:
main()

正如@eyllanesc正确解释的那样,Qt中没有“小部件旋转”支持(与大多数标准框架一样)

不过,在你的手上有一些技巧

“简单”标签(不使用
QLabel
) 这就是“简单”的解决方案。既然你说的是一个“标签”,那就可以用一些数学来实现

这种方法的最大优点是大小提示是“简单的”,这意味着它只基于文本内容(如中所示),每当主字体、文本或对齐方式发生更改时,大小提示都会反映这些内容。
虽然它支持多行标签,但是如果您需要使用富文本,这种方法的最大问题就出现了;可以使用a来代替标准字符串,但这需要更复杂的大小提示计算实现

from math import radians, sin, cos
from random import randrange

from PyQt5 import QtCore, QtGui, QtWidgets

class AngledLabel(QtWidgets.QWidget):
    _alignment = QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop

    def __init__(self, text='', angle=0, parent=None):
        super(AngledLabel, self).__init__(parent)
        self._text = text
        self._angle = angle % 360
        # keep radians of the current angle *and* its opposite; we're using
        # rectangles to get the overall area of the text, and since they use
        # right angles, that opposite is angle + 90
        self._radians = radians(-angle)
        self._radiansOpposite = radians(-angle + 90)

    def alignment(self):
        return self._alignment

    def setAlignment(self, alignment):
        # text alignment might affect the text size!
        if alignment == self._alignment:
            return
        self._alignment = alignment
        self.setMinimumSize(self.sizeHint())

    def angle(self):
        return self._angle

    def setAngle(self, angle):
        # the angle clearly affects the overall size
        angle %= 360
        if angle == self._angle:
            return
        self._angle = angle
        # update the radians to improve optimization of sizeHint and paintEvent
        self._radians = radians(-angle)
        self._radiansOpposite = radians(-angle + 90)
        self.setMinimumSize(self.sizeHint())

    def text(self):
        return self._text

    def setText(self, text):
        if text == self._text:
            return
        self._text = text
        self.setMinimumSize(self.sizeHint())

    def sizeHint(self):
        # get the bounding rectangle of the text
        rect = self.fontMetrics().boundingRect(QtCore.QRect(), self._alignment, self._text)
        # use trigonometry to get the actual size of the rotated rectangle
        sinWidth = abs(sin(self._radians) * rect.width())
        cosWidth = abs(cos(self._radians) * rect.width())
        sinHeight = abs(sin(self._radiansOpposite) * rect.height())
        cosHeight = abs(cos(self._radiansOpposite) * rect.height())
        return QtCore.QSize(cosWidth + cosHeight, sinWidth + sinHeight)

    def minimumSizeHint(self):
        return self.sizeHint()

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        textRect = self.fontMetrics().boundingRect(
            QtCore.QRect(), self._alignment, self._text)
        width = textRect.width()
        height = textRect.height()
        # we have to translate the painting rectangle, and that depends on which
        # "angle sector" the current angle is
        if self._angle <= 90:
            deltaX = 0
            deltaY = sin(self._radians) * width
        elif 90 < self._angle <= 180:
            deltaX = cos(self._radians) * width
            deltaY = sin(self._radians) * width + sin(self._radiansOpposite) * height
        elif 180 < self._angle <= 270:
            deltaX = cos(self._radians) * width + cos(self._radiansOpposite) * height
            deltaY = sin(self._radiansOpposite) * height
        else:
            deltaX = cos(self._radiansOpposite) * height
            deltaY = 0
        qp.translate(.5 - deltaX, .5 - deltaY)
        qp.rotate(-self._angle)
        qp.drawText(self.rect(), self._alignment, self._text)


class TestWindow(QtWidgets.QWidget):
    def __init__(self):
        super(TestWindow, self).__init__()
        layout = QtWidgets.QGridLayout()
        self.setLayout(layout)

        self.randomizeButton = QtWidgets.QPushButton('Randomize!')
        layout.addWidget(self.randomizeButton, 0, 0, 1, 3)
        self.randomizeButton.clicked.connect(self.randomize)

        layout.addWidget(QtWidgets.QLabel('Standard label'), 1, 0)
        text = 'Some text'
        layout.addWidget(QtWidgets.QLabel(text), 1, 2)
        self.labels = []
        for row, angle in enumerate([randrange(360) for _ in range(8)], 2):
            angleLabel = QtWidgets.QLabel(u'{}°'.format(angle))
            angleLabel.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
            layout.addWidget(angleLabel, row, 0)
            label = AngledLabel(text, angle)
            layout.addWidget(label, row, 2)
            self.labels.append((angleLabel, label))

        separator = QtWidgets.QFrame()
        separator.setFrameShape(separator.VLine|separator.Sunken)
        layout.addWidget(separator, 1, 1, layout.rowCount() - 1, 1)

    def randomize(self):
        for angleLabel, label in self.labels:
            angle = randrange(360)
            angleLabel.setText(str(angle))
            label.setAngle(angle)
        self.adjustSize()


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = TestWindow()
    w.show()
    sys.exit(app.exec_())
正如您所看到的,“随机化”函数有非常不同的结果。虽然第二种方法允许使用更复杂的小部件,但第一种方法对内容更改的反应更好

from random import randrange
from PyQt5 import QtCore, QtGui, QtWidgets

class AngledObject(QtWidgets.QGraphicsView):
    _angle = 0

    def __init__(self, angle=0, parent=None):
        super(AngledObject, self).__init__(parent)
        # to prevent the graphics view to draw its borders or background, set the
        # FrameShape property to 0 and a transparent background
        self.setFrameShape(0)
        self.setStyleSheet('background: transparent')
        self.setScene(QtWidgets.QGraphicsScene())
        # ignore scroll bars!
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)

    def angle(self):
        return self._angle

    def setAngle(self, angle):
        angle %= 360
        if angle == self._angle:
            return
        self._angle = angle
        self._proxy.setTransform(QtGui.QTransform().rotate(-angle))
        self.adjustSize()

    def resizeEvent(self, event):
        super(AngledObject, self).resizeEvent(event)
        # ensure that the scene is fully visible after resizing
        QtCore.QTimer.singleShot(0, lambda: self.centerOn(self.sceneRect().center()))

    def sizeHint(self):
        return self.scene().itemsBoundingRect().size().toSize()

    def minimumSizeHint(self):
        return self.sizeHint()


class AngledLabel(AngledObject):
    def __init__(self, text='', angle=0, parent=None):
        super(AngledLabel, self).__init__(angle, parent)
        self._label = QtWidgets.QLabel(text)
        self._proxy = self.scene().addWidget(self._label)
        self._label.setStyleSheet('background: transparent')
        self.setAngle(angle)
        self.alignment = self._label.alignment

    def setAlignment(self, alignment):
        # text alignment might affect the text size!
        if alignment == self._label.alignment():
            return
        self._label.setAlignment(alignment)
        self.setMinimumSize(self.sizeHint())

    def text(self):
        return self._label.text()

    def setText(self, text):
        if text == self._label.text():
            return
        self._label.setText(text)
        self.setMinimumSize(self.sizeHint())


class AngledButton(AngledObject):
    def __init__(self, text='', angle=0, parent=None):
        super(AngledButton, self).__init__(angle, parent)
        self._button = QtWidgets.QPushButton(text)
        self._proxy = self.scene().addWidget(self._button)
        self.setAngle(angle)


class TestWindow(QtWidgets.QWidget):
    def __init__(self):
        super(TestWindow, self).__init__()
        layout = QtWidgets.QGridLayout()
        self.setLayout(layout)

        self.randomizeButton = QtWidgets.QPushButton('Randomize!')
        layout.addWidget(self.randomizeButton, 0, 0, 1, 3)
        self.randomizeButton.clicked.connect(self.randomize)

        layout.addWidget(QtWidgets.QLabel('Standard label'), 1, 0)
        text = 'Some text'
        layout.addWidget(QtWidgets.QLabel(text), 1, 2)
        self.labels = []
        for row, angle in enumerate([randrange(360) for _ in range(4)], 2):
            angleLabel = QtWidgets.QLabel(u'{}°'.format(angle))
            angleLabel.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
            layout.addWidget(angleLabel, row, 0)
            label = AngledLabel(text, angle)
            layout.addWidget(label, row, 2)
            self.labels.append((angleLabel, label))

        for row, angle in enumerate([randrange(360) for _ in range(4)], row + 1):
            angleLabel = QtWidgets.QLabel(u'{}°'.format(angle))
            angleLabel.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
            layout.addWidget(angleLabel, row, 0)
            label = AngledButton('Button!', angle)
            layout.addWidget(label, row, 2)
            self.labels.append((angleLabel, label))

        separator = QtWidgets.QFrame()
        separator.setFrameShape(separator.VLine|separator.Sunken)
        layout.addWidget(separator, 1, 1, layout.rowCount() - 1, 1)

    def randomize(self):
        for angleLabel, label in self.labels:
            angle = randrange(360)
            angleLabel.setText(str(angle))
            label.setAngle(angle)
        self.adjustSize()


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = TestWindow()
    w.show()
    sys.exit(app.exec_())