how to print the selected pane inside FXML - java

i want to print the fxml contain pane but don't know how to do it.
i try two code inside button action .
first
void doPrint(Node printPane) {
PrinterJob job = PrinterJob.createPrinterJob();
if (job != null && job.showPageSetupDialog(printPane.getScene().getWindow())) {
job.printPage(printPane);
job.endJob();
}
}
}
second
boolean doPrint(Node printPane) {
PrinterJob job = PrinterJob.createPrinterJob();
if (job == null) {
return false;
}
if (!job.printPage(printPane)) {
return false;
}
return job.endJob();
}

This will print any node you pass into it.
private void printImage(Node node) {
PrinterJob job = PrinterJob.createPrinterJob();
if (job != null) {
boolean success = job.printPage(node);
if (success) {
System.out.println("PRINTING FINISHED");
job.endJob();
}
}
}

Try this on action event
#FXML
private void PrintAction(ActionEvent event) {
Printer printer = Printer.getDefaultPrinter(); //get the default printer
javafx.print.PageLayout pageLayout = printer.createPageLayout(Paper.NA_LETTER, PageOrientation.PORTRAIT, Printer.MarginType.DEFAULT); //create a pagelayout. I used Paper.NA_LETTER for a standard 8.5 x 11 in page.
PrinterJob job = PrinterJob.createPrinterJob();//create a printer job
if(job.showPrintDialog(tab_doctor_list.getScene().getWindow()))// this is very useful it allows you to save the file as a pdf instead using all of your printer's paper. A dialog box pops up, allowing you to change the "name" option from your default printer to Adobe pdf.
{
double pagePrintableWidth = pageLayout.getPrintableWidth(); //this should be 8.5 inches for this page layout.
double pagePrintableHeight = pageLayout.getPrintableHeight();// this should be 11 inches for this page layout.
tab_doctor_list.prefHeightProperty().bind(Bindings.size(tab_doctor_list.getItems()).multiply(35));// If your cells' rows are variable size you add the .multiply and play with the input value until your output is close to what you want. If your cells' rows are the same height, I think you can use .multiply(1). This changes the height of your tableView to show all rows in the table.
tab_doctor_list.minHeightProperty().bind(tab_doctor_list.prefHeightProperty());//You can probably play with this to see if it's really needed. Comment it out to find out.
tab_doctor_list.maxHeightProperty().bind(tab_doctor_list.prefHeightProperty());//You can probably play with this to see if it' really needed. Comment it out to find out.
double scaleX = pagePrintableWidth / tab_doctor_list.getBoundsInParent().getWidth();//scaling down so that the printing width fits within the paper's width bound.
double scaleY = scaleX; //scaling the height using the same scale as the width. This allows the writing and the images to maintain their scale, or not look skewed.
double localScale = scaleX; //not really needed since everything is scaled down at the same ratio. scaleX is used thoughout the program to scale the print out.
double numberOfPages = Math.ceil((tab_doctor_list.getPrefHeight() * localScale) / pagePrintableHeight);//used to figure out the number of pages that will be printed.
}
}
Instead of tab_doctor_list use your fx:id of pane.

Related

JavaFX target drag event null

I have a for loop that creates multiple rectangle shapes and I am adding DragDropped events to them. For some reason even though the source reports it as successful (and the color of the rectangle changes) when I go to check the target it is reported as null.
ParkingSpot is just an class that extends Rectangle and adds a new more bits of info I need to store in them.
Also, TransferMode.COPY is set on the source and target(ParkingSpot) so that shouldn't be an issue.
private ParkingSpot createRectangle(double x, double y, double width, double height){
ParkingSpot vehicleSpot = new ParkingSpot(x, y, width, height);
...
spot.setOnDragDropped(event -> {
System.out.println("onDragDropped");
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
spot.setTestinfo(db.getString());
System.out.println( " added to " + spot.getTestinfo());
spot.setFill(Color.BLUE);
success = true;
}
event.setDropCompleted(success);
event.consume();
});
}
In this spot.setFill(Color.BLUE); works but for some reason spot.getTestinfo() doesn't. The same goes with me using spot.getX() which also works. I don't understand how it could set the color but not the text. My apologies if this is a bit brief. I can add more if needed.
EDIT: This is how I am creating the rectangles:
for (ParkingSpot spot : parkingSpots){
pane.getChildren().add(createDraggableRectangle(spot.getX(), spot.getY(), spot.getWidth(), spot.getHeight()));
}
This loops through a List of ParkingSpots and adds them to the list for saving and loading.
These are the ListView items and how I copy their info to the dragboard. I know this works as when I drop it onto the shape I have it output the contents it dropped.
listCell.setOnDragDetected(event -> {
/* drag was detected, start a drag-and-drop gesture*/
/* allow any transfer mode */
Dragboard db = listCell.startDragAndDrop(TransferMode.COPY);
/* Put a string on a dragboard */
ClipboardContent content = new ClipboardContent();
content.putString(listCell.getText());
db.setContent(content);
System.out.println("Dragging" + content);
event.consume();
});
Everything here is in my Controller.java class.
Thanks!

