Print contents of JavaFx TableView - printing

I am looking for a way to print the contents of a JavaFX TableView. I understand that JavaFX doesn't have Printing capabillities just yet (what a disapointment). I have found some information about taking a screenshot of a WebView for example and print it as an image.
Is it possible to do something like that with a Table view. How to go about to handle multiple pages on tables with many data.
Thanks for your help

Printing API appeared in fx8.0. And it can print nodes. You can create printer job with javafx.print.PrinterJob class. But it prints only region that fits to a printed page, and not the one that you on a screen. So you need to make your node fit page(scale, translate, etc) by hands. Here is simple printing example:
PrinterJob printerJob = PrinterJob.createPrinterJob();
if(printerJob.showPrintDialog(primaryStage.getOwner()) && printerJob.printPage(yourNode))
printerJob.endJob();

Snip the area you want
Rectangle rect = new Rectangle(0,0,dataDisplayAreaAnchorPane.getWidth(),dataDisplayAreaAnchorPane.getHeight());
dataDisplayAreaAnchorPane.setClip(rect);
WritableImage writableImage;
writableImage = new WritableImage((int) dataDisplayAreaAnchorPane.getPrefWidth(),
(int) dataDisplayAreaAnchorPane.getPrefHeight());
dataDisplayAreaAnchorPane.snapshot(null, writableImage);
eventDispatcher.printLandscape(writableImage);
**------------------------------------**
Resize according to A4 paper size and print
public void print(WritableImage writableImage, Stage primaryStage) {
ImageView imageView =new ImageView(writableImage);
Printer printer = Printer.getDefaultPrinter();
PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.LANDSCAPE, Printer.MarginType.DEFAULT);
double scaleX = pageLayout.getPrintableWidth() / imageView.getBoundsInParent().getWidth();
double scaleY = pageLayout.getPrintableHeight() / imageView.getBoundsInParent().getHeight();
imageView.getTransforms().add(new Scale(scaleX, scaleY));
PrinterJob job = PrinterJob.createPrinterJob();
if (job != null) {
boolean successPrintDialog = job.showPrintDialog(primaryStage.getOwner());
if(successPrintDialog){
boolean success = job.printPage(pageLayout,imageView);
if (success) {
job.endJob();
}
}
}
}

I have tried this . It first shows a page dialog window, then scales, translates and prints.
cmItem2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e){
Printer printer = Printer.getDefaultPrinter();
Stage dialogStage = new Stage(StageStyle.DECORATED);
PrinterJob job = PrinterJob.createPrinterJob(printer);
if (job != null) {
boolean showDialog = job.showPageSetupDialog(dialogStage);
if (showDialog) {
table.setScaleX(0.60);
table.setScaleY(0.60);
table.setTranslateX(-220);
table.setTranslateY(-70);
boolean success = job.printPage(table);
if (success) {
job.endJob();
}
table.setTranslateX(0);
table.setTranslateY(0);
table.setScaleX(1.0);
table.setScaleY(1.0);
}
}
}});
ContextMenu menu = new ContextMenu();
menu.getItems().addAll(cmItem1, cmItem2);
table.setContextMenu(menu);

I understand that JavaFX doesn't have Printing capabillities just yet (what a disapointment).
Java 8 includes printing capabilities for JavaFX.
https://jdk8.java.net/download.html
The Java 8 printing features were implemented under RT-17383 Printing and function as described in #Asimaruk's answer.
I have found some information about taking a screenshot of a WebView for example and print it as an image. Is it possible to do something like that with a Table view.
You can do this if you can't use Java 8.
Use the JavaFX snapshot api, use SwingFXUtils to convert the JavaFX image to a BufferedImage, use Swing print methods to print the BufferedImage.
How to go about to handle multiple pages on tables with many data.
If you can't use Java 8, use the above snapshot method for each page, scrolling the table data between each snapshot.
Also see RT-17665 Make some UI controls support printing their content which is a request for a direct print api added to some controls (e.g. TableView), so you could right tableView.print() to print only the tableview and not an entire scene. This convenience API for printing has not currently been implemented but you can vote or comment on the related issue to indicate your interest in the feature.

