Подтвердить что ты не робот

Создание графического интерфейса для решения Sudoku (в комплекте с примером ASCII)

.

ОБЗОР, ОБРАЗЕЦ

Привет всем,

Я создал базовый решатель Sudoku, который может решить большинство проблем довольно быстро. У меня все еще впереди много работы, чтобы решить даже самые сложные проблемы, но сначала я хотел бы попытаться реализовать основной графический интерфейс JFrame.

Я работал с интернет-апплетами в прошлом, но никогда раньше с JFrames.

Я хочу создать нечто похожее на изображение ниже (для начала):

-------------------------------------------------------------------------------------------------
! Sudoku Solver 1.0                                                                      - [] X !
-------------------------------------------------------------------------------------------------
!  _____________ _____________ _____________         _____________ _____________ _____________  !
! |  _   _   _  |  _   _   _  |  _   _   _  |       |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !5! !_! !_! | !_! !_! !_! | !6! !_! !1! |       | !5! !7! !2! | !4! !9! !3! | !6! !8! !1! | !
! |  _   _   _  |  _   _   _  |  _   _   _  |       |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !6! !_! !_! | !_! !_! !2! | !4! !_! !_! |       | !6! !1! !3! | !8! !5! !2! | !4! !7! !9! | !
! |  _   _   _  |  _   _   _  |  _   _   _  |       |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !_! !_! !_! | !7! !_! !1! | !_! !_! !2! |       | !8! !4! !9! | !7! !6! !1! | !3! !5! !2! | !
! -_____________-_____________-_____________-       -_____________-_____________-_____________- !
! |  _   _   _  |  _   _   _  |  _   _   _  |       |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !_! !_! !4! | !_! !2! !_! | !_! !3! !_! |       | !1! !6! !4! | !9! !2! !7! | !5! !3! !8! | !
! |  _   _   _  |  _   _   _  |  _   _   _  | .---. |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !_! !3! !_! | !_! !_! !_! | !_! !9! !_! | | > | | !2! !3! !8! | !5! !1! !6! | !7! !9! !4! | !
! |  _   _   _  |  _   _   _  |  _   _   _  | '---' |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !_! !_! !_! | !_! !4! !_! | !_! !_! !_! |       | !7! !9! !5! | !3! !4! !8! | !1! !2! !6! | !
! -_____________-_____________-_____________-       -_____________-_____________-_____________- !
! |  _   _   _  |  _   _   _  |  _   _   _  |       |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !_! !2! !_! | !1! !_! !5! | !9! !_! !_! |       | !4! !2! !7! | !1! !8! !5! | !9! !6! !3! | !
! |  _   _   _  |  _   _   _  |  _   _   _  |       |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !_! !_! !_! | !6! !_! !_! | !_! !_! !5! |       | !3! !8! !1! | !6! !7! !9! | !2! !4! !5! | !
! |  _   _   _  |  _   _   _  |  _   _   _  |       |  _   _   _  |  _   _   _  |  _   _   _  | !
! | !_! !_! !6! | !_! !3! !_! | !_! !_! !7! |       | !9! !5! !6! | !2! !3! !4! | !8! !1! !7! | !
! -_____________-_____________-_____________-       -_____________-_____________-_____________- !
!                                                                                               !
! .-------------------------------------------------------------------------------------------. !
! |                                                                                           | !
! |               Solved Puzzle in 9.096ms      |      Completely Solved: True                | !
! |                                                                                           | !
! '-------------------------------------------------------------------------------------------' !
!                                                                                               !
-------------------------------------------------------------------------------------------------

.

КОНКРЕТНЫЕ

: Левая головоломка

  • 9x9 Разделы должны быть четко определены (строки между отдельными ячейками)
  • Текстовые поля должны принимать только номера/только для ввода одного номера (если возможно)

: Правая головоломка

  • 9x9 Разделы должны быть четко определены (строки между отдельными ячейками)
  • Не имеет значения, можно ли редактировать/редактировать файлы, если они могут отображать результат

