特定大小的JavaFX打印节点

时间:2015-11-06 15:48:19

标签: javafx clojure

我正在通过调整以前编写的桌面程序打印谜题,为家庭成员创建一本印刷谜题书。我需要在特定尺寸下打印每个拼图,在这种情况下为5“方形。我似乎找不到以可编程方式可靠地执行此操作的方法。

这是一个实现,它使用由反复试验确定的缩放因子来缩放绘制拼图的画布。这是用Clojure编写的,但我认为任何使用Java的人都可以理解。

(defn create-print-button-click-handler
  "Handle a click on the 'Print...' button."
  [canvas stage]
  (reify EventHandler
    (handle [this event]
      (if false
        (batch-print)
        ;; else
        (let [job (PrinterJob/createPrinterJob)]
          (if (.showPrintDialog job stage)
            (let [printer (.getPrinter job)
                  job-settings (.getJobSettings job)
                  ;; Margin settings are in points. Set to half inch left margin,
                  ;; 3/4 inch for the rest.
                  layout (.createPageLayout printer Paper/NA_LETTER PageOrientation/PORTRAIT
                                            36.0 54.0 54.0 54.0)
                  printable-width (.getPrintableWidth layout)
                  printable-height (.getPrintableHeight layout)
                  printer-dpi (.getFeedResolution (.getPrintResolution job-settings))
                  dots-across (* printer-dpi 5) ;; five inches
                  cnvs (Canvas. dots-across dots-across)
                  scale 0.25]
              (.setPrintColor job-settings PrintColor/MONOCHROME)
              (.setPageLayout job-settings layout)
              ;; Scale by the same amount along both axes.
              (.add (.getTransforms cnvs) (Scale. scale scale))
              ;; This ugliness is because I want to print the background completely white.
              ;; Since we are using the same function to draw the board to the screen and
              ;; to the canvas for printing, we need to change the background before
              ;; drawing then back afterwards.
              (def board-color (Color/web "#ffffff"))
              (redraw-board cnvs)
              (def board-color (Color/web board-web-color))
              (.printPage job cnvs)
              (.endJob job))))))))

我见过一些使用可打印宽度和高度的例子,但我没有得到可理解的结果(太大而不适合页面)。

就像我说的,这有效,但我希望程序在使用其他可能具有不同分辨率,不同水平和垂直分辨率等的打印机时能够正确响应。

1 个答案:

答案 0 :(得分:0)

好吧,我想出了一些似乎有用的东西。这是一个显示如何操作的MCVE

(ns printscaling.core
  (:gen-class
   :extends javafx.application.Application)
  (:import
   [javafx.application Application]
   [javafx.beans.value ChangeListener]
   [javafx.event EventHandler]
   [javafx.geometry Insets Pos]
   [javafx.print PrinterJob]
   [javafx.scene Scene]
   [javafx.scene.canvas Canvas]
   [javafx.scene.control Button]
   [javafx.scene.layout BorderPane Pane Region VBox]
   [javafx.scene.paint Color]
   [javafx.scene.transform Scale]
   [javafx.stage Screen]))

(def points-per-inch 72.0)

(defn redraw-board
  "Draw the board on the canvas."
  [canvas]
  (let [w (.getWidth canvas)
        h (.getHeight canvas)
        gc (.getGraphicsContext2D canvas)]

    (doto gc
      (.clearRect 0 0 w h)
      (.setLineWidth 3)
      (.setFill (Color/BLUE))
      (.setStroke (Color/BLUE))
      (.strokeRect 0 0 w h)
      (.strokeLine 0 0 w h)
      (.strokeLine w 0 0 h))))

(defn create-print-button-handler
  "Handle a click on the 'Print' button. Print a 5 inch square version
   of the board."
  [stage]
  (reify EventHandler
    (handle [this event]
      (let [job (PrinterJob/createPrinterJob)]
        (if (.showPrintDialog job stage)
          (let [dpi (.getDpi (Screen/getPrimary))
                pixels (* dpi 5)
                canvas (Canvas. pixels pixels)
                scale (/ points-per-inch dpi)]
            (.add (.getTransforms canvas) (Scale. scale scale))
            (redraw-board canvas)
            (if (.printPage job canvas)
              (.endJob job))))))))

(defn create-print-btn [stage]
  (let [btn (Button. "Print")]
    (.setOnAction btn (create-print-button-handler stage))
    btn))

(defn -start
  "Build the application interface and start it up."
  [this stage]
  (let [root (BorderPane.)
        center (Pane.)
        spacer (Region.)
        btn-pane (VBox.)
        scene (Scene. root)
        canvas (Canvas.)
        print-btn (create-print-btn stage)]

    (doto (.widthProperty canvas)
      (.bind (.widthProperty center))
      (.addListener
       (reify ChangeListener
         (changed [_ _ _ _]
           (redraw-board canvas)))))
    (doto (.heightProperty canvas)
      (.bind (.heightProperty center))
      (.addListener
       (reify ChangeListener
         (changed [_ _ _ _]
           (redraw-board canvas)))))

    (doto btn-pane
      (.setId "btn-pane")
      (.setPadding (Insets. 10))
      (.setAlignment Pos/CENTER)
      (.setStyle "-fx-background-color: slategray;"))

    (.setPrefHeight spacer Integer/MAX_VALUE)
    (.addAll (.getChildren btn-pane) [print-btn spacer])

    (.add (.getChildren  center) canvas)
    (.setCenter root center)
    (.setRight root btn-pane)

    (doto stage
      (.setTitle "Print Scaling")
      (.setScene scene)
      (.setHeight 400)
      (.setWidth 600)
      (.show))))

(defn -main [& args]
  (Application/launch printscaling.core args))

在该示例中,程序只是绘制一个带有两个对角线的框,用于屏幕上的电路板表示。

当用户单击打印按钮时,程序会创建一个用于打印的新Canvas对象。它根据显示屏的dpi调整画布的大小。在我的情况下,我想要打印出一个5英寸的方形板,这就是(* dpi 5)根据显示器上的像素计算的内容。用于在屏幕上绘制板的相同功能用于在特殊情况下绘制它创建了Canvas

缩放的技巧只是使用基于每英寸打印机点数(72)与显示器dpi(通常为96,120或更高)之比的缩放系数。将该缩放因子添加到Canvas上使用的变换会导致电路板以所需大小打印。这适用于具有不同分辨率的打印机。

目前尚未对具有不同dpi的多个显示设备进行测试,因此我非常希望听到有人在这些设备上使用此方法获得不正确(或正确)的结果。