I need the page size to change to a certain page.
For example if page 3 i set pageSize A4.
If page 2 i set pageSize new Rectangle(155,155)
String line = "Hello! Welcome to iTextPdf";
Div div = new Div();
for (int i = 0; i < 30; i++) {
Paragraph element = new Paragraph();
element.add(line + " " + i);
paragraphs.add(element);
}
--------------
if(page==1) // This is just for an example. How I want it to be
pdf.setDefaultPageSize(PageSize.A5);
else if(page==3)
element.setDefaultPageSize(PageSize.A4);
You can override the DocumentRenderer class and customize #addNewPage:
private static class CustomDocumentRenderer extends DocumentRenderer {
public CustomDocumentRenderer(Document document) {
super(document);
}
#Override
protected PageSize addNewPage(PageSize customPageSize) {
if (customPageSize != null) {
document.getPdfDocument().addNewPage(customPageSize);
return customPageSize;
} else {
PageSize pageSize = definePageSizeBasedOnPageNumber(document.getPdfDocument().getNumberOfPages() + 1);
document.getPdfDocument().addNewPage(pageSize);
return pageSize;
}
}
private PageSize definePageSizeBasedOnPageNumber(int curPageNumber) {
if (curPageNumber % 2 == 1) {
return PageSize.A4;
} else {
return PageSize.A4.rotate();
}
}
}
Here we have a helper private method definePageSizeBasedOnPageNumber to define the page size based on the page number.
Using this customized renderer is very simple now: document.setRenderer(new CustomDocumentRenderer(document));
Full snippet of code at the highest execution level:
Document document = new Document(pdfDocument);
document.setRenderer(new CustomDocumentRenderer(document));
String line = "Hello! Welcome to iTextPdf";
for (int i = 0; i < 30; i++) {
Paragraph element = new Paragraph();
element.add(line + " " + i);
document.add(element);
}
document.close();
Related
I have created documents using itext 7 and its ColumnDocumentRenderer. I would like to force some text into the last column. By "last column" I mean for example if I have a single page defined by ColumnDocumentRenderer to have 3 columns but I only have one column of text, I still want column 3 to contain my forced value. So I suppose (presupposing a solution, others appreciated) that I would need mechanisms to know the column number I'm in and to force a column break. Since StackOverflow wants this in the form of a question, (a) what are these mechanisms? and (b) what are alternative approaches?
Question How to skip text insertion point to the next column using iText? apparently asks a similar question but apparently is using an earlier release of itext; mine has no ColumnText that I can find.
Thanks in advance for any help.
I was answering from my phone yesterday, but now that I have access to a computer, I changed ColumnDocumentRenderer like this:
public class ColumnDocumentRenderer extends DocumentRenderer {
protected Rectangle[] columns;
protected int nextAreaNumber;
public ColumnDocumentRenderer(Document document, Rectangle[] columns) {
super(document);
this.columns = columns;
}
public ColumnDocumentRenderer(Document document, boolean immediateFlush, Rectangle[] columns) {
super(document, immediateFlush);
this.columns = columns;
}
#Override
protected LayoutArea updateCurrentArea(LayoutResult overflowResult) {
if (overflowResult != null && overflowResult.getAreaBreak() != null && overflowResult.getAreaBreak().getType() != AreaBreakType.NEXT_AREA) {
nextAreaNumber = 0;
}
if (nextAreaNumber % columns.length == 0) {
super.updateCurrentArea(overflowResult);
}
return (currentArea = new LayoutArea(currentPageNumber, columns[nextAreaNumber++ % columns.length].clone()));
}
public int getNextAreaNumber() {
return nextAreaNumber;
}
}
The change will be in iText 7.0.1, but you can use this code in your own renderer.
You can now use this renderer like this:
public void createPdf(String dest) throws IOException {
OutputStream fos = new FileOutputStream(dest);
PdfWriter writer = new PdfWriter(fos);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
float offSet = 36;
float gutter = 23;
float columnWidth = (PageSize.A4.getWidth() - offSet * 2) / 3 - gutter * 2;
float columnHeight = PageSize.A4.getHeight() - offSet * 2;
Rectangle[] columns = {
new Rectangle(offSet, offSet, columnWidth, columnHeight),
new Rectangle(offSet + columnWidth + gutter, offSet, columnWidth, columnHeight),
new Rectangle(offSet + 2 * (columnWidth + gutter), offSet, columnWidth, columnHeight)};
ColumnDocumentRenderer renderer = new ColumnDocumentRenderer(document, columns);
document.setRenderer(renderer);
for (int i = 0; i < 50; i++) {
document.add(new Paragraph("Hello World"));
}
while (renderer.getNextAreaNumber() % 3 != 0)
document.add(new AreaBreak());
document.add(new Paragraph("Third column"));
document.add(new AreaBreak());
for (int i = 0; i < 80; i++) {
document.add(new Paragraph("Hello World"));
}
while (renderer.getNextAreaNumber() % 3 != 0)
document.add(new AreaBreak());
document.add(new Paragraph("Third column"));
document.add(new AreaBreak());
for (int i = 0; i < 10; i++) {
document.add(new Paragraph("Hello World"));
}
while (renderer.getNextAreaNumber() % 3 != 0)
document.add(new AreaBreak());
document.add(new Paragraph("Third column"));
document.close();
}
The first column has index 0 and the next area number is 1, the second column has index 1 and the next area number is 2, and so on.
This means that you can check for and go to the third column on a page like this.
while (renderer.getNextAreaNumber() % 3 != 0)
document.add(new AreaBreak());
I have a class that takes a String parameter and performs a google search, then it gets the ten images and puts them in an array, that is then handled by another method in the same class. Using Javafx.scene.image would probably allow me to implement the buffering progress easily, but there is a bug with JavaFX Image, that misinterprets the color encoding of normal Images, and saves a weird looking image to the hard drive, so I just decided to use awt.Image.
This is the image search class:
public class GoogleCustomSearch {
static String key = //custom google id;
static String cx = // also a custom google id;
static String searchType = "image";
static java.awt.Image[] publicImageArray;
public static java.awt.Image[] Search(String searchParameter,int start) throws IOException, URISyntaxException{
String formatedText = URLEncoder.encode(searchParameter,"UTF-8");
URL url = new URL("https://www.googleapis.com/customsearch/v1?" + "key=" +key + "&cx=" +cx + "&q=" +formatedText + "&searchType=" +searchType +"&imgSize=medium" + "&start=" + start + "&num=10");
System.out.println(url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
BufferedReader br = new BufferedReader(new InputStreamReader( ( conn.getInputStream() ) ) );
GResults results = new Gson().fromJson(br, GResults.class);
java.awt.Image [] imageArray = new java.awt.Image[10];
//JProgressBar prb = new JProgressBar();
//MediaTracker loadTracker = new MediaTracker(prb);
for(int i = 0; i<10; i++){
try {
imageArray[i] = ImageIO.read(new URL(results.getLink(i)));
}catch (java.io.IOException e){
imageArray[i] = ImageIO.read(new File("C:\\Users\\FILIP.D\\IdeaProjects\\Manual_Artwork\\src\\MAT - NoImage.jpg"));
}
}
conn.disconnect();
return imageArray;
}
public static BufferedImage getImage(String searchPar, int index, boolean newSearch) throws IOException, URISyntaxException {
int adaptedIndex;
int start;
BufferedImage bimage;
if(index<10){
adaptedIndex = index;
start = 1;
}else if (index<20){
start = 11;
adaptedIndex = index % 10;
if(index == 10){
publicImageArray = new java.awt.Image[10];
publicImageArray = Search(searchPar,start);
}
}else if(index < 30){
start = 21;
adaptedIndex = index % 10;
if (index == 20) {
publicImageArray = new java.awt.Image[10];
publicImageArray = Search(searchPar,start);
}
}else{
adaptedIndex = index % 10;
start = 21; //ovo ce posle 30 da ga vrti u loop prvih 10
}
if(newSearch){
publicImageArray = new java.awt.Image[10];
publicImageArray = Search(searchPar,start);
return bimage = (BufferedImage) publicImageArray[adaptedIndex];
}else{
return bimage = (BufferedImage) publicImageArray[adaptedIndex];
}
}
public static RenderedImage getLiveImage (int index){
return (RenderedImage) publicImageArray[index % 10];
}
}
And this is the snippet of the main GUI class that just handles opening the new image in the array
private void nextImageResult() throws IOException, URISyntaxException {
if(imgNr == -1){
imgNr++;
changeImage(SwingFXUtils.toFXImage(GoogleCustomSearch.getImage(oppenedTrack.getArtistName() + "+" + oppenedTrack.getTrackName(),imgNr,true),null));
}else{
imgNr++;
changeImage(SwingFXUtils.toFXImage(GoogleCustomSearch.getImage(oppenedTrack.getArtistName() + "+" + oppenedTrack.getTrackName(),imgNr,false),null));
}
}
To summarise, I need a proper way to show a progress bar in the place of the image before it loads, and it needs not to hang the UI, for which I can use Task. I can optimise the loading of the array with MediaTracker, so it can prioritize loading the first few images first.
I have a form with a submitbutton which will get results from a database and updates a listview based on these results. If there is no result, a feedback message is shown. This all works fine.
Now I want to replace the submitlink with an IndicatingAjaxButton, so the user can see something happening when getting the result takes a long time.
The basic idea is this:
IndicatingAjaxButton submitLink = new IndicatingAjaxButton("submit", form) {
private static final long serialVersionUID = -4306011625084297054L;
#Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
Integer hourFrom = 0;
Integer hourTo = 0;
Integer minuteFrom = 0;
Integer minuteTo = 0;
hourFrom = Integer.parseInt(hour_from.getModelObject());
hourTo = Integer.parseInt(hour_to.getModelObject());
minuteFrom = Integer.parseInt(minute_from.getModelObject());
minuteTo = Integer.parseInt(minute_to.getModelObject());
Calendar from = Calendar.getInstance();
Calendar to = Calendar.getInstance();
Date dateFrom = date_from.getModelObject();
Date dateTo = date_to.getModelObject();
from.setTime(dateFrom);
to.setTime(dateTo);
from.set(Calendar.HOUR, hourFrom);
from.set(Calendar.MINUTE, minuteFrom);
to.set(Calendar.HOUR, hourTo);
to.set(Calendar.MINUTE, minuteTo);
if (topicQueueSelect.getModelObject() == null) {
error("Please select a message name.");
getSession().setAttribute("error", "");
}
if (to.before(from)) {
error("Date to must be after date from.");
getSession().setAttribute("error", "");
}
cal.setTimeInMillis(System.currentTimeMillis());
if (from.after(cal)) {
error("Date from must be in the past.");
getSession().setAttribute("error", "");
}
if (getSession().getAttribute("error") != null) {
getSession().removeAttribute("error");
return;
}
page.setModelObject(1);
List<Search> searchFields = (List<Search>) searchFieldsField
.getModelObject();
messageKeyDataList = messageController.search(
topicQueueSelect.getModelObject(), searchFields,
from.getTime(), to.getTime(),
maxResults.getModelObject(), page.getModelObject(),
sortorder);
if (messageKeyDataList.size() == 0) {
info("Search criteria didn't produce any results.");
result.setList(messageKeyDataList);
resultContainer.setVisible(false);
return;
}
resultContainer.setVisible(true);
resultSize = messageController.getResultSize();
int pages = (int) Math.ceil((float) resultSize
/ maxResults.getModelObject());
ArrayList<Integer> pageNumbers = new ArrayList<Integer>();
for (int n = 1; n <= pages; n++) {
pageNumbers.add(n);
}
page.setChoices(pageNumbers);
pageunder.setChoices(pageNumbers);
showing.setDefaultModelObject("Showing 1 to "
+ messageKeyDataList.size() + " out of " + resultSize
+ " messages");
lastSearch.put("topicQueue", topicQueueSelect.getModelObject());
lastSearch.put("searchFields", searchFields);
lastSearch.put("from", from.getTime());
lastSearch.put("to", to.getTime());
lastSearch.put("maxResults", maxResults.getModelObject());
result.setList(messageKeyDataList);
target.add(feedback);
}
};
The SubmitLink does show me either the ResultView with the new list, or the info message, the IndicatingAjaxButton doesn't. I know the form submit is called, because the system.out is being printed.
Any suggestions on this?
SubmitLink is non-Ajax component. Using it will repaint the whole page!
IndicatingAjaxButton is an Ajax component. You need to use the passed AjaxRequestTarget to add components which should be repainted with the Ajax response. For example the FeedbackPanel should be added to the AjaxRequestTarget.
I found that I had to do setOutputMarkupPlaceholderTag(true) on both the resultContainer and the feedback. After that adding them to the requesttarget works as expected.
I have figured out how to move my character around the maze using the algorithm I have written, but the count is not figuring correctly. At the end of each row my character moves up and down several times until the count reaches the specified number to exit the loop, then the character moves along the next row down until it reaches the other side and repeats the moving up and down until the count reaches the specified number again. Can anyone help me find why my count keeps getting off? The algorithm and the maze class I am calling from is listed below.
public class P4 {
public static void main(String[] args) {
// Create maze
String fileName = args[3];
Maze maze = new Maze(fileName);
System.out.println("Maze name: " + fileName);
// Get dimensions
int mazeWidth = maze.getWidth();
int mazeHeight = maze.getHeight();
// Print maze size
System.out.println("Maze width: " + mazeWidth);
System.out.println("Maze height: " + mazeHeight);
int r = 0;
int c = 0;
// Move commands
while (true){
for (c = 0; c <= mazeWidth; c++){
if (maze.moveRight()){
maze.isDone();
c++;
}
if (maze.isDone() == true){
System.exit(1);
}
if (maze.moveRight() == false && c != mazeWidth){
maze.moveDown();
maze.moveRight();
maze.moveRight();
maze.moveUp();
c++;
}
}
for (r = 0; r % 2 == 0; r++){
maze.moveDown();
maze.isDone();
if (maze.isDone() == true){
System.exit(1);
}
}
for (c = mazeWidth; c >= 0; c--){
if (maze.moveLeft()){
c--;
maze.isDone();
System.out.println(c);
}
if (maze.isDone() == true){
System.exit(1);
}
if (maze.moveLeft() == false && c != 0){
maze.moveDown();
maze.moveLeft();
maze.moveLeft();
maze.moveUp();
c--;
}
}
for (r = 1; r % 2 != 0; r++){
maze.moveDown();
maze.isDone();
if (maze.isDone() == true){
System.exit(1);
}
}
}
}
}
public class Maze {
// Maze variables
private char mazeData[][];
private int mazeHeight, mazeWidth;
private int finalRow, finalCol;
int currRow;
private int currCol;
private int prevRow = -1;
private int prevCol = -1;
// User interface
private JFrame frame;
private JPanel panel;
private Image java, student, success, donotpass;
private ArrayList<JButton> buttons;
// Maze constructor
public Maze(String fileName) {
// Read maze
readMaze(fileName);
// Graphics setup
setupGraphics();
}
// Get height
public int getHeight() {
return mazeHeight;
}
// Get width
public int getWidth() {
return mazeWidth;
}
// Move right
public boolean moveRight() {
// Legal move?
if (currCol + 1 < mazeWidth) {
// Do not pass?
if (mazeData[currRow][currCol + 1] != 'D')
{
currCol++;
redraw(true);
return true;
}
}
return false;
}
// Move left
public boolean moveLeft() {
// Legal move?
if (currCol - 1 >= 0) {
// Do not pass?
if (mazeData[currRow][currCol - 1] != 'D')
{
currCol--;
redraw(true);
return true;
}
}
return false;
}
// Move up
public boolean moveUp() {
// Legal move?
if (currRow - 1 >= 0) {
// Do not pass?
if (mazeData[currRow - 1][currCol] != 'D')
{
currRow--;
redraw(true);
return true;
}
}
return false;
}
// Move down
public boolean moveDown() {
// Legal move?
if (currRow + 1 < mazeHeight) {
// Do not pass?
if (mazeData[currRow + 1][currCol] != 'D')
{
currRow++;
redraw(true);
return true;
}
}
return false;
}
public boolean isDone() {
// Maze solved?
if ((currRow == finalRow) && (currCol == finalCol))
return true;
else
return false;
}
private void redraw(boolean print) {
// Wait for awhile
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
if (print)
System.out.println("Moved to row " + currRow + ", column " + currCol);
// Compute index and remove icon
int index = (prevRow * mazeWidth) + prevCol;
if ((prevRow >= 0) && (prevCol >= 0)) {
buttons.get(index).setIcon(null);
}
// Compute index and add icon
index = (currRow * mazeWidth) + currCol;
if ((currRow == finalRow) && (currCol == finalCol))
buttons.get(index).setIcon(new ImageIcon(success));
else
buttons.get(index).setIcon(new ImageIcon(student));
// Store previous location
prevRow = currRow;
prevCol = currCol;
}
// Set button
private void setButton(JButton button, int row, int col) {
if (mazeData[row][col] == 'S') {
button.setIcon(new ImageIcon(student));
currRow = row;
currCol = col;
} else if (mazeData[row][col] == 'J') {
button.setIcon(new ImageIcon(java));
finalRow = row;
finalCol = col;
} else if (mazeData[row][col] == 'D') {
button.setIcon(new ImageIcon(donotpass));
}
}
// Read maze
private void readMaze(String filename) {
try {
// Open file
Scanner scan = new Scanner(new File(filename));
// Read numbers
mazeHeight = scan.nextInt();
mazeWidth = scan.nextInt();
// Allocate maze
mazeData = new char[mazeHeight][mazeWidth];
// Read maze
for (int row = 0; row < mazeHeight; row++) {
// Read line
String line = scan.next();
for (int col = 0; col < mazeWidth; col++) {
mazeData[row][col] = line.charAt(col);
}
}
// Close file
scan.close();
} catch (IOException e) {
System.out.println("Cannot read maze: " + filename);
System.exit(0);
}
}
// Setup graphics
private void setupGraphics() {
// Create grid
frame = new JFrame();
panel = new JPanel();
panel.setLayout(new GridLayout(mazeHeight, mazeWidth, 0, 0));
frame.add(Box.createRigidArea(new Dimension(0, 5)), BorderLayout.NORTH);
frame.add(panel, BorderLayout.CENTER);
// Look and feel
try {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
// Configure window
frame.setSize(mazeWidth * 100, mazeHeight * 100);
frame.setTitle("Maze");
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setAlwaysOnTop(true);
// Load and scale images
ImageIcon icon0 = new ImageIcon("Java.jpg");
Image image0 = icon0.getImage();
java = image0.getScaledInstance(100, 100, Image.SCALE_DEFAULT);
ImageIcon icon1 = new ImageIcon("Student.jpg");
Image image1 = icon1.getImage();
student = image1.getScaledInstance(100, 100, Image.SCALE_DEFAULT);
ImageIcon icon2 = new ImageIcon("Success.jpg");
Image image2 = icon2.getImage();
success = image2.getScaledInstance(100, 100, Image.SCALE_DEFAULT);
ImageIcon icon3 = new ImageIcon("DoNotPass.jpg");
Image image3 = icon3.getImage();
donotpass = image3.getScaledInstance(100, 100, Image.SCALE_DEFAULT);
// Build panel of buttons
buttons = new ArrayList<JButton>();
for (int row = 0; row < mazeHeight; row++) {
for (int col = 0; col < mazeWidth; col++) {
// Initialize and add button
JButton button = new JButton();
Border border = new LineBorder(Color.darkGray, 4);
button.setOpaque(true);
button.setBackground(Color.gray);
button.setBorder(border);
setButton(button, row, col);
panel.add(button);
buttons.add(button);
}
}
// Show window
redraw(false);
frame.setVisible(true);
}
}
One error I can see in your code is that you're incrementing your c counter more often than you should. You start with it managed by your for loop, which means that it will be incremented (or decremented, for the leftward moving version) at the end of each pass through the loop. However, you also increment it an additional time in two of your if statements. That means that c might increase by two or three on a single pass through the loop, which is probably not what you intend.
Furthermore, the count doesn't necessarily have anything obvious to do with the number of moves you make. The loop code will always increase it by one, even if you're repeatedly trying to move through an impassible wall.
I don't really understand what your algorithm is supposed to be, so I don't have any detailed advice for how to fix your code.
One suggestion I have though is that you probably don't ever want to be calling methods on your Maze class without paying attention to their return values. You have a bunch of places where you call isDone but ignore the return value, which doesn't make any sense. Similarly, you should always be checking the return values from your moveX calls, to see if the move was successful or not. Otherwise you may just blunder around a bunch, without your code having any clue where you are in the maze.
I want to know how I can get out everyone of the the longest persons if there are several with the same length?
If only one person is the longest, then it works fine and the longest person with it´s name will show in MessageBox. But if there are more than one who are the longest, this code will not work...
public partial class Form1 : Form
{
int[] längdArray = new int[5];
string[] namnArray = new string[5];
int namn = 0;
int längd = 0;
public Form1()
{
InitializeComponent();
}
private void btnVisa_Click(object sender, EventArgs e)
{
int längst = 0;
int längdvärdet = 0;
int längdindex = 0;
string name = textBox1.Text;
namnArray[namn] = name;
namn = namn + 1;
textBox1.Clear();
int centimeter = int.Parse(textBox2.Text);
längdArray[längd] = centimeter;
längd++;
textBox2.Clear();
listBox1.Items.Add(name + " " + centimeter + " centimeter ");
if (längd == 5)
{
btnVisa.Enabled = false;
foreach (int antalLängder in längdArray)
{
if (antalLängder > längst)
{
längst = antalLängder;
längdvärdet = längdindex;
}
längdindex++;
}
string test = namnArray[längdvärdet]
MessageBox.Show(" Längsta person är " + test + " som är " + längst + " centimeter lång ");
}
Define behavior you want your app to present when there is more than one person. Should all display, or any one, or other? Try to use object constructions, it's easier to operate on them. C# is an object-oriented language. Put name and length in one structure then use LINQ.