NetBeans 8.2+树莓派3环境下Login跳转后MainForm主方法代码不执行问题
问题根源分析
你遇到的核心问题是对Java程序入口的误解:
- 当你直接右键运行
MainForm.java时,IDE会将它作为程序启动入口,自动执行MainForm里的main方法,所以GPIO初始化、中断监听这些核心逻辑都会正常运行。 - 但运行整个项目时,程序入口是
Login的main方法,验证通过后你只是通过new MainForm()创建了一个实例——这只会调用MainForm的构造函数,不会触发它的main方法。记住:main方法只有被JVM作为程序启动入口时才会执行,手动创建类实例不会调用它。
另外还有个隐藏坑:MainForm的main方法里有个死循环for (;;),如果直接放在UI线程里会导致界面彻底卡死,必须把这个阻塞逻辑放到独立的工作线程中。
解决方案
我们需要把MainForm中main方法里的GPIO初始化、中断监听逻辑,从main移到构造函数(或专门的初始化方法)中,同时处理线程阻塞UI的问题:
修改后的MainForm.java代码
package Kiosk; import javax.swing.JLabel; import javax.swing.WindowConstants; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import com.pi4j.wiringpi.Gpio; import com.pi4j.wiringpi.GpioInterrupt; import com.pi4j.wiringpi.GpioInterruptListener; import com.pi4j.wiringpi.GpioInterruptEvent; import com.pi4j.wiringpi.GpioUtil; public class MainForm extends javax.swing.JFrame { public static volatile int pulses = 0; public static boolean display = true; public MainForm() { initComponents(); // 调用初始化方法,替代原来main里的逻辑 initGpioAndListeners(); } private void initGpioAndListeners() { // 创建中断监听器 GpioInterrupt.addListener(new GpioInterruptListener() { @Override public void pinStateChange(GpioInterruptEvent event) { if (event.getPin() == 0) { if (event.getState() == false) { pulses++; display = true; } } if (event.getPin() == 7) { if (event.getState() == false) { int bpulses = 0; bpulses++; pulses += bpulses * 10; display = true; } } } }); // 初始化wiringPi if (Gpio.wiringPiSetup() == -1) { System.out.println("Setup Failed!"); return; } // 配置引脚 GpioUtil.export(7, GpioUtil.DIRECTION_IN); GpioUtil.export(0, GpioUtil.DIRECTION_IN); // 设置边缘检测 GpioUtil.setEdgeDetection(7, GpioUtil.EDGE_FALLING); GpioUtil.setEdgeDetection(0, GpioUtil.EDGE_FALLING); // 配置引脚模式和上拉下拉 Gpio.pinMode(7, Gpio.INPUT); Gpio.pullUpDnControl(7, Gpio.PUD_UP); GpioInterrupt.enablePinStateChangeCallback(7); Gpio.pinMode(0, Gpio.INPUT); Gpio.pullUpDnControl(0, Gpio.PUD_UP); GpioInterrupt.enablePinStateChangeCallback(0); // 把阻塞循环放到单独线程,避免卡死UI new Thread(() -> { for (;;) { try { // 加短睡眠降低CPU占用 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); break; } if (display == true) { // Swing组件必须在EDT线程更新,否则会有异常 javax.swing.SwingUtilities.invokeLater(() -> { jTextField_pulses.setText(String.valueOf(pulses)); }); display = false; } } }).start(); } @SuppressWarnings("unchecked") // 这里保留IDE自动生成的initComponents()方法 /** * 这个main方法现在只作为单独运行MainForm时的入口 */ public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { new MainForm().setVisible(true); } }); } }
关键修改点说明
- 迁移初始化逻辑到构造函数调用的方法:这样无论通过
new MainForm()创建实例,还是单独运行MainForm,都会执行GPIO初始化逻辑。 - 将死循环放入独立线程:避免阻塞Swing的事件调度线程(EDT),防止界面无响应。
- 使用
SwingUtilities.invokeLater更新UI:Swing组件必须在EDT线程中操作,否则会出现线程安全问题和界面渲染异常。
额外提醒
- 确保树莓派的GPIO权限配置正确,Pi4J依赖也已正确导入(直接运行MainForm没问题的话,这部分应该是正常的)。
- 测试时运行整个项目,登录后MainForm的GPIO相关功能应该就能正常工作了。
内容的提问来源于stack exchange,提问作者patrickdg142
相关产品推荐
相关产品推荐

