I am making a custom JComponent to my Swing GUI.
public class BreadCrump extends JComponent implements MouseListener,
MouseMotionListener{
JPanel cajaPrincipal;
JLabel nombre;
JLabel propiedadUsada;
JLabel numeroApariciones; //OPCIONAL
public BreadCrump(String nombre, String relacion)
{
}
public BreadCrump(String nombre)
{
this.nombre = new JLabel(nombre);
this.cajaPrincipal = new JPanel();
this.cajaPrincipal.setPreferredSize(new Dimension(60,40));
this.cajaPrincipal.setSize(60, 40);
this.cajaPrincipal.add(this.nombre);
this.cajaPrincipal.setBackground(Color.blue);
this.nombre.setLocation(10, 10);
this.cajaPrincipal.setVisible(true);
this.setPreferredSize(new Dimension(60,40));
this.setSize(60,40);
this.setBackground(Color.red);
this.setVisible(true);
addMouseListener(this);
addMouseMotionListener(this);
}
And create the objects in this fragment of code:
JPanel a = new JPanel();
JScrollPane sp = new JScrollPane(a);
sp.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
sp.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
//sp.setBounds(0, 0,father.getSize().width, height);
this.add(sp);
father.add(this, java.awt.BorderLayout.PAGE_END);
for (int i = 0; i < 8; i++) {
BreadCrump prueba = new BreadCrump("prueba " + i);
a.add(prueba);
}
The problem is that I cant see the component. The component exists an is inside my JPanel 'a' and the JScrollPane detect it because the scroll bar appears.
I tried to change JComponent to JPanel and it works, i can see the JPanel(when I change the color and the preferredSize). But I dont know why can not see my JComponent.
Anyone knows what I am doing wrong? Maybe I need put a location to the component? I tried to add size and visible but nothing occurs.
Thanks for your time!
Related
I'm creating a program that features a grid of 12 JPanels. When the "add image" button is pressed, an image appears in the first JPanel in the grid and a counter is incremented by one. From then onwards, every time the "add image" is clicked again, an image would be added to the next JPanel. For some reason, the button only adds an image to the first JPanel and then stops working. Here's the code I've got so far.
public class ImageGrid extends JFrame {
static JPanel[] imageSpaces = new JPanel[12];
int imageCounter = 0;
ImageGrid() {
this.setTitle("Image Grid");
setSize(750, 750);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel p3 = new JPanel();
p3.setLayout(new GridLayout(3, 4, 10, 5));
p3.setBackground(Color.WHITE);
p3.setOpaque(true);
p3.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
for (int j = 0; j < imageSpaces.length; j++) {
imageSpaces[j] = setImageSpace();
p3.add(imageSpaces[j]);
}
MyButtonPanel p1 = new MyButtonPanel();
add(p1, BorderLayout.SOUTH);
add(p3, BorderLayout.CENTER);
}
public JPanel setImageSpace() {
JPanel test;
test = new JPanel();
test.setOpaque(true);
test.setPreferredSize(new Dimension(100, 100));
return test;
}
class MyButtonPanel extends JPanel implements ActionListener {
final JButton addImage = new JButton("Add Image");
ImageIcon lorryPicture = new ImageIcon(ImageGrid.class.getResource("/resources/lorry.png"));
JLabel lorryImage = new JLabel(lorryPicture);
MyButtonPanel() {
add(addImage);
addImage.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == addImage) {
imageSpaces[imageCounter].add(lorryImage);
revalidate();
repaint();
imageCounter++;
}
}
}
public static void main(String[] args) {
ImageGrid test = new ImageGrid();
test.setVisible(true);
}
}
You should be revalidating and repainting the panel, (which is the containter being affected by the addition), not the frame
imageSpaces[imageCounter].add(lorryImage);
imageSpaces[imageCounter].revalidate();
imageSpaces[imageCounter].repaint();
Diclaimer: This may work as a simple fix, but also note that a component (in this case your JLabel lorryImage) can only have one parent container. The reason the above fix still works is because you don't revalidate and repaint the previous panel, the label was added to. So you may want to think about doing it correctly, and adding a new JLabel to each panel.
if (e.getSource() == addImage) {
JLabel lorryImage = new JLabel(lorryPicture);
imageSpaces[imageCounter].add(lorryImage);
imageSpaces[imageCounter].revalidate();
imageSpaces[imageCounter].repaint();
imageCounter++;
}
Disclaimer 2: You should add a check, to only add a label if the count is less than the array length, as to avoid the ArrayIndexOutOfBoundsException
Side Notes
Swing apps should be run from the Event Dispatch Thread (EDT). You can do this by wrapping the code in the main in a SwingUtilities.invokeLater(...). See more at Initial Threads
You could also just use a JLabel and call setIcon, instead of using a JPanel
I am a beginer at programing and i wanted to add a scroll panel to a JTextArea so i tried to research tutorials online. i followed the examples but its not working can someone plz tell me what i am doing wrong. thank you so much
public View(Model model) {
this.model = model;
setBounds(100,50, 800, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container c = getContentPane();
addDisplay(c);
addButtons(c);
addTxt(c);
}
private void addDisplay(Container c){
JPanel p = new JPanel();
addTxt2(p);
addTxt(p);
add(p, "North");
}
private void addTxt(JPanel p){
txt = new JTextArea(15, 35);
txt.setBackground(Color.BLACK);
txt.setForeground(Color.WHITE);
txt.setEditable(true);
JScrollPane scroll= new JScrollPane (txt);
p.add(scroll);
}
Always invoke revalidate and repaint after adding any components to a JPanel
p.add(scroll);
p.revalidate();
p.repaint();
From the use of setBounds, it appears that there is no layout manager in use. Don't use absolute positioning (null layout). By default, components have a size of 0 x 0 so will not appear unless their size is set. A layout manager should be used here instead.
Post an SSCCE for better help sooner
You have to set the bounds of your scroll setBounds(int, int, int, int)
and define the area of your JTextArea
Here's an example:
public class ScrollingTextArea extends JFrame {
JTextArea txt = new JTextArea();
JScrollPane scrolltxt = new JScrollPane(txt);
public ScrollingTextArea() {
setLayout(null);
scrolltxt.setBounds(3, 3, 300, 200);
add(scrolltxt);
}
public static void main(String[] args) {
ScrollingTextArea sta = new ScrollingTextArea();
sta.setSize(313,233);
sta.setTitle("Scrolling JTextArea with JScrollPane");
sta.show();
}
}
I've found it here
I'm trying to add an ImageIcon to a panel through paintComponent, but it doesn't work. The panel i'm trying to add it to is set to a GridLayout. Could this be why? or is it being drawn over? Or my path could be set incorrectly... I've never
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Frame implements MouseListener, KeyListener {
JFrame f = new JFrame();
JPanel p = new JPanel();
JPanel[][] panel = new JPanel[10][10];
int k = 1;
Color previous;
ImageIcon icon = new ImageIcon("/Users/Admin/Desktop/stickFigure.jpg");
static String title = "Grid World";
public Frame(String s) {
f.setTitle(s);
p.setLayout(new GridLayout(10, 10));
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
panel[i][j] = new JPanel();
p.add(panel[i][j], i, j);
panel[i][j].addMouseListener(this);
panel[i][j].setBackground(Color.WHITE);
}
}
p.setSize(500, 500);
f.add(p);
f.setSize(490, 492);
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation(3);
f.addKeyListener(this);
f.setLocationRelativeTo(null);
}
public void paintComponent(Graphics g) {
icon.paintIcon(f, g, 100, 100);
}
You've got a paintComponent method in a class that does not extend JPanel, JComponent or any similar object, and thus it will never be called and serve no purpose. If you want paintComponent to work as intended, it must be in a class that extends JComponent or one of its children such as JPanel. And then you must use that JPanel in your GUI. Please read the Swing painting tutorials to see how to do this correctly.
Edit
Another way to display an ImageIcon is to simply add it to a JLabel and then display the JLabel in a Swing GUI.
Edit 2
Also, even if your class extended JPanel, it still wouldn't work since your icon is never added to anything. I've not seen graphics done as you're doing -- by calling the icon's paintIcon(...) method. I can't say that it's wrong; just that I haven't seen done this way.
I have a situation like this.
I have scrollpane whose viewportView is a JPanel
And that JPanel has the layout as BoxLayout. In this panel I add one class which extends JPanel and that class contains JComponents.
So while running an application, the JComponents are shown in the JScrollPane.
This is how my ScrollPane is formed.
The problem here is, When the data exceeds more than around 750 rows, The scrollbar starts giving problems.
When scrolling up or down by mouse wheel, scroll doesnot move smoothly, It suddenly stops in the middle and again starts, say it has a jerky movement.
my Question is how can i get the smooth mouse movement in this scenario.
My scrollPane is like this
public JScrollPane getScrollPane() {
if (scrollPane == null) {
scrollPane = new JScrollPane();
scrollPane.setSize(new Dimension(1000, 433));
scrollPane.setLocation(new Point(10, 10));
scrollPane.setColumnHeaderView(getHeaderOfRowPanel());
scrollPane
.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setViewportView(getScrollPanel());
scrollPane
.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.getVerticalScrollBar().setUnitIncrement(
unitIncrement);
}
return scrollPane;
}
private JPanel getScrollPanel() {
if (scrollPanel == null) {
scrollPanel = new JPanel();
scrollPanel.setBorder(null);
scrollPanel.setLayout(new BoxLayout(getScrollPanel(),
BoxLayout.Y_AXIS));
}
return scrollPanel;
}
private class RowPanel extends JPanel {
//My components are here ..
//I add this Panel in scrollPanel
}
Have look at JScrollBar.setUnitIncrement, beacuse bunch of JPanels in the JScollPane has un_natural scrolling in compare with JList, JTable or JTextArea
example
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class JScrollBarUnitIncrement {
public static void main(String[] args) {
final JFrame f = new JFrame("");
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2000, 1));
for (int i = 0; i != 2000; i++) {
JButton btn = new JButton("Button 2");
panel.add(btn);
}
final JScrollPane sPane = new JScrollPane(panel);
final int increment = 50;
sPane.getVerticalScrollBar().setUnitIncrement(increment);
KeyStroke kUp = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
KeyStroke kDown = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
sPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(kUp, "actionWhenKeyUp");
sPane.getActionMap().put("actionWhenKeyUp", new AbstractAction("keyUpAction") {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
final JScrollBar bar = sPane.getVerticalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue - increment);
}
});
sPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(kDown, "actionWhenKeyDown");
sPane.getActionMap().put("actionWhenKeyDown", new AbstractAction("keyDownAction") {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
final JScrollBar bar = sPane.getVerticalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue + increment);
}
});
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(sPane);
f.pack();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
f.setVisible(true);
}
});
}
private JScrollBarUnitIncrement() {
}
}
It is never good to populate such huge no. of rows in JScrollPane. Because, the visible portion is only around let's say 20 to 30 rows in viewport depending on the height of the scrollpane and the height of your RowPanel. So, why to populate such huge rows at once ? The problem with the smoothness is because there might be exception (see the console ). So, resolve this, I see two options for you. One is to use pagination and another is to allow users to enter some search criteria to filter out the unwanted records.
As #mKorbel notes, both JTable and JList implement Scrollable for convenient scroll increments, and they both use the flyweight pattern for rendering speed. If you can't use either component directly, you can still use the patterns. The tutorial includes Scrollable examples, and there's a CellRendererPane example here.
I'm trying to add several JLabels to a JPanel along with mouse listeners using a loop. These JLabels are going to have mouse listeners so that they change their icon when clicked (Using label.setIcon()). However, I only want to have one "selected" at a time. So, I need them to know when another label is clicked so it knows to turn itself off before the new label gets selected. However, my problem is that because I'm adding these labels with a loop they all have the same MouseListener.
Can anyone teach me a simple way to accomplish this?
This is a short example, how you could implement it (please note, that I didn't use the icon, but change the label instead):
public class MouseListenerExample extends JFrame {
public static class MyMouseListener extends MouseAdapter {
private static final Collection<JLabel> labels = new ArrayList<JLabel>();
private final JFrame frame;
public MyMouseListener(JFrame frame, JLabel label) {
this.frame = frame;
labels.add(label);
}
#Override
public void mouseClicked(MouseEvent e) {
for (JLabel label : labels) {
String text = label.getText();
if (text.startsWith("X ")) {
label.setText(text.substring(2));
}
}
JLabel currentLabel = (JLabel) e.getComponent();
currentLabel.setText("X " + currentLabel.getText());
}
}
public MouseListenerExample() {
super("MouseListener Example");
Container c = getContentPane();
c.setLayout(new FlowLayout());
for (int i = 0; i < 10; i++) {
JLabel jLabel = new JLabel("Label " + i);
c.add(jLabel);
jLabel.addMouseListener(new MyMouseListener(this, jLabel));
}
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new MouseListenerExample();
}
}
The main idea is, that you create a new MouseListener for each label, but keep a list of labels outside of each listener's scope (in this example I just use a static variable, but you could also have a field containing the list of labels in the frame.