Related

Set cursor position of the editor control exactly where user tapped in Xamarin.forms

I am working in Xamarin.forms project. I want to set the cursor position of the Editor control exactly where the user tapped. I want to achieve this specifically in IOS (better to have a solution in Android too). I have gone through a couple of articles where they suggested using a custom renderer but I don't know how. I have gone through the following articles
https://social.msdn.microsoft.com/Forums/en-US/5bf7c17c-51c2-4e9e-bc09-73e9a5512fc3/how-to-change-the-cursor-position-of-entry-or-editor-programmatically?forum=xamarinforms
Set CursorPosition in Editor Xamarin Forms
Based on the above link, I have made a custom renderer of the Editor control. The code inside OnElementPropertyChanged in custom render keeps my cursor on the starting position of the editor control but I don't want this. The cursor position should change where the user tapped. we need to update the code inside the renderer according to my use-case.
public class CustomEditor : Editor
{
}
public class CustomEditorRenderer : EditorRenderer
{
public CustomEditorRenderer() { }
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Control != null)
{
// just change this statement to the one that works.
Control.SelectedTextRange = Control.GetTextRange(fromPosition: Control.BeginningOfDocument, toPosition: Control.BeginningOfDocument);
}
}
}
I have to use Editor control, not Entry control because I want to enter text in multiple lines. Editor control doesn't have a CursorPosition property like Entry control.
Can anyone suggest a better way through a custom renderer or via utilizing TextChanged, Focused event?
You can change your Renderer code to change the cursor position:
//Change the cursor position to the fifth character
var test = Control.GetPosition(Control.BeginningOfDocument, 5);
Control.SelectedTextRange = Control.GetTextRange(test, test);
If you want to change the cursor to the user's clicked position, you need to get the user's clicked position and convert it to the corresponding index value. For getting the user's click position, you can refer to the documentation:Walkthrough: Using Touch in Xamarin.iOS

Vaadin Dataprovider: how to avoid "auto-fetch"?

