• electron开发


    Electron打印

    标签打印

    标签打印一般有两种方式:

    1. 驱动打印,与普通打印机一样通过驱动方式打印。
    2. 通过指令打印,不同厂家的的打印机指令集不一样,可查看厂家提供的手册。

    electron 打印方式

    1. 直接调用打印机打印
    2. 打印到pdf

    打印流程

    1. 本机安装打印机驱动
    2. 配置打印机名称
    3. 调用打印前判断打印机是否可用
    4. 打印

    打印机返回状态参考

    status为0时表示打印机可用

    调用方式

    1. 通过window的webcontent对象,使用此种方式需要单独开出一个打印的窗口,可以将该窗口隐藏,但是通信调用相对复杂
    2. 使用页面的webview元素调用打印,可以将webview隐藏在调用的页面中,通信方式比较简单

    webcontent打印

    1. 主进程创建一个打印窗口(print.html)
    2. 通过主进程和组件(渲染进程)交互,确认打印机可用
    3. 组件选择打印机,推送打印机详情和需要打印的信息到独立的print.html(打印窗口)
    4. 打印窗口通知主进程打印

    // 主进程
    
    // 创建窗口
    function createPrintWindow() {
      printWindow = new BrowserWindow({
        title: '打印',
        // show: false,
         800,
        height: 600,
        webPreferences: {
          nodeIntegration: true,
        }
      })
      printWindow.loadURL(`file://${path.join(__dirname, '../electron/print/print.html')}`);
      electronHelper.initPrintEvent(printWindow, mainWindow)
    }
    
    // 初始化打印机
    
    function initPrintEvent(printWindow, mainWindow) {
      ipcMain.on('print-start', (event, obj) => {
        console.log('print-start')
        printWindow.webContents.send('print-edit', obj);
      })
      // 获得打印机列表
      ipcMain.on('getPrinters', () => {
        console.log('received getPrinters msg');
        const printers = printWindow.webContents.getPrinters();
        mainWindow.send('printerList', printers)
      })
      // 验证打印机状态并打印
      ipcMain.on('tagPrint', (event, deviceName) => {
        const printers = printWindow.webContents.getPrinters();
        console.log('printers:', printers)
        printers.forEach(element => {
          if (element.name === deviceName && element.status !== 0) {
            mainWindow.send('print-error', deviceName + '打印机异常');
            printWindow.webContents.print({
              silent: false,
              printBackground: false,
              deviceName: ''
            },
              (data) => {
                console.log("回调", data);
              });
          } else if (element.name === deviceName && !element.status) { // 打印机正常
            console.log(element.status + '-' + deviceName)
            printWindow.webContents.print({
              silent: true,
              printBackground: false,
              deviceName: element.name
            }, (success, failureReason) => {
              if (success) {
                console.log('print success')
              }
              if (failureReason === 'cancelled') {
                console.log('print cancelled');
              }
              if (failureReason === 'failed') {
                console.log('print failed');
              }
            });
          }
        });
    
      })
    }
    
    // 组件(渲染进程)
    /**
     * 经营管理 - 商品价签打印
     */
    
    import React, { useState } from 'react'
    import CommonWrap from '@cpsCommon/CommonWrap'
    import { withRouter, RouteComponentProps } from 'react-router-dom'
    import { ipcRenderer as ipc } from 'electron'
    import { Button, Select } from 'antd'
    
    const { Option } = Select;
    
    const TagPrint = (props: any & RouteComponentProps) => {
    
      const [state, setState] = useState({
        printMsg: '这是我要打印的测试内容: TAG_PRINT',
        dataItem: [],
        currentPrinter: ''
      })
    
      const changeLoginInfo = (type: string, value: any) => {
        setState({ ...state, [type]: value })
      }
    
      const handleChange = (value) => {
        console.log(`selected ${value}`);
        changeLoginInfo('currentPrinter', value)
      }
    
      const getPrint = () => {
        console.log('发送获取打印机列表消息');
        if (!ipc) return;
        ipc.send('getPrinters');
        ipc.on('printerList', (event, data: []) => {
          console.log(data); // data就是返回的打印机数据列表
          changeLoginInfo('dataItem', data)
        });
      }
      const startPrint = () => {
        if (!ipc) return;
        ipc.send('print-start', {
            html: state.printMsg,
            deviceName: state.currentPrinter
        });
      }
      return (
        <CommonWrap id='logincomwrap'>
          <div>商品价签打印</div>
          <div>{state.printMsg}</div>
          <Button onClick={getPrint}>
            获取打印机列表
          </Button>
          <Button onClick={startPrint}>
            开始打印
          </Button>
          <h5>打印机选择</h5>
          <Select defaultValue="" style={{  120 }} onChange={handleChange}>
            {state.dataItem.map((item: any) => {
              // eslint-disable-next-line react/jsx-key
              return (<Option value={item}>{item}</Option>);
            })}
          </Select>
        </CommonWrap>
      )
    }
    
    export default withRouter(TagPrint)
    
    
    
    // 打印窗口(print.html)
    const { ipcRenderer } = require('electron');
    const _mockDevice = {
        pageUrl: 'http://192.168.2.205:8042/cw?defaultLogin=true&deviceCode=8011',
        deviceName: 'Printer001'
    }
    ipcRenderer.on('print-edit', (event, obj) => {
        console.log('打印页接收到print-edit', obj);
        let html = '';
        html += `<div>${obj.html}</div>`
        document.body.innerHTML = html;
        ipcRenderer.send('tagPrint', obj.deviceName);
        // ipcRenderer.send('do', _mockDevice.deviceName);
    });
    
    

    这个窗口不能随时打印随时创建,比较耗费性能。可以将它在程序运行时启动好,并做好事件监听。

    // 主进程
    function createPrintWindow() {
      printWindow = new BrowserWindow({
        title: '打印',
        // show: false,
         800,
        height: 600,
        webPreferences: {
          nodeIntegration: true,
        }
      })
      printWindow.loadURL(`file://${path.join(__dirname, '../electron/print/print.html')}`);
      electronHelper.initPrintEvent(printWindow, mainWindow)
    }
    
    
    app.whenReady().then(() => {
      createPrintWindow()
    });
    

    webview打印

    渲染进程和打印的webview页面做通信,无需通过主进程,性能较好;

    流程

    1. 从主进程获取打印机列表(和上一个方式一致)
    2. 组件初始化时,通过webview发送 ipc-message事件建立连接
    3. 处理需要打印的信息
    4. 点击打印,通过webview.send发送事件和打印信息,引用的页面(webview src)接收通知
    5. 引用的页面渲染打印信息,通过ipcRenderer.sendToHost通知组件可以打印了
    6. webview.print()打印
    // 组件
      useEffect(() => {
        console.log('htmlURl', state.printHtmlUrl);
        const webview: any = document.getElementById("printWebview");
        console.log('webview',webview);
        if (webview) {
          webview.addEventListener('ipc-message', (event: any) => {
            console.log('进入webview打印');
            if (event.channel === 'webview-print-do' && state.currentPrinter) {
              // if (event.channel === 'webview-print-do') {
              webview.print(
                {
                  silent: false,
                  printBackground: true,
                  deviceName: state.currentPrinter
                },
                (data) => {
                  console.log('打印结果:', data);
                },
              )
            }
          })
        }
      }, [])
    
      const startPrintWebview = () => {
        const webview: any = document.getElementById("printWebview");
        webview.send('webview-print-render', {
          printName: state.currentPrinter,
          html: state.printMsg
        })
      }
    
    
    // webview
    const { ipcRenderer } = require('electron');
    const _mockDevice = {
        pageUrl: 'http://192.168.2.205:8042/cw?defaultLogin=true&deviceCode=8011',
        deviceName: 'Microsoft Print to PDF'
    }
    ipcRenderer.on('print-edit', (event, obj) => {
        console.log('打印页接收到print-edit', obj);
        let html = '';
        html += `<div>${obj.html}</div>`
        document.body.innerHTML = html;
        ipcRenderer.send('tagPrint', obj.deviceName);
        // ipcRenderer.send('do', _mockDevice.deviceName);
    });
    
    ipcRenderer.on('webview-print-render', (event, info) => {
        console.log('webview-print-render')
        // 执行渲染
        document.body.innerHTML = info.html
        ipcRenderer.sendToHost('webview-print-do')
    })
    
    注意事项

    默认情况下,Electron >= 5禁用 webview 标签。 在构造 BrowserWindow 时,需要通过设置 webviewTag webPreferences选项来启用标签。 更多信息请参看 BrowserWindows 的构造器文档。

  • 相关阅读:
    [LeetCode] 875. Koko Eating Bananas 科科吃香蕉
    [LeetCode] 874. Walking Robot Simulation 走路机器人仿真
    [LeetCode] 995. Minimum Number of K Consecutive Bit Flips 连续K位翻转的最小次数
    [LeetCode] 873. Length of Longest Fibonacci Subsequence 最长的斐波那契序列长度
    [LeetCode] 872. Leaf-Similar Trees 叶结点相似的树
    [LeetCode] 870. Advantage Shuffle 优势洗牌
    [LeetCode] 869. Reordered Power of 2 重新排序为2的倍数
    [LeetCode] 868. Binary Gap 二进制间隙
    [LeetCode] 867. Transpose Matrix 转置矩阵
    [LeetCode] 866. Prime Palindrome 质数回文数
  • 原文地址:https://www.cnblogs.com/mapleChain/p/12516354.html
Copyright © 2020-2023  润新知