Как исправить ошибку QPropertyAnimation «запуск анимации без конечного значения» - PullRequest
1 голос
/ 18 июня 2019

Я пытаюсь перенести пример qt с c ++ на pyqt / pyside2. В этом примере показано действие «скрыть / показать» с полем textedit с использованием QPropertyAnimation.

Это не кажется сложным, но я все еще не могу понять, почему он не работает должным образом

Основная идея заключается в следующем: виджет textEdit «сворачивается» при нажатии кнопки ">" и возвращается при повторном нажатии кнопки.

Вот мой код Python:

import PySide2
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
import sys

class myWidget(QWidget):
    def __init__(self):
        super(myWidget, self).__init__()

        self.m_deltaX = 0
        self.m_isClosed = False

        self.btn = QPushButton(self)
        self.btn.setText(">")
        self.btn.setCheckable(True)
        self.btn.setFixedSize(QSize(25, 25))
        self.btn.connect(SIGNAL("clicked()"), self.closeOpenEditor)

        self.text1 = QTextEdit(self)
        self.text1.setText("some sample text")

        self.text2 = QTextEdit(self)

        self.layout_btn = QVBoxLayout()
        self.layout_btn.addWidget(self.btn)

        self.layout_m = QHBoxLayout()
        self.layout_m.addWidget(self.text1, 10)
        self.layout_m.addSpacing(15)
        self.layout_m.addLayout(self.layout_btn)
        self.layout_m.setSpacing(0)
        self.layout_m.addWidget(self.text2, 4)

        self.setLayout(self.layout_m)
        self.resize(800, 500)

    def closeOpenEditor(self):
        self.m_isClosed = self.btn.isChecked()

        animation1 = QPropertyAnimation(self.text2, b"geometry")

        if self.m_isClosed:
            self.text2.setMaximumWidth(self.text2.width())
            text2Start = int(self.text2.maximumWidth())

            self.m_deltaX = text2Start
            text2End = int(3)

            animation1.setDuration(250)
            animation1.setStartValue(text2Start)
            animation1.setEndValue(text2End)

            self.btn.setText("<")
        else:
            text2Start = int(self.text2.maximumWidth())
            text2End = int(self.m_deltaX)

            animation1.setDuration(250)
            animation1.setStartValue(text2Start)
            animation1.setEndValue(text2End)

            self.btn.setText(">")

        animation1.start()

    def resizeEvent(self, event:QResizeEvent):
        if not self.m_isClosed:
            self.text2.setMaximumWidth(QWIDGETSIZE_MAX)



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

Я также добавлю код C ++:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QTextEdit>
#include <QPushButton>
#include <QHBoxLayout>

class MyWidget : public QWidget
{

    Q_OBJECT

    QTextEdit       *m_textEditor1;
    QTextEdit       *m_textEditor2;
    QPushButton     *m_pushButton;
    QHBoxLayout     *m_layout;
    QVBoxLayout     *m_buttonLayout;

    int              m_deltaX;
    bool             m_isClosed;


public:

    MyWidget(QWidget * parent = 0);
    ~MyWidget(){}

    void resizeEvent( QResizeEvent * event );

private slots:
    void closeOrOpenTextEdit2(bool isClosing);

};

#endif // MAINWINDOW_H

main.cpp

#include <mainwindow.h>
#include <QPropertyAnimation>
#include <QApplication>
#include <QIcon>



MyWidget::MyWidget(QWidget * parent):QWidget(parent),m_deltaX(0)
{

  m_pushButton = new QPushButton(this);
  m_pushButton->setText(">");
  m_pushButton->setCheckable(true);
  m_pushButton->setFixedSize(25,25);
  //m_pushButton->setStyleSheet("background-color: yellow;");
  connect(m_pushButton, SIGNAL(clicked(bool)), this, SLOT(closeOrOpenTextEdit2(bool)));

  m_textEditor1 = new QTextEdit(this);
  m_textEditor1->setText("И рвется в пляс душа моя, головой я выбиваю дверцы...");

  m_textEditor2 = new QTextEdit(this);

  m_buttonLayout = new QVBoxLayout();
  m_buttonLayout->addWidget(m_pushButton);
  m_buttonLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding) );


  m_layout = new QHBoxLayout;
  m_layout->addWidget(m_textEditor1, 10);
  m_layout->addSpacing(15);
  m_layout->addLayout(m_buttonLayout);
  m_layout->setSpacing(0);
  m_layout->addWidget(m_textEditor2, 4);

  setLayout(m_layout);
  resize(800,500);
}