Use Case 1 is answered below, Use Case 2 has been moved to a separate question (Vaadin Flow: Returning to a view, the view should not reload data from the backend)
I'd like to use a Vaadin Flow (v14 LTS/v19) grid component backed by a lazy DataProvider which does not automatically fetch data from the backend when the grid is shown.
There are at least two use cases:
showing grid data does not make sense unless the user provided filter parameters
returning to a #PreserveOnRefresh tagged view should not replace the shown data with current data. (further elaborated in update)
Being pretty new to Vaadin 14+, I could not figure out how to achieve this. Every time my GridView is displayed, the count and fetch callbacks of DataProvider are queried. The call originates from the DataCommunicator of the grid.
So for Use Case 1: How to stop the DataProvider from fetching data as long as it does not make sense?
And for Use Case 2: How to prevent overwriting the grid state when adding a grid to the UI for the second time?
Thanks a lot!
StackTrace to my fetch callback (Vaadin Flow 14):
at org.vaadin.example.GridView.fetch(GridView.java:46)
at org.vaadin.example.GridView.lambda$new$c4b2c115$1(GridView.java:23)
at com.vaadin.flow.data.provider.CallbackDataProvider.fetchFromBackEnd(CallbackDataProvider.java:137)
at com.vaadin.flow.data.provider.AbstractBackEndDataProvider.fetch(AbstractBackEndDataProvider.java:61)
at com.vaadin.flow.data.provider.DataCommunicator.fetchFromProvider(DataCommunicator.java:362)
at com.vaadin.flow.data.provider.DataCommunicator.activate(DataCommunicator.java:647)
at com.vaadin.flow.data.provider.DataCommunicator.collectKeysToFlush(DataCommunicator.java:589)
at com.vaadin.flow.data.provider.DataCommunicator.flush(DataCommunicator.java:461)
at com.vaadin.flow.data.provider.DataCommunicator.lambda$requestFlush$2f364bb9$1(DataCommunicator.java:425)
at com.vaadin.flow.internal.StateTree.lambda$runExecutionsBeforeClientResponse$2(StateTree.java:390)
at [java.util.stream] omitted
at com.vaadin.flow.internal.StateTree.runExecutionsBeforeClientResponse(StateTree.java:387)
at com.vaadin.flow.server.communication.UidlWriter.encodeChanges(UidlWriter.java:411)
at com.vaadin.flow.server.communication.UidlWriter.createUidl(UidlWriter.java:187)
at com.vaadin.flow.server.communication.UidlRequestHandler.writeUidl(UidlRequestHandler.java:122)
at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:91)
at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1547)
at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:247)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
update 20210430
Here's the code of my GridView which also fakes the backend DataProvider:
#Route(value = "grid", layout = MainView.class)
public class GridView extends VerticalLayout {
public GridView() {
final Grid<Person> g = new Grid(Person.class);
g.setColumns("name");
g.setDataProvider(DataProvider.fromCallbacks(q -> fetch(q), q -> count(q)));
add(g);
// filter omitted
final Button refresh = new Button("refresh");
refresh.addClickListener(e -> {
System.out.println("refresh clicked");
g.getDataProvider().refreshAll();
});
add(refresh);
add(new TextField("State check"));
}
// fake DataProvider
private int count(Query<Person, Void> q) { return 3; }
private Stream<Person> fetch(Query<Person, Void> q) {
q.getLimit(); //vaadin checks these have been called
q.getOffset(); //vaadin checks these have been called
System.out.println("fetching again");
new Exception().printStackTrace(); //figure out who called
return Arrays.asList(new Person("1"), new Person("2"), new Person("3")).stream();
}
}
My MainView is used to switch between GridView and EmptyView
#PreserveOnRefresh
public class MainView extends AppLayout {
private Component emptyBView;
private Component gridBView;
public MainView() {
final Button emptyB = new Button("Btn empty");
emptyB.addClickListener(e -> {
if (emptyBView == null) { emptyBView = new EmptyView();}
setContent(emptyBView);
});
addToNavbar(emptyB);
final Button gridB = new Button("Btn grid");
gridB.addClickListener(e -> {
if (gridBView == null) gridBView = new GridView();
setContent(gridBView);
});
addToNavbar(gridB);
}
}
MainView is an AppLayout used to switch the contents of the AppLayout from GridView to EmptyView and back.
Use Case 2 is: When returning to GridView, the GridView should be exactly same state as before (which works fine with the TextField).
open GridView -> grid should not be filled with data
enter filter params (not shown in code)
click "refresh" to populate the grid
enter "Spiderman" in TextField "stateCheck"
switch to EmptyView
in the real app: do something in EmptyView and potentially other views
return to GridView -> the grid should not reload the data, it should just stay as it was - just like the TextField still displays "Spiderman", the grid should display the same data as before without reloading it.
For Case 1: In the callback check if you have filter parameters, return an empty set if not. Using the new V17+ API it would look like this:
grid.setItems(query -> {
if(filterParameters.isEmpty()) {
// Return an empty stream
} else {
// Fetch from backend
}
});
You can read more in the docs here: https://vaadin.com/docs/latest/flow/binding-data/data-provider (V19) or https://vaadin.com/docs/v14/flow/binding-data/tutorial-flow-data-provider (V14)
I would need more info on what you're currently doing to help out with Case 2. How are you constructing the view, what does your code look like? A full stack trace with the "Caused by" would also help.
I would recommend only setting the DataProvider to the Grid once the first filter parameter is set. The client-side Grid expects to receive the number of items it requires from the fetch query; it might work in some corner case if you don't provide the requested numbers of items from fetch, but it's not designed to behave like that.
Note that this applies specifically to using DataProviders with filters in Vaadin 14 series - Vaadin 17 introduced a new optional simplified way of fetching items, which changes this equation a bit. It's not backported to Vaadin 14 yet (currently planned for 14.7).

Drawing static full screen images using DirectX11

