Swing components overlapping when content in changed - java

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

Related

Increase the thickness of the border of the focused area in swing

I have a problem with Java Swing and the LAF.
I am using JGoodies and I tried to increase the thickness of the border of the focused area. I tried it via the UIDefault but there is no such option. example of the Border Can you give me a hint how to set the border?
I saw this post: Change the color of the Java Swing Component Focus indicator but there is no solution to my problem.
example
This style depends on the L&F, if it supports the Table.border propriety or the Table.scrollPaneBorder.
In some cases, this property Table.scrollPaneBorder is enough but there aren't rules to have the table wrapped inside the scroll pane wrap table. In other words, you can have a table without a scroll panel.
if you have a table without scroll panel, the problem can be resolve from LookAndFeel, if your actual L&f doesn't have this support, the solutions are multiple, such as:
Use another l&f. such as Material-ui-swing, the table.border is under the developing branch, you can compile the source.
Develop a personal TableUI to set the border inside the UI such as the point one
you can wrapper your table inside a scroll pane, but it should respect the L&f rules.
1. Implement the Table UI. (from material-ui-swing)
insert a Border inside the propriety Table.border, such as:
UiManager.put("Table.border", new BorderUIResources(YOUR_BORDER));
You need to wrap the border inside the BorderUIResource because, if you implement the switch L6f inside your APP, Swing doesn't remove the propriety without the UIResource interface.
public class MaterialTableUI extends BasicTableUI {
public static ComponentUI createUI (JComponent c) {
return new MaterialTableUI();
}
#Override
public void installUI (JComponent c) {
super.installUI (c);
table.setBorder(UIManager.getBorder("Table.border"));
}
}
This answer makes an overview of all possible solutions that exist if the table is unwrapped from the Scroll Pane. In fact the propriety Table.scrollPaneBorder should be work fine
Example with material-ui-swing
set border
UIManager.put("Table.border", BorderFactory.createLineBorder(MaterialColors.COSMO_BLACK, 5));

Set the vertical scroll to current position after revalidate

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);
}
});

changing text of jLabel in a draggable jPanel

In my program, I have a jPanel with a jLabel inside of it. I added this code to make the jPanel draggable, and it works perfectly.
private void formMousePressed(java.awt.event.MouseEvent evt) {
prevX = evt.getXOnScreen();
}
private void formMouseDragged(java.awt.event.MouseEvent evt) {
this.setLocation(this.getX() + evt.getXOnScreen() - prevX, this.getY());
prevX = evt.getXOnScreen();
// this.labBirthDate.setText(Integer.toString(this.getX()));
}
However, when I added the commented-out code, which updates the label to show the position of the panel, it's stopped working. Specifically, when I click and drag to move the panel, instead of following the mouse, the panel just sort of stutters, and the text changes to a value of ~10, changing whenever I move the mouse.
Making things ever more confusing, if I instead change it so that it just sets the text to "blah", it doesn't produce the error. As well, if I just set a variable to be equal to this.getX(), it doesn't produce the error. If I then set the label to be the value of that local variable, the error comes back.
Does anyone know why this might be happening? Is there a workaround I can use to get the same effect?
When you invoke the setText() method on the label the revalidate() and repaint() methods are invoked on the label. This will cause the layout manager to be invoked and I'm guessing the layout manager will reset the panel to its default position.
If you want to be able to randomly move components around a screen then you need to use a null layout on the parent of the panel that is being dragged. Once you do this you will also need to manually set the size and location of your components.
You might find the Drag Layout handy to use in this case.

JScrollPane with transparent background and content

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();
}
});

The contents of my JComponent only refresh after a manual resize

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.

Categories

Resources