void MyWidget::closeOrOpenTextEdit2(bool isClosing)
{
    m_isClosed = isClosing;
    QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "maximumWidth");

    if(isClosing) //close the second textEdit
    {
        m_textEditor2->setMaximumWidth(m_textEditor2->width());

        int textEdit2_start = m_textEditor2->maximumWidth();

        m_deltaX = textEdit2_start;
        int textEdit2_end = 3;



        animation1->setDuration(250);
        animation1->setStartValue(textEdit2_start);
        animation1->setEndValue(textEdit2_end);


        m_pushButton->setText("<");

    }
    else //open
    {


        int textEdit2_start = m_textEditor2->maximumWidth();
        int textEdit2_end = m_deltaX;


        animation1->setDuration(250);
        animation1->setStartValue(textEdit2_start);
        animation1->setEndValue(textEdit2_end);


        m_pushButton->setText(">");
        //m_pushButton->setIcon()

    }

    animation1->start();

}


void MyWidget::resizeEvent( QResizeEvent * event )
{
    if(!m_isClosed)
        m_textEditor2->setMaximumWidth( QWIDGETSIZE_MAX );
}


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyWidget w;
    w.show();

    return a.exec();
}

В моем переписанном коде он не хочет запускать анимацию. Вы должны нажать кнопку дважды, и после этого виджет будет свернут навсегда без какой-либо анимации. Таким образом, вы не можете открыть его снова.

Также я получил несколько ошибок:

QPropertyAnimation :: updateState (geometry, QTextEdit,): запуск анимации без конечного значения

и

NameError: имя 'QWIDGETSIZE_MAX' не определено

1 Ответ

1 голос
/ 18 июня 2019

В вашем коде есть следующие ошибки:

  • Свойство, которое изменяется в коде C ++, является MaximumWidth, но в вашем коде Python вы используете геометрию, в случае MaximumWidth целое число равноожидается, но геометрия ожидает QRect, так что вы получите сообщение об ошибке, так как endValue имеет неправильный тип, поэтому он не устанавливается, отмечая, что он не установил значение.

  • В Python aЛокальная переменная удаляется, когда заканчивается ее область, за исключением случая PyQt, если локальная переменная является QObject, который имеет в качестве родителя другой QObject с большей областью действия.В случае C ++ помимо использования родительского элемента для расширения жизненного цикла необходимо использовать указатели.

  • QWIDGETSIZE_MAX не определен в PySide2 (но он определен в PyQt5: QtWidgets.QWIDGETSIZE_MAX) поэтому вы должны определить переменную, которая принимает значение в C ++.

from PySide2 import QtCore, QtWidgets

# https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/kernel/qwidget.h#n873
QWIDGETSIZE_MAX = (1 << 24) - 1

class MyWidget(QtWidgets.QWidget):
    def __init__(self):
        super(MyWidget, self).__init__()
        self.m_deltaX = 0
        self.btn = QtWidgets.QPushButton(
            ">", checkable=True, clicked=self.closeOpenEditor
        )
        self.btn.setFixedSize(QtCore.QSize(25, 25))

        self.text1 = QtWidgets.QTextEdit()
        self.text1.setText("some sample text")

        self.text2 = QtWidgets.QTextEdit()

        layout_btn = QtWidgets.QVBoxLayout()
        layout_btn.addWidget(self.btn)

        lay = QtWidgets.QHBoxLayout(self)
        lay.addWidget(self.text1, 10)
        lay.addSpacing(15)
        lay.addLayout(layout_btn)
        lay.setSpacing(0)
        lay.addWidget(self.text2, 4)

        self.resize(800, 500)

        self.m_animation = QtCore.QPropertyAnimation(
            self.text2, b"maximumWidth", parent=self, duration=250
        )

    def closeOpenEditor(self):
        if self.btn.isChecked():
            self.text2.setMaximumWidth(self.text2.width())
            text2Start = int(self.text2.maximumWidth())
            self.m_deltaX = text2Start
            text2End = 3
            self.m_animation.setStartValue(text2Start)
            self.m_animation.setEndValue(text2End)
            self.btn.setText("<")
        else:
            text2Start = int(self.text2.maximumWidth())
            text2End = self.m_deltaX
            self.m_animation.setStartValue(text2Start)
            self.m_animation.setEndValue(text2End)
            self.btn.setText(">")

        self.m_animation.start()

    def resizeEvent(self, event: "QResizeEvent"):
        if not self.btn.isChecked():
            self.text2.setMaximumWidth(QWIDGETSIZE_MAX)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MyWidget()
    w.show()
    sys.exit(app.exec_())
...