public class Gui extends JFrame{
JTextField tf_input;
JTextArea ta_output;
JScrollPane sp_taop;
private class klis implements KeyListener{
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode()==KeyEvent.VK_ENTER){
//System.out.println("enter"); //debug
if (!tf_input.getText().isEmpty()){
String input = tf_input.getText();
ta_output.setText(ta_output.getText()+input+'\n');
System.out.println(input); //debug
System.out.println("ok!"); //debug
sp_taop.validate();
tf_input.setText(null);
}
}
}
}
Gui(){
System.out.println("hello");
inti();
render();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void inti() {
setSize(800, 600);
//text field input
tf_input = new JTextField();
tf_input.setSize(550, 24);
tf_input.addKeyListener(new klis());
//text Area
ta_output = new JTextArea("hello World\n",30,60);
ta_output.setSize(ta_output.getPreferredSize());
ta_output.setLineWrap(true);
ta_output.setEditable(false);
sp_taop = new JScrollPane();
sp_taop.add(ta_output);
sp_taop.setSize(ta_output.getSize().width+20,ta_output.getSize().height);
sp_taop.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
}
private void render() {
Panel p = new Panel(null);
ta_output.setLocation(0, 0);
sp_taop.setLocation(10, 10);
tf_input.setLocation(10, (sp_taop.getSize().height+20));
ta_output.repaint();
//adding
p.add(sp_taop);
p.add(tf_input);
add(p);
}
}
I'm running this on java 1.7.0_25 on vbox 4.3.4 lUbuntu
The problem is that the jscroll is not updating itself! What should i do?
I've been searching google for hours now and i have not found anything close to what I am looking for.
By the way sorry about the plain code it was hard to explain the problem without it.
Don't use JScrollPane#add, this is not how scroll panes work, instead try using JScrollPane#setViewportView
Take a look at How to use Scroll Panes
Don't add you text field to another container. Components can only have a single parent, so adding it to a second container will remove it from the first.
On a side note. I would avoid the use of KeyListener, text components have the capacity to consume key events, meaning that your listener may not actually be notified. Also, if it is called, the component will be in the middle of of mutation operation (it will be trying to update it's model) which can cause unexpected issues and possibly dirty updates.
I might be tempted to use a DocumentListener in this case, but you would need to test it.
I would also avoid the use of null layouts. To start with, you won't be able to effect the position of the text field within the context of the scroll pane as the scroll pane uses it's own layout manager.
Moreover, the differences between OS, video drivers and fonts makes the potential rendering outputs endless. Layout managers take out the guess work when dealing with these situations
Related
I have recently begun working with JComponents to create GUI systems. Everything is working but the bottom and right sides of the JFrame do not get painted over and remain white.
Screenshot of running GUI:
In the screenshot you can see the 'drknBtn' is displayed correctly; this is because I hovered over it with the mouse before taking the picture. Hovering over the buttons refreshes them and they appear as normal. Due to this, I would assume the panel that holds them, 'bottomPnl' is covering that white space, but that panels background is not showing at the bottom portion. Any ideas on what could cause this? I have tried calling 'bottomPnl.repaint()' directly before calling pack(), but no change.
My code is below.
Note: For each JComponent, I created a class extending that component. This way I could set default values for the components in the constructors of these classes instead of doing each one individually. I'll list the relevant properties of the Frame and Panels.
Frame: setSize(width,height); setResizeable(false); setLocationRelativeTo(null);
Panel: setLayoutManager(from contructor); setPreferredSize(new Dimension(width,height)); same for setMinimumSize and setMaximumSize.
public Display(String title, int w, int h){
width=w;
height=h;
frame = new FrameUI(title,w,h);
//parent panel
parentPnl= new PanelUI(width,height, new FlowLayout(FlowLayout.CENTER,0,0));
parentPnl.setBackground(new Color(100,175,175));
//top panel
topPnl= new PanelUI(width,(int)(height*.15), new FlowLayout(FlowLayout.CENTER,0,0));
topPnl.setBackground(new Color(100,175,175));
chooseFileBtn = new ButtonUI("Browse...",topPnl.getWidth()/4,(int)(topPnl.getHeight()*.9),new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
fc = new FileChooserUI();
fc.setFileFilter(new FileNameExtensionFilter("Image files", ImageIO.getReaderFileSuffixes()));
int result = fc.showOpenDialog(null);
try {
if (result == JFileChooser.APPROVE_OPTION) {
picture.setIcon(new ImageIcon(ImageIO.read(fc.getSelectedFile()).getScaledInstance(picture.getWidth(),picture.getHeight(), 0)));
}
} catch (Exception iOException) {
}
}
});
//middle panel
midPnl= new PanelUI((int)(width*.85),(int)(height*.7), new FlowLayout(FlowLayout.CENTER,0,0));
midPnl.setBackground(new Color(75,125,125));
picture = new LabelUI("",midPnl.getWidth(),midPnl.getHeight());
picture.setBackground(new Color(75,125,125));
picture.setVisible(true);
picture.setOpaque(true);
picture.setIcon(null);
//bottom panel
bottomPnl= new PanelUI(width,(int)(height*.15), new FlowLayout(FlowLayout.CENTER,0,0));
bottomPnl.setBackground(new Color(100,175,175));
ltnBtn = new ButtonUI("Lighten Picture",bottomPnl.getWidth()/3,(int)(bottomPnl.getHeight()*.9),new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
}
});
ltnBtn.setBackground(Color.LIGHT_GRAY);
ltnBtn.setForeground(Color.BLACK);
drknBtn = new ButtonUI("Darken Picture",bottomPnl.getWidth()/3,(int)(bottomPnl.getHeight()*.9),new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
}
});
drknBtn.setBackground(Color.DARK_GRAY);
drknBtn.setForeground(Color.WHITE);
//add UI Objects
topPnl.add(chooseFileBtn);
midPnl.add(picture);
bottomPnl.add(ltnBtn);
bottomPnl.add(drknBtn);
parentPnl.add(topPnl);
parentPnl.add(midPnl);
parentPnl.add(bottomPnl);
Container contentPane = frame.getContentPane();
contentPane.add(parentPnl);
frame.pack();
frame.setVisible(true);
}
}
topPnl= new PanelUI(width,(int)(height*.15), new FlowLayout(FlowLayout.CENTER,0,0));
looks to me like you are manually trying to control the size of the panels and therefore the size of the components added to your panels. Your calculations are wrong and some components aren't displayed properly. Also all your sizes are fixed at creation time and will not adjust if the size of the frame ever changes.
Don't try to control the sizes manually. Use layout managers to dynamically size components based on the properties of the component.
I fail to see why you would want a button to be 15% of the space available to the frame.
If you want the button to be larger than normal you can set extra empty space around the text of the button by using:
button.setMargin( new Insets(50, 50, 50, 50) );
Then just add the button to a panel using a FlowLayout and let the layout manager do its job.
The default layout for a frame is a BorderLayout, so you can then add the "topPnl" to the frame using:
frame.add(topPnl, BorderLayout.PAGE_START);
The other panels can then be added using:
frame.add(midPnl, BorderLayout.CENTER);
frame.add(bottomPnl, BorderLayout.PAGE_END);
This is how Swing was designed to be used with layout managers.
Read the section from the Swing tutorial on How to Use BorderLayout for more information and examples.
The main point is use methods like setMargin(...), to provide hints to the component on what their preferred size should be.
I fixed the problem by removing the 'setSize()' method in the FrameUI constructor. However, I still do not understand how you could dynamically size panels as you said while still maintaining the proportions I want for them. Thank you #camickr for the pointers, my original problem is fixed. I'll look into more javadocs and tutorials on layout managers and such.
I'm creating a text field in java using swing components. I want to make a search text field like one appears in Mozilla or other browsers.
I have added a button in text field. I have set border layout of JTextField. everything is working fine but whenever large text is written in text field (as it reaches the given size of text field) it goes behind the button. As everyone of you must have seen, this does not occur in search bars. Text must not go behind the button rather there must be some gap between button and text.
Does anyone know how to do that?
Maybe start with something like this:
The blinking cursor is positioned at the far right of the text field.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
class ButtonsInTextField {
JPanel gui = new JPanel(new GridBagLayout());
JTextField textField;
ButtonsInTextField(int cols) {
JPanel textFieldWithButtonsPanel = new JPanel(new FlowLayout(
SwingConstants.LEADING, 5, 1));
textField = new JTextField(cols);
textFieldWithButtonsPanel.add(textField);
addButtonToPanel(textFieldWithButtonsPanel, 8);
addButtonToPanel(textFieldWithButtonsPanel, 16);
addButtonToPanel(textFieldWithButtonsPanel, 24);
// WARNING: Not sensitive to PLAF change!
textFieldWithButtonsPanel.setBackground(textField.getBackground());
textFieldWithButtonsPanel.setBorder(textField.getBorder());
textField.setBorder(null);
// END WARNING:
gui.add(textFieldWithButtonsPanel);
}
private final void addButtonToPanel(JPanel panel, int height) {
BufferedImage bi = new BufferedImage(
// find the size of an icon from the system,
// this is just a guess
24, height, BufferedImage.TYPE_INT_RGB);
JButton b = new JButton(new ImageIcon(bi));
b.setContentAreaFilled(false);
//b.setBorderPainted(false);
b.setMargin(new Insets(0,0,0,0));
panel.add(b);
}
public final JComponent getGui() {
return gui;
}
public final JTextField getField() {
return textField;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ButtonsInTextField bitf = new ButtonsInTextField(20);
JOptionPane.showMessageDialog(null, bitf.getGui());
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
As people have noted above, it might have helped to see the code, especially the Layout manager.
However, you might try the following (if you haven't yet):
Call setColumns
http://docs.oracle.com/javase/7/docs/api/javax/swing/JTextField.html#setColumns(int)
Call setPreferredSize /setMaximumSize/setMinimumSize depending on your layout manager.
But I'd try to avoid this solution because it's pixel-level maintenance.
Regards
As an alternative solution you can use a Component Border, which allows you to use the button as a Border so it appears within the text field.
I am having a bit of problem regarding Swing. I have a JFrame called FrameMain. Inside it is a JPanel called panelChoices.
When FrameMain is called/created, it fills up the panelChoices object with a number of PanelEntries objects, which is a JPanel with a number of JButtons in it (it is a different class that I wrote).
What I want to do is when I click one of the buttons inside the PanelEntries object, I want to destroy/remove FrameMain, along with the rest of it components (including the PanelEntries object that contains the JButton).
I've tried using super but it returns the JPanel (the PanelEntries object) that holds the JButton and not FrameMain that holds them all together. How can I achieve this?
EDIT: It seems that I am not clear enough, so here's a bit more information from my work. I don't have the actual code right now because I am on a different machine but I hope this will help elaborate my question.
public class FrameMain() {
private JFrame frameMain;
private JPanel panelChoices;
public FrameMain(args) {
createGUI();
loadData();
}
private void createGUI() {
JFrame frameMain = new JFrame();
JPanel panelChoices = new JPanel(new GridLayout(1,1));
frameMain.add(panel);
// removed formatting and other design codes since they are not important.
pack();
}
private void loadData() {
boolean available;
for (int i = 1; i <= 10; i++) {
// do some if/else and give value to boolean available
PanelEntries panel = new PanelEntries(i, available);
frameMain.add(panel);
// more code here to handle data.
}
}
}
public class PanelEntries() extends JPanel {
public PanelEntries(int num, boolean avb) {
JButton button = new JButton("Button Number " + num);
button.setEnabled(avb);
add(button);
// add action listener to created button so that it calls 'nextScreen()' when clicked.
// more code
pack();
}
private void nextScreen() {
// destroy/dispose MainFrame here.
// See Notes.
AnotherFrame anotherFrame = new AnotherFrame();
}
}
Notes:
All classes are inside their own .java file.
I need to know how to dispose FrameMain from the button inside the PanelEntries object, not just disposing a JFrame.
As per the given information,
If you want to exit the application, its not a big deal use System.exit(0); :)
If you mean to dispose the frame, jframe.dispose();
If you want to remove a componet / all components you can use .remove(Component) / .removeAll() etc
If this did not help, please re-write your question with more information.
My Code:
public MyConstructor() {
view = new JPanel(new GridLayout(3, 1));
header = new JPanel(new GridLayout(2, 1));//2 ROWS 1 COLUMN
foot = new JLabel("Copyright...");
content = new JPanel();
info = new JLabel("");
logo = new JLabel() {
BufferedImage img;
#Override
public void paint(Graphics g) {
try {
img = ImageIO.read(new File("logo.jpg"));
} catch (IOException e) {
}
g.drawImage(img, 0, 0, null);
}
};
window.add(view);
header.add(logo);
header.add(info);
view.add(header);
view.add(content);
view.add(foot);
window.setLocation(width / 2, 100);
window.setSize(width, height);
window.setPreferredSize(new Dimension(width, height));
content.setSize(window.getWidth(), height-70);
content.setPreferredSize(new Dimension(window.getWidth(), height-70));
}
"window" is the frame...the class is not extending JFrame
My class is going to be a super class to others, the subclasses inherit the public content JPanel. In my super class i'm trying to set the width and height of the 3 sections of my GridLayout, the logo and info components add up to 70 for their height...I've set the other components (view,header,info,logo) private so that subclasses can't access them...
When the application runs a window is shown for the login, this displays and resizes properly. once logged in an instance of one of the subclasses is created, the login window is then hidden site setVisible(false)
when the new window is shown however, the JFrame is the correct size but the header,content and footer are not the currect sizes.
I've tried setting the size and preferred size each of the components but still not working...I've also tried calling repaint and validate/revalidate
Any ideas?
It sounds like your design could be improved. Why do these variables need to be attributes of a superclass? Why not just have a method that constructs the panels that you need and a constructor that adds them so that you get fresh panels for each instance?
In fact, why not just create the header and footer classes and reuse them instead of having to subclass a frame just to get the same header and footer?
Why are you overriding the label to paint an image?
that is what the setIcon() method is for
you should never read a file in the custom painting code since this method is invoked multiple times
custom painting, when necessary, is done in the paintComponent() method.
Try setting preferred sizes before adding components to containers, and adding components "bottom-up". Otherwise, try calling pack(), revalidate(), repaint() etc.to adjust things.
Read up on Layout Managers, too, you're not using them correctly.
Also, Swing sucks. Try Netbeans, it makes it a little bit more bearable. It helps a lot when you need to manually place and resize things, too.
I am currently desigining a calculator panel using Java Swing. However, it's an extreme PAIN to line up all of the buttons because they are always resizing and repositioning themseleves whenever I add a new button or change the size of a button.
Is there a type of layout or something that can "lock" the buttons in position so they are not affected when I move/resize/add other buttons?
Thanks,
Bob
Extending what Tom said...
To allow a component to become invisible yet hold its place, you can place it in a CardLayout along with an empty label and just swap which is visible.
You can create a class to do this for you as follows The main just shows an example where if you click a button it's deleted while retaining its position. I put in showComponent/hideComponent and setVisible(t/f) - depends on the style you like.
This might not exactly answer what you're looking for, but might be a useful piece for part of your application.
public class Placeholder extends JPanel {
private static final long serialVersionUID = 1L;
private CardLayout cardLayout_;
public Placeholder(JComponent component) {
cardLayout_ = new CardLayout();
setLayout(cardLayout_);
add(component, "visible"); // the component
add(new JLabel(), "hidden"); // empty label
}
public void showComponent() {
cardLayout_.show(this, "visible");
}
public void hideComponent() {
cardLayout_.show(this, "hidden");
}
public void setComponentVisible(boolean visible) {
if (visible)
showComponent();
else
hideComponent();
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setLayout(new GridLayout(2,0));
for (int n = 1; n < 10; n++) {
JButton b = new JButton(n + "");
final Placeholder placeholder = new Placeholder(b);
f.add(placeholder);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
placeholder.hideComponent();
}
});
}
f.pack();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
I suggest instead of adding and removing buttons, you change their visibility property (setVisible). Some layout manager ignore non-visible components, so you may need to add a non-opqaue (or matching background) component in the same position that follows the preferred/minimum/maximum sizes of the original component. More simple you may want to use OverlayLayout.
You could use GridBagLayout to keep them in a grid, but allow them to resize
Extending what the others said...
Instead of making the components invisible, you can also disable them...
Of course, it depends on your application and your preferences.
Beside the above mentioned layouts, there are some freely available ones, like TableLayout and the versatile MigLayout.
It probably depends on the development environment you are using.
In Netbeans you can right-click the control container (form/panel) and select from a number of layout options. 'Absolute Layout' will let you position the controls without them all being resized automatically, although it won't let you place controls on top of each other.
I suggest you to check A Visual Guide to Layout Managers. Depending on the look and functionality you want there are different layouts that could work for you. If the main problem is the resize operation (of the parent JFrame o JPanel I assume), the Spring Layout allows you to establish constraints regarding the relative place of components.