: кнопка в центре

  • Должен запускать [SudokuPuzzle].solve();

: нижнее текстовое поле

  • Нельзя редактировать

.

ЧТО Я ИЩУ ДЛЯ

Я знаю из прошлых опытов, что все это можно сделать в JFrame, но поскольку я никогда не строил его сам, я не совсем уверен, что components (элементы контента, панели, настройки и т.д.). Мне нужно использовать для выполнения моих спецификаций. Мне еще предстоит найти способ ограничить мои текстовые поля номерами и не позволять пользователю вставлять более одного значения за раз. Являются ли текстовые окна действительно лучшим вариантом, или я пропускаю что-то, что может более конкретно удовлетворить мои потребности?

Мне нужно не только знать, какие классы мне нужны, но и как их организовать, чтобы кнопка оставалась комфортно между двумя головоломками, а текстовое поле сидит внизу. Из того, что я читал, MigLayout кажется вариантом упрощения этот процесс.

.

ПРИМЕЧАНИЯ КОНЕЦ

Многие, огромное спасибо всем, кто помогает. Если какая-либо часть этого вопроса окажется немного грубой или резкой, я извиняюсь. Я, как правило, размещаю большинство своих вопросов ночью, поэтому у сообщества есть несколько часов, чтобы разглядеть его, прежде чем я попробую все ответы (что и тот факт, что я больше всего занимаюсь делами).

Я буду бодрствовать в течение 1-2 часов, чтобы ответить на любые вопросы.

Снова спасибо,

Жюстьян

4b9b3361

Ответ 1

GUI Sudoku

Хорошо, я не мог с собой поделать... Вот моя попытка. Все это в одном пакете:

  • GUI со всеми элементами, соответствующими спецификации (вопрос)
  • гибкий макет
  • нет внешних зависимостей - используются стандартные макеты Swing
  • подтверждение ввода (только цифры 0-9)
  • Архитектура контроллера модели Model
  • бегун фонового задания (ваш графический интерфейс никогда не зависает)
  • встроены некоторые методы отладки (вывод Sudoku в виде текста)
  • фиктивная реализация - имитирует длительное вычисление, показывающее отзывчивость GUI.

Я изо всех сил старался сделать код максимально читаемым. Могут быть довольно неясные детали. Вероятно, резьбовая часть не ясна, но если кто-нибудь найдет это для использования, я был бы рад описать ее лучше.

Итак, моя цель была самым простым использованием. Если вы посмотрите на интерфейсы, очень сложно сломать этот материал (заморозить UI, получить Null Pointer Exc и т.д.) В качестве упражнения при написании публичных API. Это может быть не самая лучшая реализация, но это одно из лучших, что я написал.:)

Надеюсь, что это поможет.

Вот как это выглядит: Пример выполнения http://a.imageshack.us/img256/754/sudokusolvergui.png

(примечание: значения являются случайными)

Использование

Все, что вам нужно сделать, это реализовать интерфейс:

public interface SudokuImplementation {

    void goButtonPressed(Integer[][] leftSudokuValues, SudokuController resultAcceptor);
}

Просто выполните все вычисления в этом методе и сохраните результаты с помощью resultAcceptor.setSudokuResult()

Вот как на самом деле показывать GUI:

    SudokuImplementation sudokuImplementation =
        new YourSuperSudoku(); // <- your implementation

    SudokuView sudokuView = new SudokuView();
    sudokuView.setSudokuImplementation(sudokuImplementation);
    sudokuView.setVisible(true);

И это все!

код

Все классы находятся в пакете по умолчанию - рефакторинг по вашему желанию. Вот список из них:

  • SudokuView - основной графический интерфейс
  • SudokuRun - пример бегуна
  • SudokuController - позволяет безопасно управлять просмотром.
  • SudokuImplementation - интерфейс для реализации судоку
  • DummySudokuImplementation - пример реализации

