Set correct dialog location without knowing parent component - java

I am trying to figure out how to get rid of parents passed in application just for the reason to center dialogs over window or frame.
Application I am responsible for is quite large and not written nicely. Refactoring is in process however it's not easy to decouple some things. Part I am trying to change now is window with tabbed pane. Tabs are same class and consists of several panels which are responsible for different things, so they are also in different packages and classes. Good thing that each class is responsible for single thing only now, bad one is that there are lots of dialog (error, info, question...) which require parent to be centered correctly over window.
I would like not to use these parents all the way down, however at this moment it seems impossible to move all dialogs up in hierarchy. Just setting parent null also doesn't solve problem as they appears somewhere else then window (may be problem on dual screen).
I was thinking about static method in main window which returns current location (or null if doesn't exist). Then set all references to parent as null and set modality type to application. Finaly setLocation on point given by static method. I feel it's not the best solution, but I think it's much better then passing whole window as parameter cca 10 levels down.
What do you think about it? Is it acceptable or do you have some better idea how to handle parent in large GUI application?
EDIT: To specify my intention more deeply - I need dialog boxes to be centered over it's parent. In other words, it doesn't need to be centered on the screen, it should be located directly over the window (not necessarily in the center of window bot just over it). If I set parent to null or location to center of the screen, it can happen that dialog box will display somewhere else than parent window.
EDIT2: So I did it for now as I suggest above. I have created static field JFrame parent = null. Next static method was created public static Point getCenterPosition(Dimension dimension). If something calls this method and parent doesn't exist yet, topleft of the screen is returned (however it can't happen).
As parameter is passed size of dialog I want to center, which is used for inner calculation. As a result method return point, so I can use dialog.setLocation(ParentFrame.getCenterPosition(dialog.getSize()));
Now I have dialog nicely centered and I don't need passed parent at all. It's not very nice solution, but it works.

While I am not entirely sure what specific effect you are trying to create without some form of illustration I believe you are trying to get a dialog or pane centered in the screen.
Common practice for the creation of GUI is to base your sizes on the screen resolution that is being used. (this helps your application scale to different resolution monitors)
If you know the screen resolution it is also relatively easy to determine the center point of the screen where you want to display your dialog or pane.
An out of the box solution for determining screen size can be found in the Toolkit (Java7)
I propose you use getScreenSize() or getScreenResolution() (depending on your preferred approach) and then take half of each dimension to find the center point of the screen.
subtract half of your dialog or pane size and you will know the origin point for your pane.

You could put inside of the dialog which has to be centered something like
Window ancestor = SwingUtilities.getWindowAncestor(this);
setLocationRelativeTo(ancestor);
I use it all the time and it avoids having to pass the parent explicitly.
Of course the dialog has to be called by the parent you want to center to.

Related

Java Swing: Resizing component in JFrame without affecting other components

