Put object in x,y position JFrame - java

I'm trying to do something in Java, where I simply place an object at a specific x, y coordinates on a JFrame. I need to know what layout to use, or what I need to do to do this.. Any help would be great. Thanks

You would do this with a null layout and then call setLocation or setBounds on the component. But you shouldn't be doing this in general as this makes for very inflexible GUI's that look good on one platform and terrible on another and that are very difficult to update and maintain. Just don't do this.

This example provides 'white space' (or in this case 'green space') using an empty border. Of course, all this 'specific co-ordinates' becomes more complicated if there are other components in the frame, but the same technique can be used to provide white space to particular components.
Note that it is usually best to wrap the component in a panel when providing white space, to preserve the existing border(s) of the component.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
class SpecificCoords {
public static void main(String[] args) {
final int specificX = 40;
final int specificY = 20;
Runnable r = new Runnable() {
#Override
public void run() {
// imagine this is our 'frame'
JPanel gui = new JPanel(new BorderLayout());
JTextField tf = new JTextField(10);
JPanel borderPanel = new JPanel(new GridLayout());
borderPanel.add(tf);
borderPanel.setBorder(new EmptyBorder(
specificX, specificY,
specificX, specificY));
borderPanel.setBackground(Color.GREEN);
gui.add(borderPanel);
JOptionPane.showMessageDialog(null, gui);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}

Related

JTextBox and all following JComponents don't show up

I want do design a simple login format and in order to do so I want two JTextFields for Username/Password and a Login Button. The Login button is display as expected but when I add the JTextField, nothing shows in my JFrame. Would be nice if someone could help a beginner out...
Here's my code (I know it's ugly but this is just a "code sketch"):
package bucketlistpackage;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GameFrame extends JFrame {
public GameFrame(String title) {
super(title); //sets title of frame
startFrame(); //sets details of main frame
final Container logincont = getContentPane(); //creates content pane
JFrame loginframe = new JFrame();
usernameField(loginframe);
loginButton(loginframe);
logincont.add(loginframe);
}
private void usernameField(JFrame loginframe) {
JTextField usernameF = new JTextField("Username", 1);
usernameF.setBounds(50, 50, 50, 20);
loginframe.add(usernameF);
usernameF.setVisible(true);
}
private void startFrame() {
this.setSize(1000, 1000);
this.setVisible(true);
}
private void loginButton(Container cont) {
JButton loginB = new loginButton();
loginB.setSize(300, 150);
loginB.setText("Login");
cont.add(loginB);
}
}
The problem lies on how you are adding component to one another in your case.
You are adding a JFrame to a Container, when in all case it should be the other way around.
The other problem is that you are not using Layouts to manage the components positions on the JFrame.
Another problem as well is that you are not refreshing the windows after adding all the stuff on it.
A bit of a resume on how Java works with native UIs:
Java creates a new thread for the UI. So if you open the debugger you will see AWT threads as well as the main threads and others. This means that you have to manage this in a correct way, because after the application starts SWING and the functions you determine for reactions will lay the ground on how it will behave. Your main thread will die, but the visual threads will keep active.
If you are just starting to program I would encourage you to practice a bit more native java language before moving to SWING or AWT. This libraries can be really painful and tricky to use.
The other thing is SWING library follows a hierarchy for the components:
JFrame > JPanels > Components
In your code you have already worked with all of them but in a disorganized way. JFrame is the main application window, where the graphics will be displayed (can also be a Canvas or whatever class you want to use for that matter). JPanels are organizers, you can use different layouts to organize whatever is inside it. And finally the Components are well... everything! A component can be a JTextField, but it can also be a JPanel, or JButton.
The idea with SWING is to create multiple Panels and organize the end components inside them, using the help of the different layouts to see whats the best approach to make them attractive in many different window sizes.
Finally, if you are using Eclipse, there is a plugin called WindowBuilder which might help you. I don't recommend you using it if you are very new to Java since it will make you depend a lot on it instead of learning how to actually code with SWING.
Hope this helps!!!
Btw, to fix the code above I would do something like this:
public GameFrame(String title) {
super(title); //sets title of frame
startFrame(); //sets details of main frame
final Container logincont = getContentPane(); //creates content pane
logincont.setLayout(new BorderLayout());
usernameField(logincont, BorderLayout.NORTH);
loginButton(logincont, BorderLayout.CENTER);
this.revalidate();
this.repaint();
}
private void usernameField(Container loginframe, String direction) {
JTextField usernameF = new JTextField("Username");
// usernameF.setBounds(50, 50, 50, 20);
loginframe.add(usernameF, direction);
usernameF.setVisible(true);
}
private void startFrame() {
this.setSize(1000, 1000);
this.setVisible(true);
}
private void loginButton(Container cont, String direction) {
JButton loginB = new JButton();
loginB.setSize(300, 150);
loginB.setText("Login");
cont.add(loginB, direction);
}

I created my GUI in a GUI class' constructor. How would I access its Frames, Panels etc. from another class?

First of all, this is a more specific question than it seems to be. To start off: I am currently doing a small application with a rather small GUI, so I decided to make a GUI class, and initialize my whole GUI in this constructor.
This would look like this:
public class GUI extends JFrame{
public GUI{
//Initialize GUI here, including its Frames, Panels, Buttons etc.
}
}
How can I now access the GUIs frame etc. from an external class? If I would create an object of the GUI class, I would simply duplicate my GUI window. I did not come across any other ideas than making the frame, panel and so on static.
I'm somewhat lost right now. Also I'm pretty sure that I am not thinking the right way into this case, but I need someone to point me to the right direction. If someone could help me out, I would be very thankful.
First of all, using static is the worst solution possible, even if your GUI class is a singleton (buf if it is, at least it will work fine).
Why don't you simply create getters and/or setters ? And finally, it is usually not normal that external classes need to access the components of another graphic class. You should wonder if your design is the most fitted for your needs.
Here's a simple GUI to change the background color of a JPanel with a JButton. Generally, this is how you construct a Swing GUI.
package com.ggl.testing;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ChangeDemo implements Runnable {
private boolean isYellow;
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new ChangeDemo());
}
#Override
public void run() {
frame = new JFrame("Change Background Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
JPanel namePanel = new JPanel();
JLabel nameLabel = new JLabel(
"Click the button to change the background color");
nameLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
namePanel.add(nameLabel);
mainPanel.add(namePanel);
final JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
buttonPanel.setBackground(Color.YELLOW);
isYellow = true;
JButton changeButton = new JButton("Change Color");
changeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
isYellow = !isYellow;
if (isYellow) buttonPanel.setBackground(Color.YELLOW);
else buttonPanel.setBackground(Color.RED);
}
});
buttonPanel.add(changeButton);
mainPanel.add(buttonPanel);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
You don't access the Swing components of the GUI from other classes. You create other classes to hold the values of the GUI.
Generally, you use the model / view / controller pattern to construct a Swing GUI. That way, you can focus on one part of the GUI at a time.
Take a look at my article, Java Swing File Browser, to see how the MVC pattern works with a typical Swing GUI.
You don't need to make it static or to create a new JFrame object every time.
Have a look at this simple code :
class UseJFrame {
public static void main(String...args) {
Scanner sc = new Scanner(System.in);
JFrame frame = new GUI();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
System.out.println("Press E to exit");
String ip;
while(true) {
System.out.println("Show GUI (Y/N/E)? : ");
ip = sc.nextLine();
if(ip.equalsIgnoreCase("y") {
frame.setVisible(true);
} else if(ip.equalsIgnoreCase("n") {
frame.setVisible(false);
} else { // E or any other input
frame.dispose();
}
}
}
}
Note : Don't make GUI visible through constructor or it will show window at the very starting of creation of JFrame object.
If you want to use the same JFrame object at other places too then pool architecture would be better approach.

Using Java pack() method

I can't make the pack() method work. I tried several things. My code looks like this at the moment:
Class 1:
public static void main( String[] args )
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run()
{
JavaGui mygui = new JavaGui();
// mygui.setSize(1154, 753);
mygui.setVisible(true);
mygui.pack();
Class 2:
public class JavaGui extends javax.swing.JFrame
{
public JavaGui()
{
getContentPane().setLayout(null);
..
getContentPane().add(panelLeft);
...
getContentPane().add(panelRight);
I tried putting the pack method in everywhere, but it's not going to work with this way of adding gui elements. Any suggestions why? I also tried adding everything to a JFrame instead of the getContentPane(), but I can't make that work either.
Don't use null layouts together with pack(). The pack method tells the layout managers and components to size themselves optimally, and if you instead use null layouts, then the gui risks shrinking to a minimal size, since there is no layout to hold it together.
Don't use null layouts at all for the most part. Using these risk your creating rigid GUI's that are almost impossible to extend, improve, debug.
Don't use setSize(...) and pack(). The layouts mostly respect the preferred sizes of components, not their sizes.
Instead:
Use a pleasing and sensible combination of nested JPanels, each using its own layout manager.
Let the components and the layout managers size themselves.
Then pack should help.
The general order that I do is to add all components to the GUI, then call pack(), then setLocationByPlatform(true) (I think), then setVisible(true).
For better help, please check out the Swing Layout Manager Tutorials.
Here are a couple examples to other questions on this site that use various layout managers:
A combination of BorderLayout and GridLayout to create a calculator
BorderLayout and BoxLayout Combination for labels and JTextFields
Using GridBagLayout to create flexible label/textfield grid
I would recommened beginners on building up swing guis to use a good ide with a builtin gui designer like eclipse and windowbuilder or netbeans with matisse. It will help you building up a prototype of your desired gui and gives you an insight how the layouting is done in the source code.
Experiment with the differenet layouts and what is happening when some values are changed.
one does not simply build up a well behaving gui without understanding how the layout works, so doing the recommended tutorials and looking at examples as already posted by Hovercraft Full Of Eels is absolutely necessary.
For your case i just guess what you were up to. Because youre mentioning left and right panels i suggest a JSplitPane which let you divide your screen in two areas which are customizable in size and orientation.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
public class JavaGui extends JFrame {
//SerialVersionId http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
//Calls to Gui Code must happen on the event dispatch thread that the gui does not get stuck
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new JavaGui().setVisible(true);
}
});
}
public JavaGui() {
// Set the desired size of the frame to determine the maximum size of its components
setPreferredSize(new Dimension(1024, 768));
// Set the default close operation, if press x on frame, destroy the frame and exit the application - others are just destroy the frame or just hide the
// frame
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// BorderLayout because we just need a centric gui with one component, here JSplitPane in full size
getContentPane().setLayout(new BorderLayout(0, 0));
// JsplitPane is a bit special as it depends on the divider location between both panels, for the sake of a small example we take the default -1,
JSplitPane splitPane = new JSplitPane();
// 0.5 divides extra space equally to left and right component when resizing the frame - so specifiying a size for the left and right component is not
// necessary
// use the divider location default -1 to let the width of the left component decide where the right component begins, in that case because of the
// resize weight half and half
splitPane.setDividerLocation(-1);
splitPane.setResizeWeight(0.5);
getContentPane().add(splitPane, BorderLayout.CENTER);
// For the panels the same layout as default as the intention is not stated in your question
JPanel leftPanel = new JPanel();
splitPane.setLeftComponent(leftPanel);
leftPanel.setLayout(new BorderLayout(0, 0));
JPanel rightPanel = new JPanel();
splitPane.setRightComponent(rightPanel);
rightPanel.setLayout(new BorderLayout(0, 0));
// Add a button Panel to the south for doing something - flow layout for letting the components flow to the right side
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
// Close Button for closing the frame
JButton btnExit = new JButton("Destroy this frame, but let application run");
btnExit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
buttonPanel.add(btnExit);
// Set every component to its preferred size
pack();
// Make it visible
setVisible(true);
}
}
If you want your JFrame to work with a null layout, rearrange your code so that it looks like this:
public class JavaGui extends javax.swing.JFrame
{
public JavaGui()
{
setMinimumSize(1154, 753); // Make sure you do setMinimumSize() instead of setSize() when using pack() so that the JFrame does not shrink to 0 size
setLayout(null);
add(panelLeft);
add(panelRight);
pack();
}
// Next is main method
Main:
public static void main(String[] args)
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run()
{
new JavaGui().setVisible(true);
// Do not do any formatting for your JFrame here
}
});
Before, you were modifying the JFrame after it was set visible, so that usually does not work, except for pack(). All components and settings for your JFrame should not be in the main method if you are using an anonymous inner class.
You can also use other layouts. Null layouts are for getting pixels in precise locations, which is used for advanced GUI design such as creating a custom GUI, but it seems that you are making a generic GUI with JPanels. For this, I would recommend using a GridBagLayout, which keeps everything centered if the frame is resized and is easy to use. To use a GridBagLayout, you have to replace setLayout(null); with setLayout(new GridBagLayout()); and set GridBagConstraints. Here is some example code of making a panel with a component and a GridBagLayout:
JPanel pane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
if (shouldFill) {
//natural height, maximum width
c.fill = GridBagConstraints.HORIZONTAL;
}
//For each component to be added to this container:
//...Create the component...
//...Set instance variables in the GridBagConstraints instance...
pane.add(theComponent, c);
// Source: Oracle Docs

