Perché i pulsanti di opzione vengono visualizzati in modo errato in java.awt.Dialog sul Mac quando la finestra di dialogo è modale?

StackOverflow https://stackoverflow.com/questions/1002394

  •  05-07-2019
  •  | 
  •  

Domanda

Sto testando la mia applicazione Java su Mac e ho riscontrato un problema molto strano. Le caselle di controllo visualizzate in una finestra di dialogo modale non vengono visualizzate correttamente, sebbene le finestre di dialogo non modali funzionino correttamente.

Ad esempio, supponiamo che io abbia una finestra con 2 pulsanti di opzione. Quando si apre la finestra di dialogo, viene selezionata la prima. Quando faccio clic sul secondo pulsante, all'improvviso sembra che entrambi siano selezionati. Facendo clic in qualsiasi altra parte della finestra di dialogo, il rendering si risolverà automaticamente e verrà visualizzato solo il pulsante selezionato.

Il seguente codice riproduce questo per me:

package mactest;

import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Main {
  public static void main(String[] args) {
    boolean modal = false;
    if(args.length > 0) {
      modal = args[0].toLowerCase().equals("true");
    }

    TestDialog dlg = new TestDialog(new Frame(), modal);

    dlg.setVisible(true);
  }

  private static class TestDialog extends Dialog {
    private Checkbox cb1;
    private Checkbox cb2;

    private CheckboxGroup cbg;

    public TestDialog(Frame owner, boolean modal) {
      super(owner);

      cbg = new CheckboxGroup();

      cb1 = new Checkbox("One", true, cbg);
      cb2 = new Checkbox("Two", false, cbg);

      this.setLayout(new FlowLayout());
      this.add(cb1);
      this.add(cb2);

      this.setModal(modal);
      this.pack();

      this.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          TestDialog.this.setVisible(false);
          System.exit(0);
        }
      });
    }
  }
}

Se lo chiamo così:

  

java -cp MacTest.jar mactest.Main false

la finestra di dialogo non è modale e tutto funziona bene. Tuttavia, se dico che è modale:

  

java -cp MacTest.jar mactest.Main true

quindi si verificano i problemi di rendering.

Ho provato tutti i trucchi a cui riesco a pensare per risolvere il problema (invalidate, doLayout, richiesta di focus, impostazione esplicita dello stato di ogni pulsante quando ne viene selezionato uno, ecc.), ma finora l'unica cosa che ho ho scoperto che funziona è rendere il dialogo non modale. Sfortunatamente, questa non è un'opzione nella mia applicazione.

Nel caso in cui sia importante, ciò si trova su un MacBook con OS X 10.5 con Java 1.5.0_16.

È stato utile?

Soluzione 2

Ho trovato qualcosa che sembra risolverlo, anche se è un brutto hack. Ho aggiunto listener di voci a ciascuna delle caselle di controllo. Quando si attivano, ridimensiono la finestra di 1 pixel, quindi eseguo invokeLater () su pack () (le mie finestre di dialogo non sono ridimensionabili). Ecco il codice di prova modificato:

package mactest;

import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Rectangle;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Main {
  public static void main(String[] args) {
    boolean modal = false;
    boolean tweak = false;
    if(args.length > 0) {
      modal = args[0].toLowerCase().equals("true");
    }
    if(args.length > 1) {
      tweak = args[1].toLowerCase().equals("true");
    }

    TestDialog dlg = new TestDialog(new Frame(), modal, tweak);

    dlg.setVisible(true);
  }

  private static class TestDialog extends Dialog {
    private Checkbox cb1;
    private Checkbox cb2;

    private CheckboxGroup cbg;

    public TestDialog(Frame owner, boolean modal, boolean tweak) {
      super(owner);

      cbg = new CheckboxGroup();

      cb1 = new Checkbox("One", true, cbg);
      cb2 = new Checkbox("Two", false, cbg);

      this.setLayout(new FlowLayout());
      this.add(cb1);
      this.add(cb2);

      this.setModal(modal);
      this.pack();

      if(tweak) {
        cb1.addItemListener(new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            onSelection();
          }
        });
        cb2.addItemListener(new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            onSelection();
          }
        });
      }

      this.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          TestDialog.this.setVisible(false);
          System.exit(0);
        }
      });
    }

    private void onSelection() {
      Rectangle bounds = this.getBounds();
      this.setBounds(bounds.x, bounds.y, bounds.width + 1, bounds.height);
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          TestDialog.this.pack();
        }
      });
    }
  }
}

Per i componenti ridimensionabili è necessario memorizzare le dimensioni pre-ottimizzazione e ripristinarle anziché chiamare pack ().

In Windows vedevo lo sfarfallio della finestra di dialogo ogni tanto quando cambiavo la selezione, anche se sul Mac non si notava affatto.

Altri suggerimenti

Stai chiedendo informazioni su caselle di controllo o pulsanti radio? Citi entrambi.

Per creare un ambito di esclusione multipla è necessario utilizzare la classe ButtonGroup

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top