GridBagLayouts in GridLayout - swing

Trying to build about this GUI in Swing:
In my MainFrame i set a GridLayout like that to achieve 1 row, 2 columns:
setLayout(new GridLayout(1, 2));
In the Left Column i figures i would need a GridBagLayout as in the right column. Normal GridLayout doesn't work anymore because i want different sizes of each row. For the left column i tried this:
GridBagConstraints gbc = new GridBagConstraints();
mapPanel = new MapPanel(map);
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 10;
add(mapPanel, gbc);
controlPanel = new JPanel();
controlPanel.add(new JButton("Test"));
controlPanel.add(new JButton("Test 2"));
controlPanel.add(new JButton("Test 3"));
controlPanel.add(new JButton("Test 4"));
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridheight = 1;
add(controlPanel, gbc);
logPanel = new LogPanel();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridheight = GridBagConstraints.REMAINDER;
add(logPanel, gbc);
This however will result in everything "packed together" in the left column. It won't expand to the 100% height and 50% width the column has. How can i achieve a GUI as in the picture?
Thanks!

Look at JNodeLayout. RectNode is exactly what you Need.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import com.smartg.swing.layout.JNodeLayout;
import com.smartg.swing.layout.LayoutNode.RectNode;
public class RectNodeDemo {
public static void main(String[] args) {
String rootName = "root";
RectNode root = new RectNode(rootName);
JNodeLayout layout = new JNodeLayout(root);
layout.setHgap(1);
layout.setVgap(1);
JPanel target = new JPanel();
target.setBorder(new EmptyBorder(10, 10, 10, 10));
target.setLayout(layout);
addPanel(target, root, new Rectangle2D.Double(0, 0, .5, .5));
addPanel(target, root, new Rectangle2D.Double(0, .5, .5, .1));
addPanel(target, root, new Rectangle2D.Double(0, .6, .5, .4));
addPanel(target, root, new Rectangle2D.Double(.5, 0, .5, .9));
addPanel(target, root, new Rectangle2D.Double(.5, .9, .5, .1));
layout.syncNodes();
JFrame frame = new JFrame();
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(target, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
static void addPanel(JPanel target, RectNode node, Rectangle2D r) {
JPanel p = new JPanel();
target.add(p);
p.setBorder(new LineBorder(Color.BLACK, 1));
node.add(p, r);
}
}

You could use the Relative Layout. This layout allows you to specify the relative sizes of each component.
To create your panel on the left the code would be something like:
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true );
JPanel left = new JPanel( rl );
left.add(panel1, new Float(50));
left.add(panel2, new Float(10));
left.add(panel3, new Float(40));

Using only GridBagLayout will suffice.
By setting gbc.gridheight = 10 you tell GridBag to use 10 rows for the component. (Similar to rowspan in HTML.) This, however, says nothing about the actual height of the component since rows don't have a fixed height. Consequently, this constraint doesn't have any effect when you're only using a single column. The name of the constraint is IMHO confusing.
Use GridBagConstraints.weightx and GridBagConstraints.weighty to specify where extra space should go. See How to Use GridBagLayout for more.
In combination with component's preferred sizes you'll be able to obtain a panel that will show your components when the panel is small and distribute extra space when the panel is 'too big'.
Though, as Andrew Thompson pointed out, using setPreferredSize() is not a very good way to go. Often, components already have their preferred size just fine as constructed. Just play around with all of GridBagConstraints and see what happens.
This might in the end be a better looking solution.

Related

Positioning a button on a JPanel

I am trying to set the three buttons in the middle of this JPanel which is set above another panel.
Everything is working fine, but three buttons remains at the same position, no matter what.
How can I move the three buttons in the center of the panel2? Right now the three buttons are at the center Left of the panel2.
Code for my panel is here:
public AbcGeniusPanel()
{
//this.setVisible(false);
ImageIcon[] alphabets = new ImageIcon[26];
ImageIcon[] images = new ImageIcon[26];
setBackground(Color.yellow);
//Load the images for alphabet images into the alphabets array using a for loop
for(int i = 0; i < alphabets.length; i++)
{
alphabets[i] = new ImageIcon("C:\\Users\\Dip\\Desktop\\Java Projects\\AbcGeniusApp\\src\\Alphabets\\"+(i+1)+".png");
}
//Load the images images in the IMageIcon array
for(int i = 0; i < images.length; i++)
{
images[i] = new ImageIcon("C:\\Users\\Dip\\Desktop\\Java Projects\\AbcGeniusApp\\src\\Images\\"+(i+1)+".png");
}
//Create two JPanel objects
JPanel panel = new JPanel();
JPanel panel2 = new JPanel();
//Set a layoutManager on the panel
panel.setLayout(new GridLayout(2, 13, 5, 5)); //This is good for now
//Create an array for holdoing the buttons
buttons = new JButton[26];
/
//Try passing Images inside the JButton parameter later.
for(int i = 0; i < 26; i++)
{
buttons[i] = new JButton(alphabets[i]);
}
setLayout(new BorderLayout(2,0));
panel2.setLayout(new BoxLayout(panel2, BoxLayout.X_AXIS));
//add the panel to the Border layout
add(panel,BorderLayout.SOUTH);
add(panel2);
//Add evenHandling mechanism to all the buttons
for(int k = 0; k<26; k++)
{
buttons[k].addActionListener(this);
}
for(int count1 = 0; count1<26; count1++)
{
panel.add(buttons[count1]);
}
JButton button1 = new JButton();
JButton button2 = new JButton();
JButton button3 = new JButton();
panel2.add(button1);
panel2.add(button2);
panel2.add(button3);
}
You can use the BoxLayout (it may be easier just using Box.createHorizontalBox()) but you have to put vertical glue at each end of the box. You also may want to put horizontal struts between the buttons to give them some spacing.
It will be easier to just use a FlowLayout for your buttons, which does the equivalent of what I said without the extra code. There may be a potential drawback of the layout causing a button or 2 to flow over to the next line, but with your simple application it is probably not much of a chance.
Here are the two examples. Comment out one line and Comment in (???) the other line to see a different approach to the buttons:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class AlphabetExample {
public static void main(String[] args) {
AlphabetExample alphabetExample = new AlphabetExample();
JFrame frame = alphabetExample.createGui();
frame.setVisible(true);
}
private JFrame createGui() {
JFrame frame = new JFrame("Letters!");
frame.setSize(400, 300);
Container contentPane = frame.getContentPane();
contentPane.add(setupLetters(), BorderLayout.CENTER);
// contentPane.add(setupButtonsWithBox(), BorderLayout.NORTH); // <-- with a BoxLayout
contentPane.add(setupButtonsWithFlowPane(), BorderLayout.NORTH); // <-- with a FlowLayout
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
return frame;
}
private JPanel setupLetters() {
String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
JPanel lettersPanel = new JPanel(new GridLayout(2, 13, 5, 5));
for (char x : letters.toCharArray()) {
final String letter = String.valueOf(x);
JButton button = new JButton(letter);
button.setActionCommand(letter);
lettersPanel.add(button);
}
return lettersPanel;
}
private JComponent setupButtonsWithBox() {
Box b = Box.createHorizontalBox();
b.add(Box.createHorizontalGlue());
b.add(new JButton("Left Button"));
b.add(Box.createHorizontalStrut(5));
b.add(new JButton("Center Button"));
b.add(Box.createHorizontalStrut(5));
b.add(new JButton("Right Button"));
b.add(Box.createHorizontalGlue());
return b;
}
private JComponent setupButtonsWithFlowPane() {
JPanel panel = new JPanel(); // default layout manager is FlowLayout
panel.add(new JButton("Left Button"));
panel.add(new JButton("Center Button"));
panel.add(new JButton("Right Button"));
return panel;
}
}
This solved my problem
for(int count1 = 0; count1<3; count1++)
{
panel2.add(Box.createHorizontalGlue());
panel2.add(imageButtons[count1]);
panel2.add(Box.createHorizontalGlue());
}

Place an object at another objects current position

I am trying to place an object at my players current position but when i move away the object sticks to my player. I kind of know why it sticking to my player but i cant think of any other code to use.
Hero is my player that i move around the screen.
Thanks Lochy
var trap1:trap = new trap();
function keydown(event:KeyboardEvent) :void {
if(event.keyCode ==32)
addChild(trap1);
trap1.x = hero.x;
trap1.y = hero.y;
There are several ways to accomplish this task. There is basically a detail you have to know. In Flash, the display list is responsible for managing elements on the screen. The DisplayObject and DisplayObjectContainer classes provide the API to access and manipulate the display list.
A naive approach would be
function placeAbove(d1:DisplayObject, d2:DisplayObject):void
{
if (!d1 || !d2) return;
d1.x = d2.x;
d1.y = d2.y;
}
But when both DisplayObjects have different parents, the DisplayObjects are not part of te same coordinate system, so this little method won't work. I coded a small example:
package
{
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.geom.Point;
public class Points extends Sprite
{
public function Points()
{
const child1:Sprite = createSquare(50, 50, 0xFF0000, .5)
, child2:Sprite = createSquare(100, 100, 0x0000FF, .5)
, container1:Sprite = new Sprite()
, container2:Sprite = new Sprite();
DisplayObjectContainer(placeRandomly(addChild(container1))).addChild(child1);
DisplayObjectContainer(placeRandomly(addChild(container2))).addChild(child2);
placeAbove(child1, child2);
}
private function createSquare(width:Number, height:Number, color:uint = 0, alpha:Number = 1):Sprite
{
const sprite:Sprite = new Sprite();
sprite.graphics.beginFill(color, alpha);
sprite.graphics.drawRect(0, 0, width, height);
sprite.graphics.endFill();
return sprite;
}
private function placeAbove(child1:Sprite, child2:Sprite):void
{
const point:Point = child2.localToGlobal(new Point(0, 0))
, point2:Point = child1.globalToLocal(point);
child1.x = point2.x;
child1.y = point2.y;
}
private function placeRandomly(displayObject:DisplayObject):DisplayObject
{
displayObject.x = Math.random() * 100;
displayObject.y = Math.random() * 100;
return displayObject;
}
}
}
The Application generate 2 squares and adds it into different parents. The containers (parents) are placed randomly on the screen and so are the two child display objects. The placeAbove method does all the magic. It calculates the position from the second display object globally and the maps it to the first display objects target local position within the parent's coordinate system.
Ii hope it helps.
It's not very clear how your display list is organized, but try adding the trap as a child of the hero's parent. i.e.:
hero.parent.addChild(trap1);

JPanels won't show in GridBagLayout

When I add a JPanel(1) into my GridBagLayout JPanel(2), my JPanel(1) is shrinked into a tiny square located in the middle. I don't know why this happened, because in theory it should work. I think it might have something to do with default BorderLayout? cause I read somewhere that BorderLayout puts your JPanel in the middle. But I have already set my Layout as GridBag, so I don't know why this is happening. Here's my code:
JFrame f = new JFrame("TEST");
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
f.setSize(300, screenSize.height);
f.setLocation(screenSize.width - 300, 0);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GridBagConstraints gbc = new GridBagConstraints();
JPanel panel = new JPanel(new GridBagLayout());
JPanel A = new JPanel();
Dimension d = new Dimension(270, 50);
A.setSize(d);
A.setBackground(Color.GREEN);
JPanel B = new JPanel();
B.setSize(d);
B.setBackground(Color.BLUE);
gbc.gridy = 0;
panel.add(A, gbc);
gbc.gridx = 1;
panel.add(B, gbc);
f.add(panel);
f.validate();
f.repaint();
More over, when I set the border for A and B to 100 pixels, both of them start showing up. So I am really confused!
Stop pulling your hair with GridBagLayout, try MigLayout instead, you'll save a lot of time:
http://www.miglayout.com

miglayout: can't get right-alignment to work

Something's not right here. I'm trying to get the rightmost button (labeled "help" in the example below) to be right-aligned to the JFrame, and the huge buttons to have their width tied to the JFrame but be at least 180px each. I got the huge button constraint to work, but not the right alignment.
I thought the right alignment was accomplished by gapbefore push (as in this other SO question), but I can't figure it out.
Can anyone help me?
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class RightAlignQuestion {
public static void main(String[] args) {
JFrame frame = new JFrame("right align question");
JPanel mainPanel = new JPanel();
frame.setContentPane(mainPanel);
mainPanel.setLayout(new MigLayout("insets 0", "[grow]", ""));
JPanel topPanel = new JPanel();
topPanel.setLayout(new MigLayout("", "[][][][]", ""));
for (int i = 0; i < 3; ++i)
topPanel.add(new JButton("button"+i), "");
topPanel.add(new JButton("help"), "gapbefore push, wrap");
topPanel.add(new JButton("big button"), "span 3, grow");
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new MigLayout("",
"[180:180:,grow][180:180:,grow]","100:"));
bottomPanel.add(new JButton("tweedledee"), "grow");
bottomPanel.add(new JButton("tweedledum"), "grow");
mainPanel.add(topPanel, "grow, wrap");
mainPanel.add(bottomPanel, "grow");
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
never mind, I got it: looks like there needs to be a gap constraint in the column spec, not at the component level:
topPanel.setLayout(new MigLayout("", "[][][]push[]", ""));
a much easier/cleaner way (IMOH) is using component constraints and doing
topPanel.add(new JButton("help"), "push, al right, wrap");
Push will push the cell out as the window stretches but you need to tell the component to bind itself to the right of the cell. You could achieve the above with the following code.
JPanel topPanel = new JPanel();
frame.setContentPane(topPanel);
for (int i = 0; i < 3; ++i)
topPanel.add(new JButton("button"+i), "");
topPanel.add(new JButton("help"), "push, al right, wrap");
topPanel.add(new JButton("big button"), "span 3, grow, wrap");
topPanel.add(new JButton("tweedledee"), "span, split2,grow, w 180, h 100");
topPanel.add(new JButton("tweedledum"), "w 180, h 100, grow");

How to Draw a circle displaying a number in flex

I am flex newbie , so please forgive me if i am not using the right words to ask the following question. I want to know if there is a way to draw a circle which shows a number , like for ex. Graduated Circles representing its radius to show it's relevance. Is there a component which already do so , if not what is the best way to do this.
thanks.
Here's a quick example on how you could do it (to be continued to achieve your particular needs)
package
{
import flash.text.TextFormatAlign;
import flash.text.TextField;
import flash.display.Sprite;
import flash.text.TextFormat;
public class LabeledCircle extends Sprite
{
private var textField:TextField;
public function LabeledCircle(radius:Number, label:String = "")
{
// Prepares the textField
var textFormat:TextFormat = new TextFormat();
textFormat.align = TextFormatAlign.CENTER;
textField = new TextField();
textField.defaultTextFormat = textFormat;
addChild(textField);
// Sets the default parameters
this.radius = radius;
this.label = label;
}
public function set radius(radius:Number):void
{
// redraws the circle
graphics.clear();
graphics.beginFill(0x000000, .5);
graphics.drawCircle(0, 0, radius);
// recenters the textfield depending on the radius
textField.width = radius * 2;
textField.x = -radius;
}
public function set label(label:String):void
{
textField.text = label;
}
}
}
Flare has a component which is similar to the concentric circle example in the link you have posted. See Layouts > CirclePack in the demo.
I am not yet sure what you mean by 'associating a number'. Try this: Rendering text on a path.
Actionscript Drawing API - example here
Degrafa - Graphics framework which makes the Drawing API easier to use and includes a circle class