swing笔记

swing

JFrame

jframe是一个顶层容器

创建jframe并设置标题为Swing
java 复制代码
JFrame frame = new JFrame("Swing");
显示JFrame
java 复制代码
frame.setVisible(true);
退出swing应用
java 复制代码
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
退出的四个常数
  • JFrame.DO_NOTHING_ON_CLOSE: 表示窗口关闭时不执行任何操作。通常用于自定义关闭逻辑,例如显示确认对话框后再决定是否关闭窗口。
  • JFrame.HIDE_ON_CLOSE: 表示窗口关闭时隐藏窗口而不终止应用程序。这个选项适用于需要隐藏窗口而不完全退出应用程序的情况。
  • JFrame.DISPOSE_ON_CLOSE: 表示窗口关闭时释放窗口占用的所有资源,并终止应用程序。这是通常的默认行为,适用于大多数独立应用程序。
  • JFrame.EXIT_ON_CLOSE : 表示窗口关闭时终止应用程序。这个选项会导致 System.exit() 被调用,完全退出 Java 虚拟机。
JFrame的大小设置
java 复制代码
frame.setSize(int width,int height);
JFrame的位置设置
java 复制代码
frame.setLocation(int x,int y);
同时设置位置和大小
java 复制代码
frame.setBounds(int x,int y,int widht,int height);
添加组件

要将JFrame放在屏幕中央,使用null参数调用其setLocationRelativeTo()方法

当向JFrame添加UI控件时,需要将其添加到JFrame的内容窗格

获取内容窗格的引用及添加

java 复制代码
Container contentPane = frame.getContentPane();
contentPane.add(aComponent); //aComponent为UI组件

添加一个按钮Close

java 复制代码
frame.getContentPane().add(new JButton("Close"));
包JFrame

JFrame的pack()方法检查JFrame上的所有组件,并决定它们的首选大小,并设置JFrame的大小刚好足以显示所有组件

当我们调用pack()方法时,我们不需要设置JFrame的大小,pack()方法将计算JFrame的大小并设置它

当使用pack()方法时,我们不需要调用setBounds()方法,要在pack()方法后定位JFrame,请使用setLocation(x,y)方法

JFrame状态

设置JFrame的状态

java 复制代码
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);

状态常量

JFrame状态常量 描述
NORMAL JFrame以正常大小显示。
ICONIFIED JFrame显示为最小化状态。
MAXIMIZED_HORIZ JFrame显示为水平最大化,但垂直尺寸正常。
MAXIMIZED_VERT JFrame显示为水平最大化,但垂直尺寸正常。...
MAXIMIZED_BOTH JFrame显示为水平和垂直最大化。
默认按钮

将自定义的按钮设置为默认按钮

java 复制代码
// Create a  JButton
JButton okButton   = new JButton("OK");
// Set  okButton   as  the   default  button 
frame.getRootPane().setDefaultButton(okButton);
窗口事件

可以使用WindowListener接口和WindowAdapter类

java 复制代码
	JFrame frame = new JFrame();
    frame.addWindowListener(new WindowListener() {
      @Override
      public void windowOpened(WindowEvent e) {
        System.out.println("JFrame has  been  made visible first  time");
      }

      @Override
      public void windowClosing(WindowEvent e) {
        System.out.println("JFrame is closing.");
      }

      @Override
      public void windowClosed(WindowEvent e) {
        System.out.println("JFrame is closed.");
      }

      @Override
      public void windowIconified(WindowEvent e) {
        System.out.println("JFrame is  minimized.");
      }

      @Override
      public void windowDeiconified(WindowEvent e) {
        System.out.println("JFrame is restored.");
      }

      @Override
      public void windowActivated(WindowEvent e) {
        System.out.println("JFrame is activated.");
      }

      @Override
      public void windowDeactivated(WindowEvent e) {
        System.out.println("JFrame is deactivated.");
      }
    });

    // Use the WindowAdapter class to intercept only the window closing event
    frame.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        System.out.println("JFrame is closing.");
      }
    });

dispose()方法使窗口不可见,并将资源释放到操作系统。

Swing布局管理器

容器使用布局管理器来定位其所有组件

JFrame的内容窗格的默认布局管理器时BorderLayout

JPanel的默认布局管理器是FlowLayout

可以使用setLayout()方法更改,传入null则为删除布局管理器

容器的getLayout()方法返回容器当前正在使用的布局管理器的引用

java 复制代码
JFrame  frame  = new JFrame("Frame"); 
Container contentPane = frame.getContentPane(); 
contentPane.setLayout(new FlowLayout());
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
空布局管理器

也称为绝对定位,使用setBounds()方法设置组件的位置

java 复制代码
Container contentPane = frame.getContentPane();
contentPane.setLayout(null);
JButton b1 = new JButton("Button");
contentPane.add(b1);
b1.setBounds(10, 10, 100, 20);
FlowLayout流式布局

FlowLayout按照添加容器的顺序布置组件水平或垂直

水平布局调用setComponentOrientation()方法来设置容器的方向

容器及其子项的方向使用applyComponentOrientation()方法

