JComboBox displaying invisible drop-down menu

970 Views Asked by At

This is my first question on stackoverflow and I'm in need of some help.

As part of a grander java application, I would like to bring up a JDialog with a couple of JComboBoxes querying the user to select a printer to use and then select the association resolution at which to print.

However, if I select a printer and the resolution which I pick is shared amongst several printers, then when I pick a printer which contains the same resolution, the drop down menu which gets displayed for the resolution combo box is invisible. The size of the drop down menu is correct, it just doesn't get populated. Try my code out and you'll see what I mean. For example, two of my printing options are Win32 Printer : Kyocera FS-1035MFP KX and Win32 Printer : Adobe PDF (print to pdf). They both share the resolution 300x300, so if I select this resolution for the Kyocera and then select the Adobe PDF printer, the drop down menu will be the correct size, but will be empty.

I'm not really sure what is going on. Hopefully someone can help me. Thank you for your time.

import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Vector;
import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.PrinterResolution;
import javax.swing.*;

public final class ComboDemo extends JDialog {

    private JComboBox selectPrinterBox;
    private JLabel selectPrinterLabel;
    private JComboBox selectResolutionBox;
    private JLabel selectResolutionLabel;
    private PrintService printService;
    private Resolution resolution;
    private DocFlavor flavor;
    private PrintRequestAttributeSet aset;
    private Vector<Resolution> resolutionVector;
    private double xDPI = 300.0;
    private double yDPI = 300.0;

    public PrintService[] getPrintServices() {
        this.flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        this.aset = new HashPrintRequestAttributeSet();

        return PrintServiceLookup.lookupPrintServices(flavor, aset);
    }

    public Vector<Resolution> getVectorOfResolutions(PrintService service) {
        PrinterResolution[] supportedResolutions =
                (PrinterResolution[]) service.getSupportedAttributeValues(
                javax.print.attribute.standard.PrinterResolution.class,
                flavor, aset);
        Vector<Resolution> resolutions = new Vector<Resolution>();
        for (PrinterResolution supportedResolution : supportedResolutions) {
            Resolution res = new Resolution();
            res.setxDPI(supportedResolution.getResolution(PrinterResolution.DPI)[0]);
            res.setyDPI(supportedResolution.getResolution(PrinterResolution.DPI)[1]);
            resolutions.add(res);
        }

        return resolutions;
    }

    public ComboDemo() {

        super();
        initComponents();
        setContent();
        setItemListeners();

    }

    public void initComponents() {

        this.selectPrinterLabel = new JLabel("Select Printer: ");

        PrintService[] services = this.getPrintServices();
        this.selectPrinterBox = new JComboBox(services);

        this.printService = (PrintService) this.selectPrinterBox.getSelectedItem();
        this.resolutionVector = this.getVectorOfResolutions(printService);

        this.resolution = new Resolution();
        this.selectResolutionLabel = new JLabel("Select Resolution: ");
        this.selectResolutionBox = new JComboBox(this.resolutionVector);
    }

    public void setContent() {

        JPanel selectPrinterPanel = new JPanel();
        selectPrinterPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        selectPrinterPanel.add(selectPrinterLabel);
        selectPrinterPanel.add(selectPrinterBox);

        JPanel selectResolutionPanel = new JPanel();
        selectResolutionPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        selectResolutionPanel.add(selectResolutionLabel);
        selectResolutionPanel.add(selectResolutionBox);

        JPanel mainPanel = new JPanel();
        BoxLayout fP = new BoxLayout(mainPanel, BoxLayout.Y_AXIS);
        mainPanel.setLayout(fP);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        mainPanel.add(selectPrinterPanel);
        mainPanel.add(selectResolutionPanel);

        this.setContentPane(mainPanel);
        this.setTitle("ComboDemo");
        this.setLocation(85, 79);
        this.pack();

    }

    public void setItemListeners() {

        selectPrinterBox.addItemListener(
                new ItemListener() {

                    @Override
                    public void itemStateChanged(ItemEvent evt) {
                        if (evt.getSource().equals(selectPrinterBox)) {
                            if (evt.getStateChange() == ItemEvent.SELECTED) {
                                System.out.println("in printerBox itemListener");
                                printService = (PrintService) selectPrinterBox.getSelectedItem();
                                resolution = (Resolution) selectResolutionBox.getSelectedItem();
                                System.out.println("resolution (PrinterBox) : " + resolution.toString());
                                resolutionVector.clear();
                                resolutionVector.addAll(getVectorOfResolutions(printService));
                                if (resolutionVector == null) {
                                    System.out.println("resVec is null");
                                }
                                if (resolutionVector.contains(resolution)) {
                                    selectResolutionBox.setSelectedIndex(resolutionVector.lastIndexOf(resolution));

                                } else {
                                    selectResolutionBox.setSelectedIndex(0);
                                }
                            }
                        }

                    }
                });

        selectResolutionBox.addItemListener(
                new ItemListener() {

                    @Override
                    public void itemStateChanged(ItemEvent evt) {
                        if (evt.getSource().equals(selectResolutionBox)) {
                            if (evt.getStateChange() == ItemEvent.SELECTED) {
                                System.out.println("in resolutionBox itemListener");
                                resolution = (Resolution) selectResolutionBox.getSelectedItem();
                                System.out.println("resolution (ResolutionBox) : " + resolution.toString());
                                xDPI = (double) resolution.getxDPI();
                                yDPI = (double) resolution.getyDPI();
                            }
                        }
                    }
                });

    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                ComboDemo cd = new ComboDemo();
                cd.setVisible(true);

            }
        });
    }
}

class Resolution {

    private int xDPI;
    private int yDPI;

    public int getxDPI() {
        return xDPI;
    }

    public void setxDPI(int xDPI) {
        this.xDPI = xDPI;
    }

    public int getyDPI() {
        return yDPI;
    }

    public void setyDPI(int yDPI) {
        this.yDPI = yDPI;
    }

    @Override
    public String toString() {
        return (this.getxDPI() + "x" + this.getyDPI());
    }

    @Override
    public boolean equals(Object obj) {
        if ( obj instanceof Resolution ) {
            Resolution r = (Resolution) obj;
            return (this.xDPI == r.xDPI) && (this.yDPI == r.yDPI);
        }
        return false;
    }

    @Override
    public int hashCode() {
      return (this.getxDPI()*1000)+ this.getyDPI();  
    }
}
1

There are 1 best solutions below

1
On

The problem is that you are manipulating the Vector that backs up the implicit ComboBoxModel you are using, behind the back of that ComboBoxModel. If the resolution is not contained, you call setSelectedIndex(0) which eventually triggers a refresh of the items of the combo box (because of some twisted internals of JComboBox/DefaultComboBoxModel.

So:

  1. Either use a ComboBoxModel and when you want to modify the content of the JComboBox, do it with the ComboBoxModel (take a look at the DefaultComboBoxModel)
  2. Or use the JComboBox API (removeAllItems, addItem)
  3. Use an ActionListener on the comboboxes. instead of ItemListener You will only be notified of "selection-change" events