Results 1 to 8 of 8

Thread: Show/Hide height animation with SetFixedSize

  1. #1
    Join Date
    Sep 2010
    Posts
    4
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Show/Hide height animation with SetFixedSize

    I've been trying for quite a while now to have a window which automatically shrinks to the size of its widgets, and whose child widgets' hide/show operations will be animated.

    So far I've managed to get a window which will shrink, using window.layout().setSizeConstraint(QLayout.SetFixed Size) - and then overriding the widget's sizeHint (see the code).

    I have been experimenting with different sizePolicies on the widget and different sizeConstraints on the encapsulating layouts -- needless to say, they have each had slightly different (and horrible) results. Here is my code -- in which the animation doesn't work at all:

    Qt Code:
    1. #!/usr/bin/env python
    2.  
    3. from PyQt4.QtGui import *
    4. from PyQt4.QtCore import *
    5. import sys
    6.  
    7. connect = QObject.connect
    8.  
    9. app = QApplication(sys.argv)
    10.  
    11. def print_qsize(sz, title=""):
    12. print title, "W: ", sz.width(), " H: ", sz.height()
    13.  
    14. class ResizingWindow(QMainWindow):
    15. def __init__(self, parent=None):
    16. QMainWindow.__init__(self, parent)
    17. centralwidget = QWidget(self)
    18. self.setCentralWidget(centralwidget)
    19. layout = QVBoxLayout()
    20. centralwidget.setLayout(layout)
    21.  
    22. checkbox1 = QCheckBox("Show First Widget", self)
    23. checkbox2 = QCheckBox("Show Second Widget", self)
    24. textedit1 = QPlainTextEdit(self)
    25. textedit2 = QPlainTextEdit(self)
    26.  
    27. layout.addWidget(checkbox1)
    28. layout.addWidget(textedit1)
    29. layout.addWidget(checkbox2)
    30. layout.addWidget(textedit2)
    31.  
    32. connect(checkbox1, SIGNAL("toggled(bool)"), lambda b: self.hide_resize(textedit1, b))
    33. connect(checkbox2, SIGNAL("toggled(bool)"), lambda b: self.hide_resize(textedit2, b))
    34.  
    35. self.modify_widget(textedit1)
    36. self.modify_widget(textedit2)
    37. textedit1.hide()
    38. textedit2.hide()
    39.  
    40. self.layout().setSizeConstraint(QLayout.SetFixedSize)
    41.  
    42. def modify_widget(self, widget):
    43. #this is needed so that the widget 'inherits' the existing size of the
    44. #layout rather than forcing the layout to expand even further.. don't ask
    45. #me how this works
    46. def sizeHint():
    47. return QSize(1, 1)
    48. widget.sizeHint = sizeHint
    49.  
    50. def hide_resize(self, widget, show=True):
    51. if show:
    52. #this doesn't work
    53. widget.resize(widget.width(), 1)
    54. widget.show()
    55.  
    56. #neither does this
    57. widget.resize(widget.width(), 1)
    58.  
    59. #and neither do these:
    60. a = QPropertyAnimation(widget, "height", widget)
    61. a.setStartValue(1)
    62. a.setEndValue(100)
    63. a.setDuration(250)
    64. a.start()
    65. else:
    66. widget.hide()
    67.  
    68. mw = ResizingWindow()
    69. mw.show()
    70. app.exec_()
    To copy to clipboard, switch view to plain text mode 

    My question is how to make the animation here work? I'm quite sure it involves a magic combination of sizeConstraints and sizePolicy settings, and maybe even a wrapping container widget -- but I haven't found the right combination yet.

    Update: Trying to animate the size property rather than just the height yields some results, however I prefer to only dabble with the height, as I would like to leave the width managed by other things - it would be a pain to go through all the layouts and their margins, and then set that width manually by calculating the size of the top-most widget, then subtracting the margins of the layouts

    Also, it seems that the animation only works on the widget, but not the window itself (which would be really nice) -- so e.g. the window first expands the full (allowed?) size, and then the widget animates (improperly though)
    Last edited by mnunberg; 20th September 2010 at 00:00. Reason: spelling corrections

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Show/Hide height animation with SetFixedSize

    Trying with size policies and size constraints is not a good solution. You should just implement your own layout.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Sep 2010
    Posts
    4
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Show/Hide height animation with SetFixedSize

    I poked around a bit at this idea, but I don't see how it will help me with the animation part, - I've only managed to see that the layout's setGeometry is called whenever a widget is shown/hidden.. I tried to play around with that a bit, (some nasty animation stuff with setGeometry, which didn't work, and didn't seem the right way to do it anyway)
    Can you give some pointers?

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Show/Hide height animation with SetFixedSize

    If you implement your own layout you are a master of allocating space for all the managed widgets. You can gradually (i.e. using a timer) increase the size hint returned by the layout to make your main widget grow and you can use setGeometry to manage where the child widgets go. You can also hide/show widgets as you see fit. Of course then you won't be able to show()/hide() those widgets directly or it would break your layout - you'd have to add appropriate API for that in your layout class.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    Feb 2008
    Posts
    491
    Thanks
    12
    Thanked 142 Times in 135 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Talking Re: Show/Hide height animation with SetFixedSize

    Not sure if this is what you are after or not, but I got the animation to work using the "geometry" property.

    I couldn't get it to work using "height" either. Could it be because "height" is constant (int height () const), Wysota?
    Qt Code:
    1. #!/usr/bin/env python
    2. # -*- coding: utf-8 -*-
    3.  
    4. from PyQt4.QtGui import *
    5. from PyQt4.QtCore import *
    6. import sys
    7.  
    8. connect = QObject.connect
    9.  
    10. app = QApplication(sys.argv)
    11.  
    12. def print_qsize(sz, title=""):
    13. print title, "W: ", sz.width(), " H: ", sz.height()
    14.  
    15. class ResizingWindow(QMainWindow):
    16. def __init__(self, parent=None):
    17. QMainWindow.__init__(self, parent)
    18. centralwidget = QWidget(self)
    19. self.setCentralWidget(centralwidget)
    20. layout = QVBoxLayout()
    21.  
    22.  
    23. checkbox1 = QCheckBox("Show First Widget", self)
    24. checkbox2 = QCheckBox("Show Second Widget", self)
    25. textedit1 = QPlainTextEdit(self)
    26. textedit2 = QPlainTextEdit(self)
    27.  
    28. layout.addWidget(checkbox1)
    29. layout.addWidget(textedit1)
    30. layout.addWidget(checkbox2)
    31. layout.addWidget(textedit2)
    32. centralwidget.setLayout(layout)
    33. connect(checkbox1, SIGNAL("toggled(bool)"), lambda b: self.hide_resize(textedit1, b))
    34. connect(checkbox2, SIGNAL("toggled(bool)"), lambda b: self.hide_resize(textedit2, b))
    35.  
    36. textedit1.hide()
    37. textedit2.hide()
    38.  
    39. self.layout().setSizeConstraint(QLayout.SetFixedSize)
    40.  
    41. def hide_resize(self, widget, show=True):
    42. if show:
    43. widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) #got some flicker as the widget was growing without this
    44. widget.show()
    45. a = QPropertyAnimation(widget, "geometry", widget)
    46. a.setStartValue(QRect(widget.geometry().x(),widget.geometry().y(),0,0)) #use widget's original (x,y)
    47. a.setEndValue(QRect(widget.geometry().x(),widget.geometry().y(),256,192))
    48. a.setDuration(250)
    49. a.start()
    50. else:
    51. widget.hide()
    52.  
    53. mw = ResizingWindow()
    54. mw.show()
    55. app.exec_()
    To copy to clipboard, switch view to plain text mode 
    HTH
    Last edited by norobro; 20th September 2010 at 17:58. Reason: corrected code formatting

  6. #6
    Join Date
    Sep 2010
    Posts
    4
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Show/Hide height animation with SetFixedSize

    norobo: Your solution works fine, save for the problem that the resizing of the main window itself is not animated - which is also my goal.

    I have managed to come up with my own crappy layout implementation. It *works* and does everything i *want* it to, but there must be a better way

    a sample run gives me:
    Qt Code:
    1. increment is 0.5
    2. increment is 0.5
    3. show, going for height 125
    4. got begin 0 end 125 step 0.5
    5. amount_grown is 124
    6. hides
    7. amount_shrunk is 0
    8. show, going for height 125
    9. got begin 0 end 125 step 0.5
    10. amount_grown is 124
    11. hides
    12. amount_shrunk is 0
    13. show, going for height 125
    14. got begin 0 end 125 step 0.5
    15. amount_grown is 124
    16. show, going for height 125
    17. got begin 0 end 125 step 0.5
    18. amount_grown is 124
    19. hides
    20. amount_shrunk is 0
    21. show, going for height 125
    22. got begin 0 end 125 step 0.5
    23. amount_grown is 124
    24. hides
    25. amount_shrunk is 0
    26. show, going for height 125
    27. got begin 0 end 125 step 0.5
    28. amount_grown is 124
    29.  
    30. real 0m13.645s
    31. user 0m2.369s
    32. sys 0m1.193s
    To copy to clipboard, switch view to plain text mode 

    -- way too much CPU time for this

    The updated code is:
    Qt Code:
    1. #!/usr/bin/env python
    2. # -*- coding: utf-8 -*-
    3.  
    4. from PyQt4.QtGui import *
    5. from PyQt4.QtCore import *
    6. import sys
    7.  
    8. connect = QObject.connect
    9.  
    10. app = QApplication(sys.argv)
    11.  
    12. def copy_size(size):
    13. return QSize(size.width(), size.height())
    14.  
    15. def xfloat_range(begin,end,step):
    16. print "got begin", begin, "end", end, "step", step
    17. while begin < end:
    18. yield begin
    19. begin += step
    20.  
    21. def xfloat_range_decrement(begin, end, step):
    22. while begin > end and begin > 0:
    23. yield begin
    24. begin -= step
    25.  
    26.  
    27. def print_qsize(sz, title=""):
    28. print title, "W: ", sz.width(), " H: ", sz.height()
    29.  
    30. class AnimatedLayout(QHBoxLayout):
    31. def __init__(self, child, size, parent = None):
    32. QHBoxLayout.__init__(self, parent)
    33. self._name = ""
    34.  
    35. child.sizeHint = lambda: QSize()
    36. child.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Ignored)
    37.  
    38. self.child = child
    39. self.addWidget(child)
    40. self.mandated_size = QSize(size.height(), 0)
    41. self.preferred_size = size
    42.  
    43. self.setContentsMargins(0,0,0,0)
    44. self.setSpacing(0)
    45.  
    46. self.duration = 250
    47.  
    48. self.amount_grown = 0
    49. self.amount_shrunk = 0
    50. self.generator = None
    51.  
    52. self.timer = QTimer(self)
    53. self.child.setVisible(True)
    54.  
    55. self.show = self.startShow
    56. self.hide = self.startHide
    57. self.child.show = self.show
    58. self.child.hide = self.hide
    59.  
    60. print "increment is ", self.increment
    61.  
    62. @property
    63. def increment(self):
    64. return float(float(self.preferred_size.height())/float(self.duration))
    65.  
    66. def setGeometry(self, rect):
    67. #print_qsize(rect.size(), self._name)
    68. super(type(self), self).setGeometry(rect)
    69.  
    70. def sizeHint(self):
    71. return self.mandated_size
    72.  
    73. def setAnimationDuration(self, msecs):
    74. self.duration = msecs
    75.  
    76. def timer_fire_show(self):
    77. if not self.generator:
    78. raise Exception("Generator not initialized!")
    79. try:
    80. h = int(self.generator.next())
    81. #print h
    82. if h > self.amount_grown:
    83. self.mandated_size.setHeight(h)
    84. self.amount_grown = h
    85. self.update()
    86. except StopIteration:
    87. #finished:
    88. print "amount_grown is", self.amount_grown
    89. self.timer.stop()
    90. #do any cleanup, just a final check
    91. self.mandated_size = copy_size(self.preferred_size)
    92. self.update()
    93. QObject.disconnect(self.timer, SIGNAL("timeout()"), self.timer_fire_show)
    94. del self.generator
    95.  
    96. def startShow(self):
    97. print "show, going for height", self.preferred_size.height()
    98. #start an animation here using a timer that will update both our sizeHint
    99. #as well as the widget's size accordingly
    100. self.generator = xfloat_range(0, self.preferred_size.height(), self.increment)
    101. QObject.connect(self.timer, SIGNAL("timeout()"), self.timer_fire_show)
    102. self.amount_grown = 0
    103. self.timer.start(1)
    104.  
    105. def timer_fire_hide(self):
    106. if not self.generator:
    107. raise Exception("Generator not initialized")
    108. try:
    109. h = int(self.generator.next())
    110. #print h
    111. if h < self.amount_shrunk:
    112. self.mandated_size.setHeight(h)
    113. self.amount_shrunk = h
    114. self.update()
    115. except StopIteration:
    116. print "amount_shrunk is", self.amount_shrunk
    117. self.timer.stop()
    118. self.mandated_size.setHeight(0)
    119. self.update()
    120. QObject.disconnect(self.timer, SIGNAL("timeout()"), self.timer_fire_hide)
    121.  
    122. def startHide(self):
    123. print "hides"
    124. self.generator = xfloat_range_decrement(self.preferred_size.height(), 0, self.increment)
    125. QObject.connect(self.timer, SIGNAL("timeout()"), self.timer_fire_hide)
    126. self.amount_shrunk = self.preferred_size.height()
    127. self.timer.start(1)
    128.  
    129. def setVisible(self, b):
    130. "convenience method"
    131. if b:
    132. self.startShow()
    133. else:
    134. self.startHide()
    135.  
    136. class ResizingWindow(QMainWindow):
    137. def __init__(self, parent=None):
    138. QMainWindow.__init__(self, parent)
    139. self.layout().setSizeConstraint(QLayout.SetFixedSize)
    140.  
    141. centralwidget = QWidget(self)
    142. self.setCentralWidget(centralwidget)
    143. layout = QVBoxLayout()
    144.  
    145.  
    146. checkbox1 = QCheckBox("Show First Widget", self)
    147. checkbox2 = QCheckBox("Show Second Widget", self)
    148. textedit1 = QPlainTextEdit(self)
    149. textedit2 = QPlainTextEdit(self)
    150.  
    151. anim_wrapper1 = AnimatedLayout(textedit1, QSize(150, 125))
    152. anim_wrapper1._name = "anim_wrapper1"
    153. self.anim_wrapper1 = anim_wrapper1
    154. anim_wrapper2 = AnimatedLayout(textedit2, QSize(150, 125))
    155. anim_wrapper2._name = "anim_wrapper2"
    156. self.anim_wrapper2 = anim_wrapper2
    157.  
    158.  
    159. layout.addWidget(checkbox1)
    160. layout.addLayout(anim_wrapper1)
    161. layout.addWidget(checkbox2)
    162. layout.addLayout(anim_wrapper2)
    163. centralwidget.setLayout(layout)
    164.  
    165. connect(checkbox1, SIGNAL("toggled(bool)"), anim_wrapper1.setVisible)
    166. connect(checkbox2, SIGNAL("toggled(bool)"), anim_wrapper2.setVisible)
    167. mw = ResizingWindow()
    168. mw.show()
    169. app.exec_()
    To copy to clipboard, switch view to plain text mode 
    Last edited by mnunberg; 21st September 2010 at 01:55. Reason: updated contents

  7. #7
    Join Date
    Sep 2010
    Posts
    4
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Show/Hide height animation with SetFixedSize

    Well, I've reworked a cleaner example, but this one jitters, and it doesn't seem to work in my actual code -- I get the children widgets in their own windows?:

    Qt Code:
    1. #!/usr/bin/env python
    2. # -*- coding: utf-8 -*-
    3.  
    4. from PyQt4.QtGui import *
    5. from PyQt4.QtCore import *
    6. import sys
    7.  
    8. connect = QObject.connect
    9.  
    10. app = QApplication(sys.argv)
    11.  
    12. def print_qsize(sz, title=""):
    13. print title, "W: ", sz.width(), " H: ", sz.height()
    14.  
    15. class AnimatedLayout(QLayout):
    16. STATE_HIDDEN, STATE_VISIBLE, STATE_ANIMATING = range(3)
    17.  
    18. def __init__(self, child, size, parent = None):
    19. super(type(self),self).__init__(parent)
    20. self._name = ""
    21.  
    22. child.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
    23. #self.setSizeConstraint(QLayout.SetFixedSize)
    24.  
    25. self.child = child
    26. self.mandated_size = QSize(size.width(), 0)
    27. self.preferred_size = size
    28.  
    29. self.setContentsMargins(0,0,0,0)
    30. self.setSpacing(0)
    31.  
    32. self.duration = 250
    33. self.child.setVisible(True)
    34.  
    35. self.show = self.startShow
    36. self.hide = self.startHide
    37. self.child.show = self.show
    38. self.child.hide = self.hide
    39. self.child.setVisible = self.setVisible
    40.  
    41. self.child_state = self.STATE_VISIBLE
    42.  
    43. #these two segfaulted if i tried to do anything legit with them?
    44. def count(self):
    45. return 0
    46. def itemAt(self, index):
    47. return None
    48.  
    49. def setGeometry(self, rect):
    50. if not self.child_state in (self.STATE_ANIMATING, self.STATE_VISIBLE):
    51. return
    52. #super(type(self), self).setGeometry(rect)
    53. self.child.setGeometry(rect)
    54.  
    55. def sizeHint(self):
    56. return self.mandated_size
    57. #return self.child.sizeHint()
    58.  
    59. def setAnimationDuration(self, msecs):
    60. self.duration = msecs
    61.  
    62. def startShow(self):
    63. self._start_animation(True)
    64. def startHide(self):
    65. self._start_animation(False)
    66.  
    67. def _start_animation(self, show=True):
    68. a = QPropertyAnimation(self.child, "geometry", self)
    69. g = self.child.geometry()
    70. g.setHeight(0)
    71. a.setStartValue(g)
    72. g.setHeight(self.preferred_size.height())
    73. a.setEndValue(g)
    74. a.setEasingCurve(QEasingCurve.OutQuad)
    75. a.setDuration(self.duration)
    76. def valueChanged(qv):
    77. r = qv.toRect()
    78. self.mandated_size.setHeight(r.height())
    79. self.update()
    80. connect(a, SIGNAL("valueChanged(QVariant)"), valueChanged)
    81.  
    82. if not show:
    83. a.setDirection(a.Backward)
    84. connect(a, SIGNAL("finished()"), lambda: setattr(self, "child_state", self.STATE_HIDDEN))
    85. else:
    86. a.setDirection(a.Forward)
    87. connect(a, SIGNAL("finished()"), lambda: setattr(self, "child_state", self.STATE_VISIBLE))
    88. a.start(a.DeleteWhenStopped)
    89.  
    90.  
    91. def setVisible(self, b):
    92. "convenience method"
    93. if b:
    94. self.startShow()
    95. else:
    96. self.startHide()
    97.  
    98. class ResizingWindow(QMainWindow):
    99. def __init__(self, parent=None):
    100. QMainWindow.__init__(self, parent)
    101. self.layout().setSizeConstraint(QLayout.SetFixedSize)
    102.  
    103. centralwidget = QWidget(self)
    104. self.setCentralWidget(centralwidget)
    105. layout = QVBoxLayout()
    106.  
    107.  
    108. checkbox1 = QCheckBox("Show First Widget", self)
    109. checkbox2 = QCheckBox("Show Second Widget", self)
    110. textedit1 = QPlainTextEdit(self)
    111. textedit2 = QPlainTextEdit(self)
    112. textedit1.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
    113. textedit2.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
    114.  
    115. anim_wrapper1 = AnimatedLayout(textedit1, QSize(150, 125))
    116. anim_wrapper1._name = "anim_wrapper1"
    117. self.anim_wrapper1 = anim_wrapper1
    118. anim_wrapper2 = AnimatedLayout(textedit2, QSize(150, 125))
    119. anim_wrapper2._name = "anim_wrapper2"
    120. self.anim_wrapper2 = anim_wrapper2
    121.  
    122.  
    123. layout.addWidget(checkbox1)
    124. layout.addLayout(anim_wrapper1)
    125. layout.addWidget(checkbox2)
    126. layout.addLayout(anim_wrapper2)
    127. centralwidget.setLayout(layout)
    128.  
    129. connect(checkbox1, SIGNAL("toggled(bool)"), anim_wrapper1.setVisible)
    130. connect(checkbox2, SIGNAL("toggled(bool)"), anim_wrapper2.setVisible)
    131. mw = ResizingWindow()
    132. mw.show()
    133. app.exec_()
    To copy to clipboard, switch view to plain text mode 
    Last edited by mnunberg; 21st September 2010 at 04:41. Reason: updated contents

  8. #8
    Join Date
    Apr 2009
    Posts
    3
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Show/Hide height animation with SetFixedSize

    I have same kind of problem and would like to resize window when i hide a widget from layout(so this will give user dock kind of experience), this can be easily done by setting layout property QLayout::setSizeConstraint(QLayout::SetFixedSize), but then i can't resize window.

    so is there any way where i can re size window without loosing dock kind of effect when i hide or show child widget from layout.

    Please note that i don't want to implement re size event handling.
    thanks.
    Last edited by junky; 24th November 2010 at 11:22.

Similar Threads

  1. how to show an app if it manually hide
    By jthacker in forum Qt Programming
    Replies: 1
    Last Post: 26th March 2010, 13:02
  2. how to show and hide frames?
    By rambo83 in forum Qt Programming
    Replies: 2
    Last Post: 6th January 2010, 09:53
  3. Hide and Show QMenu
    By febil in forum Qt Programming
    Replies: 3
    Last Post: 25th March 2009, 09:31
  4. hide from taskbar but show to ALT-TAB
    By musikit in forum Qt Programming
    Replies: 0
    Last Post: 15th August 2008, 16:14
  5. Show or hide a form
    By Gayathri in forum Newbie
    Replies: 11
    Last Post: 17th November 2006, 12:39

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.