How to keep rotating a FontAwesome-icon in Processing?

I'd like to keep rotating a icon from FontAwesome in Processing java. (the fa-spin icon to be precisely.) (\f110)
Link to effect: Example
My create-function for an icon
public void drawIcon(int size, String icon, float custom_height) {
font = createFont("fontawesome-webfont.ttf",size);
textFont(font);
if(icon != null && !icon.trim().isEmpty()) {
text(icon, width / 2, height / custom_height);
}
}
Initialization object + called method
To create my icon, I initialized an object and called my function in the draw()-method :
Content content = new Content(); // content object
PFont font; // font object
public void draw() {
content.drawIcon(46, "\uf110", 7);
}
I found the rotate/translate methods from the documentation, but can't figure out the correct parameters for rotating this icon 360 degrees continiously.
Attempt
public void draw() {
rotate(degrees(360));
content.drawIcon(46, "\uf110", 7);
}
I recommended loading the font once in setup() rather than potentially multiple times a second in drawIcon().
You can simply use text() after you've loaded the font and called textFont().
e.g.
PFont font; // font object
public void setup() {
font = loadFont("fontawesome-webfont.ttf",46);
textFont(font);
}
public void drawIcon(String icon, float custom_height) {
if(icon != null && !icon.trim().isEmpty()) {
text(icon, width / 2, height / custom_height);
}
}
In terms of rotating, at the moment you're specifying the same angle continuously. What you probably want to do is create a variable to keep track of the current angle, increment the angle and pass that to rotate() in draw().
PFont font; // font object
int angle = 0;
public void setup() {
font = loadFont("fontawesome-webfont.ttf",46);
textFont(font);
}
public void drawIcon(String icon, float custom_height) {
if(icon != null && !icon.trim().isEmpty()) {
text(icon, width / 2, height / custom_height);
}
}
public void draw() {
//increment angle (angle++; would to the same, but hopefully expanded version is easier to read)
angle = angle + 1;
rotate(degrees(angle));
content.drawIcon("\uf110", 7);
}
Be sure to checkout the Rotate Processing example as well.
You may notice that the symbol might not rotate from the centre.
This will require you to use multiple coordinate spaces using pushMatrix();/popMatrix(); calls. Do read the 2D transformations tutorial for more info on how to do that.

How do I handle pagination when printing text?

I am attempting to send some potentially long text to a printer for... well, printing. Here is a minimal example that demonstrates how I am currently printing text:
#FXML
private void print() {
Text printText = new Text(textArea.getText());
TextFlow printArea = new TextFlow(printText);
printArea.setTextAlignment(TextAlignment.LEFT);
printArea.setMaxHeight(Region.USE_COMPUTED_SIZE);
PrinterJob printerJob = PrinterJob.createPrinterJob();
if (printerJob != null && printerJob.showPrintDialog(textArea.getScene().getWindow())) {
PageLayout pageLayout = printerJob.getJobSettings().getPageLayout();
printArea.setMaxWidth(pageLayout.getPrintableWidth());
if (printerJob.printPage(pageLayout, printArea)) {
printerJob.endJob();
// done printing
} else {
System.err.println("Printing failed!");
}
} else {
System.err.println("Unable to create printer job or printer dialog cancelled by user");
}
}
The code above prints text as expected, except that no matter how much text is being printed, it always prints just a single page. In the print dialog that is shown, under the section for "Print range", I have been selecting the "All" option. I have tried choosing the "Pages" option (which for some reason has been defaulting from 1 to 9999 - this is a little odd since the text should be at most two pages long), but have not had any success in printing more than a single page. I have also tried manually setting the page range on the JobSettings object, but that didn't seem to do anything either.
How can I use the PrinterJob and its related classes to get a long piece of text to properly print on multiple pages?
As far as I know you need to supply multiple Nodes, printAreas in your case, to the PrinterJob, having divided them up beforehand in your code (unfortunately...) Placing your TextFlow in a styled Scene will give you the total size, you can divide that up based on the PageLayout.getPrintableWidth and getPrintableHeight, with the proviso that the user can potentially alter these in the print settings dialog.
job.getJobSettings().setPageRanges(new PageRange(1, numPages));
Tells the job how many pages you can supply. You generally set this before showing the print dialog so that the user can choose how many pages to print, what range etc.
After showing the dialog the JobSettings will be updated with the selected PageRanges the user has chosen, which you then loop over and print individually.
if (job.showPrintDialog(null)) {
JobSettings js = job.getJobSettings();
for (PageRange pr : js.getPageRanges()) {
for (int p = pr.getStartPage(); p <= pr.getEndPage(); p++) {
boolean ok = job.printPage(...code to get your node for the page...);
...take action on success/failure etc.
}
}
}