java 复制代码
JFrame  frame  = new JFrame("Test");
Container pane  = frame.getContentPane();
pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
JFrame  frame  = new JFrame("Test");
Container pane  = frame.getContentPane();
pane.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

流式布局尝试将所有组件放入一行,给他们的首选大小

如果所有组件不适合一行,则会启动另一行

流式布局可以为宽度和高度添加额外的空间

设置对齐

java 复制代码
FlowLayout  flowLayout = new FlowLayout(FlowLayout.RIGHT);

FlowLayout  flowLayout = new FlowLayout(FlowLayout.LEFT);
flowLayout.setAlignment(FlowLayout.RIGHT);

5种对齐方式

  • LEFT
  • RIGHT
  • CENTER
  • LEADING
  • TRAILING
BorderLayout边框布局

容器上的组件按照上北下南左西右东的顺序摆放

java 复制代码
// 设置布局器为BorderLayerout
// 容器上的组件按照上北下南左西右东中的顺序摆放
f.setLayout(new BorderLayout());
JButton b1 = new JButton("aa");
JButton b2 = new JButton("bb");
JButton b3 = new JButton("cc");
JButton b4 = new JButton("dd");
JButton b5 = new JButton("ee");

// 加入到容器的时候,需要指定位置
f.add(b1,BorderLayout.NORTH);
f.add(b2,BorderLayout.SOUTH);
f.add(b3,BorderLayout.EAST);
f.add(b4,BorderLayout.WEST);
f.add(b5,BorderLayout.CENTER);
GridLayout网格布局
java 复制代码
// 设置布局器为GridLayerout,即网格布局器
// 该GridLayerout的构造方法表示该网格是2行3列
f.setLayout(new GridLayout(2,3));
JButton b1 = new JButton("aa");
JButton b2= new JButton("bb");
JButton b3 = new JButton("cc");
JButton b4 = new JButton("dd");
JButton b5 = new JButton("ee");

f.add(b1);
f.add(b2);
f.add(b3);
f.add(b4);
f.add(b5);

setPreferredSize建议大小,只对部分布局有效

java 复制代码
b3.setPreferredSize(new Dimension(180,40));
CardLayout卡片布局

卡片布局将容器分成许多层,每层的显示空间占据整个容器的大小,但是每层只允许放置一个组件

GridBagLayout网格包布局'

网格包布局不需要组件的尺寸一致,允许组件扩展到多行多列

BoxLayout盒布局

盒布局通常和Box容器联合使用

组件

标签JLable

标签是可以包含文本和图像的非交互组件

按钮JButton
点击按钮弹出新窗口查看日志
java 复制代码
private void jButton8ActionPerformed(java.awt.event.ActionEvent evt) {
    // 查看更新日志
    javax.swing.JFrame frame = new javax.swing.JFrame("接口数据更新日志");
    frame.setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
    jPanel12.add(jPanel14, java.awt.BorderLayout.NORTH);
    JPanel jPanel = new JPanel();
    jPanel.setLayout(new java.awt.BorderLayout());
    frame.setContentPane(jPanel);
    javax.swing.JScrollPane js = new javax.swing.JScrollPane();
    js.setPreferredSize(new java.awt.Dimension(1000, 600));
    javax.swing.JTable table = new javax.swing.JTable();
    table.setModel(new javax.swing.table.DefaultTableModel(
        new Object[][]{},
        new String[]{
            "更新时间", "节点名称", "更新类型", "旧值", "新值"
        }
    ) {
        boolean[] canEdit = new boolean[]{
            false, false, false, false, false
        };

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return canEdit[columnIndex];
        }
    });
    table.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
    js.setViewportView(table);
    jPanel.add(js, java.awt.BorderLayout.CENTER);
    DefaultTableModel dtm = (DefaultTableModel) table.getModel();
    List<String[]> logList = service.qryXnyagcLog();
    TableOperate.setTModelData(dtm, logList);
    int[] cols = {0, 1, 2, 3, 4};
    int[] widths = {200, 200, 70, 60, 60};
    Column_Width.setColumnWidth(table, cols, widths);
    com.qctc.view.common.MyInterpro.MyInterpro(jPanel.getComponents());
    frame.pack();
    frame.setPreferredSize(new Dimension(1000, 600));
    frame.setVisible(true);
    Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
    int screenWidth = screenSize.width;
    int screenHeight = screenSize.height;
    int frameWidth = frame.getSize().width;
    int frameHeight = frame.getSize().height;
    int x = (screenWidth - frameWidth) / 2;
    int y = (screenHeight - frameHeight) / 2;
    frame.setLocation(x, y);
    frame.setAlwaysOnTop(true);
}                    
单行文本JTextField
文本域JTextArea
复选框JCheckBox
单选按钮JRadioButton
下拉列表JComboBox
添加选择项监听事件
java 复制代码
        qCombox1.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    String selectedOption = (String) qCombox1.getSelectedItem();
                    qLabel6.setText(idMap.getOrDefault(selectedOption, ""));
                }
            }
        });
