JSlider won't show up unless the window is expanded - java

Hello im making a game using an MVC layout and cannot get the JSlider to become visible. It's working an fully functional, but will not show unless the window is expanded. Here is my method that creates the JSlider in GameView:
`public void startView() {
playerXPosition = 5; // Initializing the X position
playerYPosition = 80; // Initializing the Y position
score = 0;
tds = 0;
level = 1;
lives = 3;
MyPanel drawingWindow = new MyPanel();
drawingWindow.setSize(800, 500);
drawingWindow.setVisible(true);
this.add(drawingWindow);
SliderView jSlider = new SliderView();
jSlider.setSize(this.getWidth() / 4, 50);
jSlider.setAlignmentX((this.getWidth() / 2) - (this.getWidth() / 2));
jSlider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int tacklerspeed = jSlider.getValue();
getGameController().updateRatio(tacklerspeed);
System.out.println("Speed changed ");
System.out.println(tacklerspeed);
}
});
this.setSize(800, 700);
this.setVisible(true);
this.add(jSlider, BorderLayout.NORTH);
drawingWindow.setFocusable(true);
}`
And here's my SliderView class: `public class SliderView extends JSlider {
public SliderView() {
this.setEnabled(true);
this.setPaintTicks(true);
this.setMaximum(2);
this.setVisible(true);
this.setFocusable(false);
this.setValue(1);
this.setSnapToTicks(true);
}
}`

You look to be shooting yourself in the foot with your attempts to set sizes of things, but most important, you're calling setVisible(true) on the JFrame before adding the JSlider -- so it remains invisible until the next repaint (resize).
Get rid of all setSize's from your program. Instead let the components size themselves,
or override a getPreferredSize, but in a smart way that allows all components to fully show.
You're adding the slider to its container in the BorderLayout.NORTH position. Be sure that this container is in fact using a BorderLayout.
Be sure to call pack() on your top level window (a JFrame?) before displaying it.
MOST important -- call setVisible(true) on the JFrame after adding all components -- including the JSlider
You're also calling this.getWidth() before rendering your GUI components -- this will return a size of 0 -- test it out to see for yourself.

Related

Java swing setLocation / setSize not working for JPanel

So I have made a chess game where Inside the JFrame there is a boardPanel (chessboard) and a sidePanel (contains buttons like flipBoardButton).
The whole JFrame has a Dimension of 900x640 and the boardPanel therefore is 640x640.
public class BoardPanel extends JPanel{
private static final long serialVersionUID = 1L;
public BoardPanel() {
this.setSize(640, 640);
this.setLocation(0, 0);
}
#Override
public void paint(Graphics g){
boolean white = true;
for(int y = 0; y < 8; y++){
for(int x = 0; x < 8; x++){
if(white){
g.setColor(new Color(235, 235, 235));
}
else{
g.setColor(new Color(166, 123, 90));
}
g.fillRect(x*80, y*80, 80, 80);
white = !white;
}
white = !white;
}
for(Piece p : BoardHandler.piecesOnBoard)
{
Image image;
image = p.getImage();
g.drawImage(image, p.getX(), p.getY(), this);
}
}
}
My SidePanel should be on the right (at x=641 y=0) and have a width of 900-640=260 and a height of 640...
public class SidePanel extends JPanel{
public SidePanel()
{
this.setSize(260,640);
this.setLocation(641, 0);
}
#Override
public void paint(Graphics g) {
g.setColor(new Color(50,50,50));
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
}
}
This is how I implemented both the panels (usual stuff):
JFrame frame = new JFrame("Chess");
BoardPanel boardPanel = new BoardPanel();
SidePanel sidePanel = new SidePanel();
frame.add(boardPanel);
frame.add(sidePanel);
frame.setVisible(true);
And I thought everything is working because this is what I got:
BUT: when I go into SidePanel calss and change the setSize to 100x100 or when I set the Location to 700,0 , I get the SAME result !
However, when I change Location / Size in the BoardPanel class, it works perfectly fine ?! (the chessboard then gets rearranged/resized)
How is this possible when I used the "same" code for both classes !?
The whole JFrame has a Dimension of 900x640 and the boardPanel therefore is 640x640.
The frame and boardPanel can't possibly have the same height because the frame has a border and a titlebar. Don't attempt to set the size/location of components. That is the job of layout managers.
Many issues:
Swing components are responsible for determining their own size. So when you do custom painting you need to implement the getPreferredSize() method so the layout manager can do its job.
For the boardPanel is would be something like:
#Override
public Dimension getPreferredSize()
{
return new Dimension(640, 640);
}
By default a JFrame uses a BorderLayout. You do NOT specify a constraint when you add your components to the frame, so be default each component is added to the CENTER. However, only the last component is managed by the BorderLayout so it will set the size/location of the sidePanel, which is why your attempt to do so is ignored.
Because the BorderLayout ignores the chessBoard your attempt to set the size/location appears to work.
However you should not attempt to set the size/location. Let the layout manager do its job.
Instead your code should be:
frame.add(boardPanel, BorderLayout.CENTER);
frame.add(sidePanel, BorderLayout.LINE_START);
Custom painting is done by overriding the paintComponent(...) method, not paint() and you always invoke super.paintComponent(...) first to make sure the background of the panel is cleared.
Custom painting is relative to the component, not relative to its location in the frame.
The following code in your sidePanel class is wrong:
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
The getX()/getY() is wrong. If you really need to do custom painting then you should just use (0, 0).
However, there is no need to even use custom painting.
In the constructor of your class you just use:
setBackground( new Color(...) );
and the background will be painted automatically.

How to use multiple jpanels in the general jframe

I'm going to visualize the implementation of cluster analysis k-means and for this I use swing. There was a problem with the fact that the second jpanel (nodePanel), which was added, is not processed as it happens with clusters.
I tried to deal with the classes jframe and jpanel, as I understood it can be solved not at the level of multithreading, but then I had difficulties with the implementation of this idea.
public class MainUI extends JFrame {
JPanel canvas;
NodePanel nodePanel;
ClusterPanel clusterPanel;
public static boolean isPaintCluster;
MainUI(String title) {
super(title);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
init();
super.setSize(700, 540);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frm = super.getSize();
int xpos = (int) (screen.getWidth() / 2 - frm.getWidth() / 2);
int ypos = (int) (screen.getHeight() / 2 - frm.getWidth() / 2);
super.setLocation(xpos, ypos);
super.setVisible(true);
}
void init(){
this.setLayout(null);
canvas = new JPanel();
nodePanel = new NodePanel();
clusterPanel = new ClusterPanel();
nodePanel.addMouseListener(new NodeClickListener(nodePanel));
clusterPanel.addMouseListener(new ClusterClickListener(clusterPanel));
canvas.setBackground(Color.white);
canvas.setBounds(10,10,480,480);
nodePanel.setBounds(10,10,480,480);
clusterPanel.setBounds(10,10,480,480);
this.add(canvas);
this.add(clusterPanel);
this.add(nodePanel);
JPanel ButtonPanel = new JPanel();
JRadioButton radioButtonNodes = new JRadioButton("add Nodes");
radioButtonNodes.addActionListener(new isPaintNode());
JRadioButton radioButtonCluster = new JRadioButton("add Clusters");
radioButtonCluster.addActionListener(new isPaintCluster());
ButtonPanel.setLayout(null);
this.add(ButtonPanel);
ButtonPanel.setBounds(500,10,180,480);
ButtonPanel.add(radioButtonNodes);
radioButtonNodes.setBounds(0,200,120,20);
ButtonPanel.add(radioButtonCluster);
radioButtonCluster.setBounds(0,230,120,20);
}
class isPaintCluster implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(isPaintCluster){isPaintCluster = false;}
else {isPaintCluster = true;}
}
}
class isPaintNode implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(isPaintNode){isPaintNode = false;}
else {isPaintNode = true;}
}
}
}
I expect to get a solution in which the clusters and nodes will be independent as end classes, but in the application at each step of learning the position of the cluster will be redefined and the color of the nodes will also change according to the color of the cluster.
canvas.setBounds(10,10,480,480);
nodePanel.setBounds(10,10,480,480);
clusterPanel.setBounds(10,10,480,480);
this.add(canvas);
this.add(clusterPanel);
this.add(nodePanel);
Swing paints components in the reverse order the component is added to a panel. So the nodePanel is painted, then the clusterPanel is painted and finally the canvas panel is painted.
Since your panels have the same location and size, the canvas paints on top of the clusterPanel which paints on top of the nodePanel. So in reality you will only see the "canvas" panel.
You could try making all the panels non-opaque by using setOpaque( false ), but I would not recommend this approach.
Instead, I suggest you should only have a single panel and then you override the paintComponent() method of the panel to paint multiple objects on the panel.
Check out Custom Painting Approaches for an example of this approach.
I didn’t think of anything better than to combine the NodePanel and СlusterPanel classes into one class that will process the added nodes and clusters in the form.

JLayeredPane display problems

I am working on a little card game and I have been having some trouble: when I try to add dynamic components to my JLayeredPane it does not display them.
I have a custom component that represents a card and I want to display 2 of them in a layered fashion. For that I have the following class:
public class PairView extends JPanel {
private JLayeredPane layeredPane;
private CardView attackCard;
private CardView defenceCard;
private static Point origin = new Point(0, 0);
private static int offset = 10;
public PairView() {
}
public PairView(Card attackCard) {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(120, 170));
this.defenceCard = null;
this.attackCard = new CardView(attackCard);
this.attackCard.setOpaque(true);
this.attackCard.setForeground(Color.black);
this.attackCard.setBorder(BorderFactory.createLineBorder(Color.black));
this.attackCard.setBounds(origin.x, origin.y, 100, 150);
layeredPane.add(this.attackCard, 0);
this.origin.x += offset;
this.origin.y += offset;
}
public void addDefenceCard(Card defenceCard) throws DurakException {
if (this.defenceCard == null) {
this.defenceCard = new CardView(defenceCard);
this.defenceCard.setOpaque(true);
this.defenceCard.setForeground(Color.black);
this.defenceCard.setBorder(BorderFactory.createLineBorder(Color.black));
this.defenceCard.setBounds(origin.x, origin.y, 100, 150);
layeredPane.add(this.defenceCard, 1);
} else {
throw new DurakException("A defence Card is already present");
}
}
I tested this via the drag and drop interface in NetBeans and I have the following problem:
From what I understand, the default constructor is always called, so when I create 2 random CardView components and add them to the layered pane in the default constructor the parent JFrame display them just fine.
If I use the overwritten constructor or try to add another component (like the addDefenceCard method) it does not display the added component.
calling revalidate() or repaint() isn't doing anything.
How to get the components to show?
Your class extend JPanel, but you never add any components to the panel so there is nothing to display.
You need to add the JLayeredPane to the panel:
layeredPane = new JLayeredPane();
this.add( layeredPane );
I don't know if you need the set the layout to a BoxLayout. The default FlowLayout of the panel will respect the preferredSize of any component added to it.
this.attackCard.setOpaque(true);
this.attackCard.setForeground(Color.black);
this.attackCard.setBorder(BorderFactory.createLineBorder(Color.black));
You may want to consider setting these properties in the constructor of the CardView class. That way the default properties are set in one place and can easily be changed.
Instead of using a layered pane you may want to consider using the Overlap Layout. It was designed to support the requirement of overlapping components.

swing gui flickering white error

I have a Gui I'm making for a program that has an outer container centered to the JFrame that contains an inner container that holds 22*12 cells. When I run this program, the background just flickers white and stays like that. If you could point me out where I'm going wrong that would be awesome!
public class Gui extends JFrame
{
private JPanel outer, inner;
private JLabel[][] labels = new JLabel[22][12];
public Gui()
{
setBackground(Color.black);
setSize(1000,1000);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
outer = new JPanel();
outer.setLayout(new BorderLayout());
outer.setSize(620,920);
outer.setBackground(Color.white);
inner = new JPanel();
inner.setLayout(new GridLayout(22,12,10,10));
inner.setSize(600,900);
inner.setBackground(Color.white);
for (int i = 0; i < 22; i++)
{
for (int j = 0; j < 12; j++)
{
labels[i][j] = new JLabel();
JLabel label = labels[i][j];
label.setSize(50,50);
label.setBackground(Color.gray);
inner.add(label);
}
}
outer.add(inner, BorderLayout.CENTER);
add(outer, BorderLayout.CENTER);
}
}
The gui is set visible in the main class that instantiates it.
The gui is created and sized correctly. It starts out with a black background then randomly turns to white just after and stays like that.
EDIT: if this is still important:
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Gui gui = new Gui();
gui.setVisible(true);
}
});
}
Use the new static variable names which follow final static naming convention. That is the variable should be upper cased:
//setBackground(Color.black);
setBackground(Color.BLACK);
Don't use setSize() for components. Instead add the components to the frame and then use the pack() method so the components are displayed at their preferred size:
//setSize(1000,1000);
add(component1);
add(anotherComponent);
pack();
Layout managers use the preferred size not the size as a layout tip:
//label.setSize(50,50);
label.setPreferredSize(new Dimension(50, 50));
This is your main problem. A JLabel is transparent by default, so the background color you set is ignored:
label.setBackground(Color.gray);
label.setOpaque(true);
By the way, my screen height is only 738, so won't event be able to see you entire frame since you want a height of 22*50. You should be aware of this and probably add your panel to a JScrollPane so people like me can actually use your application. This is why you should not hardcode a preferred size.

Slide JPanel Content in a JForm on Java

I have a question. I want to make a swing form that, when clicking in a button he slides a panel (with his content) to the left so the panel on the right replaces it with a smooth effect.
I Have tried to do a while how checks the size of the panel and then minimize it and shows the next one like this :
while (jpanelprincipal1.getWidth() < 439 || jpanelprincipal1.getHeight() > 250)
{
int panel1width = jpanelprincipal1.getWidth();
int panel2height = jpanelprincipal1.getHeight();
jpanelprincipal1.setSize(panel1width -- , panel2height --);
jpanelprincipal2.setSize(440,250);
}
I used this trick in C# but with the Application.DoEvent(); (how obviously it's not available on java).
Is there anyway i can make a slide effect of 2 or more panels?
BTW : Sorry for my very bad english !
Thanks In Advance,
Luis Da Costa
he slides a panel (with his content) to the left so the panel on the right replaces it with a smooth effect
You question mentions you want the panel to "slide", but the code looks like you are trying to get the panel to "shrink", so it is replaced by another panel.
Assuming you have two panels each with the same size, then you can "slide" one out of view while the other slides into view.
To do this you an use a panel with a GridLayout. This way each component will be the same size. Then you add the panel to a scrollpane without any scrollbars. The size of the scrollpane will need to be set to the size of the first compnoent. Then you can "slide" the two panels by changing the position of the viewport. So in your Timer you would have code something like:
JViewport viewport = scrollPane.getViewport();
Point position = viewport.getViewPosition();
position.x += 5;
viewport.setViewPosition( position );
You would then stop the Timer when the position is greater than the size of the component.
As suggested by #HFOE, javax.swing.Timer is a good choice for animation. The setDividerLocation() method of JSplitPane can be called from the ActionListener. See How to Use Split Panes for additional options.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/** #see http://stackoverflow.com/questions/5069152 */
public class SplitPaneTest {
double ratio = 0.5;
double delta = ratio / 10;
private void create() {
JFrame f = new JFrame("JSplitPane");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel p1 = new MyPanel(Color.red);
MyPanel p2 = new MyPanel(Color.blue);
final JSplitPane jsp = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT, true, p1, p2);
Timer timer = new Timer(200, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ratio += delta;
if (ratio >= 1.0) {
ratio = 1.0;
delta = -delta;
} else if (ratio <= 0) {
delta = -delta;
ratio = 0;
}
jsp.setDividerLocation(ratio);
}
});
f.add(jsp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
timer.start();
}
private static class MyPanel extends JPanel {
Color color;
public MyPanel(Color color) {
this.color = color;
this.setPreferredSize(new Dimension(300, 300));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.drawLine(0, 0, getWidth(), getHeight());
g.drawLine(getWidth(), 0, 0, getHeight());
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new SplitPaneTest().create();
}
});
}
}
I would probably do this with a Swing Timer. Change a class field representing the x, y position of the sliding JPanel in the timer's ActionListener and then call repaint on the container holding the JPanels. A JLayeredPane could work well as the container for the sliding JPanels.
Edit 1: regarding your request for code, I think the best thing is for you to try to create a very small compilable runnable program that attempts to do this, and then post your code with an explanation of your program's behavior as an edit to your original post. Also send us a comment to notify us of your changes. Then we can inspect your code, test it, modify it, and help you mold it into a working program. This is called creating a "Short, Self Contained, Correct (Compilable), Example" or SSCCE (please check the link).

Categories