Setting event listener for two JTextArea's

I am developing an image processing software (just for fun) and one of the features it has is image resizing option. Basically window pops up, with two JTextArea components to get desired image width and height for resizing. There is also JCheckBox for keeping Aspect ratio if user desires it. The problem is. When check box is selected and user supposedly inputs either width or height first. I want the other text area to update itself accordingly every time a change is made so it would keep AR. I have developed some code that deals with this, but it does not provide what I really want due to lack of understanding what listener to what component should I really assign.
Code:
String height, width;
if (checkBoxImage.isSelected()){
// aspect ratio = width / height
width = widthArea.getText();
height = heightArea.getText();
double aspectRatio = (double) images.get(tabbedPane.getSelectedIndex()).getWidth() / images.get(tabbedPane.getSelectedIndex()).getHeight();
/**
* to do, update width, height area
* to the closest user input
*/
if(heightArea.getText().length() != 0 && heightArea.getText().length() <= 5
&& heightArea.getText().charAt(0) != '0'){
//parsing string to integer
try{
int heightNum = Integer.parseInt(height);
int widthNum = (int) Math.round(aspectRatio * heightNum);
widthArea.setText(String.valueOf(widthNum) );
widthArea.updateUI();
frameimgSize.repaint();
}
catch(NumberFormatException e1){JOptionPane.showMessageDialog(error,e1.getMessage(),"Error", JOptionPane.ERROR_MESSAGE);}
}
//width has been entered first
else if(widthArea.getText().length() != 0 && widthArea.getText().length() <= 5 &&
widthArea.getText().charAt(0) != '0'){
try{
int widthNum = Integer.parseInt(width);
int heightNum = (int) Math.round(aspectRatio * widthNum);
heightArea.setText(String.valueOf(heightNum) );
heightArea.updateUI();
frameimgSize.repaint();
}
catch(NumberFormatException e1){JOptionPane.showMessageDialog(error,e1.getMessage(),"Error", JOptionPane.ERROR_MESSAGE);}
}
}
Is it ever valid to have non-numeric values in your width and height fields?
If not, then use JSpinners or JFormattedTextFields instead of JTextFields. If so, (say for example you allow a "units" to be entered as well as width and height) you should attach a DocumentListener to your JTextFields to monitor changes to the content of the underlying text documents. Here's an example:
widthField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
update();
}
public void removeUpdate(DocumentEvent e) {
update();
}
public void insertUpdate(DocumentEvent e) {
update();
}
// your method that handles any Document change event
public void update() {
if( aspectCheckBox1.isSelected() ) {
// parse the width and height,
// constrain the height to the aspect ratio and update it here
}
}
});
You'd then add a similar DocumentListener to your heightTextField.
Note that if you use JTextFields you need to parse their contents, read the units (where applicable) and handle NumberFormatExceptions in the case where the user enters invalid numeric values.
To answer your question about where to add your handlers...
The update of the Width should happen when there is a Document change to the Height GUI element. Similarly the update of the Height should happen when there is a document change to the Width GUI element.
You'll need to gracefully handle divide by zero errors (or restrict input to always be greater than 0), perform your calculations using doubles and preferably use Math.round() to get the best integer values for preserving aspect.
ie:
int calculateHeight(int width, double aspect) {
if( aspect <= 0.0 ) {
// handle this error condition
}
return (int)Math.round(width / aspect);
}
For actually tracking the aspect ratio, I would store it in a member variable and add an ActionListener to the JCheckBox... because updating the target aspect ratio on every value change of the width and height fields could result in aspect-ratio "creeping" due to integer round-off.
Here's an example on tracking your aspect every time the aspect ratio check state changes:
private double aspect = 1.0;
aspectCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
preserveAspectActionPerformed(evt);
}
});
private void preserveAspectActionPerformed(java.awt.event.ActionEvent evt) {
try {
double w = Double.parseDouble(widthField.getText());
double h = Double.parseDouble(heightField.getText());
aspect = w / h;
}
catch(NumberFormatException ex) {
// ... error occurred due to non-numeric input
// (use a JSpinner or JFormattedTextField to avoid this)
}
}
The most important thing is to avoid using the wrong input type for the job:
JTextAreas are good for multiline text
JTextFields are good for single line text
JFormattedTextFields are good for text constrained to specific format
JSpinners are good for numeric entry.
Hope that helps you.
First, I wouldn't use JTextArea, it's meant for free form text editing (think NotePad). Instead you should, at the very least, use a JTextField but a JSpinner might actually even be better.
Take a look at How to Use Text Fields for more details.
Essentially, for JTextField, you could use a ActionListener and/or a FocusListener to monitor for changes to the field.
This listeners will tend to be notified after the fact, that is, only once the user has finished editing fields. If you want real time feed back, you could use a DocumentListener which will notifiy each time the underlying Document of the field is modified, in real time.
A JSpinner is a little more complicated as it's a component that contains an editor and controls. You can use a ChangeListener, which will notifiy when a change to the fields model is commited. This occurs in place of the ActionListener and FocusListener mentioned previously, so you should only require a single listener, but won't provide real time feedback (at least, not without a lot more work)

