Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
New Developer
vprise
Posts: 16
Registered: ‎01-05-2009
My Device: Not Specified
Accepted Solution

Reflowing a layout manager and detecting size changes

Hi,

I'm trying to create a UI that mixes elements I draw myself with native widgets and I accomplish this by overriding paint and drawing an image in the background before drawing the fields themselves.

To position the fields I created my own manager and I position the fields in absolute position based on my own component positions. For basic cases this works really well...

 

When I type into a field it grows, I don't detect this growth so I can't reflow the UI. How can I detect a change to the preferred size of the field? I track the muddy/dirty state of the field but that doesn't seem to help here is an image of my test case, the white field in the middle is a native field and I find it hard to track its growth in realtime:

2908i0943C52639996579

 

When I start scrolling the UI the native fields remain in place, I tried invoking invalidateLayout but it throws an exception? How do I trigger the blackberry UI to invoke sublayout again?

This is what I'm getting the fields are now on top of my drawn text area:

2909i1F46CB56221358FE

 

Thanks,

Shai.

Please use plain text.
Developer
arkadyz
Posts: 2,268
Registered: ‎07-08-2009
My Device: various
My Carrier: various

Re: Reflowing a layout manager and detecting size changes

I'm pretty sure EditField and its ilk invoke updateLayout() each time they want to add or remove a line.

 

Thus, your main job should be in your Manager's sublayout().  Don't use getPreferredWidth() / getPreferredHeight() there!  What you need to do is layoutChild() with whatever width and height you have for that (again, don't ask for preferred dimensions - if you want to limit the width, give the one you are ready to give, but then pass all height available) then ask that child about its dimensions using child.getExtent() (or getWidth() and getHeight() - but that's two calls rather than one).  Only then you should make decisions about where to position the child and what areas are available for the rest of your managed fields.

 

I hope to see the images soon (they are not yet visible for me, which seems to be an overall problem with this lithium forum engine - but they will "materialize" soon), but the above is an important first step.

 

As for scrolling - you don't need to invoke sublayout() for that again.  What you should do, though, is:

1) pass the desired style bits (VERTICAL_SCROLL and/or HORIZONTAL_SCROLL) to super in your constructor.

2) in your sublayout(), make your available width/height (depending on scrolling style bits) very big (the built-in gadgets use 0x3FFFFFFF) and pass your "children" available size based on that.  Calculate your actual total dimensions.  Then setExtent() to the minimum between those dimensions and passed width and height (sublayout's parameters) and setVirtualExtent() to your total size.

3) If you are using MainScreen but want to control scrolling with your own custom Manager, make sure to create that MainScreen with NO_VERTICAL_SCROLL bit (the default is VERTICAL_SCROLL).

4) Don't forget to use getVerticalScroll() and getHorizontalScroll() in your paint().

----------------------------------------------------------
please click 'Accept Solution' on posts that provide the solution to the question you've posted. Don't say "Thanks", press 'Like' button instead!
Please use plain text.
Developer
arkadyz
Posts: 2,268
Registered: ‎07-08-2009
My Device: various
My Carrier: various

Re: Reflowing a layout manager and detecting size changes

[ Edited ]

Now that I see your images I have some idea about what you are trying to achieve.  So here are some thoughts:

 

1) I guess you invoke setPositionChild() on each field, be it your own custom field or the native widget.

2) While doing that during sublayout(), do you calculate the positions of those custom fields which should appear below the native fields?  Or do you just set some absolute positions with no regard to the other fields?  Like I said before - don't just go by their getPreferredHeight() - use layoutChild() followed by getHeight() to determine how much does it actually take.

3) "Scrolling" - are you using BlackBerry native scrolling or reacting to navigation events and repainting the screen?  I'd suggest using the native scrolling - either with focusable fields in the manager or with setVerticalScroll() calls.  It will be much easier and more efficient.  If you go that route, re-read my previous message - I stand by everything I said there.

 

If you have any further questions or try something and see weird results, please post again.  Don't forget - the images you are posting will not be visible to others immediately, so please continue describing the screen in words, just like you've done in the first message.  This way help will come faster. :smileyhappy:

 

Edit: fixed some typos.

----------------------------------------------------------
please click 'Accept Solution' on posts that provide the solution to the question you've posted. Don't say "Thanks", press 'Like' button instead!
Please use plain text.
New Developer
vprise
Posts: 16
Registered: ‎01-05-2009
My Device: Not Specified

