PyQt progress bar not updating or appearing until 100% - python

EDIT: There are a number of similar posts on PyQt4 progress bars not updating. They all focus on the issue of threads & where the program actually updates the window. Although helpful, my code was so structured that the replies were not practical. The accepted answer given here is simple, to the point & works.
I am using Python 2.7 and PyQT 4 on a Win 7 x64 machine.
I am trying to clear my window of one widget, an 'Accept' button, see code, and replace it with a progress bar.
Even though I close the 'Accept' button & add the progress bar before the processing loop is entered into. The window is only updated after the loop has finished & the progress bar jumps straight to 100%.
My code,
from PyQt4 import QtCore, QtGui
import sys
import time
class CentralWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(CentralWidget, self).__init__(parent)
# set layouts
self.layout = QtGui.QVBoxLayout(self)
# Poly names
self.pNames = QtGui.QLabel("Import file name", self)
self.polyNameInput = QtGui.QLineEdit(self)
# Polytype selection
self.polyTypeName = QtGui.QLabel("Particle type", self)
polyType = QtGui.QComboBox(self)
polyType.addItem("")
polyType.addItem("Random polyhedra")
polyType.addItem("Spheres")
polyType.addItem("Waterman polyhedra")
polyType.activated[str].connect(self.onActivated)
# Place widgets in layout
self.layout.addWidget(self.pNames)
self.layout.addWidget(self.polyNameInput)
self.layout.addWidget(self.polyTypeName)
self.layout.addWidget(polyType)
self.layout.addStretch()
# Combobox choice
def onActivated(self, text):
if text=="Random polyhedra":
self.randomPolyhedra(text)
if text=="Spheres": # not implementaed yet
self.polyTypeName.setText("Not implemented yet.")
self.polyTypeName.adjustSize()
if text=="Waterman polyhedra": # not implementaed yet
self.polyTypeName.setText("Not implemented yet.")
self.polyTypeName.adjustSize()
# New options for random polyhedra choice
def randomPolyhedra(self, text):
self.polyNumberLbl = QtGui.QLabel("How many: ", self)
self.polyNumber = QtGui.QLineEdit(self)
self.acceptSeed = QtGui.QPushButton('Accept') # Accept button created
self.acceptSeed.clicked.connect(lambda: self.ranPolyGen())
self.layout.addWidget(self.polyNumberLbl)
self.layout.addWidget(self.polyNumber)
self.layout.addWidget(self.acceptSeed) # Accept button in layout
self.randFlag = True
self.polyTypeName.setText(text)
self.polyTypeName.adjustSize()
# Act on option choices for random polyhedra
def ranPolyGen(self):
polyCount = int(self.polyNumber.text())
self.progressBar = QtGui.QProgressBar() # Progress bar created
self.progressBar.setMinimum(1)
self.progressBar.setMaximum(polyCount)
self.acceptSeed.close() # Accept button closed
self.layout.addWidget(self.progressBar) # Add progressbar to layout
for poly in range(1, polyCount+1):
time.sleep(1) # Calls to main polyhedral generating code go here
print poly
self.progressBar.setValue(poly)
self.doneLbl = QtGui.QLabel("Done", self)
self.layout.addWidget(self.doneLbl)
# Creates GUI
class Polyhedra(QtGui.QMainWindow):
def __init__(self):
super(Polyhedra, self).__init__()
# Place central widget in layout
self.central_widget = CentralWidget(self)
self.setCentralWidget(self.central_widget)
# Set up window
self.setGeometry(500, 500, 300, 300)
self.setWindowTitle('Pyticle')
self.show()
# Combo box
def onActivated(self, text):
self.central_widget.onActivated(text)
def main():
app = QtGui.QApplication(sys.argv)
poly = Polyhedra()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Below is a picture of during loop execution & after completion.
I dont think I have got my head around the addWidget() method. I was under the impression that this would add another widget to the present layout (a vbox layout here) & that the .close() method removed a widget when directed to do so.
What am I missing?

You can add:
from PyQt4.QtGui import QApplication
Then in your for loop:
QApplication.processEvents()
Your app is actually becoming unresponsive, you need to call processEvents() to process the events and redraw the gui. I am not overly familiar with pyqt but I imagine another alternative is using a thread.

Related

Issue about PyQt5

