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();
}
}
The problem is that you are manipulating the
Vector
that backs up the implicitComboBoxModel
you are using, behind the back of thatComboBoxModel
. If the resolution is not contained, you callsetSelectedIndex(0)
which eventually triggers a refresh of the items of the combo box (because of some twisted internals ofJComboBox
/DefaultComboBoxModel
.So:
ComboBoxModel
and when you want to modify the content of the JComboBox, do it with theComboBoxModel
(take a look at theDefaultComboBoxModel
)JComboBox
API (removeAllItems
,addItem
)ActionListener
on the comboboxes. instead ofItemListener
You will only be notified of "selection-change" events