I am rather new to this whole Swing, but nevertheless it already got me quite annoyed.
I am trying to do something simple, that behaves like WPF's list with custom item template. That is, item are of fixed size and as it overflows the given area a scroll bar pops up.
And I've been trying and trying, but I just can't get it to work. The closest I got was with BoxLayout, the problem there however, is that if there are too few items to take available space, they get stretched -.-
I bet there is some simple way to achieve that, I just don't know about. Thanks in advance.
Here's the code I got (java):
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class App
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new MainFrame();
}
});
}
}
class MainFrame extends JFrame
{
private JPanel itemsPanel;
private JButton addButton;
public MainFrame()
{
// create components
itemsPanel = new JPanel();
addButton = new JButton("Add");
// layout
itemsPanel.setLayout(new BoxLayout(itemsPanel, BoxLayout.Y_AXIS));
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
buttons.add(addButton);
setLayout(new BorderLayout());
add(new JScrollPane(itemsPanel), BorderLayout.CENTER);
add(buttons, BorderLayout.SOUTH);
// actions
addButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0)
{
itemsPanel.add(new SampleItem());
itemsPanel.revalidate();
}
});
// frame size and close action
setDefaultCloseOperation(EXIT_ON_CLOSE);
Dimension size = new Dimension(300, 300);
setMinimumSize(size);
setSize(size);
setVisible(true);
}
}
class SampleItem extends JPanel
{
public SampleItem()
{
setBorder(BorderFactory.createLineBorder(Color.black));
setPreferredSize(new Dimension(200, 100));
}
}
EDIT:
I ended up writing custom renderer and editor thanks to rcook's answer.
EDIT2:
Eh, after turning it in, I got scolded really badly for this... Apparently the problem is that JScrollPane resizes viewport so that the control fills all available space and the solution is to create JPanel implements Scrollable and return false in public boolean getScrollableTracksViewportHeight(). Oh well, I hope someone will find it useful, editors are just so much pain.
Use a JList, put it inside a JScrollPane, put that within a pane in the middle part of a BorderLayout; BorderLayout is the default for a JFrame, so you may not need to create one. Put the lower button on the bottom portion of the BorderLayout.
Related
What's wrong? ImageIcon and the frame's size are working properly.
But the JTextField and the JButton aren't.
I need the solution.
import javax.swing.*;
import javax.swing.ImageIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Frame {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("Alkalmazás");
frame.setVisible(true);
frame.setSize(500,500);
frame.setResizable(false);
JTextField field = new JTextField();
field.setBounds(40,250, 300,35);
JButton button = new JButton(new ImageIcon("table.png"));
button.setBounds(40,400, 250,25);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tf.setText(""something);
}
});
frame.add(field);
frame.add(button);
}
}
You didn't mention what's "not working properly", but there are a few errors with your code:
Don't call your class Frame, it may confuse you or others about java.awt.Frame, something that may work would be MyFrame
Right now all your class is inside the main method and it's not placed inside the Event Dispatch Thread (EDT), to fix this, create an instance of your class and call a method createAndShowGUI (or whatever you want to name it) inside SwingUtilities.invokeLater()
For Example:
public static void main(String args[]) {
SwingUtilities.invokeLater(new MyFrame()::createAndShowGUI)
}
Or if using Java 7 or lower, use the code inside this answer in point #2.
setVisible(true) should be the last line in your code, otherwise you may find some visual glitches that may be resolved until you move your mouse above your window or something that triggers the call to repaint() of your components.
Instead of calling setSize(...) directly, you should override getPreferredSize(...) of your JPanel and then call pack() on your JFrame, see this question and the answers in it: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
You're adding 2 components to the CENTER of BorderLayout, which is a JFrame's default layout manager, there are other layout managers and you can combine them to make complex GUI's.
setBounds(...) might mean that you're using null-layout, which might seem like the easiest way to create complex layouts, however you will find yourself in situations like this one if you take that approach, it's better to let Swing do the calculations for you while you use layout managers. For more, read: Why is it frowned upon to use a null layout in Swing?
With all the above tips now in mind, you may have a code similar to this one:
import java.awt.Dimension;
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.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class MyFrame {
private JFrame frame;
private JPanel pane;
private JTextField field;
private JButton button;
public static void main(String[] args) {
SwingUtilities.invokeLater(new MyFrame()::createAndShowGUI);
}
private void createAndShowGUI() {
frame = new JFrame("Alkalmazás");
pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
field = new JTextField(10);
button = new JButton("Click me");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
field.setText("something");
}
});
pane.add(field);
pane.add(button);
frame.add(pane);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Now you have an output similar to this one:
What about you want the JTextField to have a more "normal" size? Like this one:
You'll have to embed field inside another JPanel (with FlowLayout (the default layout manager of JPanel)), and then add that second JPanel to pane, I'm not writing the code for that as I'm leaving that as an exercise to you so you learn how to use multiple layout managers
I can't seem to find a solution online for why I'm getting this error on attempted run
I'm working on making a simple test system for a different program when are button press will yield value in a text box. I would like them to be on different lines to make it cleaner, so I looked into layouts. I decided a Box Layout would fit me best. I looked at different examples before attempting this and my code ended up looking like this, (apologies for the messy code)
Update
Got the box layout error to disappear but the code will not center them on the panel/frame. The label and button align left while the textfield becomes very large. I don't need it todo that
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import static javax.swing.BoxLayout.Y_AXIS;
import static javax.swing.SwingConstants.CENTER;
public class button extends JFrame {
static JFrame f;
static JButton b;
static JLabel l;
// main class
public static void main(String[] args)
{
// create a new frame to stor text field and button
f = new JFrame("panel");
BoxLayout layout = new BoxLayout(f, BoxLayout.Y_AXIS);
f.setLayout(layout);
// create a label to display text
l = new JLabel("panel label");
b = new JButton("button1");
JTextField textArea = new JTextField(5);
textArea.setEditable(false);
//textArea.append("Hello World");
// create a panel to add buttons
JPanel p = new JPanel();
// add buttons and textfield to panel
f.add(p);
f.setSize(300, 300);
p.add(l);
p.add(b);
p.setBackground(Color.white);
p.add(textArea);
f.show();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Random r = new Random();
textArea.setText(String.valueOf(r));
}
});
}
}
Error
Exception in thread "main" java.awt.AWTError: BoxLayout can't be shared
at java.desktop/javax.swing.BoxLayout.checkContainer(BoxLayout.java:461)
at java.desktop/javax.swing.BoxLayout.invalidateLayout(BoxLayout.java:245)
at java.desktop/javax.swing.BoxLayout.addLayoutComponent(BoxLayout.java:278)
at java.desktop/java.awt.Container.addImpl(Container.java:1152)
at java.desktop/java.awt.Container.add(Container.java:1029)
at java.desktop/javax.swing.JFrame.addImpl(JFrame.java:553)
at java.desktop/java.awt.Container.add(Container.java:436)
at button.main(button.java:36)
I would like the three items to all to be stacked one on top of another with a space between them. The order doesn't matter right now.
Swing was first added to the JDK in 1998 and has undergone a lot of changes since. Unfortunately, when you read Web pages about Swing, it is not obvious when that page was last updated. Consequently you may be learning outdated techniques for writing Swing code.
First of all, according to the code you posted, class button does not need to extend class JFrame since you use a static variable as your application's JFrame. Also, JFrame is a top-level container which makes it a special kind of container and not the same kind of continer as a JPanel. You need to set the layout manager for your JPanel and then add the JLabel, JTextField and JButton to that JPanel. And then add the JPanel to the JFrame.
Calling method pack() of class JFrame will automatically set the preferred sizes for the components inside the JFrame. It appears in the code below.
Please also look at Java coding conventions which allows others to more easily read and understand your code. And note that, according to these conventions, I renamed your class from button to Buttons and also because there are already several class in the JDK named Button.
Here is my rewrite of your code...
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class Buttons implements Runnable {
public void run() {
createAndShowGui();
}
private void createAndShowGui() {
JFrame f = new JFrame("Box");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel p = new JPanel();
BoxLayout layout = new BoxLayout(p, BoxLayout.Y_AXIS);
p.setLayout(layout);
JLabel l = new JLabel("panel label");
JTextField textField = new JTextField(5);
JButton b = new JButton("button1");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Random r = new Random();
textField.setText(String.valueOf(r.nextBoolean()));
}
});
p.add(l);
p.add(textField);
p.add(b);
f.add(p);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
public static void main(String[] args) {
Buttons instance = new Buttons();
EventQueue.invokeLater(instance);
}
}
I've made a JFrame with Diferent JButtons and i'd like to get an image from another class. Any ideas? Or how draw on the same class but on the action performed?
Because it doesnt let me to do any drawings...my complier always gives me error messages
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.*;
public class red extends JFrame {
public JButton b;
public JButton b1;
public JButton b2;
public JButton b3;
public JButton b4;
public static Image p;
public static Graphics g;
public red() throws IOException {
gui1 x = new gui1();
setTitle(" ");
setSize(1200,700);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
b= new JButton("click");
b1= new JButton();
b.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e0){
b1.setBounds(0, 0, 200, 200);
b.show(false);
add(x);
}
});
b.setBounds(0, 0, 100, 100);
add(b1);
add(b);
setVisible(true);
}
public static void main(String[] args) throws IOException {
red k = new red();
}
}
import java.awt.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class gui1 extends Canvas {
public static Image p;
public void paint(Graphics g){
g.drawImage(p, 700, 200, 100, 100, this);
}
{
try {
p= ImageIO.read(new File("Lighthouse.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Phew! I see A LOT of errors in your code (even after I corrected the compilation errors):
You're not following the Java naming conventions:
Class names should be nouns, in mixed case with the first letter of each internal word capitalized
while red is a noun it should be more descriptive and be capitalized. The same goes for gui1
You're extending JFrame which in plain english would say: red is a JFrame, you should really avoid this and create your GUI based on JPanels instead... see Java Swing using extends JFrame vs callint it inside of class
You're setting size (a REAAAAAAALLY big one window for the JButton sizes you're using), instead use pack()
You're using null-layout, while pixel-perfect GUIs might seem like the easiest way to create complex GUIs for Swing newbies, the more you use them the more problems related to this you'll find in the future, they are hard to maintain and cause random problems, they don't resize, etc. Please read Null layout is evil and Why is it frowned upon to use a null layout in Swing? for more information about why you should avoid its use and why you should change your GUI to work with Layout Managers along with Empty Borders for extra spacing between components.
You're making use of a deprecated method JFrame#show() you should be using JFrame#setVisible(...) instead.
Related to point #4, you shouldn't be calling setBounds(...) method, but let that calculations to the layout managers.
You're not placing your program on the Event Dispatch Thread (EDT), Swing is not thread safe, you can fix this by changing your main() method as follows:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//Your constructor here
}
});
}
You're mixing AWT and Swing components, instead of using AWT's Canvas use Swing's JPanel which has more functionality and support.
Images will become embedded resources once they're packaged in a JAR file, so it's wise to start treating them as if they already were, not as external files as shown in the embedded-resource tag.
Once you change from Canvas to JPanel you should override its paintComponent(...) method and not paint(...) and call it's super.paintComponent(g) method as the first line, also don't forget to add the #Overrides annotation. See the tutorial on Swing custom painting.
You're abusing the use of static keyword, see how does the static keyword works?
After seeing all the above errors I recommend you to go back and Learn the basics of the language before starting with a graphical environment which will only add more difficulty to your learning.
From what I understand you want to draw an image on a button click, if that's the case then you can wrap your image in a JLabel and add that JLabel to a JPanel which then is added to a parent JPanel which is later added to the JFrame:
As you can see in the GIF above, the icon is displayed after user presses the button.
Obviously this can be improved for the GUI to be more "attractive" with combinations of layout managers and empty borders as stated before.
This was done with the following code:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ImageDrawingFromOneClassToAnother {
private JFrame frame;
private JPanel pane;
private JPanel leftPane;
private JPanel rightPane;
private ImageIcon icon;
private JButton button;
private JLabel label;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ImageDrawingFromOneClassToAnother().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
icon = new ImageIcon(this.getClass().getResource("king.png")); //Read images as if they were already embedded resources
button = new JButton("Draw image");
label = new JLabel(""); //Create an empty label
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(icon); //On button click, we set the icon for the empty label
}
});
pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200); //Set a size for the main panel
}
};
pane.setLayout(new GridLayout(1, 2)); //The main panel
leftPane = new JPanel(); //The button panel
leftPane.setLayout(new BoxLayout(leftPane, BoxLayout.PAGE_AXIS));
leftPane.add(button);
rightPane = new JPanel(); //The panel where the image will be drawn
rightPane.add(label);
//We add both (button and image) panels to the main panel
pane.add(leftPane);
pane.add(rightPane);
frame.add(pane); //Add the main panel to the frame
frame.pack(); //Calculate its preferred size
frame.setVisible(true); //Set it to be visible
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I'm currently working on an irc bot and today I would like to create a GUI for it.
I'm trying to create a column layout that has two parts, left and right.
The left side will show console output, the right will contain all the controls (joining channels, commands etc).
I'm having issues creating the two columns. I have a JPanel that is the whole width and height of the window and has a border of 10 pixels, and then I have two panels within that; left and right.
The left and right panels are for some reason taking the whole size of the window, and the right panel is overlapping everything.
Here's an example picture: http://i.imgur.com/lc4vHVH.png
The white is the right panel, it should only be half the size and have an identical but black panel on the left of it.
Here's my current code, sorry if it's messy, new to the whole Swing GUI.. Thanks for any help.
package tk.TaylerKing.GribbyBot;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.BorderFactory;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import com.alee.laf.WebLookAndFeel;
import com.alee.laf.menu.WebMenuBar;
import com.alee.laf.menu.WebMenuItem;
import com.alee.laf.panel.WebPanel;
import com.alee.laf.rootpane.WebFrame;
public class GribbyBot extends WebFrame {
private static final long serialVersionUID = 4641597667372956773L;
public static HashMap<String, ArrayList<String>> connections = new HashMap<String, ArrayList<String>>();
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(WebLookAndFeel.class.getCanonicalName());
SwingUtilities.invokeLater(new Runnable(){
public void run(){
GribbyBot gb = new GribbyBot();
gb.setVisible(true);
}
});
}
public GribbyBot(){
WebPanel panel = new WebPanel();
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.setPreferredSize(new Dimension(780, 580));
WebMenuBar menu = new WebMenuBar();
WebMenuItem file = new WebMenuItem("Exit");
file.setMnemonic(KeyEvent.VK_E);
file.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
menu.add(file);
setJMenuBar(menu);
WebPanel left = new WebPanel();
left.setPreferredSize(new Dimension(380, 580));
left.setBackground(Color.BLACK);
WebPanel right = new WebPanel();
right.setPreferredSize(new Dimension(380, 580));
right.setBackground(Color.WHITE);
add(panel);
panel.add(left);
panel.add(right);
setTitle("GribbyBot");
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
}
}
On a side note, all the variables that are prefixed with "Web" are the same as Swing, but it's a custom GUI.
Override JComponent#getPreferredSize() instead of using setPreferredSize()
Read more Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
If extremely needed in case of Performing Custom Painting then try in this way:
Sample code:
final JPanel panel = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// your custom painting code here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(40, 40);
}
};
Why are using setPreferredSize() method whereas you can achieve this design easily using any proper layout such as BoxLayout, GridLayout, BorderLayout etc.
Read more about layout How to Use Various Layout Managers
EDIT
try JPanel panel = new JPanel(new GridLayout(1,2));
I have wrote a java program, it has a CardLayout with a JPanel for each card.
The JPanel contains long text, I just need to implement a little "search bar" that just search for specified text on the viewed JPanel.
It simply has to highlight the searched text inside the JPanel.
In order to make it clearer, I'm talking about something like the Chrome's of Firefox's search bar (ctrl-f) but that works just for one JPanel in my program.
Here is a picture.
Is it possible? How can I do that?
Thanks
Easiest way is to create a small search JPanel that is positioned above your text JPanel. Both JPanels would be inside of another JPanel. I'd use a JTextField and a JButton, because I like the user in control of when to search.
Here's one of my GUI's with a search JPanel.
And here's the code to create the search JPanel. Note that I used a JPanel. You only extend Swing components when you want to override one of the component methods.
package gov.bop.cobol.paragraph.structure.view;
import gov.bop.cobol.paragraph.structure.model.ParagraphStructureModel;
import gov.bop.cobol.paragraph.structure.thread.SearchActionThread;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class SearchPanel {
protected JPanel panel;
protected JTextField findTextField;
protected ParagraphStructureFrame frame;
protected ParagraphStructureModel model;
public SearchPanel(ParagraphStructureFrame frame,
ParagraphStructureModel model) {
this.frame = frame;
this.model = model;
createPartControl();
}
protected void createPartControl() {
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
JLabel findLabel = new JLabel("Search:");
panel.add(findLabel);
panel.add(Box.createRigidArea(new Dimension(6, 0)));
findTextField = new JTextField(30);
panel.add(findTextField);
panel.add(Box.createRigidArea(new Dimension(6, 0)));
JButton findButton = new JButton("Search");
findButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
String s = findTextField.getText().toUpperCase().trim();
if (!s.equals("")) {
findTextField.setText(s);
Thread thread = new Thread(new SearchActionThread(frame,
model, s));
thread.start();
}
}
});
panel.add(findButton);
}
public JPanel getPanel() {
return panel;
}
}