1.SudokuView:

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.border.*;
/**
 * View which constructs every component and creates it own controller.
 */
public class SudokuView extends JFrame {

    SudokuController controller;

    public void setSudokuImplementation(SudokuImplementation listener) {
        controller.setListener(listener);
    }

    /** Creates new form NewJFrame */
    public SudokuView() {
        controller = new SudokuController();
        setTitle("Sudoku Solver 1.0");
        getContentPane().add(createCenterPanel(), BorderLayout.CENTER);
        getContentPane().add(createBottomPanel(), BorderLayout.SOUTH);
        setMinimumSize(new Dimension(600, 300));
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private JPanel createBottomPanel() {
        JPanel bottomPanel = new JPanel(new GridBagLayout());
        JLabel leftLabel = createLabel("left");
        JLabel rightLabel = createLabel("right");

        controller.bindLeftLabel(leftLabel);
        controller.bindRightLabel(rightLabel);

        bottomPanel.add(leftLabel, getWholeCellConstraints());
        bottomPanel.add(new JSeparator(JSeparator.VERTICAL));
        bottomPanel.add(rightLabel, getWholeCellConstraints());

        bottomPanel.setBorder(new BevelBorder(BevelBorder.LOWERED));
        return bottomPanel;
    }

    private JLabel createLabel(String text) {
        JLabel label = new JLabel(text);
        label.setHorizontalAlignment(JLabel.CENTER);
        return label;
    }

    private JPanel createCenterPanel() {
        JPanel centerPanel = new JPanel(new GridBagLayout());
        centerPanel.add(createLeftPanel(), getWholeCellConstraints());
        centerPanel.add(createCenterButton(), getPreferredSizeConstraint());
        centerPanel.add(createRightPanel(), getWholeCellConstraints());
        return centerPanel;
    }

    private GridBagConstraints getPreferredSizeConstraint() {
        // default will do
        return new GridBagConstraints();
    }

    private JButton createCenterButton() {
        JButton goButton = new JButton(">");
        controller.bindCenterButton(goButton);
        return goButton;
    }
    private static final Insets sixPixelInset = new Insets(6, 6, 6, 6);

    private JPanel createRightPanel() {
        JPanel rightPanel = create3x3Panel(6);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                JPanel panel2 = create3x3Panel(2);
                fillPanelWithNonEditable(panel2, i, j);
                rightPanel.add(panel2);

            }
        }
        rightPanel.setBorder(new EmptyBorder(sixPixelInset));
        return rightPanel;
    }

    private JPanel createLeftPanel() {
        JPanel leftPanel = create3x3Panel(6);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                JPanel panel2 = create3x3Panel(2);
                fillPanelWithEditable(panel2, i, j);
                leftPanel.add(panel2);

            }
        }
        leftPanel.setBorder(new EmptyBorder(sixPixelInset));
        return leftPanel;
    }

    private GridBagConstraints getWholeCellConstraints() {
        GridBagConstraints wholePanelCnstr = getPreferredSizeConstraint();
        wholePanelCnstr.fill = java.awt.GridBagConstraints.BOTH;
        wholePanelCnstr.weightx = 1.0;
        wholePanelCnstr.weighty = 1.0;
        return wholePanelCnstr;
    }

    private void fillPanelWithEditable(JPanel panel, int majorRow, int majorColumn) {
        for (int minorRow = 0; minorRow < 3; minorRow++) {
            for (int minorColumn = 0; minorColumn < 3; minorColumn++) {
                final JFormattedTextField editableField = createEditableField();
                int column = majorColumn * 3 + minorColumn;
                int row = majorRow * 3 + minorRow;
                controller.bindLeftSudokuCell(row, column, editableField);
                panel.add(editableField);
            }
        }
    }

    private void fillPanelWithNonEditable(JPanel panel, int majorRow, int majorColumn) {
        for (int minorRow = 0; minorRow < 3; minorRow++) {
            for (int minorColumn = 0; minorColumn < 3; minorColumn++) {
                final JFormattedTextField editableField = createNonEditableField();
                int column = majorColumn * 3 + minorColumn;
                int row = majorRow * 3 + minorRow;
                controller.bindRightSudokuCell(row, column, editableField);
                panel.add(editableField);
            }
        }
    }

    private JPanel create3x3Panel(int gap) {
        final GridLayout gridLayout = new GridLayout(3, 3, 1, 1);
        gridLayout.setHgap(gap);
        gridLayout.setVgap(gap);
        JPanel panel = new JPanel(gridLayout);
        return panel;
    }

    private JFormattedTextField createNonEditableField() {
        JFormattedTextField field = createEditableField();
        field.setEditable(false);
        field.setBackground(Color.WHITE); // otherwise non-editable gets gray
        return field;
    }

    private JFormattedTextField createEditableField() {
        JFormattedTextField field = new JFormattedTextField();
        // accept only one digit and nothing else
        try {
            field.setFormatterFactory(new DefaultFormatterFactory(new MaskFormatter("#")));
        } catch (java.text.ParseException ex) {
        }
        field.setPreferredSize(new Dimension(16, 30));
        field.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        field.setText(" ");
        field.setBorder(null);
        return field;
    }
}

