#java #swing
#java #swing
Вопрос:
Я кодирую небольшую игру, в которой я взял сетку JButtons в JFrame, и я хочу обновить цвета кнопок, содержащихся в JFrame, который уже виден.Как описано ниже
void foo(){
mainFrame.setVisible(true);//mainFrame is defined at class level.
//color update code for the buttons.
mainFrame.setVisible(true);
}
Результат, который я получаю, не соответствует ожиданиям, и мой экран зависает.Разве это не правильный способ достичь того, чего я хотел?
РЕДАКТИРОВАТЬ
хорошо, я подробно объясняю, чего я хочу достичь. у меня есть класс, как:-
import javax.swing.*;
import java.awt.*;
import java.util.*;
class Brick extends JButton{
public void setRandomColors(){
int random = (int) (Math.random()*50);
if(random%13==0){
this.setBackground(Color.MAGENTA);
}
else if(random%10==0){
this.setBackground(Color.red);
}
else if(random%9==0){
this.setBackground(Color.yellow);
}
else if(random%7==0){
this.setBackground(Color.orange);
}
else if(random%2==0){
this.setBackground(Color.cyan);
}
else{
this.setBackground(Color.PINK);
}
}
public void setBlackColor(){
this.setBackground(Color.black);
}
}
class Grid {
JFrame mainGrid = new JFrame();
ArrayList<Brick> bunchOfBricks = new ArrayList<>();
int gridLength = 8;//gridlenth is equals to gridweight as i have considered a Square grid.
int totalBricks = gridLength*gridLength;
public void formBunchOfBricks(){
for(int i=0;i<totalBricks;i ){
bunchOfBricks.add(new Brick());
}
}
public void formColoredGrid(){
Brick aBrick;
mainGrid.setLayout(new GridLayout(8,8));
for(int i=0;i<totalBricks; i){
aBrick = (bunchOfBricks.get(i));
aBrick.setRandomColors();
mainGrid.add(aBrick);
}
mainGrid.setVisible(true);//its ok upto here iam getting randomly colored Frame of Bricks or so called JButtons.
delay(15);//Sorry for this one,i warn you not to laugh after looking its defination.
}
/*
I want following function to do following things:-
1.it should firstly display the Grid whose all buttons are black Colored.
2.After some time the original colored,first Row of grid formed by formColoredGrid should be displayed and all the rest Rows should be black.
3.Then second row turns colored and all other rows should be black......and so on upto last row of Grid.
*/
public void movingRows(){
setGridBlack();
delay(1);//see in upper method,for this horrible thing.
for(int i=0;i<gridLength; i){
setGridBlack();
for (int j=0;j<gridLength; j){
Brick aBrick = bunchOfBricks.get((gridLength*i) j);
aBrick.setRandomColors();//Bricks are colored Row by Row.
}
delay(5);//already commented this nonsense.
mainGrid.setVisible(true);//using setVisible again,although this frame is already visible,when i called formColoredGrid.
setGridBlack();
}
//oh! disappointing,i have almost broken my arm slamming it on table that why the function result in a screen full of black buttons.
}
public void setGridBlack(){
for(int i=0;i<totalBricks;i ){
bunchOfBricks.get(i).setBlackColor();
}
}
public void delay(int a){
for ( int i=0;i<90000000; i){
for(int j=0;j<a; j){
}
}
}
public static void main(String args[]){
Grid g1 = new Grid();
g1.formBunchOfBricks();
g1.formColoredGrid();
g1.movingRows();
}
}
Пожалуйста, помогите мне, каков выход?
Комментарии:
1. Нет необходимости скрывать / показывать рамку. Просто измените цвета кнопок. Если экран зависает, то у вас, вероятно, есть какой-то другой код, который блокирует поток отправки событий и не позволяет графическому интерфейсу перерисовывать себя. Опубликуйте свой SSCCE , который демонстрирует проблему.
2. docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
3. Ага… изучите это досконально. Проблема в вашем цикле, как отметил @HovercraftFullOfEels. Используйте таймер для задержки
4. @peeskillet спасибо. Но в чем причина сбоя в программе.
5. У вас есть бессмысленный цикл, который повторяется миллион раз без причины. Это ваша проблема
Ответ №1:
Ваша проблема в коде, не показанном здесь:
//color update code for the buttons.
Вероятно, вы запускаете цикл, который никогда не заканчивается в потоке событий Swing, возможно, бесконечный цикл while, который опрашивает состояние чего-либо (предположение), замораживая ваш графический интерфейс. Решение: не делайте этого; не используйте непрерывный цикл опроса. Вместо этого измените цвета на основе ответов на события, поскольку Swing управляется событиями.
Для получения более подробной справки, пожалуйста, покажите код-нарушитель и расскажите нам больше о вашей программе.
Редактировать
Если вы пытаетесь отобразить цветные строки, одну за другой перемещающиеся вниз по доске, то, как я предполагаю, вы захотите использовать Swing Timer, который использует индекс int, чтобы указать, какая строка отображается в цвете. Вы бы увеличили индекс внутри класса actionPerformed таймера, а затем, когда будут отображены все строки, остановите таймер. Например, что-то вроде этого:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.*;
@SuppressWarnings("serial")
public class MyGrid extends JPanel {
private static final int GRID_LENGTH = 8;
private static final Color BTN_BACKGROUND = Color.BLACK;
private static final Color[] COLORS = { Color.MAGENTA, Color.CYAN,
Color.RED, Color.YELLOW, Color.ORANGE, Color.PINK, Color.BLUE,
Color.GREEN };
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 800;
private JButton[][] buttonGrid = new JButton[GRID_LENGTH][GRID_LENGTH];
private Map<JButton, Color> btnColorMap = new HashMap<>();
private Random random = new Random();
public MyGrid() {
setLayout(new GridLayout(GRID_LENGTH, GRID_LENGTH));
for (int row = 0; row < buttonGrid.length; row ) {
for (int col = 0; col < buttonGrid[row].length; col ) {
JButton btn = new JButton();
btn.setBackground(BTN_BACKGROUND);
// !! add action listener here?
add(btn);
buttonGrid[row][col] = btn;
}
}
new Timer(TIMER_DELAY, new TimerListener()).start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void resetAllBtns() {
for (JButton[] row : buttonGrid) {
for (JButton btn : row) {
btn.setBackground(BTN_BACKGROUND);
}
}
}
private class TimerListener implements ActionListener {
private int row = 0;
@Override
public void actionPerformed(ActionEvent e) {
resetAllBtns(); // make all buttons black
if (row != buttonGrid.length) {
for (int c = 0; c < buttonGrid[row].length; c ) {
int colorIndex = random.nextInt(COLORS.length);
Color randomColor = COLORS[colorIndex];
buttonGrid[row][c].setBackground(randomColor);
// !! not sure if you need this
btnColorMap.put(buttonGrid[row][c], randomColor);
}
row ;
} else {
// else we've run out of rows -- stop the timer
((Timer) e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
MyGrid mainPanel = new MyGrid();
JFrame frame = new JFrame("MyGrid");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Пожалуйста, взгляните также на руководство по таймеру Swing.
Правка 2
Вы спрашиваете:
но в чем причина сбоя этой программы, это бесполезная функция задержки?
Ваш метод задержки не выполняет ничего, кроме вычислений в потоке событий Swing:
public void delay(int a) {
for (int i = 0; i < 90000000; i) {
for (int j = 0; j < a; j) {
}
}
}
Это немного отличается от грубой попытки вызова Thread.sleep(...)
и является грубым, потому что вы не можете явно контролировать, как долго он будет выполняться, как вы можете с помощью режима ожидания потока. Опять же, проблема в том, что вы выполняете эти вызовы в потоке отправки событий Swing или EDT, единственном потоке, который отвечает за все рисование Swing и взаимодействия с пользователем. Блокировка этого потока заблокирует вашу программу, сделав ее нерабочей или замороженной.
Комментарии:
1. да, вы догадались, я использую цикл обновления цвета
2. тогда каков выход?
3. @Bayant_singh: опять же, не используйте цикл. Серьезно, вам нужно улучшить свой вопрос, показать больше кода, более подробно описать, что вы пытаетесь сделать. Вашего комментария
// color update...
недостаточно, чтобы позволить нам что-либо понять. Вы могли бы также опубликовать// and here some magic happens
4. @Bayant_singh: возможно, вы хотите использовать таймер переключения, если ваша цель — изменять цвета кнопок по расписанию? Пожалуйста, объясните ваше конкретное желаемое поведение вместе с добавленным вами кодом.
5. Приятно!.. Я впервые вижу, как ты публикуешь gif!