目录
1.准备设备,二维码扫描模块及其信息、它的dll文件(在Windows)。
2.参考 HidPosApi 使 用 说 明 文 档 ,编写接口
7.2重点:对二维码模块的识别和把数据传输到swing界面上的JTextArea文本框中
1.准备设备,二维码扫描模块及其信息、它的dll文件(在Windows)。
文件在自己的阿里云盘:
1.1获取设备信息(vid与pid)
在“我的电脑“的管理-》
得到
vid:1FC9
pid: 5AA7
2.参考 HidPosApi 使 用 说 明 文 档 ,编写接口,准备一点本地jna的jar
本地的jna jar包
3.准备一个图形化界面(swing)
3.1这是主界面程序(不完整版)
package org.frame;
import com.sun.jna.ptr.IntByReference;
import org.api.HidPosAPI;
import org.myClass.MyCallback;
import org.util.PathUtils;
import org.util.ScreenUtils;
import org.util.SerialReader;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.text.NumberFormat;
public class UserFrame {
//TODO 对象new区
final int WIDTH = 500;
final int HEIGHT = 600;
private static final short VENDOR_ID = 0x1FC9; // USB设备的供应商ID
private static final short PRODUCT_ID = 0x5AA7; // USB设备的产品ID
//usb变量设置全局变量
/*UsbDevice device = null;*/
/*Usbdevice device = null;*/
JFrame frame = new JFrame("打标信息系统");
JMenuBar menuBar = new JMenuBar();
JPanel jPanel = new JPanel();
JPanel jPanel2 = new JPanel();
JPanel jPanel3 = new JPanel();
//
JLabel jLabel = new JLabel("打标数量:");
//
Box vBox = Box.createVerticalBox();
//
JTextArea jTextArea = new JTextArea("",15,30);
//整数输入的文本框
NumberFormat format = NumberFormat.getIntegerInstance();
JFormattedTextField numberTextField = new JFormattedTextField(format);
//USB文本传输对象
private InputStream input;
SerialReader serialReader = new SerialReader(input);
//
//TODO 组件区
JMenu fileMenue = new JMenu("文件");
JMenu editMenue = new JMenu("配置");
//TODO 监听器区
JMenuItem open = new JMenuItem(new AbstractAction("打开") {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
//
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION){
//
File selectedFile = fileChooser.getSelectedFile();
String filePath = selectedFile.getAbsolutePath();
//
try {
BufferedReader reader = null;
//防止中文乱码
reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"UTF-8"));
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null){sb.append(line).append("\n");
}
reader.close();
//
jTextArea.setText(sb.toString());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}});
//
JMenuItem save = new JMenuItem(new AbstractAction("另存为") {
@Override
public void actionPerformed(ActionEvent e) {
//
JFileChooser fileChooser = new JFileChooser(".");
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
String contentType = null;
try {
contentType = Files.probeContentType(selectedFile.toPath());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
if (contentType != null) {
String extension = null;
switch (contentType) {
case "image/jpeg":
extension = "jpg";
break;
case "image/png":
extension = "png";
break;
case "application/pdf":
extension = "pdf";
break;
// add more cases for other file types
default:
extension = "dat";
}
String originalFileName = selectedFile.getName();
String newFileName = originalFileName.substring(0, originalFileName.lastIndexOf(".")) + "." + extension;
String newFilePath = selectedFile.getParent() + File.separator + newFileName;
try (InputStream in = new BufferedInputStream(new FileInputStream(selectedFile));
OutputStream out = new BufferedOutputStream(new FileOutputStream(newFilePath))) {
byte[] buffer = new byte[1024];
int lengthRead;
while ((lengthRead = in.read(buffer)) > 0) {
out.write(buffer, 0, lengthRead);
out.flush();
}
} catch (IOException ex) {
ex.printStackTrace();
}
} else {
System.out.println("Unknown file type");
}
}
}
//
});
//
JMenuItem auto = new JMenuItem("自动换行");
/*添加图标在菜单条上*/
JMenuItem copy = new JMenuItem("复制",new ImageIcon("D:\\IDEA\\xmFile\\txhdb\\src\\main\\resources\\images\\copy.png"));//从绝对路径改过来的,不知道是不是相对路径
JMenu paste = new JMenu("主题风格");
JMenu msMenu = new JMenu("模式");
//创建了一个单选分组,以及单选内容
ButtonGroup moshiButton = new ButtonGroup();
JRadioButtonMenuItem moshi = new JRadioButtonMenuItem("手动模式");
JRadioButtonMenuItem moshi2 = new JRadioButtonMenuItem("连续模式");
//设置了默认为感应模式
JRadioButtonMenuItem moshi3 = new JRadioButtonMenuItem("感应模式",true);
//风格组
ButtonGroup fengeButtonGroup = new ButtonGroup();
JRadioButtonMenuItem metalItem = new JRadioButtonMenuItem("mtetal 风格");
JRadioButtonMenuItem NimbusItem = new JRadioButtonMenuItem("Nimbus 风格");
JRadioButtonMenuItem windowsItem = new JRadioButtonMenuItem("windows 风格");
JRadioButtonMenuItem motifItem = new JRadioButtonMenuItem("motif 风格");
/*JButton end = new JButton("结束");*/
//
JToolBar jToolBar = new JToolBar("功能条",SwingConstants.HORIZONTAL);
//TODO 工具按钮点击监听
Action start2 = new AbstractAction("开始",new ImageIcon("D:\\IDEA\\xmFile\\txhdb\\src\\main\\resources\\images\\开始.png")) {
@Override
public void actionPerformed(ActionEvent e) {
}
};
/*java.net.URI imgURL = UserFrame.class.getResource("/images/end.png");
ImageIcon img1 = new ImageIcon(imgURL);*/
Action end2 = new AbstractAction("结束",new ImageIcon("D:\\IDEA\\xmFile\\txhdb\\src\\main\\resources\\images\\end.png")) {
@Override
public void actionPerformed(ActionEvent e) {
}
};
//监听装入JButton可以显示文字
JButton start = new JButton(start2);
JButton end = new JButton(end2);
public UserFrame() throws URISyntaxException {
}
public void init(){
//TODO 组装中的new对象
//usb工具类
/* UsbDataUtil usbDataUtil = new UsbDataUtil();
usbDataUtil.setjTextArea(jTextArea);*/
// TODO 组装视图
JPanel bottomPaner = new JPanel();
/*bottomPaner.add(start);
bottomPaner.add(end);*/
/*frame.add(bottomPaner,BorderLayout.SOUTH);*/
//把JButton放入工具条
jToolBar.add(start);
jToolBar.add(end);
//
fileMenue.add(open);
fileMenue.add(save);
//TODO 组装中间文本框
frame.add(jToolBar,BorderLayout.SOUTH);
//拖动条文本框
/* jTextArea.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // 设置字体
jTextArea.setLocale(Locale.CHINA); // 设置字符集*/
JScrollPane jScrollPane = new JScrollPane(jTextArea);
//组装数量文本框预留空间大小
numberTextField.setPreferredSize(new Dimension(40,numberTextField.getPreferredSize().height));
//
jPanel2.add(jLabel);
jPanel2.add(Box.createHorizontalStrut(20));
jPanel2.add(numberTextField);
//向左边挤数量框
jPanel2.add(Box.createHorizontalStrut(200));
vBox.add(jScrollPane);
vBox.add(jPanel2);
jPanel.add(vBox);
frame.add(jPanel);
/*System.out.println(new File("."));*/
moshiButton.add(moshi);
moshiButton.add(moshi2);
moshiButton.add(moshi3);
//风格组装
fengeButtonGroup.add(metalItem);
fengeButtonGroup.add(NimbusItem);
fengeButtonGroup.add(windowsItem);
fengeButtonGroup.add(motifItem);
paste.add(metalItem);
paste.add(NimbusItem);
paste.add(windowsItem);
paste.add(motifItem);
//TODO USB文本输出到程序文本框,并设置程序主窗口监听
//给工具类一个文本框
/*serialReader.setjTextArea(jTextArea);*/
//监听主窗口关闭则,释放串口
/* frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
try {
input.close();
} catch (IOException e1) {
e1.printStackTrace();
}
frame.dispose();
}
});*/
//TODO 初始化usb口
//采用JNA调用第三方dll文件
//
IntByReference ref = new IntByReference();
HidPosAPI myLibrary = HidPosAPI.hidPos;
//dll类加载路径
System.out.println("当前dll加载路径:"+System.getProperty("java.library.path"));
boolean idxx = HidPosAPI.hidPos.OpenDevice(VENDOR_ID, PRODUCT_ID);
if (idxx) {
//
boolean connectStaus = HidPosAPI.hidPos.ConnectStaus();
if (connectStaus){
String str = "hh";
boolean getDeviceSn = HidPosAPI.hidPos.GetDeviceSn(str, ref);
if (getDeviceSn){
System.out.println("当前设备的SN号: "+ref.getValue());
//
MyCallback myCallback = new MyCallback();
myLibrary.SetCallback(myCallback);
}else {
System.out.println("设备状态信息异常:--》"+getDeviceSn);
HidPosAPI.hidPos.CloseDevice();
}
}else {
System.out.println("设备状态信息异常:--》"+connectStaus);
HidPosAPI.hidPos.CloseDevice();
}
}
if (!idxx)
HidPosAPI.hidPos.CloseDevice();
//1.查找usb设备
/* try {
device = usbDataUtil.findDevice(UsbHostManager.getUsbServices().getRootUsbHub(), VENDOR_ID, PRODUCT_ID);
//2.
usbDataUtil.initUseDevice(device);
boolean connectSuccess = usbDataUtil.isConnectSuccess();
System.out.println("连接信息:");
System.out.println(connectSuccess);
System.out.println("------------->");
//3.把获取的数据添加到jTexeArea中
String s = usbDataUtil.getjTextArea().getText();
jTextArea.append(s);
} catch (UsbException e) {
throw new RuntimeException(e);
}
*/
//TODO 监听区2
//风格监听器
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
try {
changeFlavor(actionCommand);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
};
//整数文本监听--->需要有一个定时器
numberTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
handleEdit(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
handleEdit(e);
}
@Override
public void changedUpdate(DocumentEvent e) {
handleEdit(e);
}
//
private void handleEdit(DocumentEvent e){
String text = numberTextField.getText().replace(",", "");
try {
int value = Integer.parseInt(text);
System.out.println("new value:"+ value);
//TODO 整数值 此处添加相应代码,将值发送到另一个组件或者通过其他协议发送
} catch (NumberFormatException ex) {
System.err.println("Invalid number format");
}
}
});
//注册风格监听
metalItem.addActionListener(listener);
NimbusItem.addActionListener(listener);
windowsItem.addActionListener(listener);
motifItem.addActionListener(listener);
//组装组件
msMenu.add(moshi);
msMenu.add(moshi2);
msMenu.add(moshi3);
editMenue.add(auto);
editMenue.add(copy);
editMenue.add(paste);
//中间的横线
editMenue.addSeparator();
editMenue.add(msMenu);
//菜单条
menuBar.add(fileMenue);
menuBar.add(editMenue);
// TODO frame中间做了一个炫彩边框
Border beveborder = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.RED,Color.GREEN, Color.BLUE, Color.GRAY);
//当前炫彩框与文本框重叠了,故注释掉
/* frame.add(getJPanelWithBorder(beveborder,"ceshi"));*/
getJPanelWithBorder(beveborder,"程序信息");
//让工具条可以拖动
jToolBar.setFloatable(true);
//TODO frame组装区
//把菜单条加入frame
frame.setJMenuBar(menuBar);
//frame点击X关闭
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
//窗口居中
frame.setBounds((ScreenUtils.getScreenWidth()-WIDTH)/2,(ScreenUtils.getScreenHeight()-HEIGHT)/2,WIDTH,HEIGHT);
frame.setResizable(false);
/*
try {
frame.setIconImage(ImageIO.read(new File(PathUtils.getRealPath("开始.png"))));
} catch (IOException e) {
throw new RuntimeException(e);
}*/
}
//TODO 主线程main
public static void main(String[] args) throws URISyntaxException {
new UserFrame().init();
}
//定义一个方法,用于改变界面风格
private void changeFlavor(String command) throws Exception {
switch (command) {
case "Metal 风格":
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
break;
case "Nimbus 风格":
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
break;
case "Windows 风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
break;
case "Windows 经典风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
break;
case "Motif 风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
break;
}
//刷新组件的外观
SwingUtilities.updateComponentTreeUI(frame.getContentPane());
SwingUtilities.updateComponentTreeUI(menuBar);
//SwingUtilities.updateComponentTreeUI(jPopupMenu);
}
//TODO 边框炫彩模块
public void getJPanelWithBorder(Border border,String content){
//
jPanel.add(new JLabel(content));
//
jPanel.setBorder(border);
}
}
3.2 项目的pom.xml文件(不一定全用上)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.ithyy</groupId>
<artifactId>txhdb</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
</properties>
<dependencies>
<!--json数据转换-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
<!--USB串口传输库-->
<!-- <dependency>
<groupId>comm</groupId>
<artifactId>rxtxcomm</artifactId>
<version>20081208</version>
</dependency>-->
<!--usb口传输库-->
<dependency>
<groupId>org.usb4java</groupId>
<artifactId>usb4java</artifactId>
<version>1.3.0</version>
</dependency>
<!--usb包啊api-->
<!-- <dependency>
<groupId>javax.usb</groupId>
<artifactId>javax.usb-api</artifactId>
<version>1.0.2</version>
</dependency>-->
<!--<dependency>
<groupId>com.test</groupId>
<artifactId>rxtxcomm</artifactId>
<version>2.2</version>
<!–<scope>system</scope>
<systemPath>${basedir}/lib/RXTXcomm.jar</systemPath>–>
</dependency>-->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.13.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
<!--日志插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-Xlint:all</arg>
</compilerArgs>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>lib/**</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
4.声明当前的各种版本
jdk 17
jna 5.13.0
5.项目结构
7.重点部分:
7 .1接口类文件
package org.api;
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import org.util.DllIntoUtil;
import javax.swing.*;
public interface HidPosAPI extends Library {
public static HidPosAPI hidPos = Native.load("lib/HidPosApi", HidPosAPI.class);
//打开设备
boolean OpenDevice(int vid,int pid);
//关闭设备
boolean CloseDevice();
//获取设备连接状态
boolean ConnectStaus();
//获取设备Sn号
boolean GetDeviceSn(String pSn,IntByReference pSnLength);
//设置超时接收时间
boolean SetReceiveTimeOut(int nTimeOutMillisecond);
//发送数据
boolean WriteUsb(Pointer lpBuffer,int dwSize);
//
interface ReceivePosData extends Callback{
int callback(Pointer pData,int pDataLength,byte cResult);
}
//设置回调函数
int SetCallback(ReceivePosData pf);
}
7.1.1回调函数实现类
package org.myClass;
import com.sun.jna.Pointer;
import org.api.HidPosAPI;
import javax.swing.*;
//回调函数的实现类,具体实现数据的发送到jTeextArea中去
public class MyCallback implements HidPosAPI.ReceivePosData {
public JTextArea jTextArea;
public MyCallback(JTextArea jTextArea) {
this.jTextArea = jTextArea;
}
public MyCallback() {
}
@Override
public int callback(Pointer pData, int pDataLength, byte cResult) {
String data = pData.getString(0);
//
SwingUtilities.invokeLater(()->{
jTextArea.append(data+"\n");
});
return 0;
}
}
7.2重点:对二维码模块的识别和把数据传输到swing界面上的JTextArea文本框中
//采用JNA调用第三方dll文件
//
IntByReference ref = new IntByReference();
HidPosAPI myLibrary = HidPosAPI.hidPos;
//dll类加载路径
System.out.println("当前dll加载路径:"+System.getProperty("java.library.path"));
boolean idxx = HidPosAPI.hidPos.OpenDevice(VENDOR_ID, PRODUCT_ID);
if (idxx) {
//
boolean connectStaus = HidPosAPI.hidPos.ConnectStaus();
if (connectStaus){
String str = "hh";
boolean getDeviceSn = HidPosAPI.hidPos.GetDeviceSn(str, ref);
if (getDeviceSn){
System.out.println("当前设备的SN号: "+ref.getValue());
//
MyCallback myCallback = new MyCallback();
myLibrary.SetCallback(myCallback);
}else {
System.out.println("设备状态信息异常:--》"+getDeviceSn);
HidPosAPI.hidPos.CloseDevice();
}
}else {
System.out.println("设备状态信息异常:--》"+connectStaus);
HidPosAPI.hidPos.CloseDevice();
}
}
if (!idxx)
HidPosAPI.hidPos.CloseDevice();
8.回忆项目中我面临的难点
8.1 接口类的相对路径的设置(lib前不要/),
public static HidPosAPI hidPos = Native.load("lib/HidPosApi", HidPosAPI.class);
在寻找文件路径的时候,感觉这个加载jvm中的参数比较重要
在寻找这个文件的时候要有
jna依赖
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.13.0</version>
</dependency>
在<build>中要有这个打包插件,
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>lib/**</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
顺便提一下Maven插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
8.2回忆遇到的问题
8.2.1 在debug调试的时候遇到了提示变量未初始化,然后找了很久,找到一个文件为找到(eutc.tte字体文件),最终查询了win10已经丢弃这个文件了,在jdk9中需要这个文件,于是我将jdk换成17的就没要求了(当然是在Windows系统中)
换jdk的步骤:1.更换系统变量 JAVA_HOME17(前提配好了jdk多环境配置)(后面发现,跟jdk没关系)
2.项目中的更换jdk
8.2.2 要是Maven中刷不出jna的依赖,就用本地jar包导入