2. SudokuRun:

import java.awt.EventQueue;
import javax.swing.UIManager;

public class SudokuRun implements Runnable {

    public void run() {
        // ******************** here You can swap Your true implementation
        SudokuImplementation sudokuImplementation = new DummySudokuImplementation();
        // ***************************** *************** ********* **** ** *


        SudokuView sudokuView = new SudokuView();
        sudokuView.setSudokuImplementation(sudokuImplementation);
        sudokuView.setVisible(true);
    }

    public static void main(String args[]) {
        tryToSetSystemLookAndFeel();
        EventQueue.invokeLater(new SudokuRun());
    }

    private static void tryToSetSystemLookAndFeel() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ex) {
            System.out.println("Couldn't set LAF");
        }
    }
}

3. SudokuController:

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;

public class SudokuController {

    JLabel leftLabel, rightLabel;
    JFormattedTextField[][] leftSudoku, rightSudoku;
    JButton goButton;

    public SudokuController() {
        leftSudoku = new JFormattedTextField[9][9]; // standard sudoku size
        rightSudoku = new JFormattedTextField[9][9];
    }

    void bindLeftLabel(JLabel label) {
        leftLabel = label;
    }

    void bindRightLabel(JLabel label) {
        rightLabel = label;
    }

    void bindLeftSudokuCell(final int row, final int column, JFormattedTextField field) {
        field.addPropertyChangeListener("value", new PropertyChangeListener() {

            // if user edits field than You could do something about it here
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getNewValue() != null) {
                    String newValue = (String) evt.getNewValue();
                    userEditedValueAt(row, column, Integer.valueOf(newValue));
                }
            }
        });
        leftSudoku[row][column] = field;
    }

    void userEditedValueAt(int row, int column, int value) {
        System.out.println("Value changed at row:" + row + ", column:" + column + " to " + value);
    }

    void bindRightSudokuCell(int row, int column, JFormattedTextField field) {
        rightSudoku[row][column] = field;
    }

    void spitOutSudokus() {
        System.out.println("Left:");
        System.out.println(getPrettyPrinted(leftSudoku));
        System.out.println("Right:");
        System.out.println(getPrettyPrinted(rightSudoku));
    }

    private String getPrettyPrinted(JFormattedTextField[][] sudoku) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 9; i++) {
            sb.append("|");
            for (int j = 0; j < 9; j++) {
                if (sudoku[i][j] != null) {
                    sb.append(sudoku[i][j].getText());
                } else {
                    sb.append("-");
                }
                sb.append(" ");
            }
            sb.append("|\n");
        }
        return sb.toString();
    }

    void bindCenterButton(JButton goButton) {
        this.goButton = goButton;
        goButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                goButtonPressed();
            }
        });
    }
    SudokuImplementation listener;

    public void setListener(SudokuImplementation listener) {
        this.listener = listener;
    }
    Thread backGroundThread;

    private void goButtonPressed() {
        if (listener != null) {
            if (backGroundThread == null || (backGroundThread != null && !backGroundThread.isAlive())) {
                backGroundThread = new Thread() {

                    @Override
                    public void run() {
                        listener.goButtonPressed(getLeftValues(), SudokuController.this);
                    }
                };
                backGroundThread.start();
            }
        }
    }

    private Integer[][] getLeftValues() {
        Integer[][] values = new Integer[9][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (!leftSudoku[i][j].getText().equals(" ")) {
                    values[i][j] = Integer.valueOf(leftSudoku[i][j].getText());
                }
            }
        }
        return values;
    }

    public void setSudokuResult(final Integer[][] result) {
        // Any GUI interaction must be done on EDT
        // We don't want to block computation so we choose invokeLater
        // as opposed to invokeAndWait.
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                for (int i = 0; i < 9; i++) {
                    for (int j = 0; j < 9; j++) {
                        rightSudoku[i][j].setValue(String.valueOf(result[i][j]));
                    }
                }
            }
        });
    }

    public void setSudokuTime(final String time) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                leftLabel.setText("<html>Running time: <b>" + time);
            }
        });
    }

    public void setSudokuCompleted(final boolean completed) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {

                rightLabel.setText("<html>Completely Solved: <b>" + completed);
                if (completed) {
                    spitOutSudokus();
                }

            }
        });
    }
}

4. SudokuImplementation:

public interface SudokuImplementation {

    void goButtonPressed(Integer[][] leftSudokuValues, SudokuController resultAcceptor);
}

5. DummySudokuImplementation:

import java.util.concurrent.TimeUnit;

/**
 * Simulates Sudoku solver. Demonstrates how to update GUI. The whole
 * implementation is constructed so GUI never freezes.
 */
class DummySudokuImplementation implements SudokuImplementation {

    public DummySudokuImplementation() {
    }

    public void goButtonPressed(Integer[][] leftSudokuValues, SudokuController resultAcceptor) {
        System.out.println("Long running computation simulation...");
        for (int i = 0; i < 50; i++) {
            resultAcceptor.setSudokuCompleted(false);
            resultAcceptor.setSudokuTime(String.valueOf(i * 50) + "ms");
            resultAcceptor.setSudokuResult(getRandomResult());
            waitSomeTime();
        }
        resultAcceptor.setSudokuResult(leftSudokuValues);
        resultAcceptor.setSudokuCompleted(true);
        waitSomeTime();
        System.out.println("Done!");
    }

    private void waitSomeTime() {
        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException ex) {
        }
    }

    private Integer[][] getRandomResult() {
        Integer[][] randomResult = new Integer[9][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                randomResult[i][j] = (int) (Math.random() * 9);
            }
        }
        return randomResult;
    }
}

Описание

Я не утверждаю, что то, что я сделал, является лучшим. Мне бы хотелось увидеть другой ответ, допустим, все, что было сделано с MigLayout. Это было бы очень поучительно. Я изучал Swing GUI, когда реализация Sun была единственной, так что она преобладала в моем стиле. Тем не менее, я рекомендую обратиться к короткому курсу GUI Sun Swing. Он также включает простой пример исследования. После прочтения почти вся часть SudokuView должна быть четкой.

Я разделил код, чтобы сделать его более читаемым. Вот почему контроллер - это еще один класс, а не часть представления. Представление предназначено только для построения виджетов и макета, но чтобы сделать его простым (не создавать несколько классов), я также инициализирую его в контроллере.

Реальная работа находится в контроллере. Он содержит самые жёсткие детали... Threading также идет туда, поэтому это не так очевидно, что это на самом деле. Я реализовал класс Thread с нуля. Существует альтернатива: использование SwingWorker. Это может быть клише, но ясно: я использую threading, чтобы сделать GUI отзывчивым в любое время. Без правильной резьбы весь GUI замерзнет, ​​когда будет проведено вычисление. Я решил сделать это как можно проще с точки зрения реализации Sudoku, например, неблокирующих инкрементных обновлений.

Что касается потоковой передачи, важно знать, какой код работает в этом потоке. Каждое действие, выполняемое компонентом GUI, выполняется по EDT (потоку отправки событий). Если вы выполняете какую-либо долгосрочную задачу, графический интерфейс не будет реагировать. Поэтому я просто делаю еще один поток (см. Реализацию goButtonPressed()) и запускаю его. После этого EDT может обрабатывать любые другие события без блокировки.

Итак, ваш Sudoku работает в специальном фоновом потоке. Он может делать все, что захочет, если только он не должен обновлять GUI. Это почти наверняка, потому что это происходит, когда происходят частичные обновления. Вот уловка: если вы вызываете какой-либо компонент GUI напрямую (устанавливаете некоторые значения), то графический интерфейс будет зависеть. Это состояние, вызванное нарушением диспетчеризации EDT. Все взаимодействие с Swing должно выполняться на EDT, чтобы избежать зависания. Как это сделать? Для этого у EDT есть специальная очередь событий. Вы отправляете событие обновления в очередь. В коде EDT постоянно отслеживаются входящие события и соответственно обновляется графический интерфейс. Таким образом, в основном это связь между фоновым потоком и EDT. Чтобы отправить событие в очередь, вы можете использовать специальный метод утилиты, разработанный именно для этого: EventQueue.invokeLater(new Runnable() { /* here goes your GUI interaction */ });. Взгляните на методы SudokuController:

  • setSudokuResult()
  • public void setSudokuTime()
  • setSudokuCompleted()

Это были события обновления графического интерфейса пользователя.

Ответ 2

старый источник: http://i38.tinypic.com/5mieqa.png Это должно дать вам достаточно, чтобы начать. Просто добавьте логику getter, чтобы вытащить значения, которые они ввели в текстовые поля.

Main:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sudoku;

import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author nicholasdunn
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        JFrame frame = new JFrame("");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel();

        panel.add(new Board());
        panel.add(new JButton(">"));
        panel.add(new Board());
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }
}

NineSquare:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sudoku;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**
 *
 * @author nicholasdunn
 */
public class NineSquare extends JPanel {

    // What direction in relation to the center square
    private JTextField nw,n,ne,e,se,s,sw,w,c;
    private JTextField[] fields = new JTextField[]{
        nw,n,ne,e,se,s,sw,w,c
    };
    private static final int BORDER_WIDTH = 5;

    public NineSquare(Color bgColor) {
        setLayout(new GridLayout(3,3));
        initGui();
        setBackground(bgColor);
    }

    private void initGui() {
        for (int i = 0; i < fields.length; i++) {
            fields[i] = new JTextField(1);
            fields[i].setDocument(new NumericalDocument());
            add(fields[i]);
        }
        setBorder(BorderFactory.createMatteBorder(BORDER_WIDTH,BORDER_WIDTH,BORDER_WIDTH,BORDER_WIDTH, Color.BLACK));
    }

    public Dimension getPreferredDimension() {
        return new Dimension(100,100);
    }

    public static class NumericalDocument extends PlainDocument {
        String numbers = "0123456789";
        @Override
        public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
            if (getLength() == 0 && str.length() == 1 && numbers.contains(str)) {
                super.insertString(offs, str, a);
            }
            else {
                Toolkit.getDefaultToolkit().beep();
            }
        }
    }
}

Совет:

package sudoku;

import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JPanel;

/**
 *
 * @author nicholasdunn
 */
