Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issues with PrinterJob #612

Closed
Abu-Abdullah opened this issue Apr 3, 2020 · 11 comments
Closed

issues with PrinterJob #612

Abu-Abdullah opened this issue Apr 3, 2020 · 11 comments

Comments

@Abu-Abdullah
Copy link

Hi,

i was trying to use weblaf with PrinterJob but it gives me the following:

Exception in thread "Thread-3" com.alee.managers.style.StyleException: Unable to apply style 'panel' to component: javax.swing.JSpinner$NumberEditor[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=16777225,maximumSize=,minimumSize=,preferredSize=]
	at com.alee.managers.style.data.ComponentStyle.apply(ComponentStyle.java:361)
	at com.alee.managers.style.AbstractSkin.applySkin(AbstractSkin.java:66)
	at com.alee.managers.style.StyleData.applySkin(StyleData.java:297)
	at com.alee.managers.style.StyleData.install(StyleData.java:124)
	at com.alee.managers.style.StyleManager.installSkin(StyleManager.java:1198)
	at com.alee.laf.panel.WebPanelUI.installUI(WebPanelUI.java:57)
	at java.desktop/javax.swing.JComponent.setUI(JComponent.java:685)
	at java.desktop/javax.swing.JPanel.setUI(JPanel.java:150)
	at java.desktop/javax.swing.JPanel.updateUI(JPanel.java:126)
	at java.desktop/javax.swing.JPanel.<init>(JPanel.java:86)
	at java.desktop/javax.swing.JPanel.<init>(JPanel.java:95)
	at java.desktop/javax.swing.JSpinner$DefaultEditor.<init>(JSpinner.java:621)
	at java.desktop/javax.swing.JSpinner$NumberEditor.<init>(JSpinner.java:1230)
	at java.desktop/javax.swing.JSpinner$NumberEditor.<init>(JSpinner.java:1206)
	at java.desktop/javax.swing.JSpinner$NumberEditor.<init>(JSpinner.java:1181)
	at java.desktop/javax.swing.JSpinner.createEditor(JSpinner.java:252)
	at java.desktop/javax.swing.JSpinner.<init>(JSpinner.java:157)
	at java.desktop/sun.print.ServiceDialog$CopiesPanel.<init>(ServiceDialog.java:1215)
	at java.desktop/sun.print.ServiceDialog$GeneralPanel.<init>(ServiceDialog.java:684)
	at java.desktop/sun.print.ServiceDialog.initPrintDialog(ServiceDialog.java:193)
	at java.desktop/sun.print.ServiceDialog.<init>(ServiceDialog.java:143)
	at java.desktop/javax.print.ServiceUI.printDialog(ServiceUI.java:194)
	at java.desktop/sun.print.RasterPrinterJob.printDialog(RasterPrinterJob.java:1063)
	at classes.appSystem$appSystemResults.printData(appSystem.java:1978)
	at classes.appSystem$appSystemResults$2$1.run(appSystem.java:1939)
Caused by: java.lang.ArrayIndexOutOfBoundsException: No such child: 0
	at java.desktop/java.awt.Container.getComponent(Container.java:350)
	at java.desktop/javax.swing.JSpinner$DefaultEditor.getTextField(JSpinner.java:702)
	at java.desktop/javax.swing.JSpinner$NumberEditor.setComponentOrientation(JSpinner.java:1295)
	at com.alee.laf.WebLookAndFeel.setOrientation(WebLookAndFeel.java:1526)
	at com.alee.painter.AbstractPainter.updateOrientation(AbstractPainter.java:515)
	at com.alee.painter.AbstractPainter.installPropertiesAndListeners(AbstractPainter.java:406)
	at com.alee.painter.decoration.AbstractDecorationPainter.installPropertiesAndListeners(AbstractDecorationPainter.java:159)
	at com.alee.painter.AbstractPainter.install(AbstractPainter.java:99)
	at com.alee.painter.PainterSupport.setPainter(PainterSupport.java:135)
	at com.alee.managers.style.data.ComponentStyle.apply(ComponentStyle.java:357)
	... 24 more

code snapshot

final PrinterJob prnJob = PrinterJob.getPrinterJob();
prnJob.setPrintable(this);
final PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
if(prnJob.printDialog(attr)) prnJob.print(attr);
@mgarin
Copy link
Owner

mgarin commented Apr 3, 2020

Can you provide a small executable code example which displays this issue? Because code you provided doesn't really show what exactly you're trying to print and what UI elements are involved.