Increasing the font size of a JTextPane that displays HTML text

Lets say that I have a JTextPane that is showing a HTML document.
I want that, on the press of a button, the font size of the document is increased.
Unfortunately this is not as easy as it seems... I found a way to change the font size of the whole document, but that means that all the text is set to the font size that I specify. What I want is that the font size is increased in a proportional scale to what was already in the document.
Do I have to iterate over every element on the document, get the font size, calculate a new size and set it back? How can I do such an operation? What is the best way?
In the example that you linked to you will find some clues to what you are trying to do.
The line
StyleConstants.setFontSize(attrs, font.getSize());
changes the font size of the JTextPane and sets it to the size of the font that you pass as a parameter to this method. What you want to to set it to a new size based on the current size.
//first get the current size of the font
int size = StyleConstants.getFontSize(attrs);
//now increase by 2 (or whatever factor you like)
StyleConstants.setFontSize(attrs, size * 2);
This will cause the font of the JTextPane double in size. You could of course increase at a slower rate.
Now you want a button that will call your method.
JButton b1 = new JButton("Increase");
b1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
increaseJTextPaneFont(text);
}
});
So you can write a method similar to the one in the example like this:
public static void increaseJTextPaneFont(JTextPane jtp) {
MutableAttributeSet attrs = jtp.getInputAttributes();
//first get the current size of the font
int size = StyleConstants.getFontSize(attrs);
//now increase by 2 (or whatever factor you like)
StyleConstants.setFontSize(attrs, size * 2);
StyledDocument doc = jtp.getStyledDocument();
doc.setCharacterAttributes(0, doc.getLength() + 1, attrs, false);
}
You could probably use css and modify only the styles font.
Since it renders th HTML as it is, changing the css class may be enough.
After exploring for a long time, I've found a way to zoom the fonts in a JTextPane that displays HTML in and out.
Here's the member function that enables a JTextPane to scale the fonts. It does not handle the images inside the JTextPane.
private void scaleFonts(double realScale) {
DefaultStyledDocument doc = (DefaultStyledDocument) getDocument();
Enumeration e1 = doc.getStyleNames();
while (e1.hasMoreElements()) {
String styleName = (String) e1.nextElement();
Style style = doc.getStyle(styleName);
StyleContext.NamedStyle s = (StyleContext.NamedStyle) style.getResolveParent();
if (s != null) {
Integer fs = styles.get(styleName);
if (fs != null) {
if (realScale >= 1) {
StyleConstants.setFontSize(s, (int) Math.ceil(fs * realScale));
} else {
StyleConstants.setFontSize(s, (int) Math.floor(fs * realScale));
}
style.setResolveParent(s);
}
}
}
}

Categories