Java程序运行后再次点击按钮会重复弹窗

该程序实现关机与重启操作。程序编译正常,但是Java程序运行后再次点击按钮会重复弹窗,每多一次按按钮弹窗越多。

import com.fjl.uc.MyJframe;

/**
 * @author FJL
 * @version 1.0
 */
public class app {
    public static void main(String[] args) {
        new MyJframe();

    }
}


package com.fjl.uc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

public class MyJframe extends JFrame implements ActionListener {

    JButton shotdown1= new JButton("关机");
    JButton restart1 = new JButton("重启");
    JButton shotdown2 = new JButton("定时关机1h");
    JButton restart2 = new JButton("定时重启1h");
    JButton cancel = new JButton("取消操作");

    boolean flag = false;


    public MyJframe(){
        initJFrame();

        initView();

        //显示
        this.setVisible(true);
    }

    private void initView() {

        this.getContentPane().removeAll();

        if(flag == true){
            cancel.setBounds(50,20,100,30);
            cancel.addActionListener(this);
            this.getContentPane().add(cancel);
        }


        JLabel text = new JLabel("关机程序");
        text.setFont(new Font("微软雅黑",0,30));
        text.setBounds(190,80,300,50);


        shotdown1.setBounds(200,150,100,30);
        restart1.setBounds(200,250,100,30);
        shotdown2.setBounds(200,350,100,30);
        restart2.setBounds(200,450,100,30);

        shotdown1.addActionListener(this);
        restart1.addActionListener(this);
        shotdown2.addActionListener(this);
        restart2.addActionListener(this);

        this.getContentPane().add(text);
        this.getContentPane().add(shotdown1);
        this.getContentPane().add(restart1);
        this.getContentPane().add(shotdown2);
        this.getContentPane().add(restart2);

        this.getContentPane().repaint();
    }

    private void initJFrame() {
        //设置宽高
        this.setSize(500,600);
        //设置标题
        this.setTitle("关机程序");
        //设置关闭模式
        this.setDefaultCloseOperation(3);
        //置顶
        this.setAlwaysOnTop(true);
        //居中
        this.setLocationRelativeTo(null);
        //取消内部默认布局
        this.setLayout(null);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object obj = e.getSource();
        if(obj == shotdown1){
         //关机
            flag = true;
            showJDialog("计算机将立即关机");

            try {
                Runtime.getRuntime().exec("shutdown -s -t 0");
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }

            initView();
        }else if(obj == restart1){
         //重启
            flag = true;
            showJDialog("计算机将立即重启");
            try {
                Runtime.getRuntime().exec("shutdown -r -t 0");
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
            initView();
        }else if(obj == shotdown2){
         //定时关机
            flag = true;
            showJDialog("计算机将于1hour后关机");
            try {
                Runtime.getRuntime().exec("shutdown -s -t 3600");
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
            initView();
        }else if(obj == restart2){
         //定时重启
            flag = true;
            showJDialog("计算机将于1hour后重启");
            try {
                Runtime.getRuntime().exec("shutdown -r -t 3600");
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
            initView();
        }else if(obj == cancel){
            //取消关机操作
            flag = false;
            showJDialog("操作已取消");
            try {
                Runtime.getRuntime().exec("shutdown -a");
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
            initView();
        }


    }


    public void showJDialog(String content) {
        //创建一个弹框对象
        JDialog jDialog = new JDialog();
        //给弹框设置大小
        jDialog.setSize(200, 150);
        //让弹框置顶
        jDialog.setAlwaysOnTop(true);
        //让弹框居中
        jDialog.setLocationRelativeTo(null);
        //弹框不关闭永远无法操作下面的界面
        jDialog.setModal(true);
        //关闭模式
        jDialog.setDefaultCloseOperation(2);

        //创建Jlabel对象管理文字并添加到弹框当中
        JLabel warning = new JLabel(content);
        warning.setBounds(0, 0, 200, 150);
        jDialog.getContentPane().add(warning);

        //让弹框展示出来
        jDialog.setVisible(true);
    }
}


img


你把所有button的addActionListener都放构造方法里,initView方法里对应的addActionListener都删掉就好了。
你每点击一次按钮都调用一次initView,我猜你是想控制那个取消按钮,但其实没必要,你应该把取消按钮那个部分直接放到弹窗那个代码后面就行了。或者你用我上面截图的代码也行。
这个是因为你每调用一次initView,它都会执行一次addActionListener,但你那些button是全局的,对于frame来说,它从pane上移除了并不是这个button对象销毁了,button的对象引用还在frame里,你再次把它add到panel里,还是原来那个button,但是你又绑定了一个listener,所以点一次就绑定一次。你把它放在构造方法里,就只绑定一次了。
你可以去了解一下java里对象和引用之间的关系,就明白了

showJDialog
这个函数前面定义一个局部变量JDialog jDialog
第一次
if (jDialog == null)
{
jDialog = new JDialog();
...
}
else
{
jDialog.setVisible(true); //显示之前的
}

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/358274
  • 你也可以参考下这篇文章:Java并发编程实战 02Java如何解决可见性和有序性问题
  • 除此之外, 这篇博客: Java线程相关知识点中的 一 进程是什么?线程是什么?两者有什么联系和区别? 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    1.1 进程:进程,直观点来说,保存在硬盘上的程序运行之后,会在内存空间形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级是操作系统。操作系统会 以进程为单位,分配系统资源(CPU时间片,内存等),进程是最小的资源分配单位;

    1.2 线程:有时被称为轻量级的进程,是操作系统调度执行的最小单位

    1.3 区别:

    • 调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
    • 并发性:不仅进程之间可以并发,同一个进程的多个线程之间也可并发执行
    • 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但是可以访问当前进程的资源
    • 系统开销:在创建和撤销进程的时候,系统要为它分配和回收资源,所以导致系统的开销比线程的创建和销毁时要大。但是进程有独立的地址空间,一个进程崩溃了之后,不会影响其他的进程,而线程没有独立的地址空间,一个进程死掉后,所拥有的线程全部都要销毁,所以多进程的程序比多线程的要健壮,但是在进程切换,消耗的资源比较大,性能及效率较差

    1.4 联系:

    • 一个进程有多个线程,至少有一个线程,而一个线程只能属于某一个进程
    • 同一个进程中的所有线程,共享该进程中的所有资源


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^