I have a very simple game I'm creating as a novice project. It's based on an online card game called "Castlewars". There are two players, each with a tower which is affected by cards they and their opponent play. At the moment I have the basic framework of collections and classes I need to make the game operate at a very simple level, but I'm having problems displaying these effects to the user. I have the following code, which should update, amongst other things, two jLabels on a jFrame GUI (constructed in NetBeans 7.4) which represent the player's towers:
private void adjustScreen(){
System.out.println (Integer.toString(jLabel1.getSize().height));
jLabel1.setSize(100, (playerRed.getTower().currentHeight() * 2));
System.out.println(Integer.toString(playerRed.getTower().currentHeight() * 2));
System.out.println (Integer.toString(jLabel1.getSize().height));
jLabel2.setSize(100, (playerBlue.getTower().currentHeight() * 2));
jLabel5.setText(Integer.toString(playerBlue.getTower().currentHeight()));
jLabel6.setText(Integer.toString(playerBlue.getGold()));
jLabel9.setText(Integer.toString(playerRed.getTower().currentHeight()));
jLabel10.setText(Integer.toString(playerRed.getGold()));
if (TurnBlue){
jPanel21.setBackground(inPlay);
jPanel10.setBackground(outPlay);
}else{
jPanel10.setBackground(inPlay);
jPanel21.setBackground(outPlay);
}
}
When I run it, i get the following output:
(Initial label height) - 200
(adjusted Tower().height) - 100
(adjusted label height) - 100
Which suggests that what I'm trying to do is working on some level, but the actual labels visually stay the same size.
At start (the initiation of the game should have set the labels to half their visible size):
After a couple of plays - the Blue's new tower height is shown in the top left
I've played around with enabling and disabling the resize property, both on the label and on the frame, and I did once manage to get it to resize, but it then shifted the other components of the frame in an unfortunate way. As you can see, the "Cards" at the bottom do seem to resize themselves, although I am not explicitly instructing them to do this (maybe an effect of the text length in the "Cards"?) What am I doing wrong?
After re-reading the question I realized the answer is not really an answer to the question but more of a list of suggestions. Rather than deleting it, I'll leave it up in case someone can gain something from it :-)
"What am I doing wrong?"
Welcome to the world of "Why I should use Layout Managers"
There's an ocean of problems that may arise from null layouts and trying to set size and location to everything. Swing was made to be used with Layout Managers.
Some layout managers will respect preferred sizes and some wont.
Use the correct layout manager and make use of nested JPanel with different layout managers to get your desired result
Make use of EmptyBorder and vgap and hgap for empty space.
Don't set size or location to anything. Let the layout managers take care of that for you.
Go over Laying out Components withing a Container to learn the different layout managers.
EDIT
If you're using Netbeans GUI BUilder take a look at this answer for some help with how to use different layout managers using the design tool.

How to resize components when resizing a JFrame? Using Null Layout

I am using the NetBeans Designer to create a JFrame. Also it is worth mentioning I am fairly new to Java so I might not understand some things / do things correctly. The frame has about 100 panels, more buttons than I would even think about counting, about ~40 tables, basically most swing components the NetBeans designer provides are being used within the frame. Also for the main frame I am using Null Layout (in order to have a background image inside a JLabel). I know it is not recommended but it doesn't affect the general layout of things as I'm using panels/LayeredPane/TabbedPane for everything, each with it's own design (most of them on Free Design with no Layout specified - that's how I started, didn't know about Layouts and it would take ages now to rearange everything after using Grid Bag Layout for example).
Now getting to my problem, I need to be able to resize the frame and make it resize all components contained. I have to carry a presentation tomorrow of it and I just noticed it doesn't fit on smaller displays (and resizing it doesn't do it properly, it just hides components). I do not care much if it's just an improvisation / not the best approach to the problem as after the 15 min presentation I will probably never open it again.
Thanks.
I would try to go through all the components tree and try to set them smaller font and reduce all their bounds to some static %.
In other words for each component multiply x,y,widht,height to e.g. 0.75 and call setFont() passing derived font of 25% smaller.

How to hide other panels or panes during coding

