JScrollPane not repaint Canvas when scrolling? - java

I trying to make a game where I add a Canvas to a JScrollPane but the canvas is larger than the visible area of the JScrollPane. So when I scroll the JScrollPane to see the rest I only see the blank area even though my Canvas is continuously redrawn. Anybody can help me??

It is common JScrollPane problem. To fix this with minimum fuss, call the following methods on your JScrollPane:
scrollpane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);

Swing components do not work with heavyweight AWT components like Canvas. Use a JComponent or a JPanel instead of a Canvas

You need to use a lightweight JPanel and 2 heavyweight objects like:
JPanel foreground = new JPanel();
Panel frame = new Panel();
Cavas canvas = new Cavas();
foreground.add(frame);
frame.add(canvas);
Heavyweight objects might be AWT, or SWT (with OLE), or mixed, it does not matter.
Then get JScrollPane and add AdjustmentListener which calls method like:
private void updateLocation() {
final JScrollPane scroll = getScrollPane();
if (null == scroll) {
// do nothing
return;
}
final Point top = getLocation();
final Rectangle visible = getVisibleRect();
// set up new location
frame.setSize(visible.width, visible.height);
frame.setLocation(visible.x - top.x, visible.y - top.y);
canvas.setSize(getWidth(), getHeight());
canvas.setLocation(top.x - visible.x, top.y - visible.y);
}

Related

Make JScrollPanel dynamically resizable with JPanel drawing

I have a JScrollPanel and a JPanel added to it. I would like to draw to the JPanel and make the scrollbars of the JScrollPane appear whenever the drawing exceeds the size of the panel and be able to scroll the drawing both vertically and horizontally.
I have tried consulting with various forums and the official docs and tried a few things (setting the borders, the preferred size, etc.) but none seems to yield the desired effects.
I have a JFrame (with GridBagLayout, btw.) :
JFrame frame1 = new JFrame("Application");
frame1.setVisible(true);
frame1.setMinimumSize(new Dimension(580,620));
frame1.setResizable(false);
frame1.setLocationRelativeTo(null);
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
The relevant components are :
JPanel panel1 = new JPanel();
JScrollPane scrollPane = new JScrollPane(panel1);
frame1.add(scrollPane, gbc_panel1); //added with layout constraints
JPanel :
panel1.setBackground(Color.BLACK);
panel1.setPreferredSize(new Dimension(500,500));
panel1.setMinimumSize(new Dimension(360,360));
panel1.setMaximumSize(new Dimension(1000,1000));
JScrollPane :
scrollPane.setAutoscrolls(true);
The relevant code from the action event
of a button that does the drawing :
Graphics g;
g = panel1.getGraphics();
panel1.paint(g);
g.setColor(new Color(0,128,0));
/* this is followed by some more code that
does the drawing of a maze with g.drawLine() methods */
The code does the drawing perfectly, I just can't seem to figure it out how to make the scrolling and dynamic resizing happen.
I would appreciate any helpful comments or remarks!
Thank you!
Ultimately rewriting the paint method did the trick as #MadProgrammer suggested. I was just hoping that I could do the painting without having to define my custom JPanel class, but looks like it doesn't work that way.
The custom class looks like this:
class Drawing extends JPanel {
int mazeSize;
public Drawing(JTextField jtf)
{
try {
this.mazeSize = Integer.parseInt(jtf.getText());
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "ERROR! Invalid size value!");
}
} // the constructor gets the size of the drawing from a textField
public Dimension getPreferredSize() {
return new Dimension(mazeSize*10,mazeSize*10);
} //getPreferredSize - this method is used by the scroll pane to adjust its own size automatically
public void drawMaze (Graphics g)
{
/* some irrelevant code that does the desired drawing to the panel by calling g.drawLine()*/
} // drawMaze method that does the de facto drawing
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawMaze(g);
}// paintComponent() #Override method - this was the tricky part
}//Drawing JPanel subclass
It is also worth noting (if some noob like myself happens to stumble upon this question), that after instantiating the new JPanel subclass in the action event, I had to add it to the JScrollPanel in the following way, instead of just simply using its add() method:
Drawing drawPanel = new Drawing(textfield1);
scrollPane.getViewport().add(drawPanel);
Again, thanks for the suggestion!
Once finished with the program (a random maze generator that uses a recursive backtracking algorithm), I will make the source code available at my github profile.

