How to place LayoutPanel in the middle center of parent LayoutPanel (RootLayoutPanel, screen, browser page)? Assuming the inner panel is of fixed size, outer panel is flexible and does resize (with the browser window).
In Vaadin it is one line command:
(VerticalLayout)outerPane).setComponentAlignment(innerPane,
Alignment.MIDDLE_CENTER);
What is the GWT equivalent?
The GWT Layout.Alignment enum provides only BEGIN END STRETCH.
Inadequate. Screen centered placement is essential for displaying smaller forms, dialog boxes, warning messages, login screens etc.
Details on my post on the GWT forum
Thank you
--- UPDATE (27.2.2012) ---------------
To use suggested technique - using setWidgetLeftRight() and setWidgetTopBottom() - I need to compute in fact NW position (x,y) of inner component relative to outer component and do it after every resize of outer container or inner container (content height).
So if GWT does not support centering, and it seems that even in the latest version it does not, there is more coding involved:
outerComponent.setWidgetLeftRight(innerComponent, x, PX, x, PX);
outerComponent.setWidgetTopBottom(innerComponent, y, PX, y, PX);
x,y to be computed as:
x = (w1 – w2) / 2
y = (h1 – h2) / 2
where:
w1 - outer component width (variable, easy to obtain?)
h1 - outer component height (variable, easy to obtain?)
w2 - inner centered component width (fixed)
h2 - inner centered component height (variable, depending on content, potentially tricky to obtain)
All preferably in pixels (PX?) or EM. When mixed with %, more conversion would have to take place.
With every resize event happens the coordinates has to be recalculated (w1, h1 change).
With every change of the internal content the coordinates has to be recalculated (h2 changes).
It is pretty much absolute layout (AbsolutePanel) in disguise.
CSS solution? I found several examples on this server, but none marked as solved. None with both vertical and horizontal centering and flexible inner component height.
Why I don't prefer CSS based layout solution:
Prone to cross browser issues. GWT doesn't help you here.
I consider mixing layout in code and in CSS a bad design decision. CSS is best to be left for “decorative” declarations (font sizes and colors, margins, paddings).
My own bad experience with CSS layouts; easy to break, difficult to debug, lot's of headaches before you put everything together. Best to avoid. I had great hopes towards GWT.
I am thinking about this code based solution:
new subclass of Widget? Panel? Layout? Component? (the inner component)
implement RequiresResize expect, implement onResize() callback method
obtain actual values for variable dimensions (w1, h1, h2). How?
set new coordinates for the inner component. How?
Points to anyone providing solution based on these premises :)
Well you could use a VerticalPanel and set the HorizontalAlignment field or in case you want to use LayoutPanels you can adapt the solution in the GWT docs which you posted in the google groups thread.
LayoutPanel p = new LayoutPanel();
Widget centercontent;
p.add(centercontent);
p.setWidgetLeftRight(centercontent, 5, EM, 5, EM); // Center panel
p.setWidgetTopBottom(centercontent, 5, EM, 5, EM);
This will create a a center panel with 5 em margins left, right, top and bottom like below (only the white panel in the middle will be visible). EM is a fixed size similar to pixel but depends on the base font size. If your base font size (the one defined for your body) is set to 16 px then 1 EM = 16 px (see here for conversion infos).
You could also use relative values for the margins:
p.setWidgetLeftRight(centercontent, 5, PCT, 5, PCT); //5 % left and right margin
p.setWidgetTopBottom(centercontent, 5, PCT, 5, PCT); // 5 % top and bottom margin.
However this way you wont be able to solve your problem entirely (different form sizes -> see screenshots in the google thread) because the center panel will always have fixed margins (5 EM or 5 %) independent of the vertical size of the center panel.
Furthermore the center panel's content will be clipped if it is taller than the available screen size and will be resized when you resize your browser.
So I think the better approach is to put a FlowPanel/HTMLPanel inside a LayoutPanel and apply CSS styles to allow natural resizing.
What if you added a ResizeListener to your center panel (I'm not sure this works, will try it now). Basically, whenever the window resizes, the panel centers itself (by calculating it's height relative to the height of its parent).
EDIT
I ended up getting what I wanted by letting my panel implement ResizeHandler and having the following:
#Override public void onResize(ResizeEvent event) {
// for my case, this is the first parent element with the full height.
Widget parent = getParent().getParent();
int height = parent.getOffsetHeight();
// could make this more exact by including height of this panel.
getElement().getStyle().setPaddingTop((int)((height - 80)/2), Unit.PX);
}
// my panel is not initially visible
#Override public void onAttach() {
super.onAttach();
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override public void execute() {
onResize(null);
}
});
}
Related
I am working on a game engine mostly using ECS (not pure ECS) and I've run into a problem.
Some entities will need a Bounds component (e.g. a component that has a Rectangle that represents position, width, and height). Like buttons.
Many entities also need a component that contains the position but not necessarily bounds.
How do I reconcile the overlap?
1) If an entity has both a Bounds component and a position component, there will be two positions. Not good
2) Entity only has Bounds component which inherits from position component. Ugly because I have to override the utility methods like translate from the position component and have it update the bounds object's position. Also then the entity won't have a position component, which is weird.
3) Bounds component just contains width and height. I don't like this because then I can't use things like a Rectangle class to represent the bounds.
Any ideas? Thank you.
I would go for 3, with a requirement to have a Transform component if you have a Bound component and express the bounds in local frame.
Using a Rectangle with lower-left and upper-right corners would still make sense since the origin of the bounds are not always the same as the origin of the component.
I am wondering if there is a Swing-component which is able to be expanded, so that I am able to hide or unhide something like a menu.
As an example something similar can be found in MS Outlook:
This is the default look, where all mail folders are unhidden. But clicking on the little arrow (circled red) hides that view:
I would like to have something similar in my Java-GUI to do the same, while the included component should be hidden by default. I am not sure what component should be under that expandable "tab", but right now I am thinking about a JTree.
This is what I am generally trying. But if you want a bonus cooky, you could consider the requirement that this expandable menu has to expand in a flowing, smooth animation, instead of being hidden or unhidden instantly. The latter can be found in TeamViewer for example. There you have a menu bar on top, which can be hidden or unhidden, while it's going up and down in a smooth animation.
Example, TeamViewer:
EDIT
First I tried the JSplitPane, but moving all existing components to fit the split pane schema was not a solution I would prefer. Instead I was looking for something more independent.
The next thing I tried was using Swing Timer to expand the width of the JFrame using its setBounds-method. It works exactly the way I want when it comes to toggling additional space for a menu. The JFrame gets bigger or smaller while the resizing process is animated. But I can see two disadvantages of this approach:
The animation is kind of slow and not perfectly smooth. I removed the delay. It is quite OK so far, but a more smoother solution is preferred here. But I can totally live with it how it is currently.
A big disadvantage is that the increasing of the size leaves black spaces between the old and the new width for half of a second. If anyone knows how to avoid that, I would have my perfect solution to this problem.
To make it clearer what I mean with "black spaces", see:
Now you can see that black area. Like I said, it only remains for half of a second or even less. With Swing Timer I added 100 pixels to the width of the JFrame. The higher the value I add to the width, the higher the black area. If the JFrame's width is completely resized, everything is in the correct color again.
So does anyone know why this happens? Is this hardware related or is it just simply a standard behavior of Java or Swing? Does anyone know solutions or workarounds for this?
See splitpane.
For example
JSplitPane mainSplitPanel = new JSplitPane();
mainSplitPanel.setDividerLocation(650);
mainSplitPanel.setOneTouchExpandable(true);
For samples click here
The solution which fit the best for me can be found in the edited part of my question. I found a good combination of delay time and frame resizing which appeared smooth enough (1 millesecond delay and increasing the width with 45 pixels). The issue with the black frame is not problematical anymore. Now the black screen is even shorter in its duration, and if the user waits around 2 seconds, the black area won't be displayed (visibly) at all. In that case it's OK for me, because the user should spend some seconds after expanding anyways.
For everyone who wants to know more about this black area while resizing JFrames, see here.
The code of the solution I described in my edited question:
final Timer timer = new Timer(1, null);
timer.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt)
{
double width = myFrame.getBounds().getWidth();
if(isExpanded == false)
width += FRAME_PIXEL_CHANGE;
else
width -= FRAME_PIXEL_CHANGE;
if(myFrame.getBounds().getWidth() >= FRAME_SIZE_EXPANDED && isExpanded == false)
{
myFrame.setBounds(FRAME_X, FRAME_Y, FRAME_SIZE_EXPANDED, FRAME_HEIGTH);
btnExpand.setIcon(new ImageIcon(GUI.class.getResource("/img/close.png")));
timer.stop();
isExpanded = true;
}
else if(myFrame.getBounds().getWidth() <= FRAME_SIZE_REGULAR && isExpanded == true)
{
myFrame.setBounds(FRAME_X, FRAME_Y, FRAME_SIZE_REGULAR, FRAME_HEIGTH);
btnExpand.setIcon(new ImageIcon(GUIMain.class.getResource("/img/expand.png")));
timer.stop();
isExpanded = false;
}
else
{
myFrame.setBounds(FRAME_X, FRAME_Y, (int) width, (int) FRAME_HEIGTH);
btnExpand.setBounds((int) (width-36), 246, 36, 36);
}
}
});
return timer;
I am using a Java application to display an image on the screen. I also am using an eye-tracker device which records the absolute pixel X,Y locations where the person is looking on the screen.
However, what I need to do is convert these X,Y coordinates from the screen positions into the X,Y locations of the image. In other words, somehow I need to figure out that (just an example) 482, 458 translates to pixel 1,1 (the upper left pixel) of the image.
How can I determine the image's placement on the screen (not relative to anything)?
I saw a few posts about "getComponentLocation" and some other APIs, but in my experimentation with these, they seem to be giving coordinates relative to the window. I have also had problems with that because the 1,1 coordinate that they give is within the window, and there is actually a bar at the top of the window (that has the title and the close and minimize buttons) whose width I do not know, so I cannot easily translate.
Surely there must be a way to get the absolute pixel location on the screen of a component?
If we are talking about Swing/AWT application than class java.awt.Component has method getLocationOnScreen which seemed to do what you want
And yes as #RealSkeptic mentioned in comments to question:
SwingUtilities.html#convertPointFromScreen
will do all this work for you considering components hierarchy
I have made a GUI using Swing and layeredPanes, specifying dimensions and (x,y) co-ordinates of about 60 items. The JFrame dimensions I set are (1080, 720) but I need now to rescale the whole lot to fit (800, 600).
Is there a quick way of resizing the whole screen so all images and text retain their position and relative size without going through every component and re-specifying its setBounds(x, y, width, height)?
You could add a ComponentListener to your JLayeredPane, and then in the
void componentResized(ComponentEvent e)
you could rescale everything based on the current height and width to maintain a specific ratio. You could just do some math some simple math to get the difference ratio between say, 720 and your current width, then adjust the width of each of your components to their actual width times this ratio.
Then do the same for height. This way everything would maintain aspect ratio.
I would also store each component in a List to access them more easily.
EDIT: I just re-read your question:
without going through every component and re-specifying
I forgot about this while answering, and I don't think there is a simple way of doing it without going through all of them. But there are simple ways of looping through them tho!
I realize that there's another question relating to "infinite" JScrollPanes, however I think that what I'm looking for is something that is subtly different.
Basically, I have a collection of objects which can be dragged in any direction, and the extent of the scrolling viewport should always encompass the bounding rect of all those objects. To put it another way, the document has no fixed "origin". Thus, if you drag an object to the left, off the edge of the screen, then the viewport extent should expand in the negative direction to encompass that object's new position. (It should also auto-scroll as you drag, but that's a separate problem I realize.)
I'm not sure how to do this using the JScrollPane API, which seems to want you to set the preferred size of the underlying component, but doesn't seem to have the concept of an offset or origin for that component. (The underlying JViewport seems like it would be able to do it, but I can't really figure out the JViewport API.)
The scroll pane and view port actually have nothing to do with it. What you need to is change the preferred size of the view ports view and let the scroll pane/view port take care of this rest.
Basically, what you need to do, is calculate the widest and highest points on your component and invalidate the view port, to force to recalculate it's layout requirements.
Create yourself a custom component (using a JPanel for example) and override the getPreferredSize method. This method should return the required size of your component.
When the size requirements change, call revalidate()
OK so it turns out that the simple answer is that scroll panes cannot scroll to negative coordinates. What you have to do, as #MadProgrammer suggested, is maintain a separate offset coordinate which is a Point. The offset stores the top/left coordinates of the entire document. When rendering individual objects, set the transform of the Graphics2D object such that they are shifted down and to the right by the offset amount, so that all object are drawn at coordinates that are positive numbers even though in reality they may be located at negative coordinates. Similarly, when calculating the preferredSize for the scroll pane, add in the offset to the document width and height. Coordinates from scroll bar events also need to be offset as appropriate.
This allows you to maintain the illusion that the document bounds are not constrained to be positive numbers, and the document's boundary can expand infinitely in any direction.