模拟用户点击
java 复制代码
jRadioButton2.doClick()
列表框JList
树JTree
设置字体颜色
java 复制代码
        DefaultTreeCellRenderer dtcr = new DefaultTreeCellRenderer();
		// 设置非选中字体颜色
        dtcr.setTextNonSelectionColor(Color.WHITE);
		// 设置选中字体颜色
        dtcr.setTextSelectionColor(Color.BLUE);
        dtcr.setBackgroundNonSelectionColor(Constant.C_JPANEL_BG);
        dtcr.setBackgroundSelectionColor(new Color(57, 105, 138));
		// 设置三种图标
        dtcr.setClosedIcon(UIManager.getIcon("Tree.closedIcon"));
        dtcr.setOpenIcon(UIManager.getIcon("Tree.openIcon"));
        dtcr.setLeafIcon(UIManager.getIcon("Tree.leafIcon"));
        jTree1.setCellRenderer(dtcr);
设置单选
java 复制代码
jTree1.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
选择事件
java 复制代码
jTree1.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
    @Override
    public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
        TreePath path = jTree1.getSelectionPath();
        if (path == null) {
            return;
        }
        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        Object nodeInfo = selectedNode.getUserObject();
        TreeNodeInfo node = (TreeNodeInfo) nodeInfo;
        if (!treeList.isEmpty()) {
            for (int i = 0; i < treeList.size(); i++) {
                String[] get = treeList.get(i);
                if (!"断面".equals(get[0])) {
                    continue;
                }
                if (get[1].equals(node.Tree_Id)) {
                    selectedSection = get;
                    // System.out.println("选择的断面:" + Arrays.toString(get));
                    jLabel2.setText(get[1]); // ID
                    List<String[]> sectionList = service.querySectionById(get[6]);
                    if (sectionList.isEmpty()) {
                        jLabel12.setText(get[6]); // ID
                    } else {
                        String[] strs = sectionList.get(0);
                        jLabel12.setText(strs[0]); // ID
                    }
                    break;
                }
            }
        }
    }
});
递归加载树的数据
java 复制代码
    private void getTreeModel() {
        model = new DefaultTreeModel(null);
        IconTreeNode root = new IconTreeNode(new TreeNodeInfo(Constant.gsmc, "1", "root"));
        model.setRoot(root);
        createTree("1", root);
    }

    private void createTree(String pid, DefaultMutableTreeNode parentNode) {
        for (int i = 0; i < treeList.size(); i++) {
            String[] get = treeList.get(i);
            if (pid.equals(get[3])) {
                // 先判断断面是否匹配(本系统ID是否为空),再判断父断面是否匹配
                IconTreeNode node = new IconTreeNode(new TreeNodeInfo(get[2] + ("断面".equals(get[0]) ? ("".equals(get[6]) ? "[断面未匹配]" : (!"1".equals(get[3]) && !get[4].equals(get[9]) ? "[父断面未匹配]" : "")) : ""),
                        get[1], "电厂".equals(get[0]) ? "unit" : "sect"));
//                System.out.println("创建树节点:"+get[1]);
                parentNode.add(node);
                createTree(get[1], node);
            }
        }
    }
搜索树的层级
java 复制代码
// 定义变量
private int level;
// 归零变量,调用方法
level = 0;
searchLevel(selectedSection[1]);
// 搜索方法实现
private void searchLevel(String id) {
    for (int i = 0; i < treeList.size(); i++) {
        String[] get = treeList.get(i);
        if (id.equals(get[0])) {
            if (!"1".equals(get[3])) {
                level++;
                searchLevel(get[3]);
            }
            break;
        }
    }
}
折叠/展开/搜索 所有节点
java 复制代码
// 折叠所有节点    
public static void collapseAllNodes(javax.swing.JTree tree) {
    IconTreeNode root = (IconTreeNode) tree.getModel().getRoot();
    collapseAllNodes(tree, new TreePath(root));
}

private static void collapseAllNodes(javax.swing.JTree tree, TreePath parentPath) {
    IconTreeNode node = (IconTreeNode) parentPath.getLastPathComponent();
    if (node.getChildCount() >= 0) {
        for (int i = 0; i < node.getChildCount(); i++) {
            IconTreeNode child = (IconTreeNode) node.getChildAt(i);
            TreePath path = parentPath.pathByAddingChild(child);
            collapseAllNodes(tree, path);
        }
    }
    tree.collapsePath(parentPath);
}

// 展开所有节点
public static void expandAllNodes(javax.swing.JTree tree) {
    IconTreeNode root = (IconTreeNode) tree.getModel().getRoot();
    expandAllNodes(tree, new TreePath(root));
}

private static void expandAllNodes(javax.swing.JTree tree, TreePath parentPath) {
    IconTreeNode node = (IconTreeNode) parentPath.getLastPathComponent();
    if (node.getChildCount() >= 0) {
        for (int i = 0; i < node.getChildCount(); i++) {
            IconTreeNode child = (IconTreeNode) node.getChildAt(i);
            TreePath path = parentPath.pathByAddingChild(child);
            expandAllNodes(tree, path);
        }
    }
    tree.expandPath(parentPath);
}

// 搜索节点
public static void expandAndSelectNodes(javax.swing.JTree tree, String searchString) {
    IconTreeNode root = (IconTreeNode) tree.getModel().getRoot();
    expandAndSelectNodes(tree, new TreePath(root), searchString);
}

private static boolean containsIgnoreCase(String text, String searchString) {
    return text.toLowerCase().contains(searchString.toLowerCase());
}

private static void expandAndSelectNodes(javax.swing.JTree tree, TreePath parentPath, String searchString) {
    IconTreeNode node = (IconTreeNode) parentPath.getLastPathComponent();
    if (node.getChildCount() >= 0) {
        for (int i = 0; i < node.getChildCount(); i++) {
            IconTreeNode child = (IconTreeNode) node.getChildAt(i);
            TreePath path = parentPath.pathByAddingChild(child);

            // 判断节点名是否包含搜索字符串
            if (containsIgnoreCase(child.toString(), searchString)) {
                // 展开路径
                tree.expandPath(path);
                // 选择路径
                tree.setSelectionPath(path);
            }
            expandAndSelectNodes(tree, path, searchString);
        }
    }
}
切换按钮JToggleButton
java 复制代码
        jToggleButton1.setText("全部(切换)");
        jToggleButton1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                boolean selected = jToggleButton1.isSelected();
                DefaultTableModel model = (DefaultTableModel) jTable1.getModel();
                List<String[]> listTmp = new ArrayList<>();
                if (selected) {
                    jToggleButton1.setText("差异(切换)");
                    for (int i = 0; i < tableList.size(); i++) {
                        String[] strs = tableList.get(i);
                        if (!strs[1].equals(strs[4])) {
                            listTmp.add(strs);
                        }
                    }
                } else {
                    jToggleButton1.setText("全部(切换)");
                    for (int i = 0; i < tableList.size(); i++) {
                        String[] strs = tableList.get(i);
                        listTmp.add(strs);
                    }
                }
                TableOperate.setTModelData(model, listTmp);
            }
        });
时间选择JSpinner
java 复制代码
// 定义
final javax.swing.JSpinner spinner = new javax.swing.JSpinner(model);
javax.swing.JSpinner.DateEditor editor = new javax.swing.JSpinner.DateEditor(spinner, "yyyy-MM-dd HH");
spinner.setEditor(editor);
spinner.setValue(new java.util.Date());
upJPanel.add(spinner);
// 使用
final java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH");
String sj = sdf.format(spinner.getValue());

swing项目经验笔记

弹出加载界面

功能点使用

java 复制代码
        JFrame frame = (JFrame) tabPanel.getRootPane().getParent();
        Thread extractDataThread = new Thread(new extractDataThread());  //启动数据导入线程
        extractDataThread.start();
        WaitingDialogFactory.popUpWaitingDialog(frame, extractDataThread, "数据提取中...");
        frame.validate();
        if(flagq){
            Msg("联络线数据提取成功,请点击"保存"保存到数据库!");
        }

线程在类中定义

java 复制代码
    class extractDataThread extends Thread {

        @Override
        public void run() {
            try {
                lock.lock();
                extractData();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

注意线程同步加锁

java 复制代码
    static ReentrantLock lock = new ReentrantLock();

标签页相关

标签页通过增加标签页的方式添加图例说明并重定向点击事件

java 复制代码
        jTabbedPane1.addTab("", GetResources.getImageIcon(Constant.XianluImg), null);
        jTabbedPane1.addTab("", GetResources.getImageIcon(Constant.MuxianImg), null);
        jTabbedPane1.addTab("", GetResources.getImageIcon(Constant.ZhubianImg), null);

        jTabbedPane1.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                for (int i = 0; i < jTabbedPane1.getTabCount(); i++) {
                    Rectangle rect = jTabbedPane1.getBoundsAt(i); //拿到标签的边界
                    if (rect.contains(e.getX(), e.getY())) { //判断是否点在边界内
                        if(i>=5){
                            jTabbedPane1.setSelectedComponent(jPanel2);
                        }
                    }
                }
            }
        });

JPanel添加带标题的边框

java 复制代码
        Font titleFont = new Font("Serif", Font.BOLD, 18);
        TitledBorder border = new TitledBorder(title); // title为String类型的标题
        border.setTitleFont(titleFont); // 字体
        border.setTitleColor(grayColor); // 字体颜色
        border.setTitleJustification(TitledBorder.LEFT); // 标题对齐方式
        border.setTitlePosition(TitledBorder.TOP); // 标题位置
        // 在面板上应用边框
        panel.setBorder(border);

JTabel设置表格渲染样式

