I' m trying to change the displayed value(selected variable) to what the slider is in line with. The main issue is the worksheet I'm working from specifies this
"The displaySelected method is responsible for displaying just the selected item. Look at it,and work out why it is always element 0 that is displayed – it is something quite simple, and not something complex."
I understand that the change of display requires the variable selected, I've already tried ( g.drawString(names[selected], 200, 150);) but the issue with this is that it only does value 4 of the array and resets to 0 once moved and doesn't, I know that I have to change the value of selected then, I've tried selected = selector.getValue(); but I'm returned with a null error.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* A simple address database for Practical 5B
* Demonstrates arrays, graphics, selection.
*/
public class Addresses extends JFrame
implements ChangeListener
{
/**
* Frame coordinate constants
*/
private static final int FRAME_X = 200;
private static final int FRAME_Y = 200;
/**
* Frame size constants
*/
private static final int FRAME_WIDTH = 500;
private static final int FRAME_HEIGHT = 400;
/**
* The slider for selecting an address record (selectable 0 to size-1).
*/
private JSlider selector;
/**
* Array to hold the database.
*/
private String[] names;
/**
* To indicate which entry is currently selected.
*/
private int selected;
/**
* The drawing panel for display of information.
*/
private JPanel panel;
/**
* Drawing panel size constants
*/
private final int PANEL_WIDTH = 400;
private final int PANEL_HEIGHT = 300;
/**
* The main program launcher for the Addresses class.
*
* #param args The command line arguments (ignored here).
*/
public static void main( String[] args )
{
Addresses frame = new Addresses();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setUpData(); // Initial data set-up
frame.createGUI(); // Initial GUI set-up
frame.setVisible( true );
}
/**
* Sets up the graphical user interface.
*/
private void createGUI()
{
setDefaultCloseOperation( EXIT_ON_CLOSE );
Container window = getContentPane();
window.setLayout( new FlowLayout() );
// Slider for selecting an address entry
selector = new JSlider(JSlider.VERTICAL, 0, 0, 0);
// Note: the useable range of the slider is 0 - 0 at the moment!
window.add(selector);
selector.addChangeListener(this);
// Graphics panel for displaying the address list
panel = new JPanel()
{
// paintComponent is called automatically when a screen refresh is needed
public void paintComponent(Graphics g)
{
// g is a cleared panel area
super.paintComponent(g); // Paint the panel's background
paintScreen(g); // Then the required graphics
}
};
panel.setPreferredSize( new Dimension( PANEL_WIDTH, PANEL_HEIGHT ) );
panel.setBackground( Color.white );
window.add( panel );
}
/**
* Helper method to set up the array data, and the associated variable selected,
* with their initial configuration.
*/
private void setUpData()
{
// All the data is "built-in": set it up here - just one entry at the moment
names = new String[6]; // Create the array with space for one entry
names[0] = "James"; // The entry
names[1] = "Connor";
names[2] = "Alfred";
names[3] = "Billy";
names[4] = "Jack";
names[5] = "Chris";
selected = names.length-1; // Indicate that entry 0 is selected
}
/**
* This methods redraws the screen.
*/
private void paintScreen(Graphics g)
{
displayList(g);
displaySelected(g);
}
/**
* Display all the elements of array names in a column on the screen.
*/
private void displayList(Graphics g)
{
int y = 100; // Top y coordinate of the column
g.setColor(Color.black);
/*
g.drawString(names[0], 20, y);
g.drawString(names[1], 20, y+25);
g.drawString(names[2], 20, y+50);
g.drawString(names[3], 20, y+75);
g.drawString(names[4], 20, y+100);
g.drawString(names[5], 20, y+125);
*/
for (int i = 0; i< names.length; i++)
g.drawString(names[i], 20, y+25*i);
}
/**
* Display the single element of array names that is currently selected by the slider.
*/
private void displaySelected(Graphics g)
{
g.setColor(Color.black);
g.drawString("Current selection is:", 200, 135);
g.drawString(names[selected], 200, 150);
}
/**
* Reacts to adjustment of the slider.
* Notes the new selector setting, then forces screen refresh.
*/
public void stateChanged( ChangeEvent e )
{
// selector has been adjusted: record the new setting
selected = selector.getValue();
repaint(); // Refresh the screen
}
}
You never set the maximum value for the slider. That's why you can't move it. Make this change to your code, then you will be able to debug the rest of this program.
selector = new JSlider(JSlider.VERTICAL, 0, names.length-1 /* HERE */ , 0);
Related
I am working in a Java desktop game where I am trying to display some panels composed by a JTable with a JScrollPane, which has only one column and several rows, containing the data I want to display. This panels are not visible when the application starts, because they are shown depending on the JButton pressed.
When I start my application, these panels are already added to the frame, but not visible. At the moment I try to display them by pressing the corresponding button, they are shown, but not all the rows are visible. If I press the button again, the panel is hidden, and if I press again the button to display it again, now it is shown with all its rows visible.
For some reason, just by setting its visibility to true -> false -> true by pressing the corresponding button, the JTable of the panel displays all its rows, but when I display it the first time, it doesn't... I need to do it twice.
To check this, I try to set the panel visibility to true -> false -> true when the application starts programmatically, but it doesn't works. It only works if I press the button that displays the panel (remember, twice, the first time it doesn't shows all the rows, the second time it does). Also, I've checked by debugging if, at the moment I set the panel visibility to true the first time, it has all the data inside, and it is correct, so it is something just only graphic, because the data is there. Also I realized that by scrolling with the mouse the first time I show the panel, it shows all the data, so I guess it must be refreshing something when I scroll, or when I show the panel for the second time I press the corresponding button.
I've tried to revalidate() and repaint() the table, to fireTableDataChanged() and fireTableStructureChanged() the model of the table. Also I've created a thread which starts at the same time the application starts, which sets the visibility of these panels to true and false at the beginning, and revalidating the tables, just to try to see what could be happening when showing/hidding the panels.
After create this thread, I realized that if I set the visibility of this panels to true from the beginning, I see how the UI thread "refresh" the panels in some way, as I can see them uncomplete, and after complete, in a split second. But after, I have to close them manually, because I cannot control (I tried) the time needed to see them filled before close them.
Here is a picture of the panel when I setVisible(true) one of these panels:
And here is the picture of the same panel when I hide and show it again (manually), without perform any other actions:
Here is the code of the table model set in the JTable of the panel:
/**
* Class to create the model instance for the selector panel list
*/
public class CustomTableModelForPredefinedMessagesSelectorKeyboard extends DefaultTableModel {
private ArrayList selectedList = new ArrayList<>();
public CustomTableModelForPredefinedMessagesSelectorKeyboard() {
this.addColumn(LanguageConfiguration.getLanguageSelected().getString("selection"));
//setListType(ListType.PREDEFINED_MESSAGES);
setListType();
}
/**
* Function to get the size of the list
*
* #return the list size
*/
//#Override
public int getSize() {
return selectedList.size();
}
/**
* Function to get the element of a specific index from the list
*
* #param index index of the message to be retrieved
* #return the message text of the corresponding index
*/
public Object getElementAt(int index) {
return selectedList.get(index).toString();
}
public ArrayList getSelectedList() {
return selectedList;
}
public void setSelectedList(ArrayList selectedList) {
this.selectedList = selectedList;
}
/**
* Function to set the list of the selector panel according to the list type selected
*/
#SuppressWarnings("unchecked")
public void setListType() {
selectedList.add("selectorPanel_PredefMsg_EnemyOnSight");
selectedList.add("selectorPanel_PredefMsg_GreenAlert");
selectedList.add("selectorPanel_PredefMsg_HowAreYou");
selectedList.add("selectorPanel_PredefMsg_InminentAttack");
selectedList.add("selectorPanel_PredefMsg_No");
selectedList.add("selectorPanel_PredefMsg_Positioned");
selectedList.add("selectorPanel_PredefMsg_Ready");
selectedList.add("selectorPanel_PredefMsg_RedAlert");
selectedList.add("selectorPanel_PredefMsg_ReturnToBase");
selectedList.add("selectorPanel_PredefMsg_TargetOutOfReach");
selectedList.add("selectorPanel_PredefMsg_WaitingOrders");
selectedList.add("selectorPanel_PredefMsg_WeHaveAProblem");
selectedList.add("selectorPanel_PredefMsg_YellowAlert");
selectedList.add("selectorPanel_PredefMsg_Yes");
for (Object string : selectedList)
this.addRow(new Object[]{LanguageConfiguration.getLanguageSelected().getString((String) string)});
if (SwingInterfaceSubJPanels.getPredefinedMessagesSelectorJPanel() != null)
for (Component component : SwingInterfaceSubJPanels.getPredefinedMessagesSelectorJPanel().getComponents())
if (component instanceof JScrollPane) {
JScrollPane messagesListScrollPane = (JScrollPane) component;
JViewport viewport = messagesListScrollPane.getViewport();
preselectFirstElement((CustomJTable) viewport.getView());
break;
}
}
/**
* Function to pre-select the firs item of the list in the selector list
*
* #param customJTable the table where the selection will be performed
*/
private void preselectFirstElement(CustomJTable customJTable) {
if (customJTable.getRowCount() > 0)
customJTable.getSelectionModel().setSelectionInterval(0, 0);
}
}
And here is the code of the panel:
/**
* Class to create and manage a selector keyboard
*/
public class PredefinedMessagesSelectorKeyboard extends JPanel {
/**
* Color of shadow
*/
private final Color shadowColor;
/**
* Double values for Horizontal and Vertical radius of corner arcs
*/
private final Dimension arcs;
/**
* Variables to get the coordinates of the mouse on mouse click event over the jpanel
*/
private int xJPanelCoord, yJPanelCoord;
Component componentToManage;
SelectorConfirmationController.Type selectorPanelType;
/**
* Constructor to create the selector panel structure and add its components
*/
public PredefinedMessagesSelectorKeyboard() {
DisplayMode displayMode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode();
double screenWidth = displayMode.getWidth();
double screenHeight = displayMode.getHeight();
this.setPreferredSize(new Dimension((int) Math.round(screenWidth * 0.35), (int) Math.round(screenHeight * 0.6)));
//this.setBackground(new java.awt.Color(5, 122, 122));
this.setBackground(new Color(150, 150, 150));
addSelectorPanelComponents();
setVisible(false);
setOpaque(false);
makeJPanelDraggable();
shadowColor = Color.black;
arcs = new Dimension(100, 100);
}
/**
* Function to add the components of the JPanel
*/
private void addSelectorPanelComponents() {
this.setLayout(new GridBagLayout());
addSelectorPanelJTable();
addSelectorPanelButtons();
addSelectorPanelCloseJButton();
}
/**
* Function to add the panel with the elements available for selection
*/
private void addSelectorPanelJTable() {
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 4;
gridBagConstraints.gridheight = 2;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.insets = new Insets(40, 20, 20, 0);
CustomTableModelForPredefinedMessagesSelectorKeyboard customTableModelForPredefinedMessagesSelectorPanelList = new CustomTableModelForPredefinedMessagesSelectorKeyboard();
CustomJTable predefinedMessagesselectorPanelJTable = new CustomJTable(customTableModelForPredefinedMessagesSelectorPanelList);
predefinedMessagesselectorPanelJTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
predefinedMessagesselectorPanelJTable.setName("predefinedMessagesSelectorPanelJTable");
JScrollPane selectorJTableJScrollPane = new JScrollPane(predefinedMessagesselectorPanelJTable);
selectorJTableJScrollPane.getViewport().setBackground(new Color(24, 27, 34));
add(selectorJTableJScrollPane, gridBagConstraints);
}
/**
* Function to add the close panel button and the selection confirmation button
*/
private void addSelectorPanelButtons() {
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 4;
gridBagConstraints.gridy = 1;
gridBagConstraints.insets = new Insets(20, 20, 0, 20);
JButton selectPreviousButton = createScaledSwingShapedButton("/images/boton_popup_panel_selector_anterior.png",
"/images/boton_popup_panel_selector_anterior_seleccionado.png");
selectPreviousButton.setName("selectorPanelPreviousButton");
selectPreviousButton.setToolTipText(LanguageConfiguration.getLanguageSelected().getString("tooltipTextPreviousButton"));
selectPreviousButton.addActionListener(e -> {
for (Component component : getComponents())
if (component instanceof JScrollPane) {
JScrollPane messagesListScrollPane = (JScrollPane) component;
JViewport viewport = messagesListScrollPane.getViewport();
selectPrevious((CustomJTable) viewport.getView());
break;
}
});
JButton confirmSelectedButton = createScaledSwingShapedButton("/images/boton_popup_panel_selector_confirmar.png",
"/images/boton_popup_panel_selector_confirmar_seleccionado.png");
confirmSelectedButton.setName("selectorPanelConfirmButton");
confirmSelectedButton.setToolTipText(LanguageConfiguration.getLanguageSelected().getString("tooltipTextConfirmButton"));
confirmSelectedButton.addActionListener(new SelectorConfirmationController(componentToManage, selectorPanelType));
JButton selectNextButton = createScaledSwingShapedButton("/images/boton_popup_panel_selector_siguiente.png",
"/images/boton_popup_panel_selector_siguiente_seleccionado.png");
selectNextButton.setName("selectorPanelNextButton");
selectNextButton.setToolTipText(LanguageConfiguration.getLanguageSelected().getString("tooltipTextNextButton"));
selectNextButton.addActionListener(e -> {
for (Component component : getComponents()){
if (component instanceof JScrollPane){
JScrollPane messagesListScrollPane = (JScrollPane) component;
JViewport viewport = messagesListScrollPane.getViewport();
selectNext((CustomJTable) viewport.getView());
break;
}
}
});
JPanel lateralButtonsPanel = new JPanel();
lateralButtonsPanel.setLayout(new BoxLayout(lateralButtonsPanel, BoxLayout.Y_AXIS));
lateralButtonsPanel.setOpaque(false);
lateralButtonsPanel.setName("lateralButtonsPanel");
lateralButtonsPanel.add(selectPreviousButton);
lateralButtonsPanel.add(confirmSelectedButton);
lateralButtonsPanel.add(selectNextButton);
add(lateralButtonsPanel, gridBagConstraints);
}
/**
* Function to create and add the close panel button to the panel
*/
private void addSelectorPanelCloseJButton() {
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 4;
gridBagConstraints.gridy = 0;
//gridBagConstraints.anchor = GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new Insets(20, 20, 0, 20);
JButton closeMessagesConsoleButton = createScaledSwingShapedButton("/images/boton_consola_mensajes_2.png",
"/images/boton_consola_mensajes_2_seleccionado.png");
closeMessagesConsoleButton.setName("selectorPanelCloseButton");
closeMessagesConsoleButton.setToolTipText(LanguageConfiguration.getLanguageSelected().getString("tooltipTextClosePanelButton"));
//closeMessagesConsoleButton.addActionListener(e -> setVisible(false));
closeMessagesConsoleButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
/*if (getComponentToManage().getName().equals("messageBoxTable"))*/
SwingInterfaceSubJPanels.getMainScreenUpperInformationLabel().setVisible(false);
setVisible(false);
}
});
add(closeMessagesConsoleButton, gridBagConstraints);
}
/**
* Function to select the next item of the list in the selector list
* #param customJTable the table where the selection will be performed
*/
private void selectPrevious(CustomJTable customJTable){
if (customJTable.getSelectedRow() > 0) {
customJTable.getSelectionModel().setSelectionInterval(customJTable.getSelectedRow() - 1, customJTable.getSelectedRow() - 1);
customJTable.scrollRectToVisible(new Rectangle(customJTable.getCellRect(customJTable.getSelectedRow()-1, 0, true)));
}
}
/**
* Function to select the next item of the list in the selector list
* #param customJTable the table where the selection will be performed
*/
private void selectNext(CustomJTable customJTable){
if (customJTable.getSelectedRow() >= 0 && customJTable.getSelectedRow() < customJTable.getRowCount()-1) {
customJTable.getSelectionModel().setSelectionInterval(customJTable.getSelectedRow() + 1, customJTable.getSelectedRow() + 1);
customJTable.scrollRectToVisible(new Rectangle(customJTable.getCellRect(customJTable.getSelectedRow()+1, 0, true)));
}
}
public Component getComponentToManage() {
return componentToManage;
}
public void setComponentToManage(Component componentToManage) {
this.componentToManage = componentToManage;
}
public SelectorConfirmationController.Type getSelectorPanelType() {
return selectorPanelType;
}
public void setSelectorPanelType(SelectorConfirmationController.Type selectorPanelType) {
this.selectorPanelType = selectorPanelType;
}
/**
* Function to create and return a scaled swing shaped button with its corresponding images
*
* #param buttonImage button image when the button is not pressed
* #param buttonPressedImage button image when the button is pressed
* #return the button already built
*/
private JButton createScaledSwingShapedButton(String buttonImage, String buttonPressedImage) {
Image scaledImage;
try {
SwingShapedButton swingShapedButton = new SwingShapedButton();
JButton newButton = (JButton) swingShapedButton.createComponent(SwingShapedButton.ButtonShape.ROUND);
Image imageButton = ImageIO.read(getClass().getResource(buttonImage));
scaledImage = scaleImage(imageButton);
newButton.setIcon(new ImageIcon(scaledImage));
Image imageButtonPressed = ImageIO.read(getClass().getResource(buttonPressedImage));
scaledImage = scaleImage(imageButtonPressed);
newButton.setPressedIcon(new ImageIcon(scaledImage));
return newButton;
} catch (IllegalArgumentException | IOException e) {
e.printStackTrace();
DataBase.database.insertSystemErrorLog(Thread.currentThread().getStackTrace()[1].getMethodName(), e);
return (JButton) new SwingShapedButton().createComponent(SwingShapedButton.ButtonShape.ROUND);
}
}
/**
* Function to scale the images of the buttons according to the screen resolution
*
* #param imageButton the image to be set to the button
* #return the image resized
*/
private Image scaleImage(Image imageButton) {
return imageButton.getScaledInstance((int) Math.round(((BufferedImage) imageButton).getWidth() * InterfaceControlsManager.getWidth_percentage()),
(int) Math.round(((BufferedImage) imageButton).getHeight() * InterfaceControlsManager.getHeight_percentage()),
Image.SCALE_SMOOTH);
}
/**
* Function to allow the panel to be draggable over the frame
*/
private void makeJPanelDraggable() {
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
xJPanelCoord = e.getX();
yJPanelCoord = e.getY();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int x = e.getXOnScreen() - xJPanelCoord;
int y = e.getYOnScreen() - yJPanelCoord;
setLocation(x, y);
}
});
}
/**
* Function to set the appearance of the panel
*
* #param g the graphics to be set
*/
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
/*
Distance between shadow border and opaque panel border
*/
int shadowGap = 5;
int shadowAlpha = 10;
Color shadowColorA = new Color(shadowColor.getRed(),
shadowColor.getGreen(), shadowColor.getBlue(), shadowAlpha);
Graphics2D graphics = (Graphics2D) g;
//Sets antialiasing if HQ.
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//Draws shadow borders if any.
int strokeSize = 1;
boolean shady = true;
graphics.setColor(shadowColorA);
int shadowOffset = 4;
graphics.fillRoundRect(
shadowOffset,// X position
shadowOffset,// Y position
width - strokeSize - shadowOffset, // width
height - strokeSize - shadowOffset, // height
arcs.width, arcs.height);// arc Dimension
//Draws the rounded opaque panel with borders.
graphics.setColor(getBackground());
graphics.fillRoundRect(0, 0, width - shadowGap,
height - shadowGap, arcs.width, arcs.height);
graphics.setColor(getForeground());
graphics.setStroke(new BasicStroke(strokeSize));
graphics.drawRoundRect(0, 0, width - shadowGap,
height - shadowGap, arcs.width, arcs.height);
//Sets strokes to default, is better.
graphics.setStroke(new BasicStroke());
}
}
Can someone explain to me why I see this effect in the panel? There is some reason why the JTable doesn't show its data the first time I setVisible(true) the panel, but it is displayed properly the second time? Could be something with the UI, or maybe I am not realizing about something here?
Thanks for any comment you can give me!
I am trying to create a program in Java that is sort of like a board game. I have gameTiles, currently with only one color as I try to get the layout right. I want the tiles to appear about halfway of the width of the window and extend to the bottom, maybe anywhere from 9x9 or 11x11 different tiles. I have tried to use the grid layout to get these to be close together, not necessarily touching but close enough to look like a board game. However, no matter what I try, the tiles are space so far apart, and change shape when I resize window. I have been using the GridLayout manager to try to achieve this. Here is my code.
import java.awt.GridLayout;
import javax.swing.JFrame;
public class GameWindow extends JFrame {
public GameWindow(String title){
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1200,400);
}
/**
* #param args
*/
public static void main(String[] args) {
GameWindow gameWindow = new GameWindow("Game");
gameWindow.setLayout(new GridLayout(0,2));
GameTile greenTile = new GameTile(0,true,0,10);
GameTile greenTile2 = new GameTile(0,true,0,10);
gameWindow.add(greenTile);
gameWindow.add(greenTile2);
gameWindow.setVisible(true);
}
}
This is the GameWindow.java file. The GameTile.java I have so far (which is still mainly not finished just for testing) is as follows:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
/**
* #author Zachary Parks
*
*/
public class GameTile extends JPanel {
private Color color;
private Color[] colors = {Color.BLUE, Color.YELLOW, Color.BLACK};
private int score, multiplier,initialX,initialY;
private boolean positiveEffect;
public GameTile(int colorTile, boolean effect, int initX, int initY){
color = colors[colorTile];
score = getScore(color);
multiplier = getMultiplier(color);
positiveEffect = effect;
initialX = initX;
initialY = initY;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Image image = null;
try {
image = ImageIO.read(new File("greentile.png"));
} catch (IOException e) {
e.printStackTrace();
}
g.drawImage(image,initialX,initialY,this);
}
private int getMultiplier(Color color2) {
return 0;
}
private int getScore(Color color2) {
return 0;
}
/**
* Method that returns the data from the tile in
* array of int. 0 index = added score, 1 index = tile effect score
* #return
*/
public int[] getData() {
int [] scoreData = null;
scoreData[0] = score*multiplier;
return null;
}
}
A lot of the code is still in progress, like the GameTile's properties, all I'm trying at this point is get the tiles next to each other.
This is what I am getting:
To add tiles like a grid. A tileSize variable is great to have. Let's say the image/tile is 32 pixels.
public static final tileSize = 32;
With this, we can now add tiles using a for loop:
for(int x = 0; x < SCREEN_WIDTH / GameTile.tileSize; x++) { // loop through as many tiles fit the x-axis.
for(int y = 0; y < SCREEN_HEIGHT / GameTile.tileSize; y++) { // do the same with y-axis
GameTile greenTile = new GameTile(0,true, x * GameTile.tileSize , y * GameTile.tileSize);
gameWindow.add(greenTile);
}
}
SCREEN_WIDTH and SCREEN_HEIGHT is the size of your JFrame.
Keep in mind this loops through the whole screen, you wanted the half but it's easily configurable.
Please format your code next time (tab in), much easier to read and help you.
I highly recommend moving image = ImageIO.read(new File("greentile.png")); into the constructor, right now you're loading the image every framerate for every gameTile which will cause performance drop.
Also do not have a JPanel for every GameTile. Instead keep it in your main drawing class and loop through all GameTiles using an ArrayList
public static ArrayList<GameTile> gameTiles = new ArrayList<GameTile>();
protected void paintComponent(Graphics g) {
for(int i = 0; i < gameTiles.size(); i++) {
gameTiles.get(i).draw(g);
}
So instead of adding a JPanel to the JFrame for every gameTile, we draw gameTiles at the specified coordinates. Good luck!
To answer your question in the comment field: the code will look similar to this
public class GameWindow extends JPanel {
public static ArrayList<GameTile> gameTiles = new ArrayList<GameTile>();
public static void main(String[] args) {
new GameWindow();
}
public GameWindow() {
JFrame frame = new JFrame();
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.setVisible(true);
// add all the tiles (I just use x and y as parameters here)
gameTiles.add(new GameTile(10, 10));
gameTiles.add(new GameTile(50, 10));
}
public void paintComponent(Graphics g) {
for(int i = 0; i < gameTiles.size(); i++) {
gameTiles.get(i).draw(g);
}
}
}
And inside your GameTile class, remove the extends JPanel. And rename the paintComponent as draw or something alike.
However, no matter what I try, the tiles are space so far apart, and change shape when I resize window
A GridLayout expands each cell to fill the space available to the component. If you only have two cells each cell will take up half the width of the frame.
So the solution is to wrap your tile panel into another panel that will respect the preferred size of the tiles. So don't set the layout of the frame, set the layout of a panel holding the tiles:
Something like:
JPanel tilePanel = new JPane( new GridLayout(0, 2, 5, 5) );
tilePanel.add( new GameTile(...) );
tilePanel.add( new GameTile(...) );
JPanel wrapper = new JPanel( new GridBagLayout() );
wrapper.add(tilePanel, new GridBagConstraints() );
frame.add(wrapper, BorderLayout.CENTER );
The above code will cause the tiles to be centered in the frame.
frame.add(wrapper, BorderLayout.LINE_END);
The above will cause the tiles to display on the right of the frame vertically centered.
I am getting a cannot find symbol- method occupant(int) at the bottom of the code (line 150) probably missing something simple but cannot fix it. Only need help with this part, the program is far from incomplete.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Accommodation extends JFrame
implements ActionListener
{
/** Window layout constants (these need to be "static" to be referred to in main) */
private static final int panelWidth = 700;
private static final int panelHeight = 300;
/** The apartment block data structure */
private final int apartments = 10; // Total number of apartments (numbered from 1 for the user, but from 0 in the array!)
private String[] occupant; // Occupant information: one string per apartment
private int selectedApartment; // To identify the currently selected apartment
/** Configuration constants for the display */
private final int aptHeight = 40; // Dimensions for individual apartment rectangles
private final int aptWidth = 50;
/** A useful colour */
private final Color emptyColor = Color.green;
/** Graphical interface components */
private JButton next; // Dummy selection button
/** The drawing panel. */
private JPanel panel;
/**
* The main program launcher for the Accommodation application.
*
* #param args The command line arguments (ignored here).
*/
public static void main( String[] args )
{
Accommodation frame = new Accommodation();
frame.setSize( panelWidth+40, panelHeight+200 );
frame.setUpAccommodation();
frame.setUpGUI();
frame.setVisible( true );
frame.setTitle("Accomodation");
frame.setLocationRelativeTo(null);
} // End of main
/** Organizes overall set up of the apartment block details at launch time. */
private void setUpAccommodation()
{
// Create the occupant array and fill in first two apartments.
// The other elements need to contain "Empty"
occupant = new String[apartments];
occupant[0] = "Luke Skywalker"; // Occupants in apartments 1 and 2
occupant[1] = "The Hulk";
occupant[2] = "Empty";
occupant[3] = "Empty";
occupant[4] = "Empty";
occupant[5] = "Empty";
occupant[6] = "Iron Man";
occupant[7] = "Empty";
occupant[8] = "Empty";
occupant[9] = "Empty";
selectedApartment = 0; // Apartment 1 initially selected
} // End of setUpAccommodation
/** Organizes overall set up of the GUI at launch time. */
private void setUpGUI()
{
// Now set up the initial GUI: window, button, graphics panel and background colours.
setDefaultCloseOperation( EXIT_ON_CLOSE );
Container window = getContentPane();
window.setLayout( new FlowLayout() );
window.setBackground( Color.gray );
// Set up the next button
next = new JButton("Next");
window.add(next);
next.addActionListener(this);
// Set up the drawing panel
panel = new JPanel()
{
// paintComponent is called automatically when a screen refresh is needed
public void paintComponent(Graphics g)
{
// g is a cleared panel area
super.paintComponent(g); // Paint the panel's background
paintScreen(g); // Then the required graphics
}
};
panel.setPreferredSize( new Dimension( panelWidth, panelHeight ) );
panel.setBackground( Color.white );
window.add( panel );
} // End of setUpGUI
/**
* Handle button clicks
*
* #param e Information about the button click
*/
public void actionPerformed( ActionEvent e )
{
// In this template there is only a Next button.
// In the second stage (up to 69 marks) it should causes the display to be updated
// to show the details of the next occupant of the apartment block.
// Here is an indication of what it should do:
// Adjust the selected apartment indicator
selectedApartment++;
// And refresh the display
repaint();
} // End of actionPerformed
/**
* Display the apartment block, and the details of the occupant of the selected apartment.
*
* #param g The Graphics area to be drawn on, already cleared.
*/
private void paintScreen( Graphics g )
{
// Now draw the display
displayStatus(g);
displayBlock(g);
} // End of paintScreen
/** Display information about the currently selected apartment */
private void displayStatus(Graphics g)
{
// Just information about apartment 1 in this template
g.setColor(Color.black);
g.drawString(occupant[0], 190, 70);
} // End of displayStatus
/** Draw the apartments themselves: boundary, empty/occupied colouring, number */
private void displayBlock(Graphics g)
{
for(int i = 0; i < 10; i++)
{
if (occupant(i).equals("Empty"))
{
g.setColor(Color.green);
g.fillRect(150+(i*50), 120, aptWidth, aptHeight); //Sets the rectangle red to show the room is occupied
}
else
{
g.setColor(Color.red);
g.fillRect(150+(i*50), 120, aptWidth, aptHeight); //Sets the rectangle green to show the room is free
}
g.setColor(Color.black);
g.drawRect(150+(i*50), 120, aptWidth, aptHeight);
// Draws the numbers in the Corresponding boxes
g.setColor(Color.black);
g.drawString(Integer.toString(i+1), 150+(i*50)+15, 120+25);
}
//Drawing the key allowing the user to see what the colours refer to
g.setFont(new Font("TimesRoman", Font.PLAIN, 14));
g.drawString("Key", 20,120);
g.drawString("Occupied",60,150);
g.drawString("Empty", 60, 170);
// Drawing the boxes to show what the colours mean in the key
g.setColor(Color.red);
g.fillRect(20, 130, 25, 25);
g.setColor(Color.black);
g.drawRect(20, 130, 25, 25);
g.setColor(Color.green);
g.fillRect(20,150,25,25);
g.setColor(Color.black);
g.drawRect(20,150,25,25);
} // End of displayBlock
} // End of Accommodation
occupant(i) should be occupant[i] because it's an array and not a method
occupant(i)
This is a method call
occupant[i]
this is element i in array occupant
There are a lot of questions in here.
I wrote a code this far, but hard to write in code in some methods.
1.I don't know how to do setDice(List dice) method. If I use for(JButton b:dice), then it keeps giving me compile-time error.
2.Help me to implement setWordIsCorrect(boolean isCorrect) & clearCurrentWord() methods
Make sure you cannot touch other methods and modify the method signatures.
package cse1030.games.boggle;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* The view for the Boggle app. Please see the lab for a detailed description of
* the view.
*
* #author CSE1030_F13_14
*
*/
public class BoggleView extends JFrame implements ActionListener {
/**
* The string representing the clear command. The view listens for its own
* clear event.
*/
public static final String CLEAR_COMMAND = "clear";
/**
* The string representing the roll command.
*/
public static final String ROLL_COMMAND = "roll";
/**
* The string repesenting the submit command.
*/
public static final String SUBMIT_COMMAND = "submit";
/**
* A list that contains references to the buttons representing the dice.
*/
private List<JButton> diceButtons;
/**
* The text field that displays the current word.
*/
private JTextField word;
/**
* The set of dice buttons that have already been used to form the current
* word.
*/
private Set<JButton> usedButtons;
/**
* The text area that displays the list of correct words.
*/
private JTextArea correctWords;
/**
* The text area that displays the list of incorrect words.
*/
private JTextArea incorrectWords;
/**
* Create the Boggle user interface. Please see the lab for a detailed
* description of the user interface.
*
* #param controller
* the controller that listens for submit and roll events
*/
public BoggleView(BoggleController controller) {
super("Boggle");
this.diceButtons = new ArrayList<JButton>();
this.usedButtons = new HashSet<JButton>();
JPanel contentPanel = new JPanel();
JPanel leftPanel = this.makeLeftPanel();
JPanel rightPanel = this.makeRightPanel();
JPanel middlePanel = this.makeMiddlePanel(controller);
contentPanel.add(leftPanel);
contentPanel.add(middlePanel);
contentPanel.add(rightPanel);
this.setContentPane(contentPanel);
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* Creates the panel that contains the buttons representing the Boggle dice.
*
* #return the <code>JPanel</code> that contains the buttons representing the
* Boggle dice.
*
*/
private JPanel makeDicePanel() {
Font font = new Font(Font.SANS_SERIF, Font.BOLD, 32);
JPanel p = new JPanel();
p.setLayout(new GridLayout(4, 4));
p.setMaximumSize(new Dimension(450, 450));
for (int i = 0; i < 16; i++) {
JButton b = new JButton("" + i);
b.setPreferredSize(new Dimension(100, 100));
b.setMaximumSize(b.getSize());
b.setFont(font);
b.setBackground(Color.WHITE);
b.setActionCommand("" + i);
b.addActionListener(this);
p.add(b);
this.diceButtons.add(b);
}
return p;
}
/**
* Returns the buttons surrounding the button representing the die that was
* last selected by the user. These are the buttons that could legally be
* chosen next by the user when forming a word.
*
* #param idx
* the index of the button representing the die that was last
* selected by the user
* #return the buttons surrounding the last selected die
*/
private List<JButton> findNeighbors(int idx) {
List<JButton> neighbors = new ArrayList<JButton>();
final int row = idx / 4;
final int col = idx % 4;
final int minRow = Math.max(0, row - 1);
final int maxRow = Math.min(3, row + 1);
final int minCol = Math.max(0, col - 1);
final int maxCol = Math.min(3, col + 1);
for (int i = minRow; i <= maxRow; i++) {
for (int j = minCol; j <= maxCol; j++) {
int n = i * 4 + j;
if (n != idx) {
neighbors.add(this.diceButtons.get(n));
}
}
}
return neighbors;
}
/**
* Disable all of the buttons representing the dice.
*/
private void disableAllDiceButtons() {
for (JButton b : this.diceButtons) {
b.setEnabled(false);
}
}
/**
* Enable all of the buttons representing the dice.
*/
private void enableAllDiceButtons() {
for (JButton b : this.diceButtons) {
b.setEnabled(true);
b.setBackground(Color.WHITE);
}
}
/**
* Responds to events from the view. This method responds to an event where
* the action command is either <code>BoggleView.CLEAR_COMMAND</code>,
* <code>BoggleView.ROLL_COMMAND</code>, or
* <code>BoggleView.SUBMIT_COMMAND</code>.
*
* #param event
* an event emitted by the view
*
* #see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
#Override
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
if (command.equals(CLEAR_COMMAND)) {
this.clearCurrentWord();
} else if (command.equals(ROLL_COMMAND)) {
this.clearCorrectWords();
this.clearIncorrectWords();
this.clearCurrentWord();
} else {
try {
int d = Integer.parseInt(command);
JButton b = this.diceButtons.get(d);
b.setBackground(Color.BLUE);
this.word.setText(this.word.getText() + b.getText());
this.usedButtons.add(b);
this.disableAllDiceButtons();
List<JButton> neighbors = findNeighbors(d);
for (JButton n : neighbors) {
if (!this.usedButtons.contains(n)) {
n.setEnabled(true);
}
}
} catch (NumberFormatException ex) {
}
}
}
/**
* Creates the left-hand panel. Please see the lab for a detailed description
* of the panel's contents.
*
* #return the left-hand <code>JPanel</code> with all of its necessary
* components
*/
private JPanel makeLeftPanel() {
// create the panel
JPanel p = new JPanel();
// set the layout for the panel to use a BoxLayout;
// BoxLayout stacks its components vertically or horizontally
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
// create a label for the list of correct words and add it to the panel
JLabel label = new JLabel("Correct Words");
p.add(label);
// create the list of correct words, remove the ability for the user to
// edit the list, and add it to the panel
this.correctWords = new JTextArea(30, 16);
this.correctWords.setEditable(false);
p.add(this.correctWords);
return p;
}
/**
* Creates the right-hand panel. Please see the lab for a detailed description
* of the panel's contents.
*
* #return the right-hand <code>JPanel</code> with all of its necessary
* components
*/
private JPanel makeRightPanel() {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
JLabel label = new JLabel("Incorrect Words");
p.add(label);
this.incorrectWords = new JTextArea(30, 16);
this.incorrectWords.setEditable(false);
p.add(this.incorrectWords);
return p;
}
/**
* Creates the middle panel. Please see the lab for a detailed description of
* the panel's contents.
*
* #return the middle <code>JPanel</code> with all of its necessary components
*/
private JPanel makeMiddlePanel(BoggleController controller) {
JPanel p = new JPanel();
// 1. set the layout to a BoxLayout (same as makeLeftPanel)
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
// 2. make the dice panel and add it to p; there is a method that makes the
// dice panel for you!
p.add(makeDicePanel());
// 3. make the contorl panel and add it to p; there is a method that makes
// the control for you!
p.add(makeControlPanel(controller));
return p;
}
/**
* Creates the panel that contains the clear, submit, and re-roll buttons, and
* the text field for the word.
*
* #return the <code>JPanel</code> that contains the controls below the dice
*
*/
private JPanel makeControlPanel(BoggleController controller) {
JPanel p = new JPanel();
// You don't need to create a lay out. JPanel uses FlowLayout if you don't
// specify a lay out.
// Make the clear button
JButton clear = new JButton("Clear");
// Set its action command to the clear command
clear.setActionCommand(BoggleView.CLEAR_COMMAND);
// Add this as an action listener; see the actionPerformed method above.
// The controller does not need to listen to this button because the model
// is not needed to clear the current word.
clear.addActionListener(this);
// Add the clear button to the panel.
p.add(clear);
// Make a text field that can display a 16 character word
this.word = new JTextField(16);
// Disable editing by the user.
this.word.setEditable(false);
// Add the text field to the panel.
p.add(this.word);
// - make the submit button
JButton submit = new JButton("Submit");
// - set its action command
submit.setActionCommand(BoggleView.SUBMIT_COMMAND);
// - add the controller as an action listener
submit.addActionListener(controller);
// - add the submit button to the panel
p.add(submit);
// - make the re-roll button
JButton roll = new JButton("Re-roll");
// - set its action command
roll.setActionCommand(BoggleView.ROLL_COMMAND);
// - add the controller as an action listener
roll.addActionListener(controller);
// - add this as an action listener
roll.addActionListener(this);
// - add the re-roll button to the panel
p.add(roll);
return p;
}
/**
* Get the current string that is in the word text field.
*
* #return the current string that is in the word text field
*/
public String getWord() {
// change the return statement below
return this.word.getText();
}
/**
* Sets the text on the buttons representing the dice.
*
* #pre. <code>dice.size() == 16</code>
*
* #param dice
* a list of 16 Boggle dice
*/
public void setDice(List<BoggleDie> dice) {
**for (JButton b : dice) {
b.setText(b.getText());
}**
}
/**
* Causes the view to update after the submitted word is evaluated for
* correctness. If <code>isCorrect == true</code> then the current word is
* added to the list of correct words. If <code>isCorrect == false</code> then
* the current word is added to the list of incorrect words. In both cases,
* the current word is cleared.
*
* #param isCorrect
* <code>true</code> if the current word has been determined to be a
* legal Boggle word, <code>false</code> otherwise
*/
public void setWordIsCorrect(boolean isCorrect) {
if(isCorrect == true) {
} else {
}
}
/**
* Clears the list of correct words.
*/
private void clearCorrectWords() {
this.correctWords.setText(null);
}
/**
* Clears the list of incorrect words.
*/
private void clearIncorrectWords() {
this.incorrectWords.setText(null);
}
/**
* Clears the current word and prepares the view to accept a new word. This
* requires re-enabling all of the dice buttons and clearing the set
* this.usedButtons
*/
private void clearCurrentWord() {
// 1. enable all of the dice buttons; there is a method that does this for
// you
enableAllDiceButtons();
// 2. set the text of this.word to the empty string
// 3. remove all of the buttons from this.usedButtons
}
public static void main(String[] args) {
BoggleView v = new BoggleView(null);
v.setVisible(true);
}
}
I will appreciate you if you can help me how to do these methods...
You need to use for (BoggleDie b : dice) or (List<JButton> dice). If the list contains BoggleDie, you must use the former.
You may want to have a list of JButtons instead
public void setDice(List<JButton> dice) {
for (JButton b : dice) {
b.setText(b.getText());
}
}
You need to make sure you actually initialize the list and add JButtons to the list before you can do anything with it.
List<JButton> diceButtons = new List<JButton>();
for (int i = 0; i < 16; i++){
diceButton.add(new JButton("" + i + 1);
}
Try this for your method
public void setDice(){
for (int i = 0; i < 16; i++){
diceButtons.add(new JButton("SomeText");
}
}
Edit: with BoggleDie class
public class BoggleDie{
int value;
public BoggleDie(int value){
this.value = value;
}
}
public class BoggleView ... {
...
private List<BoggleDie> dice = new List<BoggleDie>();
private List<JButton> diceButton = new ArrayList<JButton>();
public BoggleView(){
for (int i = 0; i < 16; i++){
dice.add(new BoggleDie(i)); // or whatever value you want for the die
}
setDice(dice);
}
public void setDice(List<BoggleDie> dice) {
for (BoggleDie b : dice) {
diceButtons.add(new JButton(b.value));
}
}
}
Change the code as follows
public void setDice(List<JButton> dice) {
for (JButton b : dice) {
b.setText(b.getText());
}
}
I'm making a threaded app, and the main class is also the runnable class. for some reason, my thread WILL NOT START. any idea why? updateThread is the culprit...
here is the code:
package avtech.software.bitprice.display;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import avtech.software.bitprice.dialogs.*;
import avtech.software.bitprice.listeners.*;
#SuppressWarnings("serial")
public class Display extends JFrame implements Runnable {
/**
* variables
*/
private static final int WIDTH = 200, HEIGHT = 200;
private static double currentPrice = 0.0;
private static double pauseLength;
private static boolean running = false;
private static String greaterLess = "";
/**
* objects
*/
private static Display d;
private static Thread updateThread;
private static JLabel currentPriceLabel = new JLabel("Current Price: $" + currentPrice);
private static JTextField pullDelayArea = new JTextField("Price Pull Delay In Minutes...");
private static JTextField priceValueArea = new JTextField("Price You Are Waiting For...");
private static JButton update = new JButton("UPDATE DATA");
public Display() {
running = true; // program is now running
updateThread = new Thread(d); // create the local thread
/**
* create the frame
*/
setLayout(null);
setSize(WIDTH, HEIGHT);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("BitPrice");
/**
* set bounds of the components
*/
currentPriceLabel.setBounds(((WIDTH / 2) - (currentPriceLabel.toString().length() / 5)), 5, WIDTH, 50);
pullDelayArea.setBounds(10, 40, WIDTH - 25, 25);
priceValueArea.setBounds(10, 70, WIDTH - 25, 25);
update.setBounds(10, 100, WIDTH - 25, 25);
/**
* set up the listeners to the components
*/
pullDelayArea.addMouseListener(new PullDelayAreaListener(pullDelayArea));
pullDelayArea.addActionListener(new PullDelayAreaListener(pullDelayArea));
priceValueArea.addMouseListener(new PriceValueAreaListener(priceValueArea));
priceValueArea.addActionListener(new PriceValueAreaListener(priceValueArea));
update.addActionListener(new UpdateButtonListener());
/**
* add everything
*/
add(currentPriceLabel);
add(pullDelayArea);
add(priceValueArea);
add(update);
setLocationRelativeTo(null);
setVisible(true);
requestFocus();
/**
* start the update process
*/
System.out.println("hi");
updateThread.start();
}
/**
* everything that happens when the thread is updated, including updating
* the price label, and all that good stuff :)
*/
public static void update() {
/**
* make sure that there is data in the boxes taht is valid
*/
if (pullDelayArea.getText().equals("Price Pull Delay In Minutes...") || pullDelayArea.getText().equals("")) {
new MessageDialog(d, "Please enter a valid number into Price Pull Delay.");
}
if (priceValueArea.getText().equals("Price You Are Waiting For...") || priceValueArea.getText().equals("")) {
new MessageDialog(d, "Please enter a valid number into Price Value.");
}
// set the new price double from the website
// update the label
currentPriceLabel.setText("Current Price: $" + currentPrice);
currentPriceLabel.setBounds(((WIDTH / 2) - (currentPriceLabel.toString().length() / 5)), 5, WIDTH, 50);
currentPriceLabel.repaint();
/**
* check to see if the current value is what the client is waiting for
*/
String priceValueString = priceValueArea.getText();
double priceValue = Double.parseDouble(priceValueString);
}
/**
* this thread is checking the price of the Bitcoin, and will send out the
* notification if it reaches a certain price
*/
public void run() {
System.out.println("started");
/**
* initial pause, letting the client get all set up
*/
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
new ErrorDialog(this, "Error delaying the pull request. Please restart client.");
}
System.out.println("started");
while (running) {
update();
/**
* add a pause to not just destroy internet speeds, pause settable
* through the GUI
*/
try {
Thread.sleep((long) (pauseLength * 1000000)); // 1 million cause
// its in
// milliseconds
} catch (InterruptedException e) {
new ErrorDialog(this, "Error delaying the pull request. Please restart client.");
}
}
}
public static void main(String[] args) {
d = new Display();
}
}
Any help would be greatly appreciated.
PS: my internet is about to turn off, so responses may be delayed until tomorrow.
The short version is that the reference to d is not set until the constructor exits, so in your Display, you're creating a new thread object and passing the static reference to d, which is still presently null at that point. I would remove the new Thread(d) line, and the .start() line from the constructor, and simply invoke d.start() from the main method.