In my app, I show a popup dialog to show a large list of cards. I display them as images in many JLabel components in a JPanel subclass. I then put that object in a JScrollPane to allow for horizontal scrolling through the cards.
I want the unused space to be transparent with a dark background to show that what's behind it is disabled. I used setBackground(new Color(50, 50, 50, 200)) to achieve the look I want, but the content behind it does not redraw, so I get artifacting.
Here's what it looks like:
How would I go about fixing this? How do I get the content behind it to redraw when I scroll?
Thanks in advance.
Taking the window out of the equation for the momement.
The JScrollPane contains a JViewport which then contains you content. So you need to set your content pane to transparent, the viewport to transparent and then the scroll pane to transparent.
You can achieve this by using setOpaque(false) on each of these containers.
This will ensure that the repaint manager will now paint through the background.
The next problem is, Swing doesn't actually support "semi-transparent" components (that is, either it's opaque or transparent).
You can implement this by overriding the paintComponent method of the main component (the one on the viewport is probably sufficient)
Try the following...might give you some relief during scrolling.
You likely also have a problem when the main frame is maximized
or restored. You will need a listener for those events and a
similar fix.
jScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(final AdjustmentEvent e) {
sevenWondersframe.repaint();
}
});
jScrollPane.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(final AdjustmentEvent e) {
sevenWondersframe.repaint();
}
});
Related
I'm working on a 2D game and am now stumped on a drawing issue. I'm repainting the JPanel with the background image and characters every frame, but the GUI is created in a setup function. I think that causes the JButton to appear behind the background image, and its worth mentioning this class extends JPanel. I'm using setBounds in order to arrange GUI elements a special way. What is a possible solution to this issue?
/** Draw game to the screen **/
private void gameDraw() {
Graphics g2 = this.getGraphics();
g2.drawImage(image, 0, 0 ,null);
g2.dispose();
}
public void SetupUI() {
uploadButton = new JButton("UPLOAD");
uploadButton.setBounds(WIDTH / 2, HEIGHT - 40, 50, 30);
uploadButton.setToolTipText("Press this button to upload your AI to the ship");
uploadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//TO DO: Make upload button compile and run the users code
}
});
this.add(uploadButton);
this.setVisible(true);
}
I decided to redo the code for rendering the game component. The issue seems to have been the GUI button and the image sharing the same screen space, then the image redrawing over the button each frame. What I was trying to go for was the gui overlaid over the image, but I still do not know how to achieve that.
Instead I created two separate JPanels, one to hold the GUI elements in a 'ribbon' above the image, and one to hold the image where neither panels are overlapping then packed both of those into another panel which was then assigned to the JFrame (feel like this is a scene from the Emperors New Groove lol) . Each panel has a layout assigned. The image in its own panel can now be rendered as frequently as needed without interfering with the gui. Just remember to draw whatever images you want in order e.g. draw the background, then the player.
I couldn't solve the original problem, but this is a decent workaround.
I know that this question might have been asked before, but I just can't get by head around this, and hopefully we could produce a complete answer to a somewhat tricky interface.
The GUI could be described as follows:
Application extends JFrame. Application adds a JPanel mPanel. mPanel adds a JScrollPane ml containing a MoviePanel extending JPanel.
The JScrollPane ml has vertical scrolling. My goal is that once the content of MoviePanel changes, and a run a revalidate() on it, the scroll pane should not, as it currently does, scroll to the bottom. Rather I'd like it to scroll to what ever position it had before the change to MoviePanel. Giving the feel that it never scrolled at all.
I have tried to manually set the scroll position after I run the revalidate() method:
removeAll(); // Removes all components from the JPanel MoviePanel
add(mList()); // Adds a bunch of content (other JPanels) to MoviePanel
revalidate();
ml.getVerticalScrollBar().setValue(0); // Scroll to top (don't work) - and I'd like this value to be the position of the scroll before these lines started to run
but it seems it really doesn't do anything.
I would be so grateful if someone might help me with this!
Add the scrolling code to a SwingUtilities.invokeLater:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
ml.getVerticalScrollBar().setValue(0);
}
});
I'm having a problem when an event will change the content of a component, like changing a JLabel's name, removing buttons from a Jpanel then adding another component.
Here is my initial JFrame.
Here is what my JFrame looks when components overlaps every time there is an event.
I'm using this code to temporarily solve my problem, but of course this is not a good idea by just resizing.
setSize(panelWidth + 1, panelHeight + 1);
setSize(panelWidth, panelHeight);
I'm wondering what causes this problem and how can I address this?
NOTE: I'm using layout manager. The panel with buttons is using Grid Layout and most of other is using Grid Bag Layout.
UPDATE:Removing setOpaque(true) fix the overlapping on the panel at top. What remains is the panel with the buttons. I'm using GridLayout with only 1 column.
Here is some of my code for displaying the buttons at pnlButtons.
private void initializeShoppingModeButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnManualInput);
pnlButtons.add(btnCheckOut);
}
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
}
one of possible issues is very simple code snipped
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
}
should be
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
pnlButtons.revalidate();
pnlButtons.repaint();
}
Swings APIs haven't any notifier that content of container is changed
e.g. JComponents are removed, removed and added, some kinds of relayout (change ordering of, e.i.)
revalidate(); and repaint(); will notify used LayoutManager, use that as last code lines, after all changes to Swing GUI are done
nothing cleaver without your SSCCE, MCVE/MCTRE
Edit 1st.
have look at use CardLayout for switching between views
Easy Java question here. I have made a custom JSlider which paints squares at the last location the user has moved the slider to. We override paintcomponent and draw the squares relative to the size of the slider. Everything works good when you use the slider properly. Problems happen though when you resize the frame. The slider grows bigger, and the slider adjuster moves with it, but our squares that we placed don't move relative to the slider. Which function should we use from JSlider to repaint when we resize the frame?
I am trying to keep the JSlider code separate from the frame code, so we want the user to be able to use our custom JSlider and not be trying to handle this resizing feature themselves. Any help on which method we should use for this?
Thanks.
You can add a ComponentListener to your slider that repaints it on componentResized.
slider.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
e.getComponent().repaint();
}
}
I am trying to figure out why my JComponent refreshes when I manually drag my window, but it doesn't refresh when I call repaint or revalidate. The data is ready to be displayed, but it just won't show until I manually resize. Can anybody give some suggestions about what I can do or does this sound like it isn't a Swing problem since I tried repaint and revalidate?
One weird things I've noticed is that if I have this code:
sp.setSize(sp.getSize().width, sp.getSize().height+1);
sp.setSize(sp.getSize().width, sp.getSize().height-1);
If the first line is used, then the JComponent will refresh itself. If I use none or both of these lines it will not, which seems bizarre to me.
I am basically just putting a JPanel in a JInternalFrame in a JDesktopPane. There are two main functions for what I am trying to do. One adds the new JPanel and the other tries to refresh it so the new data will show:
public void addNewSP()
{
sp = new JInternalFrame("SP");
sp.setClosable(true);
sp.setLocation(700, 400); //this should be changed to something based on screen size
sp.setResizable(true);
sp.add(popUp);
this.parentContainer.add(sp, JLayeredPane.DRAG_LAYER);
sp.pack();
sp.show();
sp.setSize(500, 500);
sp.setPreferredSize(new Dimension(500, 500));
}
public void refreshSP()
{
sp.repaint();
sp.validate();
sp.repaint();
sp.validate();
parentContainer.validate();
parentContainer.repaint();
sp.setSize(sp.getSize().width, sp.getSize().height+1);
sp.setSize(sp.getSize().width, sp.getSize().height-1);
}
}
BTW parentContainer is the JDesktopPane
When changing the container's content, you have to call both:
revalidate() to make it recompute the layout for its content
repaint() to request a repaint for this container
but it just won't show until I manually resize.
We don't know the context of your question, which is why a SSCCE should always be posted as suggested earlier.
In general a JComponent, does not have a preferred size, so I'm guessing Swing doesn't think it needs to paint the component. When you resize the frame, chances are the component was added to the center of a BorderLayout so it automatically gets sized to fill the entire space of the frame.
The solution is to give your component a "preferred size" so that any layout manager can use this information to display the component properly.
if your are modifying container's subcomponents you should call jcomponent.validate();
I assume parentContainer is the JDesktopPane?
What kind of changes are you making to sp that are not showing up?
Changing the size of sp will cause Swing to repaint from scratch. That's why the setSize() is fixing the display.
Most likely, the changes you are making are either not happening on the EDT, or are not invalidating the right container. For example, if you change the visibility of a component in sp, you'll need to call sp.invalidate() to rerun the layout manager.
Have you checked that you're only changing components (or their models) on the EDT?
A quick test for that is to run with the Substance LAF as it will complain if you change things on another thread.