java 复制代码
        DefaultTableCellRenderer renderer = new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

                // 设置内容居中
                setHorizontalAlignment(SwingConstants.CENTER);
                // 添加单元格提示框并设置内容
                setToolTipText((String) value);
                //设置偶数行底色
                if (row % 2 == 0) {
                    setBackground(Constant.C_TABLE_OBG);
                    setForeground(Constant.C_TABLE_OFG);
                } else if (row % 2 == 1) {
                    setBackground(Constant.C_TABLE_J_BG);
                    setForeground(Constant.C_TABLE_J_FG);
                }
                // 根据某列的内容设置字体颜色和背景色
                if (column == 1) {
                    String aa = table.getValueAt(row, 1).toString();
                    if (aa.equals("待完成")) {
                        setForeground(Color.YELLOW);
                    } else if (aa.equals("已完成")) {
                        setForeground(Color.GREEN);
                    } else if (aa.equals("未完成")) {
                        setForeground(Color.RED);
                    }
                }
                table.setFont(Constant.F_TABLE_TEXT);
                table.setGridColor(Constant.C_TABLE_BORDER);
                setBorder(new MatteBorder(0, 0, 1, 1, Constant.C_TABLE_BORDER));
                int columncou = table.getColumnCount();
                if (!table.getColumnSelectionAllowed()) {
                    table.setColumnSelectionInterval(0, columncou - 1);
                }
                return component;
            }
        };

        // 将渲染方式应用到每一列
        for (int i = 0; i < table.getColumnCount(); i++) {
            table.getColumnModel().getColumn(i).setCellRenderer(renderer);
        }

关于JTabel

单元格渲染类

单元格渲染类:DefaultTableCellRenderer,这个类继承了JLabel,所以可以设置使用JLabel有的所有属性和方法

表格设置单元格tooltip和背景色等
java 复制代码
        TableColumn col5 = fixTable.getColumnModel().getColumn(5);
        col5.setCellRenderer(new DefaultTableCellRenderer(){
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                
                if (row % 2 == 0) {
                    setBackground(new Color(231, 236, 252));
                    setForeground(new Color(0, 0, 0));

                } else if (row % 2 == 1) {
                    setBackground(new Color(178, 205, 255));
                    setForeground(new Color(0, 0, 0));
                }
                
                setText((String) value);
                setToolTipText((String) value);
                return this;
            }
            
        });
设置表头行
java 复制代码
		JTableHeader tableHeader = jTable1.getTableHeader();
        Font headerFont = new Font("宋体", Font.PLAIN, 10);
        tableHeader.setFont(headerFont);
		// 设置无边框
		header.setBorder(BorderFactory.createEmptyBorder());
        tableHeader.setDefaultRenderer(new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                // 设置无边框
                label.setBorder(BorderFactory.createEmptyBorder());
                // 居中
                label.setHorizontalAlignment(SwingConstants.CENTER);
                label.setForeground(new Color(148, 148, 148));
                return label;
            }
        });
		// 设置宽度为默认,高度为35
        tableHeader.setPreferredSize(new Dimension(jTable1.getPreferredSize().width, 35));
        jTable1.setTableHeader(tableHeader);