Re: Reflowing a layout manager and detecting size changes

Thanks allot for the detailed answer :-)

 

I'm using a Manager passed to the FullScreen class since its sublayout doesn't seem to allow layoutChild on the fields within the screen.

In this Manager subclass I invoke setPositionChild and layoutChild with absolute coordinates to match the rest of the GUI. I use getPreferredWidth/Height to determine the space to allocate initially for these components, this value essentially ends up determining the width/height I'm giving to the layout child method.

 

Our own fields are entirely painted and have no native aspect, they are essentially an Image which we draw from scratch and have no form within the RIM API. Due to that, our scrolling is implemented and works correctly for touch/focus based scrolling pretty well (actually better than native on most devices). The problem is that it scrolls our components and not the native ones.

 

Moving to native scrolling or using fields for everything isn't very practicle since it will break practically every application running on our platform, so I need a way for us to update the position of the components that are already laid out.

 

Thanks,

Shai.

Please use plain text.
Developer
arkadyz
Posts: 2,268
Registered: ‎07-08-2009
My Device: various
My Carrier: various

Re: Reflowing a layout manager and detecting size changes

OK, then - you need to recalculate the position of your images shown after the native fields you are using. 

And please, notice what I was saying before - you can't use getPreferredWidth() / getPreferredHeight() to determine actual size the field is taking on the screen!  EditField, for example, will always return a single line height for its getPreferredHeight()!

 

Use getWidth() and getHeight() - when the native fields resize, they will cause re-layout of the screen, meaning your sublayout() will be called.  In there, you obviously call layoutChild() and setPositionChild() for those native widgets.  Once you have called layoutChild(), that child is ready to report its dimensions via getWidth(), getHeight() and/or getExtent().  Use that information.

 

Now I don't know why native scrolling wouldn't work for you - if you paint all your "fields" at the same positions (aside from the scrollbar, which will have to use getVerticalScroll() - I have an example of adding that to the VerticalFieldManager here: Implementing a standard-style scrollbar on a BlackBerry device), they will properly scroll on both trackball/trackpad and touchscreen devices.  But that way the native widgets will be scrolled as well.

 

If you insist on doing it your way, updateLayout() on each "scroll" and re-position the native fields according to your "scrolling position".  Say, you normally have an EditField at (40, 80).  If you "scroll" 40 pixels down, you will have to position it at (40, 40) instead.  Then super.paint() will draw it in the correct place.

 

Sometimes, though, you won't be able to position those BlackBerry gadgets as their needed position will be negative.  So really - moving to the native scrolling is actually practical enough.  Think outside of the box for a second and just try that.  You won't be disappointed.  I'm not talking about going with the native Fields (aside from the input gadgets) - just the native scrolling.

----------------------------------------------------------
please click 'Accept Solution' on posts that provide the solution to the question you've posted. Don't say "Thanks", press 'Like' button instead!
Please use plain text.
New Developer
vprise
Posts: 16
Registered: ‎01-05-2009
My Device: Not Specified

Re: Reflowing a layout manager and detecting size changes

Thanks again :-)

 

I am using getWidth/Height to calculate sizes now.

 

I think one of the problems is that I don't fully get the logic of sublayout/manager. I have the sublayout within my FullScreen class, however it doesn't allow me to layout the fields (throws an exception when I try doing that). The only way I could do this is by passing a manager subclass to the constructor of the base class and implement the layout management there.

 

The problem is that it seems that a field change invokes the sublayout call of the FullScreen rather than the manager (I can post my full code but its huge and messy with unclear logic because it needs to plugin to the library, its all open source though). Anyway in pseudo code:

 