My question is as follows. In most tutorials that I've seen there is a setup part of DirectX11 where you do something like this:
// Set the refresh rate of the back buffer.
if(m_vsync_enabled)
{
swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator;
swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator;
}
else
{
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
}
Which either sets the refresh to be as fast as possible or synched with the monitor.
However in the application that I need I only want to refresh the screen when I tell the system to do it. Is there any way to do this?
These numbers have nothing to do with the actual refreshing, which happens when you invoke Present. You can call it once per second and screen will be refreshed just once.

Swiping to a element not present in dom in appium ios

I have an app where a particular parent that has n elements lets say 10 elements (tiles) and only 5 are present in the dom and visible in the current screen. The next 5 would appear in dom/screen on swiping up. How do I swipe to a particular element say 7th element?
I'm not able to get find the element by id/name as the element is not in dom so I'm not able to use swipe until visibility of an element. also, the number of such elements varies based on how the backend system is configured so I cannot make a fixed number of swipes. Also since I do not know the last element in the parent I'm at risk of running into an infinite loop if the particular element is not present in the app (due to a bug).
Please help on how to solve this.
You can use following methods to scroll down until expected element. To avoid the infinite loop you can keep count of while loop.
public void scrollDown()
{
TouchAction action = new TouchAction((AppiumDriver)driver);
action.press(new PointOption().point(300, 701)).waitAction(newWaitOptions().waitOptions(Duration.ofSeconds(2))).moveTo(new PointOption().point(300, 441)).release();
action.perform();
}
public void scrollTillElement(By element)
{
int countofLoop = 0;
List<WebElement> elements = driver.findElements(element);
while (elements.size()==0)
{
countofLoop++;
scrollDown();
elements = driver.findElements(element);
if(countofLoop==20)
{
break;
}
}
}

Pagination Of ListView On Scrolling In Xamarin.Android

Can Any one help Me on How to Implement on Handling Pagination on Scrolling of listview in xamarin.android .any link or any sample wil be helpful
Well, Android pagination is quite easy in comparison to iOS and can be done as follows:
public class EndlessScrollListener : Java.Lang.Object, Android.Widget.AbsListView.IOnScrollListener
{
private int visibleThreshold = 5;
private int currentPage = 0;
private int previousTotal = 0;
private bool loading = true;
public EndlessScrollListener()
{
}
public EndlessScrollListener(int visibleThreshold)
{
this.visibleThreshold = visibleThreshold;
}
public void OnScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
if (loading)
{
if (totalItemCount > previousTotal)
{
loading = false;
previousTotal = totalItemCount;
currentPage++;
}
}
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold))
{
// I load the next page of gigs using a background task,
// but you can call any function here.
//new LoadGigsTask().execute(currentPage + 1);
loading = true;
}
}
public void OnScrollStateChanged(AbsListView view, [GeneratedEnum] ScrollState scrollState)
{
// throw new NotImplementedException();
}
}
Then set it to the listview as follows:
List.SetOnScrollListener(new EndlessScrollListener());
Working of code:
visibleThreshold – The minimum amount of items to have below your current scroll position, before loading more.
currentPage – The current page of data you have loaded.
previousTotal – The total number of items in the dataset after the last load.
loading – True if we are still waiting for the last set of data to load.
Next, we have a couple of constructors that allow us to set the visibleThreshold inline if we want.
The first overridden method we have is called every time the list is scrolled. This happens many times a second during a scroll, so be wary of the code you place here. We are given a few useful parameters to help us work out if we need to load some more data, but first, we check if we are waiting for the previous load to finish.
If it’s still loading, we check to see if the dataset count has changed, if so we conclude it has finished loading and update the current page number and total item count.
If it isn’t currently loading, we check to see if we have breached the visibleThreshold and need to reload more data. If we do need to reload some more data, we execute a background task and set the loading flag to true. Thus solving the problem forever!
The last method in the class we do not need, however, if you’re interested, it is primarily used for tracking changes in the scroll action itself via the scrollState parameter.
Finally, the code to call the class creates a new instance of EndlessScrollListener and bind’s it to a ListView of mine. Of course, put your own ListView in place of List.

Resources