单独设置表头居中
java 复制代码
// 设置表头文本居中
DefaultTableCellRenderer headerRenderer = (DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer();
headerRenderer.setHorizontalAlignment(JLabel.CENTER);
设置表格表头居中换行

使用html格式

java 复制代码
        qTable1.setModel(new javax.swing.table.DefaultTableModel(
                new Object[][]{},
                new String[]{
                    "时间:", "日前", "日内", "实际", "<html><center>偏差<br/>(日内-实际)</center></html>", "时间:", "日前", "日内"
                }
        ) {
            Class[] types = new Class[]{
                java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class,
                java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean[]{
                false, false, false, false, false, false, true, false
            };

            public Class getColumnClass(int columnIndex) {
                return types[columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit[columnIndex];
            }
        });
设置网格线不显示
java 复制代码
// 设置表格线为不显示
table.setShowGrid(false);
设置行高
java 复制代码
table.setRowHeight(30); // 设置行高为 30 像素
设置数据
java 复制代码
        DefaultTableModel model = (DefaultTableModel) jTable1.getModel();
        model.addRow(new String[]{"1", "机组名称11", "燃气机组", "2024-04-10", "2024-05-12"});
        model.addRow(new String[]{"2", "机组名称22", "燃气机组", "2024-04-12", "2024-05-19"});
        model.addRow(new String[]{"3", "机组名称33", "燃气机组", "2024-04-13", "2024-05-16"});
        model.addRow(new String[]{"4", "机组名称44", "燃气机组", "2024-04-15", "2024-05-12"});
        model.addRow(new String[]{"5", "机组名称55", "燃气机组", "2024-04-17", "2024-05-02"});

或者

java 复制代码
// 有TableOperate公共类的情况下,陕西现货子系统、北京校核系统
TableOperate.setTModelData(tmp8, list8);
清除数据
java 复制代码
qTable1.getTmodel().setRowCount(0);

或者

java 复制代码
jTable.setModel(new DefaultTableModel()); // 使用一个新的空表格模型

或者

java 复制代码
DefaultTableModel model = (DefaultTableModel) jTable.getModel();
while (model.getRowCount() > 0) {
    model.removeRow(0); // 删除第一行数据
}
不允许列排序
java 复制代码
DefaultTableModel model = (DefaultTableModel) qTable10.getModel();
TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<>(model);
qTable10.setRowSorter(sorter);
sorter.setSortable(0, false);

或者

java 复制代码
qTable1.setRowSorter(null);
表头不可拖拽移动位置
java 复制代码
qTable2.getTableHeader().setReorderingAllowed(false);
设置右键菜单
java 复制代码
    private void qTable1MousePressed(java.awt.event.MouseEvent evt) {                                     
        // TODO add your handling code here:
        int selcolumn = qTable1.getSelectedColumn();
        if (selcolumn == 3) {
            //鼠标右键事件,批量设置为是或者否
            if (evt.getButton() == 3) {
                rows = qTable1.getSelectedRows();
                if (rows.length <= 0) {
                    return;
                }
                String pdate = jDatePicker1.getSelectedItem().toString();
//                System.out.println("pdate  " + pdate + "    nowdate  " + nowdate + "    startIndex  " + startIndex);
                if (nowdate > Integer.parseInt(pdate.replace("-", ""))) {
                    Msg("包含历史时刻,不可选择修改");
                    qTable1.clearSelection();//清除行选中状态
                    return;
                } else {
//                    startIndex = rows[0];
                    int h = Integer.parseInt(dtfH.format(LocalDateTime.now()));
                    int m = Integer.parseInt(dtfM.format(LocalDateTime.now()));
                    startIndex = (h * 12) + (m / 5 + 1);
                    ActionListener popupmenuClicked = new java.awt.event.ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            Object MenuObject = e.getSource();
                            String MenuName = e.getActionCommand();
                            if (MenuObject instanceof QMenuItem) {
                                if (MenuName.equals("批量设置数值")) {
                                    String setpower = JOptionPane.showInputDialog("设置数值:");
                                    if (setpower == null || "".equals(setpower)) {
                                        Msg("值为空,请重新设置");
                                        return;
                                    }
                                    if (check.checkData("出力值", setpower, 10, 2, true, true)) {
                                        for (int i = rows.length - 1; i >= 0; i--) {
//                                            System.out.println(i + "  rows[i]  " + rows[i] + "    startIndex  " + startIndex);
                                            if (rows[i] >= startIndex) {//只写可编辑时刻点之后数据
                                                setpower = setpower == null || "".equals(setpower) ? qTable2.getValueAt(rows[i], 4).toString() : setpower;
                                                qTable1.setValueAt(setpower, rows[i], 3);
                                            } else {
                                                Msg("包含历史时刻,该部分未作修改");
                                                return;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    };
                    popupmenu.removeAll();
                    QMenuItem ls_menuitem = new QMenuItem();
                    ls_menuitem.setText("批量设置数值");
                    ls_menuitem.setFont(TopicStyle.F_JBUTTON_TEXT);
                    ls_menuitem.setForeground(TopicStyle.C_JLABEL_BG);
                    ls_menuitem.addActionListener(popupmenuClicked);
                    popupmenu.add(ls_menuitem);
                    this.add(popupmenu);
                    popupmenu.show(qTable1, evt.getX(), evt.getY());
                }
            }
        }
    }        
选择单元格
java 复制代码
// 设置表格单选行        
qTable1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// 设置表格多选单元格
qTable2.setColumnSelectionAllowed(true);  // 允许列选择
选择单元格监听事件
java 复制代码
        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                int row = table.getSelectedRow();
                int col = table.getSelectedColumn();
                if (row >= 0 && col >= 0) {
                    Object selectedValue = table.getValueAt(row, col);
                    System.out.println("选择了  "+row+" "+col);
                    loadPlantChart(table);
                }
            }
        });
删除列并刷新表格
java 复制代码
table.getColumnModel().removeColumn(table.getColumnModel().getColumn(columnIndex)); // 删除列
        ((DefaultTableModel) 
设置单元格不可编辑
java 复制代码
        table.setModel(new DefaultTableModel(){
            @Override
            public boolean isCellEditable(int row, int col) {
                return false;
            }
        });

关于JLabel

文本居中

setHorizontalAlignment和setHorizontalTextPosition有什么区别?

  1. setHorizontalAlignment(int alignment) 方法用于设置标签中文本的水平对齐方式,可以控制文本在标签中水平方向上的对齐方式。参数 alignment 可以接受以下常量值之一:

    • SwingConstants.LEFT:文本左对齐。
    • SwingConstants.CENTER:文本居中对齐。
    • SwingConstants.RIGHT:文本右对齐。

    这个方法影响的是文本在标签组件内的水平位置。

  2. setHorizontalTextPosition(int textPosition) 方法用于设置标签中文本相对于图标的水平位置。参数 textPosition 可以接受以下常量值之一:

    • SwingConstants.LEFT:文本在图标的左侧。
    • SwingConstants.CENTER:文本与图标水平居中对齐。
    • SwingConstants.RIGHT:文本在图标的右侧。
    • SwingConstants.LEADING:文本在图标之前,通常表示从左到右的语言文本在左侧,从右到左的语言文本在右侧。
    • SwingConstants.TRAILING:文本在图标之后,通常表示从左到右的语言文本在右侧,从右到左的语言文本在左侧。

    这个方法影响的是文本与图标之间的相对位置。

鼠标悬浮提示
java 复制代码
		// 设置鼠标悬停提示
        label.setToolTipText("This is a tooltip");
粗斜体
java 复制代码
		// 创建粗斜体字体
        Font font = new Font("Serif", Font.BOLD + Font.ITALIC, 16);
        label.setFont(font);

鼠标悬浮显示菜单

java 复制代码
		// 创建一个弹出菜单
        JPopupMenu popupMenu = new JPopupMenu();
        popupMenu.setLayout(new GridLayout(3, 1)); // 设置弹出菜单为网格布局

        // 向弹出菜单中添加多个 JLabel
        JLabel item1 = new JLabel("Item 1");
        JLabel item2 = new JLabel("Item 2");
        JLabel item3 = new JLabel("Item 3");
        popupMenu.add(item1);
        popupMenu.add(item2);
        popupMenu.add(item3);

        // 添加鼠标监听器,显示/隐藏弹出菜单
        label.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                // 计算弹出菜单的位置
                int x = label.getLocationOnScreen().x;
                int y = label.getLocationOnScreen().y + label.getHeight();
                // 显示弹出菜单
                popupMenu.show(label, x, y);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                // 隐藏弹出菜单
                popupMenu.setVisible(false);
            }
        });

布局相关

FlowLayout上下居中

添加空的JLabel占位

或者

java 复制代码
// 创建包含组件的 JPanel
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); // 居中对齐,水平间距为 0,垂直间距为 0

边框Border相关

swing中的几种Border有什么区别和特点?

在Java Swing中,Border是用于为组件添加边框装饰的对象。Swing提供了几种不同类型的Border,每种类型都具有不同的外观和特点。以下是几种常见的Border类型及其区别和特点:

  1. EmptyBorder:

    • EmptyBorder是一种简单的边框,不显示任何装饰或边框。
    • 它可以用来创建组件之间的空白间距。
  2. LineBorder:

    • LineBorder显示一个简单的边框,可以设置边框的颜色和粗细。
    • 可以用于突出显示组件的边缘。
  3. BevelBorder:

    • BevelBorder创建一个斜面或斜角边框,可以凸出或凹入组件。
    • 可以通过设置类型(凸出或凹入)、高亮色和阴影色来定制边框外观。
  4. EtchedBorder:

    • EtchedBorder显示一个凹槽或凹槽边框,类似于BevelBorder,但没有斜角。
    • 可以通过设置类型(凹槽或凹槽)、高亮色和阴影色来定制边框外观。
  5. TitledBorder:

    • TitledBorder在组件周围绘制一个标题和边框。
    • 可以用于为组件提供标题,并根据需要定制边框的外观。

这些边框类型可以单独使用,也可以组合使用,以创建复杂的边框效果。通过选择适当的Border类型,并根据需要进行自定义,可以为Swing界面增添丰富的外观和样式。

杂项组件

分割线JSeparator
java 复制代码
		JSeparator separator = new JSeparator(SwingConstants.VERTICAL); // 创建垂直分隔符
		JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL); // 水平
        separator.setPreferredSize(new Dimension(10, 50)); // 设置分隔符的尺寸
        panel.add(separator);
