Reputation: 587
I'm trying to port qt example from c++ to pyqt/pyside2. This example shows hide/show action with a textedit field using QPropertyAnimation.
It doesn't seem to be complicated, but I still can't figure out why it is not working properly
The main idea is: textEdit widget "collapses" by pressing ">" button and returns back on pressing the button again.
Here's my python code:
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_())
I will also add c++ code:
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();
}
In my rewritten code it doesn't want to start an animation. You ought to press the button twice and after that it will collapse the widget permanently without any animation. So you can't open it again.
Also i recieved some errors:
QPropertyAnimation::updateState (geometry, QTextEdit, ): starting an animation without end value
and
NameError: name 'QWIDGETSIZE_MAX' is not defined
Upvotes: 1
Views: 1894
Reputation: 243887
Your code has the following errors:
The property that is modified in the C++ code is maximumWidth but in your python code you use geometry, in the case of maximumWidth an integer is expected but geometry expects a QRect so you get the error message since the endValue is of an incorrect type so it is not established by noting that it did not establish a value.
In Python a local variable is deleted when its scope ends, except in the case of PyQt if the local variable is a QObject that has as a parent another QObject with a larger scope. In the case of C++ in addition to using the parent to extend the life cycle is to use pointers.
QWIDGETSIZE_MAX is not defined in PySide2 (but it is defined in PyQt5: QtWidgets.QWIDGETSIZE_MAX
) so you must define a variable that takes the value it takes in 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_())
Upvotes: 1