Have to move screen to get JTextArea to appear

I have a desktop pane program where a user inputs data and a jtextarea appears with their results. Instead of having just the text area, i wanted to add it to a scroll pane, which i did. So I created a new scroll pane, and added the text area to it. Now, when I put in data the text area in the scroll pane does not appear until I move the page. In other words, everything works, but I have to move the page a little in order for the results and the scroll pane to show up on the screen.
Any ideas on why this is happening?
private JTextArea matchListResults = new JTextArea();
private JPanel matchPanelBase = new JPanel(new BorderLayout());
private JScrollPane mResults = new JScrollPane();
private void matchResFrame(String[] matchResultArray) throws IOException, SQLException {
Dimension size = new Dimension();
size.setSize(400, 300);
matchListResults.setPreferredSize(size);
matchListResults.setFont(font);
.
.
.
mResults.getViewport().add(matchListResults);
matchListResults.setVisible(true);
matchPanelBase.add(mResults, BorderLayout.CENTER);
}
When you add components to a visible GUI the basic code is:
panel.add(...);
panel.revalidate();
panel.repaint();
By default all components have a size of (0, 0) so there is nothing to paint. The revalidate() will invoke the layout manager which will determine the components size and location.
After you add the new components, call repaint() on the panel.
matchPanelBase.repaint();

Graphics are blocked out when I add a JPanel to the frame (java)

I have some Graphics2D graphics displayed in my frame, and then I added a JPanel to the entire frame so that I can add a mouselistener to clicks anywhere in the panel. However, the graphics disappear, I assume blocked out by the frame. I tried setting the panel to visible false, but that didnt do anything. How can I keep my mouselistener listening on the entire window, and still display my graphics?
EDIT:
Heres a bit of code: EDIT:(and some more)
//adding the panel and mouselistener
JPanel allPanel = new JPanel();
allPanel.addMouseListener(this);
frame.add(allPanel);
//...
//drawing some of the graphics
public void draw() {
frame.add(new CustomPaintComponent());
// Display the frame
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
JPanel allPanel = new JPanel();
allPanel.addMouseListener(this);
frame.add(allPanel);
}
static class CustomPaintComponent extends Component {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.fillRoundRect(10, 10, 50, 50, 10,10);
//...
Three problems jump out...
First, JFrame uses a BorderLayout as its default layout manager, this means that only one component can occupy any of its available five positions. By using add(Component) you add each component to the CENTRE position, overriding the first component you added to it...
Second, JPanel is opaque by default, meaning, even if you did get both components to occupy the same space, the top component would block the lower one
Third, you should be using paintComponent instead of paint
Take a look at Performing Custom Painting for more details
The solution could be to add the MouseListener directly to the custom component
Another choice would be to use a BorderLayout on the lower component, make the top component transparent (using setOpaque(false)) and add it to the lower component directly...
I believe your problem is that JFrame can have only one component added to it (by default). You add a CustomPaintComponent, which paints your graphics. Then, you add the JPanel, which automatically removes the CustomPaintComponent
Are you trying to paint the custom drawing on top of the JPanel? If that is the case, simply move that code over to the JPanel (but instead of using a CustomPaintComponent, put it in the paintComponent(Graphics g) method of the JPanel)

Swing: JScrollPane causing render issues

Sometimes (not always) when scrolling the bar of my JScrollPane, some of the components (usually the text ones like JLabels) don't repaint properly and they end up only being partially rendered.
I don't know why this is. I've tried invoking paint() inside of an AdjustmentListener, but that doesn't seem to help.
Any ideas?
EDIT: Initialization of the components
panel = new JPanel();
ImageIcon img = new ImageIcon("editor.png");
setIconImage(img.getImage());
initComponents();
final JScrollPane pane = new JScrollPane(panel);
this.setContentPane(pane);
//pane.setLayout(new ScrollPaneLayout());
//pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
Dimension dim = panel.getSize();
dim.height = dim.height - 100;
pane.setSize(dim);
this.setSize(dim);
AdjustmentListener hListener = new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
repaint();
for(Component c : panel.getComponents())
c.repaint();
for(Component c : pane.getComponents())
c.repaint();
panel.repaint();
panel.revalidate();
pane.repaint();
pane.revalidate();
}
};
pane.getVerticalScrollBar().addAdjustmentListener(hListener);
panel.setVisible(true);
pane.setVisible(true);
Violations of any of these basic principles can cause rendering artifact.
Verify that Swing GUI objects are constructed and manipulated only on the event dispatch thread.
Ensure that you honor the opacity property. In particular, JLabel is not opaque by default.
"Swing programs should override paintComponent() instead of overriding paint()."—Painting in AWT and Swing: The Paint Methods.
Addendum: Incorporating these dicta, this related example scrolls thousands of flashing JLabel instances without artifact.