@mgarin mgarin self-assigned this Apr 3, 2020
@mgarin mgarin added the bug label Apr 3, 2020
@mgarin mgarin added this to the v1.4.0 milestone Apr 3, 2020
@Abu-Abdullah
Copy link
Author

the following is a sample code (sorry it is not clean at all)

package classes;

import com.alee.laf.WebLookAndFeel;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.net.URI;
import java.util.Vector;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.table.DefaultTableCellRenderer;

public class SwingDemo
{
	JDesktopPane desktopPane;
	SwingDemo()
	{
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		desktopPane = new JDesktopPane();
		mySystemResults intFrame = new mySystemResults();
		intFrame.setBounds(50, 90, 200, 250);
		frame.add(desktopPane);
		frame.setSize(600, 500);
		frame.setVisible(true);

		final JPopupMenu popup = new JPopupMenu();
		final JMenuItem menuItem1 = new JMenuItem("تجربة");

		menuItem1.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
		popup.add(menuItem1);

		desktopPane.addMouseListener(new MouseAdapter()
		{
			public void mousePressed(MouseEvent e)
			{
				maybeShowPopup(e);
			}

			public void mouseReleased(MouseEvent e)
			{
				maybeShowPopup(e);
			}

			private void maybeShowPopup(MouseEvent e)
			{
				if (e.isPopupTrigger())
				{
					if (MaknoonIslamicEncyclopedia.language)
					{
						popup.updateUI();
						popup.show(e.getComponent(), e.getX() - popup.getPreferredSize().width + 2, e.getY());
					}
					else
						popup.show(e.getComponent(), e.getX(), e.getY());
				}
			}
		});
	}

	public static void main(final String[] args)
	{
		WebLookAndFeel.install();
		WebLookAndFeel.setLeftToRightOrientation(false);
		new SwingDemo();
	}

	class mySystemResults extends JInternalFrame implements Printable
	{
		final JTable resultsTable;
		mySystemResults()
		{
			final Vector<Vector> resultsDataVector = new Vector<Vector>(10, 10);

			resultsDataVector.addElement(toVector("", "تجربة", "<html><font color=red>تجربة"));
			resultsDataVector.addElement(toVector("", "", ""));

			setTitle("تجربة");
			setLayout(new BorderLayout());
			setMaximizable(true);
			setResizable(true);

			final Vector<String> columnNames = new Vector<>();
			columnNames.add("1");
			columnNames.add("3");
			columnNames.add("3");

			resultsTable = new JTable(resultsDataVector, columnNames){public boolean isCellEditable(int row, int col){return false;}};

			final DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
			renderer.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

			final JPanel zakatMainPanel= new JPanel(new BorderLayout());
			zakatMainPanel.add(new JScrollPane(resultsTable));

			final JPanel selectedZakatPanel = new JPanel(new BorderLayout());
			selectedZakatPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "test", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_JUSTIFICATION, null, Color.red));

			final JPanel mainSelectedZakatPanel = new JPanel();
			mainSelectedZakatPanel.setLayout(new BoxLayout(mainSelectedZakatPanel, BoxLayout.Y_AXIS));
			selectedZakatPanel.add(mainSelectedZakatPanel, BorderLayout.CENTER);

			final JPanel decoratePanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
			decoratePanel.add(new JLabel("<html><font color=maroon>تجربة"));
			mainSelectedZakatPanel.add(decoratePanel);

			final JPanel printPanel = new JPanel(new BorderLayout());
			final JButton printButton = new JButton ("print");
			printButton.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					Thread runner = new Thread() {public void run() {printData();}};
					runner.start();
				}
			});

			printPanel.add(printButton, BorderLayout.SOUTH);
			selectedZakatPanel.add(printPanel, BorderLayout.WEST);

			zakatMainPanel.add(selectedZakatPanel, BorderLayout.NORTH);
			getContentPane().add(zakatMainPanel);
			desktopPane.add(this);
			pack();

			getContentPane().applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
			applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

			setVisible(true);
		}

		private Vector<String> toVector(String e1, String e2, String e3)
		{
			Vector<String> v = new Vector<String>();
			v.addElement(e1);
			v.addElement(e2);
			v.addElement(e3);

			return v;
		}

		public void printData()
		{
			try
			{
				final PrinterJob prnJob = PrinterJob.getPrinterJob();
				prnJob.setPrintable(this);
				final PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
				if(prnJob.printDialog(attr)) prnJob.print(attr);
			}
			catch (PrinterException e)
			{
				e.printStackTrace();
			}
		}

		public int print(Graphics pg, PageFormat pageFormat, int pageIndex)
		{
			return PAGE_EXISTS;
		}
	}
}