Two Components on top of each other using MigLayout

I'm trying to get two components,
frame.getContentPane().setLayout(new MigLayout("", "[53px,grow][57px][grow]", "[23px][][][]"));
JTextPane itemTitle = new JTextPane();
frame.getContentPane().add(itemTitle,"cell 0 4,alignx left,aligny top");
itemTitle.setVisible(true);
itemTitle.setMinimumSize(new Dimension(50, 50));
List choices = new List();
frame.add(choices, "cell 0 4,alignx left,aligny top");
choices.setVisible(true);
to be in the same place, but all the happens is this:
The two components highlighted at itemTitle and choices.
My aim is to have the buttons above set one "setVisible" to true and the other to false. They would never both be true. How can I get two components in one cell at the same time? It also puts my above buttons out of place and I'm not too sure why. I put above the important code referring to the two components, I could put the full GUI code if you requested.
I found this: Fill Entire Cell With Two Components Using MigLayout However it is over years old and to be honest, I don't understand the solution.
I'm sort of learning as I go, I've never used MigLayout before. Should I be using a different layout?
Thanks for any help
to be in the same place... My aim is to have the buttons above set one "setVisible" to true and the other to false. They would never both be true
Then you should be using a JPanel that contains those two components. Then you use a Card Layout on that panel and use the CardLayout to determine which component is visible at any given time. This panel can be added to the panel using the MigLayout just like any other component.
List choices = new List();
Looks to me like you are using an AWT component. You should be using JList for a Swing application.
Should I be using a different layout?
No, stick with MigLayout. You have chosen the right layout manager.
I advice you to invest some time into learning this manager; create couple
of smaller practical examples, learn the numerous constraints that this
manager provides.
It also puts my above buttons out of place and I'm not too sure why.
MigLayout is a grid-based layout manager. (Its most important mode is.)
The gap between the New and Open buttons is created because the
highlighted components and the New button form a column. The column width
is determined by the width of the largest cell. To bypass this, we can
use the split constraint. (Often used in combination with span constraint.)
In my example I use this technique to center two buttons above the
currently visible label.
If we are not sure about something in the layout, we can use the
debug layout constraint which paints the lines of the grid and bounds
of the components.
frame.getContentPane().setLayout(new MigLayout("", "[53px,grow][57px][grow]", "[23px][][][]"));
Do not set bounds in pixels. You are not utilizing of one of the
most important advantages of this manager -- independence of resolution and
DPI. Bounds in pixels are not portable. A 3px gap between buttons looks OK on a smaller screen but is not acceptable on a larger one.
MigLayout provides several options to choose from including related and unrelated gaps, logical pixels, points, or centimeters.
itemTitle.setMinimumSize(new Dimension(50, 50));
Setting a minimum size of a component is usually not necessary. But if we need to
do it, we have the wmin and wmax constraints. This should be done by the
layout manager, not by code outside of it. The set(Minimum|Maximum|Preferred)size
methods should be avoided. (With poorer managers, one cannot do without them, however.)
And again, setting dimensions in pixels is not optimal.
Now we get to the solution. MigLayout has hidemode constraint to deal
with your requirement. There are four hide modes. I assume that we need
the hidemode 3, in which all invisible components do not participate in the
layout.
package com.zetcode;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class HidingComponentsEx extends JFrame {
private ArrayList<JLabel> lbls;
private int itemVisible = 0;
public HidingComponentsEx() {
initUI();
}
private void initUI() {
createLabels();
JButton prevBtn = new JButton("Previous");
prevBtn.addActionListener(new PrevAction());
JButton nextBtn = new JButton("Next");
nextBtn.addActionListener(new NextAction());
JPanel pnl = new JPanel(new MigLayout("ins dialog"));
pnl.add(prevBtn, "split 2, center");
pnl.add(nextBtn, "wrap");
for (JLabel lbl : lbls) {
pnl.add(lbl, "cell 0 1, w 250lp, h 100lp, hidemode 3");
}
add(pnl);
pack();
setTitle("MigLayout example");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void createLabels() {
lbls = new ArrayList<>();
lbls.add(createLabel("North Sea"));
lbls.add(createLabel("Ionian Sea"));
lbls.add(createLabel("Norwegian Sea"));
lbls.add(createLabel("Bering Sea"));
lbls.add(createLabel("Dead Sea"));
lbls.get(itemVisible).setVisible(true);
}
private class NextAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
lbls.get(itemVisible).setVisible(false);
itemVisible++;
if (itemVisible > 4) {
itemVisible = 0;
}
lbls.get(itemVisible).setVisible(true);
}
}
private class PrevAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
lbls.get(itemVisible).setVisible(false);
itemVisible--;
if (itemVisible < 0) {
itemVisible = 4;
}
lbls.get(itemVisible).setVisible(true);
}
}
private JLabel createLabel(String text) {
JLabel lbl = new JLabel(text, JLabel.CENTER);
lbl.setVisible(false);
lbl.setBorder(BorderFactory.createEtchedBorder());
return lbl;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
HidingComponentsEx ex = new HidingComponentsEx();
ex.setVisible(true);
}
});
}
}
Our example has two buttons and five labels. The buttons dynamically change their
visibility.

