Results 1 to 8 of 8

Thread: How and when to repaint a widget ?

  1. #1
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default How and when to repaint a widget ?

    Hi !

    I wrote a widget class to manage animations. It is possible to set the displaying speed with a timer, and on each timeout I display an image.

    When I have to animation object (one uppon the other), the one which is behind the other is not repainted successfully.

    Actually my drawing code is in the function displayImage ... but I think it shouldn't be the right way to process.

    Something more conform should be to implement an update or repaint call in the function displayImage and then implement the drawing of the image in the function paintEvent but it is flickering.

    Here is the code I actually use to, so if someone could help me to find out how to do, it would be great.

    Qt Code:
    1. // Constructor / Destructor
    2. CAnimation::CAnimation(QWidget* parent/*=0*/, const char* name/*=0*/):
    3. QWidget(parent, name, Qt::WStyle_Customize|Qt::WStyle_NoBorder),
    4. timer(0),
    5. mode(PlayModeForeward),
    6. loopStopIndex(1),
    7. loopCurrentIndex(0),
    8. speed(500),
    9. imageStartIndex(0),
    10. imageStopIndex(0),
    11. imageCurrentIndex(0),
    12. playingStatus(Idle),
    13. displayingStatus(Hidden),
    14. transparency(false)
    15. {
    16. // Create the timer
    17. if( timer == 0 )
    18. timer = new QTimer(this, "timer");
    19.  
    20. // Connect the timer signal to the animation object slot
    21. connect(timer, SIGNAL(timeout()), SLOT(timerTick()));
    22. }
    23.  
    24.  
    25. CAnimation::~CAnimation()
    26. {
    27. // Stop the timer if active
    28. if( timer->isActive() )
    29. timer->stop();
    30.  
    31. // Delete the timer
    32. if( timer != 0 )
    33. {
    34. delete timer;
    35. timer = 0;
    36. }
    37.  
    38. // Clear the image names
    39. images.clear();
    40. }
    41.  
    42.  
    43. // Slots
    44. int CAnimation::displayImage(const QPixmap& pixmap)
    45. {
    46. if( transparency )
    47. {
    48. if ( pixmap.mask() )
    49. this->setMask( *pixmap.mask() );
    50. }
    51.  
    52. QRect rect(this->rect());
    53. bitBlt(this, rect.topLeft(), &pixmap);
    54.  
    55. return 0;
    56. }
    57.  
    58.  
    59.  
    60. void CAnimation::timerTick()
    61. {
    62. switch(mode)
    63. {
    64. case(CAnimation::PlayModeForeward):
    65. {
    66. /********************************************************************************************************************
    67. Two cases
    68. CASE 1 : if the image current index is not the image stop index then we increment it and display the image.
    69. CASE 2 : if the image current index is the image stop index, we must take care if the sequence must be looped.
    70. *********************************************************************************************************************/
    71.  
    72. // CASE 1
    73. if( imageCurrentIndex == imageStartIndex )
    74. {
    75. // Notify
    76. emit sequenceStarted();
    77. }
    78.  
    79. if( imageCurrentIndex < imageStopIndex )
    80. {
    81. // Display the image
    82. this->displayImage(images[imageCurrentIndex]);
    83.  
    84. // Notify
    85. emit frameDisplayed(imageCurrentIndex);
    86.  
    87. // Update the state
    88. this->setPlayingStatus(CAnimation::Started);
    89.  
    90. // Increment the current index
    91. imageCurrentIndex++;
    92. }
    93.  
    94. // CASE 2
    95. else if( imageCurrentIndex == imageStopIndex )
    96. {
    97. if( loopStopIndex == 0 )
    98. {
    99. // Display the image
    100. this->displayImage(images[imageCurrentIndex]);
    101.  
    102. // Notify
    103. emit frameDisplayed(imageCurrentIndex);
    104. emit sequenceFinished();
    105.  
    106. // Finish the animation
    107. this->finish();
    108. }
    109. else if( loopCurrentIndex < loopStopIndex )
    110. {
    111. // Display the image
    112. this->displayImage(images[imageCurrentIndex]);
    113.  
    114. // Notify
    115. emit frameDisplayed(imageCurrentIndex);
    116. emit sequenceFinished();
    117.  
    118. // Update the state
    119. this->setPlayingStatus(CAnimation::Started);
    120.  
    121. // Increment the loop index
    122. loopCurrentIndex++;
    123.  
    124. // Reset the image current index
    125. imageCurrentIndex = imageStartIndex;
    126. }
    127. else if( loopCurrentIndex == loopStopIndex )
    128. {
    129. // Display the image
    130. this->displayImage(images[imageCurrentIndex]);
    131.  
    132. // Notify
    133. emit frameDisplayed(imageCurrentIndex);
    134. emit sequenceFinished();
    135.  
    136. // Finish the animation
    137. this->finish();
    138. }
    139. }
    140. }
    141. break;
    142.  
    143. case(CAnimation::PlayModeBackward):
    144. {
    145. /********************************************************************************************************************
    146. Two cases
    147. CASE 1 : if the image current index is not the image stop index then we decrement it and display the image.
    148. CASE 2 : if the image current index is the image stop index, we must take care if the sequence must be looped.
    149. *********************************************************************************************************************/
    150.  
    151. // CASE 1
    152. if( imageCurrentIndex == imageStartIndex )
    153. {
    154. // Notify
    155. emit sequenceStarted();
    156. }
    157.  
    158. if( imageCurrentIndex > imageStopIndex )
    159. {
    160. // Display the image
    161. this->displayImage(images[imageCurrentIndex]);
    162.  
    163. // Notify
    164. emit frameDisplayed(imageCurrentIndex);
    165.  
    166. // Update the state
    167. this->setPlayingStatus(CAnimation::Started);
    168.  
    169. // Increment the current index
    170. imageCurrentIndex--;
    171. }
    172.  
    173. // CASE 2
    174. else if( imageCurrentIndex == imageStopIndex )
    175. {
    176. if( loopStopIndex == 0 )
    177. {
    178. // Display the image
    179. this->displayImage(images[imageCurrentIndex]);
    180.  
    181. // Notify
    182. emit frameDisplayed(imageCurrentIndex);
    183. emit sequenceFinished();
    184.  
    185. // Finish the animation
    186. this->finish();
    187. }
    188. else if( loopCurrentIndex < loopStopIndex )
    189. {
    190. // Display the image
    191. this->displayImage(images[imageCurrentIndex]);
    192.  
    193. // Notify
    194. emit frameDisplayed(imageCurrentIndex);
    195. emit sequenceFinished();
    196.  
    197. // Update the state
    198. this->setPlayingStatus(CAnimation::Started);
    199.  
    200. // Increment the loop index
    201. loopCurrentIndex++;
    202.  
    203. // Reset the image current index
    204. imageCurrentIndex = imageStartIndex;
    205. }
    206. else if( loopCurrentIndex == loopStopIndex )
    207. {
    208. // Display the image
    209. this->displayImage(images[imageCurrentIndex]);
    210.  
    211. // Notify
    212. emit frameDisplayed(imageCurrentIndex);
    213. emit sequenceFinished();
    214.  
    215. // Finish the animation
    216. this->finish();
    217. }
    218. }
    219. }
    220. break;
    221.  
    222. default:
    223. break;
    224. }
    225. }
    226.  
    227.  
    228. int CAnimation::start()
    229. {
    230. // Check conditions
    231. // ... TO DO
    232.  
    233. // Set initial values
    234. imageCurrentIndex = imageStartIndex;
    235. loopCurrentIndex = 0;
    236.  
    237. // Start timer
    238. timer->start(speed);
    239.  
    240. // Update state
    241. this->setPlayingStatus(CAnimation::Started);
    242.  
    243. // Notify
    244. emit animationStarted();
    245.  
    246. return 0;
    247. }
    248.  
    249.  
    250. int CAnimation::stop()
    251. {
    252. // Stop the timer
    253. timer->stop();
    254.  
    255. // Update the state
    256. this->setPlayingStatus(CAnimation::Stopped);
    257.  
    258. // Notify
    259. emit animationStopped();
    260.  
    261. return 0;
    262. }
    263.  
    264.  
    265. int CAnimation::pause()
    266. {
    267. // Stop the timer
    268. timer->stop();
    269.  
    270. // Update the state
    271. this->setPlayingStatus(CAnimation::Paused);
    272.  
    273. // Notify
    274. emit animationPaused();
    275.  
    276. return 0;
    277. }
    278.  
    279.  
    280. int CAnimation::resume()
    281. {
    282. // Start the timer
    283. timer->start(speed);
    284.  
    285. // Update the state
    286. this->setPlayingStatus(CAnimation::Started);
    287.  
    288. // Notify
    289. emit animationResumed();
    290.  
    291. return 0;
    292. }
    293.  
    294.  
    295. int CAnimation::finish()
    296. {
    297. // Stop the timer
    298. timer->stop();
    299.  
    300. // Reset values
    301. imageCurrentIndex = imageStartIndex;
    302. loopCurrentIndex = 0;
    303.  
    304. // Update the state
    305. this->setPlayingStatus(CAnimation::Finished);
    306.  
    307. // Notify
    308. emit animationFinished();
    309.  
    310. return 0;
    311. }
    312.  
    313.  
    314.  
    315. int CAnimation::showAnim()
    316. {
    317. // Show the widget
    318. this->show();
    319.  
    320. // Update the state
    321. this->setDisplayingStatus(CAnimation::Shown);
    322.  
    323. // Notify
    324. emit animationShown();
    325.  
    326. return 0;
    327. }
    328.  
    329.  
    330. int CAnimation::hideAnim()
    331. {
    332. // Hide the widget
    333. this->hide();
    334.  
    335. // Update the state
    336. this->setDisplayingStatus(CAnimation::Hidden);
    337.  
    338. // Notify
    339. emit animationHidden();
    340.  
    341. return 0;
    342. }
    To copy to clipboard, switch view to plain text mode 

    Thanks in advance.

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

    Default Re: How and when to repaint a widget ?

    Did you try just using QMovie?

  3. #3
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: How and when to repaint a widget ?

    Yes I did it first but it did not worked well ... in fact it did not display correctly big animations (800x640) so that's the reason why I decided to developp my own widget.

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

    Default Re: How and when to repaint a widget ?

    Maybe it would be better just to subclass it and correct things you don't like instead of doing everything on your own? Your code looks a bit complicated.

  5. #5
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: How and when to repaint a widget ?

    Is it possible to subclass the QMovie class even if it does not have any virtual method ?
    Last edited by yellowmat; 3rd April 2006 at 12:29. Reason: the term protected is not necessary

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

    Default Re: How and when to repaint a widget ?

    Sure. Why not? You can subclass and reimplement whatever you want. Just make sure you reference the right class later on. Qt doesn't use QMovie anywhere by itself, so it's just your choice if you write:

    Qt Code:
    1. QMovie *movie = MyMovie();
    To copy to clipboard, switch view to plain text mode 
    or
    Qt Code:
    1. MyMovie *movie = MyMovie();
    To copy to clipboard, switch view to plain text mode 

    The first one will not use your inherited functions which are not virtual, but the second one will, no matter that the base class methods are not virtual -- you are calling the class by name.

  7. #7
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: How and when to repaint a widget ?

    Hmm, to be sure I understood the subclassing concept let me (trying to) explain it with my words

    Subclassing and inheriting are synonyms. Subclassing consist of inheriting an existing class in order to make a specialization of it. It is up to the developper to reimplement one or more function of the base class. It will be then possible to access methods from base class or inherited class using a cast operator.

    If I use your example :
    Qt Code:
    1. class MyMovie : public QMovie
    2. {
    3. void step() { /* DO NOTHING */ }
    4. };
    To copy to clipboard, switch view to plain text mode 

    The previous code make MyMovie subclassing QMovie, and reimplements the step() method which does nothing in the specialized class (I know it's not usefull but it is just an example )

    If I do
    Qt Code:
    1. MyMovie* movie = new MyMovie();
    2. movie->step();
    To copy to clipboard, switch view to plain text mode 
    ... it will call the step() method reimplemented in MyMovie

    and if I then do
    Qt Code:
    1. QMovie* base = new MyMovie();
    2. movie->step();
    To copy to clipboard, switch view to plain text mode 
    ... then this is the base class methods which will be called.

    That's it ?

    Another things, about my CAnimation class. First, I decided to developp it from scratch because the QMovie doesn't not worked well and finally its functionnalities were too poor compared to my needs, so it was faster for me to do it this way. Second, I solved my problem using the paintEvent handler and I have modified my code as follow :
    - I have replaced each call to the displayImage with an update call
    - I have reimplemented the paintEvent function as follow :
    Qt Code:
    1. void CAnimation::paintEvent(QPaintEvent* event)
    2. {
    3. if( this->isShown )
    4. {
    5. QPixmap pixmap(images[imageCurrentIndex]);
    6. if( transparency )
    7. {
    8. if ( pixmap.mask() )
    9. this->setMask( *pixmap.mask() );
    10. }
    11.  
    12. QRect rect(event->rect());
    13. bitBlt(this, rect.topLeft(), &pixmap);
    14. }
    15. }
    To copy to clipboard, switch view to plain text mode 

    isShown is just a boolean indicating if the animation is shown or hidden ... and it works nice

    Thanks for your help.

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

    Default Re: How and when to repaint a widget ?

    Quote Originally Posted by yellowmat
    and if I then do
    Qt Code:
    1. QMovie* base = new MyMovie();
    2. movie->step();
    To copy to clipboard, switch view to plain text mode 
    ... then this is the base class methods which will be called.

    That's it ?
    I assume you meant base->step(). No, the compiler will complain there is no step() method defined in QMovie.

    Try this:

    Qt Code:
    1. #include <iostream>
    2.  
    3. class A {
    4. public:
    5. void func1(){ std::cout << "Class A func1" << std::endl; }
    6. virtual void func2(){ std::cout << "Class A func2" << std:: endl; }
    7. };
    8.  
    9. class B : public A {
    10. public:
    11. void func1(){ std::cout << "Class B func1" << std::endl; }
    12. void func2(){ std::cout << "Class B func2" << std::endl; }
    13. };
    14.  
    15. int main(){
    16. A a;
    17. B b;
    18. a.func1();
    19. a.func2();
    20. b.func1();
    21. b.func2();
    22. return 0;
    23. }
    To copy to clipboard, switch view to plain text mode 

  9. The following user says thank you to wysota for this useful post:

    yellowmat (4th April 2006)

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.