the issue is with using:

WebLookAndFeel.setLeftToRightOrientation(false);

in normal LTR, it works just fine

i have another small issue with popup and pointer location in RTL. just right click on JDesktopPane and the list is not aligned with the pointer. i believe it is the popup shadow size that is causing the pointer to be away from the list. any hint here is appreciated.

@mgarin
Copy link
Owner

mgarin commented Apr 6, 2020

Thanks for the example! I'll look into this quite soon.


Regarding the popup menu offset - there is already an issue added for it - #292 - I'm not yet sure about how or when I will be fixing this problem, so for now - you can add a custom offset if you're only using WebLaF. And yes, you are correct - offset is caused by the menu decoration that is painted on the popup window root pane, the actual window is positioned exactly at the point you've specified.


A bit unrelated to the issue, but I saw you've been using updateUI() on popup menu in the example - I strongly recommend not to do that. And that applies to all UI elements, not just the menu, for a few reasons:

  1. First and foremost - using updateUI() is a wrong approach for updating your component, use revalidate() and repaint() instead, together if necessary. In case of data components like JTable making a correct model will always ensure that component stays visually up-to-date. In this particular case with menu it is completely unnecessary and might actually cause issues, so I recommend removing it.

  2. Calling updateUI() will always (or sometimes, depending on component used) completely reset UI implementation and all related resources and create it again from a scratch. This is very ineffective and will certainly cause UI performance issues when used on complex components or used often across multiple components.

  3. As mentioned before - UI update method exists for fully resetting component's UI implementation and often used by developers as a band-aid to either fix UI element bugs or incorrect use of element models.

In case you ever see any issues with any WebLaF UI elements - I recommend reporting it as an issue here instead of trying to fix it with updateUI(), even if it does seem to work.

@mgarin
Copy link
Owner

mgarin commented Apr 6, 2020

I've tried the code example and it works correctly for me (with both RTL and LTR).
Tested it on a few JDK6 and JDK8 versions under Windows 8 and Windows 10.

So a few more questions:

  • Which WebLaF version are you using?
  • Which Java version are you using?
  • Which OS/version are you using?

@Abu-Abdullah
Copy link
Author

you are right, it seems the issue is with the JDK 10 and above. i tried it with oracle JDK8 and it works fine. it gives me this error with jdk10/jdk13/jdk14

@Abu-Abdullah
Copy link
Author

WebLaF 1.2.12 latest from maven on windows 10

@mgarin
Copy link
Owner

mgarin commented Apr 6, 2020

I'll try it on newer JDKs.

@mgarin
Copy link
Owner

mgarin commented Apr 6, 2020

It does indeed reproduce on JDK9 and later and only on RTL orientation.

I also found the cause of the issue, it's this piece of code added to JSpinner.NumberEditor:

        /**
         * {@inheritDoc}
         */
        @Override
        public void setComponentOrientation(ComponentOrientation o) {
            super.setComponentOrientation(o);
            getTextField().setHorizontalAlignment(
                    o.isLeftToRight() ? JTextField.RIGHT : JTextField.LEFT);
        }

It appeared in JDK9 first time.

The problem with this method is that call to getTextField() causes the exception you're seeing because it is called in the NumberEditor (which is a JPanel) UI initialization cycle, at that point the actual editor field simply doesn't exist.

I guess this issue haven't been raised with other L&Fs yet because they either do not have a global orientation setting or simply because no one seen that issue with later JDK versions on RTL orientation.

I'll add a dirty fix for this in the orientation update method which will simply skip NumberEditor on JDK9 and later. This will result in NumberEditor not having correct orientation internally, but it doesn't really affect anything visually.

mgarin added a commit that referenced this issue Apr 6, 2020
@mgarin
Copy link
Owner

mgarin commented Apr 6, 2020

I've pushed the fix, it will be shortly available in snapshot.

@mgarin
Copy link
Owner

mgarin commented Apr 6, 2020

Fix is now available in snapshot version and will be included in v1.3.0 update.

@mgarin mgarin closed this as completed Apr 6, 2020
@mgarin mgarin added this to the v1.2.13 milestone May 25, 2020
@mgarin
Copy link
Owner

mgarin commented Jun 19, 2020

Just a small note - this will be available in v1.2.13 update that will be going live shortly.
I will take some more time to polish v1.3.0 and meanwhile will release a few smaller updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants