Совместное использование состояния между JButtons - PullRequest
4 голосов
/ 02 февраля 2010

Я хочу создать два или более JButton с общим состоянием, т. Е. Когда кнопка мыши нажата либо на JButton, оба отображаются как нажатые (или «поставлены на охрану»), или если они являются флажками, оба проверяются / не проверяются одновременно и т. д.

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

Я могу пойти наполовину, создав одну ButtonModel и назначив одну и ту же модель обеим кнопкам. Это синхронизирует их охрану / проверенные / выбранные состояния и т. Д.

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

Есть ли чистый способ сделать это?

В идеале я бы хотел, чтобы он был независим от выбранного внешнего вида.

Редактировать: Я обнаружил еще одну проблему с разделением ButtonModel. Когда одна из кнопок теряет фокус, она устанавливает свойства armed и pressed модели на false. Это происходит после обработки mousePressed, поэтому, если вы нажмете вторую кнопку, когда первая кнопка имеет фокус, она не перейдет в нажатое состояние, пока вы не нажмете ее второй раз.

Ответы [ 3 ]

3 голосов
/ 03 февраля 2010

Вы сделали действительно хороший ход, используя одну и ту же ButtonModel для двух кнопок.

Теперь к вашей проблеме с фокусом. Ответ: Нет. L&F агностического пути нет. Вы должны переопределить BasicButtonUI (или какой ButtonUI вы используете) и переопределить логику рисования фокуса.

3 голосов
/ 03 февраля 2010

Вот что я сделал:

  • Расширить JButton новым классом SharedFocusButton
  • SharedFocusButton переопределяет hasFocus, getModel и paintBorder.
  • Когда работает либо JButton.paintBorder(Graphics), либо ButtonUI.update(Component, Graphics), временно измените поведение hasFocus, чтобы оно возвращало true, если какая-либо кнопка в группе имеет фокус. Также временно измените поведение getModel, чтобы вернуть прокси ButtonModel (в других случаях он возвращает общий ButtonModel)
  • Прокси-сервер ButtonModel ведет себя по умолчанию, совместно используемый ButtonModel, за исключением того, что он отказывается изменять значения свойств armed или pressed на false при обработке события focusLost.
  • Обрабатывать focusGained и focusLost, заставляя все кнопки в группе перерисовывать себя (это не произойдет автоматически, потому что у каждой кнопки есть собственный пользовательский интерфейс, обрабатывающий события фокуса.)

Остальные проблемы:
Обход фокуса, вероятно, следует изменить так, чтобы клавиша Tab никогда не передавала фокус с одной кнопки на другую в той же группе.

1 голос
/ 03 февраля 2010

Я предполагаю, что у вас уже есть текст, слушатели и тому подобное.

Переходя к методу рисования BasicButtonUI, мы видим, что он на самом деле проверяет, находится ли кнопка в фокусе, перед выполнением определенной рисования. Поэтому, если вы не можете иметь два сфокусированных компонента одновременно, единственный способ сделать это, о котором я могу подумать, - это использовать интерфейс другой кнопки для рисования.

Обе кнопки должны быть FocusButton и вызывать setButton друг на друга. Помимо прочего, я не удосужился добавить проверку нуля.

public class FocusButton extends JButton {
    private JButton btn;

    public FocusButton() {
        addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent e) {
                // Other button seems to repaint when focus is gained anyway
            }

            public void focusLost(FocusEvent e) {
                btn.repaint();
            }
        });
    }

    public void setButton(JButton btn) {
        this.btn = btn;
    }

    public void paint(Graphics g) {
        if (!btn.hasFocus()) {
            super.paint(g);
        } else {
            btn.paint(g);
        }
    }
}

РЕДАКТИРОВАТЬ: Это не работает слишком хорошо, если ваши кнопки не имеют одинаковый размер, и, очевидно, не работает вообще, если они должны иметь другой текст.

...