下拉列表JComboBox
添加属性监听
java 复制代码
		comboBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                // 如果是选择项发生改变
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    // 获取新的选项值
                    String selectedOption = (String) comboBox.getSelectedItem();
                    // 输出新的选项值
                    System.out.println("Selected option: " + selectedOption);
                }
            }
        });

判断退出页面

判断是否还在显示,可用于切换功能页的判断

java 复制代码
this.isDisplayable();

使用线程池自动刷新

java 复制代码
private final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);

scheduledThreadPoolExecutor.scheduleWithFixedDelay(this::scheduleGetData,60,1, TimeUnit.SECONDS);


    public void scheduleGetData(){
        if (!this.isDisplayable()) {
            log.info("view is removed cancel scheduledThreadPoolExecutor");
            log.info("页面关闭,关闭线程池");
            scheduledThreadPoolExecutor.shutdownNow();
            return;
        }
        //log.info("定时一分钟执行一次");
        String dateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        String seconds = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).substring("yyyy-MM-dd HH:mm:".length(), "yyyy-MM-dd HH:mm:ss".length());
        if (!StrUtil.equals("00",seconds)) {
            //log.info("非整点,只在整点刷新!!!");
            return;
        }
        log.info("{}整点刷新中!!!",dateTime);
        getData();
    }

设置样式不生效(异步)

尝试在EDT(事件分发线程)中更新

java 复制代码
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                jLabel4.setFont(new java.awt.Font("宋体", 1, 22));
                jLabel14.setFont(new java.awt.Font("宋体", 1, 22));
            }
        });

使用SwingWorker

基本使用
java 复制代码
    private void startBackgroundTask() {
        // 创建 SwingWorker 实例
        SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
            @Override
            protected Void doInBackground() throws Exception {
                for (int i = 0; i <= 100; i += 10) {
                    Thread.sleep(500); // 模拟耗时操作
                    publish("Progress: " + i + "%");
                }
                publish("Task completed!");
                return null;
            }

            @Override
            protected void process(List<String> chunks) {
                // 更新界面
                for (String message : chunks) {
                    textArea.append(message + "\n");
                }
            }

            @Override
            protected void done() {
                // 可选:任务完成后的操作
                // 如更新界面状态、显示提示信息等
            }
        };

        // 启动 SwingWorker
        worker.execute();
    }
