You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@pivot.apache.org by Simon Chatelain <sc...@gmail.com> on 2011/03/21 09:16:36 UTC

Activity Indicator in accordion header

Hello all,

I am trying to display an animated component inside the headers of an
accordion. For that I defined a subclass of AccordionHeaderDataRenderer
inserting a ActivityIndicator at first position in the header.

But the activity indicator animation is not refreshed unless I move the
mouse cursor over the header. What am I doing wrong and is there a way to do
that ?
You can find in attachment a sample application showing the described
behavior.

Thanks

Simon

Re: Activity Indicator in accordion header

Posted by Chris Bartlett <cb...@gmail.com>.
If you want to try this out, remember that AccordionHeaderDataRenderer (and
your custom version of it) extends BoxPane already, so you might just be
able to create multiple instance of those to use internally in the
custom TerraAccordionSkin.

And the container does not have to be a BoxPane.  Once you decide to replace
PanelHeaderSkin, you are then free to put whatever you want into the header.

On 21 March 2011 22:16, Simon Chatelain <sc...@gmail.com> wrote:

>
>>
>> Your TerraAccordionSkin might override these so that the header is a
>> simply a real BoxPane with an ActivityIndicator and a Label inside.  Then
>> the BoxPane skin (and ActivityIndicator & Label skins) will take care of
>> painting, and more importantly, animating.
>> (ie, use real, fully fledged Components, rather than a Renderer for each
>> header)
>>
>
> Yes !  that sounds good, seems elegant and efficient. I will look into this
> solution
>
> Thank you very much
>
> Simon
>
>
>
> On Mon, Mar 21, 2011 at 4:07 PM, Chris Bartlett <cb...@gmail.com>wrote:
>
>> Another thought might be to ditch the renderer approach entirely and to
>> create a custom subclass of Accordion along with a custom skin extending
>> org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.
>> (Or just copy both classes and edit to create your own parallel versions
>> rather than extending)
>> I haven't prototyped it, but I think it (or something similar) should
>> work, although I'm not sure it is necessarily preferable to just managing
>> the repaint callbacks yourself.
>>
>> TerraAccordionSkin contains these 2 inner classes which deal with the
>> Accordion headers and will normally use a supplied renderer to render the
>> header.
>> org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.PanelHeader
>> org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.PanelHeaderSkin
>>
>>
> Your TerraAccordionSkin might override these so that the header is a simply
>> a real BoxPane with an ActivityIndicator and a Label inside.  Then the
>> BoxPane skin (and ActivityIndicator & Label skins) will take care of
>> painting, and more importantly, animating.
>> (ie, use real, fully fledged Components, rather than a Renderer for each
>> header)
>>
>
>
>> For more flexibility you might expose the BoxPane used for each header so
>> that you can set its content, properties and styles as required.
>>
>> Chris
>>
>
>

Re: Activity Indicator in accordion header

Posted by Simon Chatelain <sc...@gmail.com>.
>
> Your TerraAccordionSkin might override these so that the header is a simply
> a real BoxPane with an ActivityIndicator and a Label inside.  Then the
> BoxPane skin (and ActivityIndicator & Label skins) will take care of
> painting, and more importantly, animating.
> (ie, use real, fully fledged Components, rather than a Renderer for each
> header)
>

Yes !  that sounds good, seems elegant and efficient. I will look into this
solution

Thank you very much

Simon


On Mon, Mar 21, 2011 at 4:07 PM, Chris Bartlett <cb...@gmail.com>wrote:

> Another thought might be to ditch the renderer approach entirely and to
> create a custom subclass of Accordion along with a custom skin extending
> org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.
> (Or just copy both classes and edit to create your own parallel versions
> rather than extending)
> I haven't prototyped it, but I think it (or something similar) should work,
> although I'm not sure it is necessarily preferable to just managing the
> repaint callbacks yourself.
>
> TerraAccordionSkin contains these 2 inner classes which deal with the
> Accordion headers and will normally use a supplied renderer to render the
> header.
> org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.PanelHeader
> org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.PanelHeaderSkin
>
>
Your TerraAccordionSkin might override these so that the header is a simply
> a real BoxPane with an ActivityIndicator and a Label inside.  Then the
> BoxPane skin (and ActivityIndicator & Label skins) will take care of
> painting, and more importantly, animating.
> (ie, use real, fully fledged Components, rather than a Renderer for each
> header)
>


> For more flexibility you might expose the BoxPane used for each header so
> that you can set its content, properties and styles as required.
>
> Chris
>

Re: Activity Indicator in accordion header

Posted by Chris Bartlett <cb...@gmail.com>.
Another thought might be to ditch the renderer approach entirely and to
create a custom subclass of Accordion along with a custom skin extending
org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.
(Or just copy both classes and edit to create your own parallel versions
rather than extending)
I haven't prototyped it, but I think it (or something similar) should work,
although I'm not sure it is necessarily preferable to just managing the
repaint callbacks yourself.

TerraAccordionSkin contains these 2 inner classes which deal with the
Accordion headers and will normally use a supplied renderer to render the
header.
org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.PanelHeader
org.apache.pivot.wtk.skin.terra.TerraAccordionSkin.PanelHeaderSkin

Your TerraAccordionSkin might override these so that the header is a simply
a real BoxPane with an ActivityIndicator and a Label inside.  Then the
BoxPane skin (and ActivityIndicator & Label skins) will take care of
painting, and more importantly, animating.
(ie, use real, fully fledged Components, rather than a Renderer for each
header)

For more flexibility you might expose the BoxPane used for each header so
that you can set its content, properties and styles as required.

Chris

Re: Activity Indicator in accordion header

Posted by Chris Bartlett <cb...@gmail.com>.
Given the need to manage ActivityIndicators independently, you would
probably need to use separate renderers for each Accordion header anyway, so
the renderer loses much of its worth.

And as Accordion only supports adding a single renderer for the entire
component, your renderer would need to be more complex and would probably
end being a single wrapper class than then delegated to individual 'real'
renderers depending on which panel was being renderered.  You could get
around this by modifying Accordion to accept multiple renderers, but again,
that doesn't seem likely to simplify things overall.

Anyway, good luck with it, and shout if you have any issues we might be able
to help out with.

Chris

On 21 March 2011 22:13, Simon Chatelain <sc...@gmail.com> wrote:

> For my specific use case: let's say that my application is some kind of
> monitoring tool displaying the state of some machines that could be either
> running or stopped, to keep it simple. The ActivityIndicator would show this
> state for each machine, and the content of each panel will show some details
> about the machine.
>
> So all the ActivityIndicator will be visible at all time and individually
> started and stopped depending of the state of corresponding machine.
>

Re: Activity Indicator in accordion header

Posted by Simon Chatelain <sc...@gmail.com>.
Thank you for this detailed answer, I think I understand better what's going
on, especially about how  the pivot component are used in renderers. And yes
the subclass of Accordion could be a good solution, I will try this way.

For my specific use case: let's say that my application is some kind of
monitoring tool displaying the state of some machines that could be either
running or stopped, to keep it simple. The ActivityIndicator would show this
state for each machine, and the content of each panel will show some details
about the machine.

So all the ActivityIndicator will be visible at all time and individually
started and stopped depending of the state of corresponding machine.


Simon


On Mon, Mar 21, 2011 at 3:28 PM, Chris Bartlett <cb...@gmail.com>wrote:

> Simon,
>
> I'll try to have a look at your code and send another reply later.
>
> On 21 March 2011 20:28, Simon Chatelain <sc...@gmail.com> wrote:
>
>> In fact I tried different approaches: first I had a timer calling
>> Accordion.setHeaderData() each time with a different icon, and that didn't
>> work even if setting the header data will definitely invalidate the header's
>> area, will it not ?  In this case the behavior was the same as with the
>> ActivityIndicator : refresh only when moving the mouse on the Accordion.
>>
>
> I'm no expert on the layout and painting side of things in Pivot, so
> wouldn't be able to comment with any authority unless I started digging
> around in the code and experimenting.  Unfortunately I don't have time to do
> that right now, so perhaps someone else can help out with this?  Perhaps
> repainting is the key and I was wrong about the invalidating?
>
>
> http://pivot.apache.org/2.0/docs/api/org/apache/pivot/wtk/Component.html#invalidate()
>
> Invalidating a Component layout related, so if you just need to repaint,
> calling it should not be necessary.  However I think that invalidating a
> Component *might* cause a repaint depending on circumstance.
>
> Then I tried to setup a ScheduledCallback directly in my
>> AnimatedHeaderRenderer to invalidate the ActivityIndicator (by calling
>> invalidate()), still the same behavior, and finally I set up a
>> ScheduledCallback in my application, invalidating the Accordion itself but
>> still no luck.
>>
>
> The ActivityIndicator that is embedded into your renderer should be fine
> and should not require any repainting/invalidating/whatever.  Remember that
> a Pivot renderer is often shared and used to paint multiple components. Any
> Components which might be used by the renderer during the painting process
> are non-functional (won't respond to focus requests, keypresses, mouseclicks
> etc).  The resulting image on the screen is ultimately just that - an image,
> albeit one that was drawn by a fully fledged Component.
>
> If you want this image to be animated, you will need the renderer to
> 'rubber stamp' the target area repeatedly so that it can repaint.  If
> the ActivityIndicator used by the renderer is active (it is animating
> itself) then subsequent repaints that use the renderer should also animate
> (unless they are exactly in sync with the underlying ActivityIndicator).
>
> I think you need some sort of callback that repaints the Accordion's
> header, using your custom renderer.
>
> But if I call myAccordion.repaint() instead of myAccordion.invalidate(),it
>> works. But I really don't like this solution because it means that I need
>> not only the AnimatedHeaderRenderer but also a ScheduledCallback at the
>> level of the class containing the Accordion using the custom renderer.
>>
> Is that really a problem?  You could probably subclass Accordion and bundle
> all of the logic together to hide the implementation details.
>
> Can you explain how you intend to use these animations?  It might help me
> to understand and then (hopefully) suggest some alternatives.
>
> Your initial example code showed multiple accordion headers with activity
> indicators.  Are you using the activity indicators just when loading content
> for the accordion's panels?  ie, Will the ActivityIndicator always be
> running, or will it need to start & stop (possibly multiple times) at some
> point?
>
> Will *all* of the ActivityIndicators be active/inactive at the same time,
> or individually for each Accordion header?
>
>
>> snip...
>>
> I'll try to look at this later...
>
> I don't understand either why parent and ancestor of the
>> AnimatedHeaderRenderer  are always null.
>>
> Search for 'renderer' on this page.
> http://pivot.apache.org/tutorials/platform-overview.html
>
> Although the AccordionHeaderDataRenderer is actually a subclassed BoxPane,
> it is not attached to the Display like other Components.  Because it is not
> attached to the Display, or another Container, it's parent will always be
> null.  As it *is* a BoxPane it *could* be added to the Display, but that
> would not achieve anything useful.
>
> The Accordion(s) which use a AccordionHeaderDataRenderer merely use its
> layout and painting capabilities to paint an area of the screen.  Renderers
> do not need to be subclasses of Pivot Components or Containers.  They could
> just as easily paint directly onto the Graphics2D object.
>
> http://pivot.apache.org/2.0/docs/api/org/apache/pivot/wtk/Visual.html#paint(java.awt.Graphics2D)
>
> (Note the interfaces which Renderer itself implements)
> http://pivot.apache.org/2.0/docs/api/org/apache/pivot/wtk/Renderer.html
>
>
> What am I missing ? Do you have any idea about what to do to make it work
>> from inside the AnimatedHeaderRenderer  class ?
>>
> The renderers provided with Pivot are designed to be flexible and for use
> rendering content in many Components at the same time.
>
> When you call Accordion#setHeaderDataRenderer(Button.DataRenderer), the
> AccordionHeaderDataRenderer does not know that it will being used to render
> content for that specific Accordion.  However when it is actually used, its
> render() method is passed a reference to the target Button.
>
> If you want to be able to set an AnimatedHeaderRenderer for an Accordion
> and have it manage the callbacks required to repaint, then it will need to
> contain more logic.  I won't go into details now until I better understand
> your use case, but it should be possible.
>
> Chris
>
>

Re: Activity Indicator in accordion header

Posted by Chris Bartlett <cb...@gmail.com>.
Simon,

I'll try to have a look at your code and send another reply later.

On 21 March 2011 20:28, Simon Chatelain <sc...@gmail.com> wrote:

> In fact I tried different approaches: first I had a timer calling
> Accordion.setHeaderData() each time with a different icon, and that didn't
> work even if setting the header data will definitely invalidate the header's
> area, will it not ?  In this case the behavior was the same as with the
> ActivityIndicator : refresh only when moving the mouse on the Accordion.
>

I'm no expert on the layout and painting side of things in Pivot, so
wouldn't be able to comment with any authority unless I started digging
around in the code and experimenting.  Unfortunately I don't have time to do
that right now, so perhaps someone else can help out with this?  Perhaps
repainting is the key and I was wrong about the invalidating?

http://pivot.apache.org/2.0/docs/api/org/apache/pivot/wtk/Component.html#invalidate()

Invalidating a Component layout related, so if you just need to repaint,
calling it should not be necessary.  However I think that invalidating a
Component *might* cause a repaint depending on circumstance.

Then I tried to setup a ScheduledCallback directly in my
> AnimatedHeaderRenderer to invalidate the ActivityIndicator (by calling
> invalidate()), still the same behavior, and finally I set up a
> ScheduledCallback in my application, invalidating the Accordion itself but
> still no luck.
>

The ActivityIndicator that is embedded into your renderer should be fine and
should not require any repainting/invalidating/whatever.  Remember that a
Pivot renderer is often shared and used to paint multiple components. Any
Components which might be used by the renderer during the painting process
are non-functional (won't respond to focus requests, keypresses, mouseclicks
etc).  The resulting image on the screen is ultimately just that - an image,
albeit one that was drawn by a fully fledged Component.

If you want this image to be animated, you will need the renderer to 'rubber
stamp' the target area repeatedly so that it can repaint.  If
the ActivityIndicator used by the renderer is active (it is animating
itself) then subsequent repaints that use the renderer should also animate
(unless they are exactly in sync with the underlying ActivityIndicator).

I think you need some sort of callback that repaints the Accordion's header,
using your custom renderer.

But if I call myAccordion.repaint() instead of myAccordion.invalidate(),it
> works. But I really don't like this solution because it means that I need
> not only the AnimatedHeaderRenderer but also a ScheduledCallback at the
> level of the class containing the Accordion using the custom renderer.
>
Is that really a problem?  You could probably subclass Accordion and bundle
all of the logic together to hide the implementation details.

Can you explain how you intend to use these animations?  It might help me to
understand and then (hopefully) suggest some alternatives.

Your initial example code showed multiple accordion headers with activity
indicators.  Are you using the activity indicators just when loading content
for the accordion's panels?  ie, Will the ActivityIndicator always be
running, or will it need to start & stop (possibly multiple times) at some
point?

Will *all* of the ActivityIndicators be active/inactive at the same time, or
individually for each Accordion header?


> snip...
>
I'll try to look at this later...

I don't understand either why parent and ancestor of the
> AnimatedHeaderRenderer  are always null.
>
Search for 'renderer' on this page.
http://pivot.apache.org/tutorials/platform-overview.html

Although the AccordionHeaderDataRenderer is actually a subclassed BoxPane,
it is not attached to the Display like other Components.  Because it is not
attached to the Display, or another Container, it's parent will always be
null.  As it *is* a BoxPane it *could* be added to the Display, but that
would not achieve anything useful.

The Accordion(s) which use a AccordionHeaderDataRenderer merely use its
layout and painting capabilities to paint an area of the screen.  Renderers
do not need to be subclasses of Pivot Components or Containers.  They could
just as easily paint directly onto the Graphics2D object.
http://pivot.apache.org/2.0/docs/api/org/apache/pivot/wtk/Visual.html#paint(java.awt.Graphics2D)

(Note the interfaces which Renderer itself implements)
http://pivot.apache.org/2.0/docs/api/org/apache/pivot/wtk/Renderer.html


What am I missing ? Do you have any idea about what to do to make it work
> from inside the AnimatedHeaderRenderer  class ?
>
The renderers provided with Pivot are designed to be flexible and for use
rendering content in many Components at the same time.

When you call Accordion#setHeaderDataRenderer(Button.DataRenderer), the
AccordionHeaderDataRenderer does not know that it will being used to render
content for that specific Accordion.  However when it is actually used, its
render() method is passed a reference to the target Button.

If you want to be able to set an AnimatedHeaderRenderer for an Accordion and
have it manage the callbacks required to repaint, then it will need to
contain more logic.  I won't go into details now until I better understand
your use case, but it should be possible.

Chris

Re: Activity Indicator in accordion header

Posted by Simon Chatelain <sc...@gmail.com>.
Hello Chris,

Thank you for your answer but there is still something that I do not
understand.

In fact I tried different approaches: first I had a timer calling
Accordion.setHeaderData() each time with a different icon, and that didn't
work even if setting the header data will definitely invalidate the header's
area, will it not ?  In this case the behavior was the same as with the
ActivityIndicator : refresh only when moving the mouse on the Accordion.

Then I tried to setup a ScheduledCallback directly in my
AnimatedHeaderRenderer to invalidate the ActivityIndicator (by calling
invalidate()), still the same behavior, and finally I set up a
ScheduledCallback in my application, invalidating the Accordion itself but
still no luck.

But if I call myAccordion.repaint() instead of myAccordion.invalidate(),it
works. But I really don't like this solution because it means that I need
not only the AnimatedHeaderRenderer but also a ScheduledCallback at the
level of the class containing the Accordion using the custom renderer.

Other tests I made, in the ScheduledCallback defined in the
AnimatedHeaderRenderer (see attached file for the full code):
public void run() {
                //does not work : parent is always null
//                Component parent =
AnimatedHeaderRenderer.this.getParent();
//                if (parent != null) {
//                    parent.repaint();
//                }

                //does not work : ancestor is always null
//                Container ancestor =
AnimatedHeaderRenderer.this.getAncestor(Accordion.class);
//                if (ancestor != null) {
//                    ancestor.repaint();
//                }

                //does not work : refresh only when hovering the mouse on
the Accordion, immediate or not
//                AnimatedHeaderRenderer.this.repaint();

                //does not work : refresh only when hovering the mouse on
the Accordion
//                AnimatedHeaderRenderer.this.invalidate();

                //does not work : refresh only when hovering the mouse on
the Accordion, immediate or not
//                indicator.repaint();

                //does not work : refresh only when hovering the mouse on
the Accordion
//                indicator.invalidate();
            }

So I do not understand why myAccordion.repaint() works where
myAccordion.invalidate() doesn't. I don't understand either why parent and
ancestor of the AnimatedHeaderRenderer  are always null.

What am I missing ? Do you have any idea about what to do to make it work
from inside the AnimatedHeaderRenderer  class ?

Thanks

Simon


On Mon, Mar 21, 2011 at 12:44 PM, Chris Bartlett <cb...@gmail.com>wrote:

> Simon,
>
> I think that a renderer will only be used when the area it is responsible
> for is invalidated or repainted.  If the Accordion's skin doesn't think it
> needs to repaint the header, then it wont, and therefore ActivityIndicator
> will not animate.
>
> Have a look at the default ActivityIndicator skin to see the callback it
> sets up to take care of the animation. You might want to use some similar
> code to schedule repaints of the Accordion's header when the
> ActivityIndicator is active.
>
> http://svn.apache.org/repos/asf/pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraActivityIndicatorSkin.java
>
> Chris
>
> On 21 March 2011 15:16, Simon Chatelain <sc...@gmail.com> wrote:
>
>> Hello all,
>>
>> I am trying to display an animated component inside the headers of an
>> accordion. For that I defined a subclass of AccordionHeaderDataRenderer
>> inserting a ActivityIndicator at first position in the header.
>>
>> But the activity indicator animation is not refreshed unless I move the
>> mouse cursor over the header. What am I doing wrong and is there a way to do
>> that ?
>> You can find in attachment a sample application showing the described
>> behavior.
>>
>> Thanks
>>
>> Simon
>>
>
>

Re: Activity Indicator in accordion header

Posted by Chris Bartlett <cb...@gmail.com>.
Simon,

I think that a renderer will only be used when the area it is responsible
for is invalidated or repainted.  If the Accordion's skin doesn't think it
needs to repaint the header, then it wont, and therefore ActivityIndicator
will not animate.

Have a look at the default ActivityIndicator skin to see the callback it
sets up to take care of the animation. You might want to use some similar
code to schedule repaints of the Accordion's header when the
ActivityIndicator is active.
http://svn.apache.org/repos/asf/pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraActivityIndicatorSkin.java

Chris

On 21 March 2011 15:16, Simon Chatelain <sc...@gmail.com> wrote:

> Hello all,
>
> I am trying to display an animated component inside the headers of an
> accordion. For that I defined a subclass of AccordionHeaderDataRenderer
> inserting a ActivityIndicator at first position in the header.
>
> But the activity indicator animation is not refreshed unless I move the
> mouse cursor over the header. What am I doing wrong and is there a way to do
> that ?
> You can find in attachment a sample application showing the described
> behavior.
>
> Thanks
>
> Simon
>

Re: Activity Indicator in accordion header

Posted by Greg Brown <gk...@verizon.net>.
The reason this doesn't work is because accordion header data is painted by a renderer, which, as Chris mentioned, is only painted when the accordion skin thinks it needs to be refreshed. When active, an activity indicator runs a timer that attempts to repaint it every n milliseconds. However, in order for the repaint to happen, the activity indicator must be part of the component hierarchy, which renderers are not.

Re: Chris's suggestion:

> Your TerraAccordionSkin might override these so that the header is a simply a real BoxPane with an ActivityIndicator and a Label inside.  Then the BoxPane skin (and ActivityIndicator & Label skins) will take care of painting, and more importantly, animating.
> (ie, use real, fully fledged Components, rather than a Renderer for each header)


This seems like a reasonable approach. Just one thought - while you could certainly hard-code the use of a Label here, continuing to use a renderer will offer you a little more flexibility (for example, if you want to use icons in your headers).

G

On Mar 21, 2011, at 4:16 AM, Simon Chatelain wrote:

> Hello all,
> 
> I am trying to display an animated component inside the headers of an accordion. For that I defined a subclass of AccordionHeaderDataRenderer inserting a ActivityIndicator at first position in the header.
> 
> But the activity indicator animation is not refreshed unless I move the mouse cursor over the header. What am I doing wrong and is there a way to do that ?
> You can find in attachment a sample application showing the described behavior.
> 
> Thanks
> 
> Simon
> <AnimatedHeader.zip>