I am trying to create a simple interface like this:
from PyQt5 import QtWidgets,QtGui
class program():
def __init__(self):
self.window = QtWidgets.QWidget()
self.window.setWindowTitle("how many click")
self.text = QtWidgets.QLabel(self.window)
self.text.setText(("not clicked"))
self.text.setGeometry(240,200,300,50)
self.text2 = QtWidgets.QLabel(self.window)
self.picture = QtWidgets.QLabel(self.window)
self.button=QtWidgets.QPushButton(self.window)
self.button.setText("click")
self.button.setFont(QtGui.QFont('',10))
self.button.setGeometry(250,100,200,50)
self.window.setGeometry(600,200,800,600)
self.window.show()
self.count=0
self.button.clicked.connect(self.click)
def click(self):
self.count+= 1
self.text.setText(((f"you clicked {self.count} times")))
self.text.setFont(QtGui.QFont('',10))
if self.count == 5:
self.text2.setText(("You clicked too much"))
self.text2.setGeometry(250, 250, 300, 50)
self.picture.setPixmap(QtGui.QPixmap("C:/Users/Administrator/Desktop/mypic.png"))
self.picture.move(300, 300)
app = QtWidgets.QApplication(sys.argv)
run= program()
sys.exit(app.exec_())
In this code my picture appears when I click 5 times to button but picture becomes very tiny as in pic1. However when I write setPixmap and picture.move codes into init function picture becomes normal size as in pic2.
pic1:
pic2:
The simple solution to your issue is to add the following line after setting the pixmap:
self.picture.adjustSize()
The direct reason is that when when the widget is shown the label has not yet a pixmap, so its geometry is already set to its minimum size (defaults to 100x30). Then, when the pixmap is set, the label doesn't automatically update its size.
The logical reason is that you are using fixed geometries for your widget, and this approach is generaly discouraged for lots of reasons, with the most important being the fact that elements within a window should always adapt their geometries (size and position) to the size of the parent, possibly by occupying all the available space and preventing the elements to become invisible if the window is resized to a smaller size.
To avoid that, you should always use layout managers (in your case, a QVBoxLayout could be enough).
For example:
class program():
def __init__(self):
self.window = QtWidgets.QWidget()
# ...
layout = QtWidgets.QVBoxLayout(self.window)
layout.addWidget(self.text)
layout.addWidget(self.text2)
layout.addWidget(self.picture)
layout.addWidget(self.button)
# it's good practice to always show the window *after* adding all elements
self.window.show()

Why is an absolute positioned widget not shown?

