Java定时弹窗提示与开启多线程展示图片
自顶向下介绍,首先是定时弹窗功能,可以用Java自带的ScheduledExecutorService库完成函数调用。
package healthReminder; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TimerScheduledTask { // how to write a timer task? // https://blog.csdn.net/qq_39731011/article/details/123332641 public static void main(String[] args) { // This class is a subclass of Thread OpenAPicture oap = new OpenAPicture(); ScheduledExecutorService ses = Executors.newScheduledThreadPool(2); ses.scheduleAtFixedRate(()->{ // static method to show dialog
// print current time System.out.println(new Date().toString().substring(4, 19));
TipAfterAWhile.showAlarm(); oap.start(); }, 1, 3000, TimeUnit.SECONDS); } }
其次是所被调用的函数,即弹窗。
窗口布局为:标题、文本区、勾选框、两个按键,其中一个按键同右上角一样功能为关闭,另一个按键用于打开一张图片。
该程序为设计窗口布局和功能。
package healthReminder; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; public class TipAfterAWhile extends JDialog { private static final long serialVersionUID = -6493879146336970741L; private final JPanel contentPanel = new JPanel(); /** * Launch the application. */ public static void showAlarm() { try { // UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel"); UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Throwable e) { e.printStackTrace(); } try { TipAfterAWhile dialog = new TipAfterAWhile(); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialog.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } public TipAfterAWhile() { setTitle("Health Reminder"); setBounds(100, 100, 480, 300); getContentPane().setLayout(new BorderLayout()); contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); getContentPane().add(contentPanel, BorderLayout.CENTER); contentPanel.setLayout(new BorderLayout(0, 0)); { JPanel panel = new JPanel(); contentPanel.add(panel, BorderLayout.NORTH); { JLabel label = new JLabel("Stand up and Relax!"); label.setFont(new Font("微软雅黑", Font.PLAIN, 16)); panel.add(label); } } { JPanel panel = new JPanel(); contentPanel.add(panel, BorderLayout.SOUTH); panel.setLayout(new BorderLayout(0, 0)); { JCheckBox checkBox = new JCheckBox("Don't Prompt Again!"); checkBox.setFont(new Font("微软雅黑", Font.PLAIN, 16)); panel.add(checkBox); } } { JPanel panel = new JPanel(); contentPanel.add(panel, BorderLayout.WEST); } { JPanel panel = new JPanel(); contentPanel.add(panel, BorderLayout.EAST); } { JScrollPane scrollPane = new JScrollPane(); contentPanel.add(scrollPane, BorderLayout.CENTER); { JTextArea textArea = new JTextArea(); textArea.setFont(new Font("微软雅黑", Font.PLAIN, 14)); textArea.setLineWrap(true); textArea .setText("You have been working for an hour, why not stand up and have a relax?"); scrollPane.setViewportView(textArea); } } { JPanel buttonPane = new JPanel(); buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); getContentPane().add(buttonPane, BorderLayout.SOUTH); { JButton cancelButton = new JButton("Concel"); cancelButton.setFont(new Font("微软雅黑", Font.PLAIN, 16)); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // dispose(); // 也可关闭但不是真的关闭 System.exit(0); } }); buttonPane.add(cancelButton); } { JButton okButton = new JButton("Give me a setu!"); okButton.setFont(new Font("微软雅黑", Font.PLAIN, 16)); okButton.setActionCommand("OK"); OpenAPicture oap = new OpenAPicture();
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
oap.start();
}
}); buttonPane.add(okButton); getRootPane().setDefaultButton(okButton); } } } }
接着是打开一张图片的功能(作为按键事件监听器的调用方法),该方法会访问下述自定义JPanel子类,BackgroundPanel,功能是展示图片的。
package healthReminder; import java.awt.Graphics; import java.awt.Image; import javax.swing.JPanel; public class BackgroundPanel extends JPanel { private static final long serialVersionUID = 1L; /** * 背景图片 */ private Image image; /** * 构造方法 */ public BackgroundPanel() { super(); setOpaque(false); setLayout(null); } /** * 设置图片的方法 */ public void setImage(Image image) { this.image = image; } @Override protected void paintComponent(Graphics g) {// 重写绘制组件外观 if (image != null) { g.drawImage(image, 0, 0, this);// 绘制图片与组件大小相同 // System.out.println("repaint!"); } super.paintComponent(g);// 执行超类方法 } }
最后一个功能,设计图片所用到的弹窗,将作为按键的监听器调用方法:
首先定义一个Thread的子类:
package healthReminder; public class OpenAPicture extends Thread { @Override public void run() { // TODO Auto-generated method stub new ShowAPictureOnJF(); } }
然后是方法本身:
package healthReminder; import java.awt.BorderLayout; import java.awt.Image; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.Random; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; public class ShowAPictureOnJF extends JFrame { private static final long serialVersionUID = 1L; private final JPanel contentPane = new JPanel(); public ShowAPictureOnJF() { this.setTitle("relax"); this.setBounds(100, 100, 960, 540); this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); this.setVisible(true); String ppath = this.returnFileRandomly("D:/kingz/ANIME"); System.out.println(ppath); setContentPane(this.contentPane); contentPane.setLayout(new BorderLayout(0, 0)); BackgroundPanel backgroundPanel = new BackgroundPanel();// 创建背景面板 try { Image img1 = ImageIO.read(new File(ppath)); backgroundPanel.setImage(img1); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // backgroundPanel.setImage(getToolkit().getImage( // getClass().getResource(ppath)));// 设置面板背景图片 contentPane.add(backgroundPanel);// 把背景面板添加到窗体内容面板 } // 返回某文件夹下随机一张图片 private String returnFileRandomly(String dpath) { File directory = new File(dpath); File[] flist = directory.listFiles(); int fllen = flist.length; if (flist == null || fllen == 0) { return null; } System.out.println("this directory has "+fllen+" pictures."); ArrayList<String> pngjpglist = new ArrayList<String>(); for (File f : flist) { String fname = f.getName(); if (f.isDirectory() || !((fname.substring(fname.length()-3)).equals("jpg") || (fname.substring(fname.length()-3)).equals("png"))) { continue; }else { // System.out.println(fname.substring(fname.length()-3)); pngjpglist.add(fname); } } System.out.println("the jpg or png picture's number is "+pngjpglist.size()); Random rd = new Random(); int iterNum = rd.nextInt(pngjpglist.size()); int indexCount = 0; Iterator<String> it = pngjpglist.iterator(); while (it.hasNext()) { String string = (String) it.next(); indexCount++; if (indexCount>=iterNum) { return dpath + "/" + string; } } return null; } public static void main(String[] args) { new ShowAPictureOnJF(); // System.out.println(returnFileRandomly("D:\\kingz\\ANIME")); } }
那么如果想一次打开两张图片呢?那就定义多个线程即可
// 错误案例: OpenAPicture oap = new OpenAPicture(); okButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (int i = 0; i < 2; i++) { oap.start(); } } }); // 正确示例: // OpenAPicture oap = new OpenAPicture(); okButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (int i = 0; i < 2; i++) { new OpenAPicture().start(); } } });
然后可以把该项目在命令行中通过javac进行编译,然后再通过DOS命令写一个bat文件,就更方便了。(注意路径)
~\src>javac -encoding UTF-8 healthReminder/TimerScheduledTask.java
~\src>java healthReminder/TimerScheduledTask.java
编写文件 src/TimerAlarm.bat,内含1行指令。(注意路径)
java healthReminder/TimerScheduledTask.java
优化空间:图片自适应窗口大小进行缩放、窗口最大化、多文件夹下选择图片。
System.out.println(new Date().toString().substring(4, 19));