两个泛型参数

SwingWorker 类有两个泛型参数类型:

  1. T:表示后台任务的执行结果类型。
  2. V:表示中间结果(进度更新或部分结果)的类型。

通常情况下,如果后台任务只需要返回一个结果而不需要中间过程的更新,可以将 V 设置为 Void,即不传递中间结果。这时,SwingWorker 的泛型类型就变成了 SwingWorker<T, Void>

如果后台任务需要在执行过程中更新界面或者传递部分结果,就可以使用第二个参数 V 。在这种情况下,SwingWorker 的泛型类型就是 SwingWorker<T, V>

下面是使用 SwingWorker 时如何理解和使用这两个参数类型:

  • T :指定 doInBackground() 方法的返回值类型,也就是后台任务执行完毕后的结果类型。可以是任何 Java 类型,例如 IntegerString、自定义类等。注意Void是Void不是void
  • V :指定 publish() 方法和 process() 方法的参数类型,用于在后台任务执行过程中发布中间结果或进度更新,并在 EDT 中接收并处理这些中间结果。

SwingWorker 的子类中,通常需要重写以下方法:

  1. doInBackground() :执行后台任务的方法,在这个方法中编写耗时操作。方法的返回值类型应该和 T 类型一致。
  2. process() :处理中间结果的方法,在这个方法中更新界面或处理进度信息。方法的参数类型应该和 V 类型一致。
  3. done()(可选):后台任务执行完成后的回调方法,在这个方法中进行一些清理工作或者显示最终结果。
publish()方法和process()方法

SwingWorker 类的 publish() 方法和 process() 方法是用于在后台任务中与主线程(EDT)进行交互的两个重要方法。它们允许在后台任务执行期间更新 Swing 组件的内容,而不会阻塞用户界面。

publish() 方法

publish() 方法用于从后台任务中发送数据到主线程(EDT)。它可以在 doInBackground() 方法中调用,用来将中间结果传递给 process() 方法。

  • 方法签名protected final void publish(V... chunks)
  • 参数 :可变参数 chunks 表示要传递到 process() 方法的数据片段。

process() 方法

process() 方法在 EDT 线程中执行,用于处理从 publish() 方法传递过来的数据。它通常用于更新 Swing 组件的状态或界面。

  • 方法签名protected void process(List<V> chunks)
  • 参数chunks 是一个列表,包含从 publish() 方法传递过来的数据片段。

工作流程

  1. 后台任务中的 publish() 方法
    • doInBackground() 方法中,当需要将数据传递给 EDT 时,调用 publish() 方法并传递数据片段。
    • 例如:publish(progressString);
  2. 主线程(EDT)中的 process() 方法
    • SwingWorker 会自动将通过 publish() 发布的数据传递给 process() 方法。
    • process() 方法中,你可以处理这些数据并更新 Swing 组件。
    • 例如:更新进度条或文本区域的内容。

北京项目通用

使用统一的主题
java 复制代码
        com.qctc.view.common.theme.MyInterpro.MyInterpro(this.getComponents());

导出下载Excel

java 复制代码
        JFileChooser fileChooser = new JFileChooser();
        int result = fileChooser.showSaveDialog(this);

        if (result == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
                writer.write(textArea.getText());
                JOptionPane.showMessageDialog(this, "File saved successfully.");
            } catch (IOException e) {
                JOptionPane.showMessageDialog(this, "Error saving file: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
            }
        }

导出某个JTable的内容为excel

java 复制代码
XSSFCellStyle styleData = wb.createCellStyle();
styleData.setBorderTop((short) 1);
styleData.setBorderBottom((short) 1);
styleData.setBorderLeft((short) 1);
styleData.setBorderRight((short) 1);
styleData.setFont(fontData);
styleData.setAlignment(HorizontalAlignment.CENTER);
styleData.setVerticalAlignment(VerticalAlignment.CENTER);
相关推荐
菩提树下的凡夫3 小时前
瑞芯微RV1126目标识别算法Yolov8的部署应用
java·算法·yolo
爱隐身的官人3 小时前
新后端漏洞(上)- Java RMI Registry反序列化漏洞
java·反序列化漏洞
叫我阿柒啊3 小时前
从Java全栈到前端框架:一次真实的面试对话与技术解析
java·javascript·typescript·vue·springboot·react·前端开发
晚安里3 小时前
Spring 框架(IoC、AOP、Spring Boot) 的必会知识点汇总
java·spring boot·spring
爱隐身的官人3 小时前
新后端漏洞(上)- Aapache Tomcat AJP 文件包含漏洞(CVE-2020-1938)
java·tomcat·ajp
@CLoudbays_Martin114 小时前
为什么动态视频业务内容不可以被CDN静态缓存?
java·运维·服务器·javascript·网络·python·php
四谎真好看4 小时前
Java 学习笔记(进阶篇2)
java·笔记·学习
上官浩仁4 小时前
springboot ioc 控制反转入门与实战
java·spring boot·spring
叫我阿柒啊5 小时前
从Java全栈到前端框架:一位程序员的实战之路
java·spring boot·微服务·消息队列·vue3·前端开发·后端开发