public class Board extends JPanel {
    private NineSquare[] gridSquares = new NineSquare[9];
    private Color[] bgs = {Color.blue.brighter(), Color.gray};
    public Board() {
        setLayout(new GridLayout(3,3));
        for (int i = 0; i < gridSquares.length; i++) {
            gridSquares[i] = new NineSquare(bgs[i%2]);
            add(gridSquares[i]);
        }
    }
}

Ответ 3

Я не могу понять, как вы могли бы отказаться от этой удивительной распечатки ASCII.

Вам следует по-настоящему взглянуть на обучающие материалы @http://download.oracle.com/javase/tutorial/uiswing/ и посмотреть, как работают менеджеры макетов.

Для текстовых полей я бы рекомендовал использовать JTextField. Вот какой код вы можете использовать, чтобы они принимали только одну цифру в то время:

public class textBox extends JTextField implements KeyListener{
    public textBox() {
        addKeyListener(this);       
    }

    @Override
    public void keyPressed(KeyEvent e) {
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent ke) {

        //consume the event otherwise the default implementation will add it to the text
        ke.consume(); 

        if (Character.isDigit(ke.getKeyChar())) 
            this.setText(Character.toString(ke.getKeyChar()));
    }
}

Ответ 4

Чтобы сделать это действительно полезным, вам придется настраивать множество вещей.

Я предлагаю вам использовать кнопки вместо текстовых полей. Когда кто-то нажимает кнопку, он выбирается, когда кто-то вводит номер, он переходит в выбранное текстовое поле (заменяя там номер, если таковой имеется). Это дает вам немного больше контроля над тем, как вводятся ключи.

Макет может быть жестким. Было бы неплохо воспользоваться возможностями Swing для масштабирования размеров с размером экрана, но не забудьте также масштабировать шрифты.

Почти каждый ручной графический интерфейс swing должен начинаться с BorderLayout. Это дает вам "Стороны", даже если вы используете только север или юг (ваш пример используется только на юг), BorderLayout отлично подходит для выделения всего неиспользуемого пространства в центр.

В центре вы, вероятно, захотите разместить другой контейнер, возможно, сетку.

Есть один - я думаю, что это "Box", который имеет равномерное расстояние одной строки. Поэтому, если вы настроили строку по 3 горизонтали, затем добавили по 3 вертикали к каждому ящику, вы могли бы ВСТАВИТЬ каждый из них, создав ящик (чтобы вы могли различать каждую группу из 9), а затем внутри этого поля добавить еще 3 горизонта, каждый из которых заполнен 3 вертикальными.

Макеты Swing обычно сводятся к нескольким стандартным трюкам (например, всегда смотря на BorderLayout), за которыми следуют некоторые догадки, эксперименты и некоторый уровень проклятия.

Ответ 5

Итак, вам нужно

  • Ограничить текстовые поля #s 1-9
  • Предотвращение ввода более 1 значения за раз.

(1) Чтобы ограничить ваши текстовые поля только номером, я думаю, что вы могли бы использовать его JComboBox, который заполняется с помощью ints (от 1 до 9), завернутых в поля Integer.

(2) Таким образом, пользователь должен выбрать JComboBox @для каждой (x, y) точки сетки на плате судоку. Затем необходимо выбрать желаемый номер из раскрывающегося списка, одновременно предотвращая одновременный ввод нескольких файлов.

Надеюсь, что это поможет,
Гудлак!

EDIT: ясность + 1

Ответ 6

Netbeans IDE имеет отличный графический интерфейс для создания графических интерфейсов. Тем не менее, он помогает (много) иметь базовое понимание графических интерфейсов Java, прежде чем пытаться сгенерировать его с помощью инструмента. Особенно важно играть с каждым из менеджеров макетов и получать представление о том, какое из них поможет в данной ситуации. Также обратите внимание, что вы можете вложить панели с разными менеджерами компоновки, чтобы получить больше контроля над макетом.