JEditorPane inside JScrollPane not resizing as needed

I am implementing a Comment box facility in my application which user can resize using mouse. This comment box contains a scrollpane which instead contains a JEditorPane in which user can insert comment. I have added the editor pane inside a scroll pane for the following reason:
auto scolling of jeditorpane
When the user resizes the comment box, I am setting the desired size for JScrollPane and the JEditorPane. When the user is increasing the size of the comment box, the size of these components are increasing as desired but when the size of the comment box is decreased, the size of the JEditorPane does not decrease even after setting the size. This leads to the scrollbars inside the scrollpane.
I tried using setPreferrredSize, setSize, setMaximumSize for JEditorPane. Still the size of the editor pane is not reducing. I tried calling revalidate() or updateUI() after the setting of size but no use.
I am using Java 1.4.2.
Please provide me some insight....
I realise this is long since answered, but for future reference all you need to do is override the getScrollableTracksViewportWidth() to always return true, eg.
JEditorPane pane = new JEditorPane() {
public boolean getScrollableTracksViewportWidth() {
return true;
}
};
panel.add(new JScrollPane(pane));
Actually it is possible, luiscubal. Here is how,
To the JScrollPane add a ComponentListener for resize events
public static void main(String...args) {
//our test frame
JFrame frame = new JFrame("JEditorPane inside JScrollPane resizing");
frame.setLayout(new BorderLayout());
//our editing pane
final JEditorPane editor = new JEditorPane();
//our simple scroll pane
final JScrollPane scroller = new JScrollPane(editor);
//NOTE: this is the magic that is kind of a workaround
// you can also implement your own type of JScrollPane
// using the JScrollBar and a JViewport which is the
// preferred method of doing something like this the
// other option is to create a JEditorPane subclass that
// implements the Scrollable interface.
scroller.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
editor.setSize(new Dimension(
scroller.getWidth()-20,
scroller.getHeight()-20));
}
});
//just use up the entire frame area.
frame.add(scroller, BorderLayout.CENTER);
//quick and dirty close event handler
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(320, 240); //something not too big
frame.setLocationRelativeTo(null); //centers window on screen
frame.setVisible(true); // normally done in a SwingUtilities.invokeLater
}
Look luiscubal it is possible. Don't be so quick to announce things in Java as not possible. The swing api is quiet flexible and can do a lot of the work for you. However, if you use JComponents in ways they weren't made to be used you will end up with problems and have two options.
subclass subclass subclass basically create your own component.
find a work around, like the above solution.
Decreasing the size of a JEditorPane in a JScrollPane and then reducing it, is not possible.
You may want to use a JTextArea instead.

Categories