Using Qt5 I am trying to make a widget work using absolute positioning. The code below is a minimum working example of something I am trying to do. A quick walk through of the code:
CentralWidget is the central widget of the main window and holds MyWidget using absolute positioning, e.g. without using any layouts.
MyWidget does not set its child widgets immediately but provides a SetData method which first removes all current child widgets and then adds the new child widgets to its layout.
SetData is triggered using a timer in the main window.
I commented out two lines of code. The first "enables" relative positioning using layouts by adding a layout to CentralWidget. This line shows what I am trying to achieve but with absolute positioning. The second comment enables some debug information:
MyWidget
layout.count: 3
size: PyQt5.QtCore.QSize(-1, -1)
sizeHint: PyQt5.QtCore.QSize(200, 100)
CentralWidget
size: PyQt5.QtCore.QSize(18, 18)
sizeHint: PyQt5.QtCore.QSize(18, 18)
What I am doing wrong in order for MyWidget to be visible using absolute positioning?
Code:
from PyQt5 import QtCore, QtWidgets
import sys
class MyWidget(QtWidgets.QWidget):
z = 0
def __init__(self, parent):
super().__init__(parent)
self._layout = QtWidgets.QVBoxLayout(self)
def SetData(self):
while self._layout.count() > 0:
widget = self._layout.takeAt(0).widget()
widget.hide()
widget.deleteLater()
for i in range(3):
self._layout.addWidget(QtWidgets.QLabel(str(MyWidget.z * 10 + i)))
MyWidget.z += 1
class CentralWidget(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
self._myWidget = MyWidget(self)
# QtWidgets.QHBoxLayout(self).addWidget(self._myWidget)
def SetData(self):
self._myWidget.SetData()
# print("MyWidget\n layout.count: {}\n size: {}\n sizeHint: {}\n\nCentralWidget\n size: {}\n sizeHint: {}\n\n".format(self._myWidget.layout().count(), self.sizeHint(), self.size(), self._myWidget.sizeHint(), self._myWidget.size()))
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
centralWidget = CentralWidget(self)
self.setCentralWidget(centralWidget)
self._timer = QtCore.QTimer(self)
self._timer.timeout.connect(centralWidget.SetData)
self._timer.start(500)
def main():
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
app.exec_()
if __name__ == "__main__":
main()
The reason for this behavior is directly related to the fact that the widget is not added to a layout and its contents are added after being shown.
In fact, if you call centralWidget.SetData() upon initialization and before mainWindow.show(), it will work as expected.
A lot of things happen when you add a child widget to a layout, and this usually involves multiple calls to the children size hints, allowing the parent to adapt its own size hint, and, after that, adapt its size and that of its children.
If that "container widget" is itself contained in another layout, that widget will be automatically resized (based on its hint) in the next cycle of events, but this doesn't happen in your case, since yours is a "free" widget.
The function you are looking for is QWidget.adjustSize(), but, for the aforementioned reasons, you cannot call it immediately after adding the children widgets.
To overcome your issue, you can call QApplication.processEvents() before adjustSize(), or, eventually, use a 0-based single shot QTimer:
def SetData(self):
while self._layout.count() > 0:
widget = self._layout.takeAt(0).widget()
widget.hide()
widget.deleteLater()
for i in range(3):
self._layout.addWidget(QtWidgets.QLabel(str(MyWidget.z * 10 + i)))
MyWidget.z += 1
QtCore.QTimer.singleShot(0, self.adjustSize)

Qt resize layout during widget property animation

I have an existing application that I am polishing off and I want to add some animation to a few of the widgets. Animating widgets with QPropertyAnimation outside of layouts is easy and fun, however when they are in a layout I am having various difficulties. The current one giving me a headache is that when I animate the size of a widget, the layout does not adjust to it's new size.
So lets say I have a QVBoxLayout with three widgets: a label which should expand to all available space, a treeview, and a button. When I click the button I want the tree to collapse and the label to take over it's space. Below is this example in code, and as you can see while the tree animates it's size nothing happens, and then when I hide it at the end of the animation the label pops to fill the now vacant space. So it seems that during the animation the layout does not "know" the tree is resizing. What I would like to happen is that AS the tree shrinks, the label expands to fill it.
Could this could be done not by absolute sizing of the label, but by calling a resize on the layout or something like that? I ask because I want to animate several widgets across my application and I want to find the best way to do this without having to make too many widgets interdependent upon each other.
Example code:
import sys
from PyQt4 import QtGui, QtCore
class AnimatedWidgets(QtGui.QWidget):
def __init__(self):
super(AnimatedWidgets, self).__init__()
layout1 = QtGui.QVBoxLayout()
self.setLayout(layout1)
expanding_label = QtGui.QLabel("Expanding label!")
expanding_label.setStyleSheet("border: 1px solid red")
layout1.addWidget(expanding_label)
self.file_model = QtGui.QFileSystemModel(self)
sefl.file_model.setRootPath("C:/")
self.browse_tree = QtGui.QTreeView()
self.browse_tree.setModel(self.file_model)
layout1.addWidget(self.browse_tree)
shrink_tree_btn = QtGui.QPushButton("Shrink the tree")
shrink_tree_btn.clicked.connect(self.shrink_tree)
layout1.addWidget(shrink_tree_btn)
#--
self.tree_size_anim = QtCore.QPropertyAnimation(self.browse_tree, "size")
self.tree_size_anim.setDuration(1000)
self.tree_size_anim.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
self.tree_pos_anim = QtCore.QPropertyAnimation(self.browse_tree, "pos")
self.tree_pos_anim.setDuration(1000)
self.tree_pos_anim.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
self.tree_anim_out = QtCore.QParallelAnimationGroup()
self.tree_anim_out.addAnimation(self.tree_size_anim)
self.tree_anim_out.addAnimation(self.tree_pos_anim)
def shrink_tree(self):
self.tree_size_anim.setStartValue(self.browse_tree.size())
self.tree_size_anim.setEndValue(QtCore.QSize(self.browse_tree.width(), 0))
tree_rect = self.browse_tree.geometry()
self.tree_pos_anim.setStartValue(tree_rect.topLeft())
self.tree_pos_anim.setEndValue(QtCore.QPoint(tree_rect.left(), tree_rect.bottom()))
self.tree_anim_out.start()
self.tree_anim_out.finished.connect(self.browse_tree.hide)
def main():
app = QtGui.QApplication(sys.argv)
ex = AnimatedWidgets()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
The layouts handle the geometry() of the widgets so that when wanting to change the pos property these are interfacing with their handles so it is very common that you get that type of behavior, a better option is to use a QVariantAnimation to establish a fixed height:
import sys
from PyQt4 import QtGui, QtCore
class AnimatedWidgets(QtGui.QWidget):
def __init__(self):
super(AnimatedWidgets, self).__init__()
layout1 = QtGui.QVBoxLayout(self)
expanding_label = QtGui.QLabel("Expanding label!")
expanding_label.setStyleSheet("border: 1px solid red")
layout1.addWidget(expanding_label)
self.file_model = QtGui.QFileSystemModel(self)
self.file_model.setRootPath(QtCore.QDir.rootPath())
self.browse_tree = QtGui.QTreeView()
self.browse_tree.setModel(self.file_model)
layout1.addWidget(self.browse_tree)
shrink_tree_btn = QtGui.QPushButton("Shrink the tree")
shrink_tree_btn.clicked.connect(self.shrink_tree)
layout1.addWidget(shrink_tree_btn)
#--
self.tree_anim = QtCore.QVariantAnimation(self)
self.tree_anim.setDuration(1000)
self.tree_anim.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
def shrink_tree(self):
self.tree_anim.setStartValue(self.browse_tree.height())
self.tree_anim.setEndValue(0)
self.tree_anim.valueChanged.connect(self.on_valueChanged)
self.tree_anim.start()
def on_valueChanged(self, val):
h, isValid = val.toInt()
if isValid:
self.browse_tree.setFixedHeight(h)
def main():
app = QtGui.QApplication(sys.argv)
ex = AnimatedWidgets()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Use one QPushButton with two QLineEdits, depending on last focus

I have a window, which has two QLineEdits in it. They are Line 1 and Line 2. I have a Backspace QPushButton which is to be pressed. I want some code which, when the backspace is pressed, will delete the text from the desired QLineEdit. This is to be done based on which one is focused at the time.
I understand that currently my code will backspace line1, however I want it to delete whichever line edit most recently had focus (i.e. if line1 was selected before backspace, it will get backspaced, if line 2 was the last in focus, then it will be backspaced).
I'm thinking it requires an if statement or 2, not sure though. How do I choose which line edit is deleted based on which one last had focus?
from PySide import QtGui, QtCore
from PySide.QtCore import*
from PySide.QtGui import*
class MainWindow(QtGui.QMainWindow): #The Main Window Class Maker
def __init__(self,):
QtGui.QMainWindow.__init__(self)
QtGui.QApplication.setStyle(('cleanlooks'))
mfont = QFont()
mfont.setFamily("BankGothic LT")
mfont.setPointSize(40)
mfont.setBold(True)
xfont = QFont()
xfont.setFamily("BankGothic LT")
xfont.setPointSize(40)
xfont.setLetterSpacing(QFont.AbsoluteSpacing, 15)
self.line1 = QLineEdit("Line 1", self)
self.line1.setFixedSize(460, 65)
self.line1.setFont(xfont)
self.line1.move(10,10)
self.line2 = QLineEdit("Line 2", self)
self.line2.setFixedSize(460, 65)
self.line2.setFont(xfont)
self.line2.move(10,200)
#BackSpace button
back = QPushButton("BackSpace", self)
back.move(100,100)
back.setFixedSize(300,75)
back.setFont(mfont)
back.clicked.connect(self.line1.backspace)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.setWindowTitle("BackSpace")
window.resize(480, 400)
window.setMaximumSize(480,400)
window.setMinimumSize(480,400)
window.show()
sys.exit(app.exec_())
You can accomplish this by utilizing the editingFinished signal and some manipulation of which line edit is connected to your backspace function.
I'll post then entire code block and then explain the changes I made below it.
class MainWindow(QtGui.QMainWindow):
def __init__(self,):
QtGui.QMainWindow.__init__(self)
QtGui.QApplication.setStyle(('cleanlooks'))
mfont = QFont()
mfont.setFamily("BankGothic LT")
mfont.setPointSize(40)
mfont.setBold(True)
xfont = QFont()
xfont.setFamily("BankGothic LT")
xfont.setPointSize(40)
xfont.setLetterSpacing(QFont.AbsoluteSpacing, 15)
self.line1 = QLineEdit("Line 1", self)
self.line1.setFixedSize(460, 65)
self.line1.setFont(xfont)
self.line1.move(10,10)
self.line2 = QLineEdit("Line 2", self)
self.line2.setFixedSize(460, 65)
self.line2.setFont(xfont)
self.line2.move(10,200)
self.recent_line = self.line2
self.previous_line = self.line1
#BackSpace button
self.back = QPushButton("BackSpace", self)
self.back.move(100,100)
self.back.setFixedSize(300,75)
self.back.setFont(mfont)
self.back.clicked.connect(self.recent_line.backspace)
self.line1.editingFinished.connect(self.last_lineedit)
self.line2.editingFinished.connect(self.last_lineedit)
def last_lineedit(self):
if isinstance(self.sender(), QLineEdit):
self.recent_line, self.previous_line = self.previous_line, self.recent_line
self.back.clicked.disconnect(self.previous_line.backspace)
self.back.clicked.connect(self.recent_line.backspace)
The first change that I've made is to include two new variables so that we can keep track of which QLineEdit was focused on last:
self.recent_line = self.line2
self.previous_line = self.line1
Next, I changed your back widget to be self.back, because we are going to need it outside of __init__
self.back = QPushButton("BackSpace", self)
self.back.move(100,100)
self.back.setFixedSize(300,75)
self.back.setFont(mfont)
self.back.clicked.connect(self.recent_line.backspace)
Then we are going to set up both line1 and line2 to the editingFinished signal.
This signal is emitted when the Return or Enter key is pressed or the line edit loses focus.
We'll be utilizing the "loses focus" part, because when the self.back button is pressed, the QLineEdit has lost focus.
Finally we get to the function that is going to keep track of which QLineEdit is connected to the backspace button at any given time.
def last_lineedit(self):
if isinstance(self.sender(), QLineEdit):
self.recent_line, self.previous_line = self.previous_line, self.recent_line
self.back.clicked.disconnect(self.previous_line.backspace)
self.back.clicked.connect(self.recent_line.backspace)
Within this function, we fist ensure that only one of the QLineEdits are sending the signal (just in case you connect something else to this signal that isn't a QLineEdit).
Next, we swap which QLineEdit was most recently focused on:
self.recent_line, self.previous_line = self.previous_line, self.recent_line
Then we disconnect from the previous line and connect to the new line. These last two lines are the magic that allows you to delete from both lines based on which had focus most recently. These lines are also why we changed to self.back, instead of leaving it at back. The locally scoped back wasn't accessible from the last_lineedit function.
It would be best if the backspace button didn't steal focus. That way, the caret will stay visible in the line-edit that has focus, and the user can easily see exactly what is happening. Doing it this way also makes the code much simpler:
back.setFocusPolicy(QtCore.Qt.NoFocus)
back.clicked.connect(self.handleBackspace)
def handleBackspace(self):
widget = QtGui.qApp.focusWidget()
if widget is self.line1 or widget is self.line2:
widget.backspace()
Ok guys, so I kept working on this in order to find a useful situation, where one would use this sort of functionality.
Say you were trying to create a login form for a touch screen, but you had no onscreen keyboard installed, you can 'create' one. This is what the intended use was for.
I've sort of tested this, and fixed any bugs I saw, but hey, feel free to use it. I noticed that heaps of examples existed for calculators, but no real examples existed for Keypad or Numberpad entry. Enjoy!
from PySide import QtGui, QtCore
from PySide.QtCore import*
from PySide.QtGui import*
class MainWindow(QtGui.QMainWindow): #The Main Window Class Maker
def __init__(self,):
QtGui.QMainWindow.__init__(self)
QtGui.QApplication.setStyle(('cleanlooks'))
U = QLabel("U:", self)
U.move(10,10)
P = QLabel("P:", self)
P.move(10,50)
self.line1 = QLineEdit("", self)
self.line1.move(20,10)
self.line1.setReadOnly(True)
self.line2 = QLineEdit("", self)
self.line2.move(20,50)
self.line2.setReadOnly(True)
self.line2.setEchoMode(QLineEdit.Password)
#PushButtons
back = QPushButton("<", self)
back.move(100,80)
back.setFocusPolicy(QtCore.Qt.NoFocus)
back.setFixedSize(20,20)
one = QPushButton('1', self)
one.move(10,80)
one.setFocusPolicy(QtCore.Qt.NoFocus)
one.setText("1")
one.setFixedSize(20,20)
two = QPushButton('2', self)
two.move(40,80)
two.setFocusPolicy(QtCore.Qt.NoFocus)
two.setFixedSize(20,20)
three = QPushButton('3', self)
three.move(70,80)
three.setFocusPolicy(QtCore.Qt.NoFocus)
three.setFixedSize(20,20)
four = QPushButton('4', self)
four.move(10,110)
four.setFocusPolicy(QtCore.Qt.NoFocus)
four.setFixedSize(20,20)
five = QPushButton('5', self)
five.move(40,110)
five.setFocusPolicy(QtCore.Qt.NoFocus)
five.setFixedSize(20,20)
six = QPushButton('6', self)
six.move(70,110)
six.setFocusPolicy(QtCore.Qt.NoFocus)
six.setFixedSize(20,20)
seven = QPushButton('7', self)
seven.move(10,140)
seven.setFocusPolicy(QtCore.Qt.NoFocus)
seven.setFixedSize(20,20)
eight = QPushButton('8', self)
eight.move(40,140)
eight.setFocusPolicy(QtCore.Qt.NoFocus)
eight.setFixedSize(20,20)
nine = QPushButton('9', self)
nine.move(70,140)
nine.setFocusPolicy(QtCore.Qt.NoFocus)
nine.setFixedSize(20,20)
zero = QPushButton('0', self)
zero.move(100,140)
zero.setFocusPolicy(QtCore.Qt.NoFocus)
zero.setFixedSize(20,20)
enter = QPushButton("E", self)
enter.move(100,110)
enter.setFixedSize(20,20)
enter.setFocusPolicy(QtCore.Qt.NoFocus)
#click Handles
def handleBackspace():
backh = QtGui.qApp.focusWidget()
if backh is self.line1 or backh is self.line2:
backh.backspace()
def handleZero():
zeroh = QtGui.qApp.focusWidget()
if zeroh is self.line1:
zeroh.setText((self.line1.text()+str('0')))
else:
zeroh.setText(self.line2.text()+str('0'))
def handleOne():
oneh = QtGui.qApp.focusWidget()
if oneh is self.line1:
oneh.setText(self.line1.text()+str('1'))
else:
oneh.setText(self.line2.text()+str('1'))
def handleTwo():
twoh = QtGui.qApp.focusWidget()
if twoh is self.line1:
twoh.setText(self.line1.text()+str('2'))
else:
twoh.setText(self.line2.text()+str('2'))
def handleThree():
threeh = QtGui.qApp.focusWidget()
if threeh is self.line1:
threeh.setText(self.line1.text()+str('3'))
else:
threeh.setText(self.line2.text()+str('3'))
def handleFour():
fourh = QtGui.qApp.focusWidget()
if fourh is self.line1:
fourh.setText(self.line1.text()+str('4'))
else:
fourh.setText(self.line2.text()+str('4'))
def handleFive():
fiveh = QtGui.qApp.focusWidget()
if fiveh is self.line1:
fiveh.setText(self.line1.text()+str('5'))
else:
fiveh.setText(self.line2.text()+str('5'))
def handleSix():
sixh = QtGui.qApp.focusWidget()
if sixh is self.line1:
sixh.setText(self.line1.text()+str('6'))
else:
sixh.setText(self.line2.text()+str('6'))
def handleSeven():
sevenh = QtGui.qApp.focusWidget()
if sevenh is self.line1:
sevenh.setText(self.line1.text()+str('7'))
else:
sevenh.setText(self.line2.text()+str('7'))
def handleEight():
eighth = QtGui.qApp.focusWidget()
if eighth is self.line1:
eighth.setText(self.line1.text()+str('8'))
else:
eighth.setText(self.line2.text()+str('8'))
def handleNine():
nineh = QtGui.qApp.focusWidget()
if nineh is self.line1:
nineh.setText(self.line1.text()+str('9'))
else:
nineh.setText(self.line2.text()+str('9'))
#Click Conditions
self.connect(enter, SIGNAL("clicked()"), self.close)
zero.clicked.connect(handleZero)
nine.clicked.connect(handleNine)
eight.clicked.connect(handleEight)
seven.clicked.connect(handleSeven)
six.clicked.connect(handleSix)
five.clicked.connect(handleFive)
four.clicked.connect(handleFour)
three.clicked.connect(handleThree)
two.clicked.connect(handleTwo)
one.clicked.connect(handleOne)
back.clicked.connect(handleBackspace)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.setWindowTitle("LoginWindow")
window.resize(130, 180)
window.setMaximumSize(130, 180)
window.setMinimumSize(130, 180)
window.show()
sys.exit(app.exec_())

PyQt4 - add a text edit area animation example

I have realized a python simple application, without any animation on it.
Now I want to add a simple animation, triggered by a signal (a button click for example), which on trigger enlarges the width of the windows and shows a new text area with some text in it.
Honestly, I am quite new to python/pyqt4, and I do not know much about the animation framework.
I tried to add this to my class code, for example in a method called clicking on the about menu :) :
self.anim = QPropertyAnimation(self, "size")
self.anim.setDuration(2500)
self.anim.setStartValue(QSize(self.width(), self.height()))
self.anim.setEndValue(QSize(self.width()+100, self.height()))
self.anim.start()
and this enlarge my window as I want.
Unfortunately I have no idea how to insert a new text area, avoiding the widgets already present to fill the new space (actually, when the window enlarge, the widgets use
all the spaces, thus enlarging themselves)
Could someone help me knowing how to add the text area appearance animation?
Any help is appreciated...really...
One way to achieve this is to animate the maximumWidth property on both the window and the text-edit.
The main difficulty is doing it in a way that plays nicely with standard layouts whilst also allowing resizing of the window. Avoiding flicker during the animation is also quite tricky.
The following demo is almost there (the animation is slightly jerky at the beginning and end):
from PyQt4 import QtGui, QtCore
class Window(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self)
self._offset = 200
self._closed = False
self._maxwidth = self.maximumWidth()
self.widget = QtGui.QWidget(self)
self.listbox = QtGui.QListWidget(self.widget)
self.button = QtGui.QPushButton('Slide', self.widget)
self.button.clicked.connect(self.handleButton)
self.editor = QtGui.QTextEdit(self)
self.editor.setMaximumWidth(self._offset)
vbox = QtGui.QVBoxLayout(self.widget)
vbox.setContentsMargins(0, 0, 0, 0)
vbox.addWidget(self.listbox)
vbox.addWidget(self.button)
layout = QtGui.QHBoxLayout(self)
layout.addWidget(self.widget)
layout.addWidget(self.editor)
layout.setSizeConstraint(QtGui.QLayout.SetMinAndMaxSize)
self.animator = QtCore.QParallelAnimationGroup(self)
for item in (self, self.editor):
animation = QtCore.QPropertyAnimation(item, 'maximumWidth')
animation.setDuration(800)
animation.setEasingCurve(QtCore.QEasingCurve.OutCubic)
self.animator.addAnimation(animation)
self.animator.finished.connect(self.handleFinished)
def handleButton(self):
for index in range(self.animator.animationCount()):
animation = self.animator.animationAt(index)
width = animation.targetObject().width()
animation.setStartValue(width)
if self._closed:
self.editor.show()
animation.setEndValue(width + self._offset)
else:
animation.setEndValue(width - self._offset)
self._closed = not self._closed
self.widget.setMinimumSize(self.widget.size())
self.layout().setSizeConstraint(QtGui.QLayout.SetFixedSize)
self.animator.start()
def handleFinished(self):
if self._closed:
self.editor.hide()
self.layout().setSizeConstraint(QtGui.QLayout.SetMinAndMaxSize)
self.widget.setMinimumSize(0, 0)
self.setMaximumWidth(self._maxwidth)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.move(500, 300)
window.show()
sys.exit(app.exec_())

Categories

Resources