MyClass extends FullCanvas {

     MyClass() {

        super(new Manager(NO_VERTICAL_SCROLL | NO_VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR) {
            protected void sublayout(int width, int height) {

                  // I must layout my fields here... but this isn't invoked when a field changes

            }

     }

 

     protected void sublayout(int width, int height) {

           // I can't layout my fields here so its hard for me to know where they are

           // but this *seems to be* invoked when a field changes

      }

}

 

Does this make sense, is this by design?

How come the Manager's version of sublayout isn't invoked for changes?

 

About scrolling, maybe I wasn't clear. This is work we are doing for the LWUIT framework which is open source and has its own scrolling logic for portability and deep control. The code I'm writing is entirely in a porting layer so the Blackberry native fields are sort of "tacked on" after the fact on top of a UI which is already built in place.

I added some API's so we can keep space for the native fields and allow deep integration but native scrolling would be practically impossible to use (I can go into a long discussion on the architecture of LWUIT if its interesting to you).

 

I'll try using updateLayout for scroll, I was too focused on invoking this via the field that I forgot I have access to this method in the FullScreen subclass ;-)

 

Thanks,

Shai.

Please use plain text.
Developer
arkadyz
Posts: 2,268
Registered: ‎07-08-2009
My Device: various
My Carrier: various

Re: Reflowing a layout manager and detecting size changes

Yes, I noticed you are implementing LWUIT. Two big thumbs up!

 

First - don't just pass a new Manager(...) as the parameter in your FullScreen (I hope you meant that when you wrote FullCanvas).  Create a custom Manager with its own sublayout() and do the job there. This way you will be able to instantiate that custom Manager rather than writing the same code again and again.

 

Second - override the paint() inside the Manager, not the screen.  Not necessary, but again - for better control.

 

Third - it's weird that your Manager's sublayout isn't called automatically, but you can force it anyway:

 

// in your MyClass:
protected void sublayout(int width, int height) {
  layoutDelegate(width, height);
}

 Haven't tested it but it should work.  This way you should be able to re-layout and re-position your fields in the same Manager which has all the knowledge it needs.

 

 

One problem remains, though - how are you going to partially show those fields when they slide up to the boundary of the screen?  I hope you can set negative positions for them. Manager class documentation does not specify any IllegalArgumentException on negative x and y in setPositionChild, so you might be in luck :smileyhappy:.

----------------------------------------------------------
please click 'Accept Solution' on posts that provide the solution to the question you've posted. Don't say "Thanks", press 'Like' button instead!
Please use plain text.
Developer
dnepr
Posts: 723
Registered: ‎03-12-2009
My Device: Playbook

Re: Reflowing a layout manager and detecting size changes

You can only layout/setpositon on the fields which are direct children of the manager, otherwise you'll get illegalstateexceptions

 

What I suggest you do is create a manager class variable and pass that into super call.  Afterwards just add all fields directly to that manager and not to the screen itself.

 

As far as scroll is concerned the native fields will call update layout themselves when they to resize themselves within the manager and that will propagate to that manager layout which you created as a class variable.   Within the sublayout you should do the scroll size computations, etc.

 

 

Have you considered how you will be handling scrolling on devices like the Torch.

 

p.s.

 

You guys are doing great work on LWUIT.  Big fan here :smileywink:

Please use plain text.
Developer
Developer
CMY
Posts: 1,120
Registered: ‎02-10-2009
My Device: 8130 / 8350 / 9530 / 9550 / 9850 / PlayBook
My Carrier: Verizon

Re: Reflowing a layout manager and detecting size changes

Don't overide sublayout in your screen class, it will automatically call it in your manager every time the screen changes (field added/removed, orientation change for Storm/Torch, etc).

Please use plain text.
New Developer
vprise
Posts: 16
Registered: ‎01-05-2009
My Device: Not Specified

Re: Reflowing a layout manager and detecting size changes

Thanks for the great feedback and loads of help to all of you. I think I resolved the issues I had here some of which were my own (e.g. the sublayout of the internal Manager was invoked but I had a bug that hid that from me).

 

Negative values for coordinates work great as expected, the main thing I need to fix now is clipping where scrolling a text field outside of the screen causes it to paint on top of the title. I already have a POC of this so it shouldn't be a problem (I override paint a draw the blackberry fields manually, defining a limited clipping region will probably solve that issue).

 

We already have reasonable touch support on most devices and it works OK on the Storm (it even knows how to utilize SurePress) so I'm pretty confident we can handle the Torch reasonably well. I still need to go over the code and limit the SurePress logic to only occur on the Storm but thats another subject altogether ;-)

Touch events will essentially reach the native widgets just like the key events are sent to the native widgets right now. E.g. the port recognizes the component being touched and if it is not a native widget sends the event into LWUIT's processing.

 

Thanks,

Shai.

 

Please use plain text.