Using Eclipse Juno for Java & WindowBuilder
I have three panels of the same size that lay on top of each other - they have different widgets. During coding, they all display and clutter up what I'm doing.
I can show and hide them in runtime as needed but, I want to display only the one I'm working on while doing drag and drop of widgets. I've tried using different panels and pane types (tabbed, layered...) and selecting opaque but, nothing hides them.
How do I hide the other (panes, panels...etc) during coding?
I have the same issue. Among other reasons, my solution was to create separate classes per view. So my frame would be its own class, it would maybe have a TabbedPanel (or whatever it's called), and then I would have a new class for each tab on that tabbed panel. Each class would extend JPanel so I could plop it right in there. That way not only is your gui design not cluttered up, but your code logic is separated into separate files, where it might belong anyway.
[SOLVED] Answering my own question.
It may not be perfect or the best/correct way, but it works!
WindowBuilder wants to Surround other panels/widgets that are within it's bounds so, you have to trick it by using opaque, Order>forward/backward then setting the desired bounds (all panel sizes and bounds can be equal and will overlay nicely both during widget drag&drop and runtime).
Here's how to do it with a 3-Panel example (NOTE: WindowBuilder is buggy/in-consistent and often I needed to select the items from the gui, not in the Components tree).
Create your first panel. Add your widgets and border to it.
Create your second panel (the one you want to overlay on top of the first one). This second panel MUST not be completely inside the first panel - it MUST extend beyond the edges of the first panel (parts of it can be inside the first panel). This takes a bit of trial because of the 'surround', mentioned above. Use the shift-key to stop the snapping.
Select the top panel in the gui, NOT from the Components tree, and toggle the Opaque property. The top panel (first or second) in the tree is the one you set to opaque and work on.
Add another panel and repeat the process.
Once you get your widgets/etc as you want them, use the property Bounds to set them all the same or as desired. After that, as long as you don't move a panel by dragging it, it will remain un-surrounded by the other panels. If you move by dragging, it may get set to surround...
I've done this a dozen times now and it works consistently.
Below is a shot of 3 panels overlayed, un-surrounded and not opaque, thus showing widget clutter
Below is a shot after the bounds are set (and not surounded). Opaque and order not yet set:
Below is a shot with bounds set and panel 3 moved forward and opaque set:
Below is a shot with bounds set and panel 2 moved forward and opaque set:
... etc, etc... Now you can work on a panel that's ordered to the front and, naturally, use the setVisible in your code...

Have a window track a component's location on screen

In Java Swing, I want a Window to show up right next to a component--so it will float on top of the GUI. But I need it to always stay right next to that specific component wherever it moves, whether the user moves the window, scrolls the scroll pane that the component is in, resizes, etc. Is there a straightforward way to do this?
I already know how to get it to show up in the right place to begin with. So, for example, if there was some event that fires anytime a component has changed location on the screen, that would work.
Take a look at Componet#getLocationOnScreen
You're going to have to take into account the size of the component and the possibility that the window could be opened outside of the current screen bounds, but lets start with small steps
I think I found it. The java.awt.Component.addHierarchyBoundsListener fires events when scrollbars move, windows move or resize. I think that will do what I need.

Animation with JComponents on Top

i wanted to ask, if somebody might have a solution about a problem i face. I am working at an application, which draws an animation - for instance a map with objects moving onto. My problem is, that on top of the drawing, a Jtable, Jlist as well as other Components are also placed.
In my particular example all of those components have been added to the Panel, which holds the map. In result each component gets redrawn as often as good my fps is. Therefore making one of the tables invisible reduces the already high cpu usage of sometimes around 50% to less than 30%.
My question is, how can i avoid calling somewhat static visual contents paintComponent() method, without having the "background" - the map - whited out the menu.
Since the animation redraws permanently the menu is not shown at all, if its separated from the corresponding JPanel.
First thoughts move into following directions:
Clipping - actually not as good as i would like to, since id like to enable moving around the menus.
JLayeredPane - already tried but seemed to turn out, that the paintComponent method of menus still gets called frequently.
JWindow/Internal Frame - had that thought a couple of minutes ago. Having a complete independent container shall be able to handle my regard, or?
I am looking forward, if somebody has an elegant idea, how to fix that and reduce the cpu usage significantly.
Thanks!!
Best regards.
I would create a custom Shape for clip. Use Area class and subtract from the Area all the children components' bounds.
For painting over JComponent(s) placed into JPanel you have look at
JLayer (Java7) based on JXLayer(Java6)
GlassPane, notice all JComponents must be lightweight, otherwise is GlassPane behind heavyweight (J)Components
is possible painting to the JViewport,
EDIT
you have to use Swing Timer for moving with Icon (in the JLabel) placed into JXLayer, GlassPane or JViewport, don't use Runnable#Thread and never, not by using plain Thread.sleep(int)

Categories

Resources