Java Swing JXTaskPane: how to set bg and border?

I have written the following example code:
import org.jdesktop.swingx.*;
import javax.swing.*;
import java.awt.*;
public class TaskPaneExample{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TaskPaneExample();
}});
}
public TaskPaneExample() {
JFrame frame = new JFrame("TaskPane Example 1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(doInit(), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private Component doInit() {
JXTaskPaneContainer taskpanecontainer = new JXTaskPaneContainer();
taskpanecontainer.setLayout(new VerticalLayout(2));
final JXTaskPane taskpane1 = new JXTaskPane(){
public void setCollapsed(boolean w){
super.setCollapsed(w);
}};
taskpane1.setTitle("First TaskPane");
JPanel panel1 = new JPanel();
panel1.setBackground(Color.red);
panel1.setSize(100,100);
taskpane1.add(panel1);
taskpanecontainer.add(taskpane1);
JXTaskPane taskpane2 = new JXTaskPane(){
public void setCollapsed(boolean w){
super.setCollapsed(w);
}};
taskpane2.setTitle("My Tasks");
JPanel panel2 = new JPanel();
panel2.setBackground(Color.blue);
panel2.setSize(100,100);
taskpane2.add(panel2);
taskpanecontainer.add(taskpane2);
taskpanecontainer.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
return taskpanecontainer;
}
}
}
What I need are two things:
how do I change the bgcolor of the title? I think it is done with the taskpane2.setUI(..) option but I had no luck working with it.
how to set the border between the JXTaskPane and the Jpanel to zero?
Originally, the JXTaskPane was designed as a kind of "fixed-properties" component - it should look exactly like the corresponding native component (then of WinXP): custom appearance wasn't meant to be supported. As a consequence, the implementation of the title/border is deeply hidden in the XXTaskPaneUI - actually, everything boils down to be a Border.
1) as dogbane already mentioned, some of the properties can be changed on a per-application basis. Just beware: those are implementation details which might change or not be supported by concrete ui implementations (Nimbus is always a good candidate to not respecting them, even our not-really-synth implementation might not, forgot)
2) the "gap" is the border of the contentPane, you can set your own. Again a beware: might not survive an updateUI (could be that the ui delegates override them unconditionally, if so, please file an issue in the SwingX issuetracker)
((JComponent) taskpane2.getContentPane()).setBorder(BorderFactory.createEmptyBorder());
BTW: those panel.setSize have exactly no effect - layoutManagers rule ;-)
To change the bgcolour of the title, you can try setting the start and end background gradient colours in the UIManager:
UIManager.put("TaskPane.titleBackgroundGradientStart", Colors.White.color());
UIManager.put("TaskPane.titleBackgroundGradientEnd", Color.GREEN);
I also found an open swingx jira task for this: SWINGX-731 Support to define the color to JXTaskPane header.

Categories

Resources