diff --git a/src/main/java/com/luoboduner/moo/info/ui/Init.java b/src/main/java/com/luoboduner/moo/info/ui/Init.java index 1c55b04..1029178 100644 --- a/src/main/java/com/luoboduner/moo/info/ui/Init.java +++ b/src/main/java/com/luoboduner/moo/info/ui/Init.java @@ -205,6 +205,7 @@ public class Init { ThreadUtil.execute(NetworkForm::init); ThreadUtil.execute(UsbForm::init); ThreadUtil.execute(VariablesForm::init); + ThreadUtil.execute(ProcessesForm::init); // Check the new version if (App.config.isAutoCheckUpdate()) { diff --git a/src/main/java/com/luoboduner/moo/info/ui/UiConsts.java b/src/main/java/com/luoboduner/moo/info/ui/UiConsts.java index e4e33d0..83fe712 100644 --- a/src/main/java/com/luoboduner/moo/info/ui/UiConsts.java +++ b/src/main/java/com/luoboduner/moo/info/ui/UiConsts.java @@ -74,5 +74,10 @@ public class UiConsts { */ public static final String CHECK_VERSION_URL = "https://gitee.com/zhoubochina/MooInfo/raw/master/src/main/resources/version_summary.json"; + public static final int REFRESH_FAST = 1000; + public static final int REFRESH_SLOW = 5000; + + public static final int REFRESH_SLOWER = 15_000; + } diff --git a/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.form b/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.form index 6ef2c95..7a6775c 100644 --- a/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.form +++ b/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.form @@ -82,7 +82,7 @@ - + diff --git a/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.java b/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.java index 8dcfd90..fd3f5fc 100644 --- a/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.java +++ b/src/main/java/com/luoboduner/moo/info/ui/form/MainWindow.java @@ -22,6 +22,7 @@ public class MainWindow { private JPanel detailPanel; private JPanel usbPanel; private JPanel VariablesPanel; + private JPanel processesPanel; private static MainWindow mainWindow; @@ -44,6 +45,7 @@ public class MainWindow { mainWindow.getNetworkPanel().add(NetworkForm.getInstance().getMainPanel(), gridConstraints); mainWindow.getUsbPanel().add(UsbForm.getInstance().getMainPanel(), gridConstraints); mainWindow.getVariablesPanel().add(VariablesForm.getInstance().getMainPanel(), gridConstraints); + mainWindow.getProcessesPanel().add(ProcessesForm.getInstance().getMainPanel(), gridConstraints); mainWindow.getMainPanel().updateUI(); } @@ -88,9 +90,9 @@ public class MainWindow { VariablesPanel = new JPanel(); VariablesPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); tabbedPane.addTab("Variables", VariablesPanel); - final JPanel panel4 = new JPanel(); - panel4.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); - tabbedPane.addTab("Processes", panel4); + processesPanel = new JPanel(); + processesPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + tabbedPane.addTab("Processes", processesPanel); usbPanel = new JPanel(); usbPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); tabbedPane.addTab("USB Devices", usbPanel); diff --git a/src/main/java/com/luoboduner/moo/info/ui/form/ProcessesForm.form b/src/main/java/com/luoboduner/moo/info/ui/form/ProcessesForm.form new file mode 100644 index 0000000..acd33de --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/form/ProcessesForm.form @@ -0,0 +1,26 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/luoboduner/moo/info/ui/form/ProcessesForm.java b/src/main/java/com/luoboduner/moo/info/ui/form/ProcessesForm.java new file mode 100644 index 0000000..cd6182e --- /dev/null +++ b/src/main/java/com/luoboduner/moo/info/ui/form/ProcessesForm.java @@ -0,0 +1,181 @@ +package com.luoboduner.moo.info.ui.form; + +import cn.hutool.log.Log; +import cn.hutool.log.LogFactory; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.luoboduner.moo.info.App; +import com.luoboduner.moo.info.ui.UiConsts; +import lombok.Getter; +import oshi.PlatformEnum; +import oshi.SystemInfo; +import oshi.software.os.OSProcess; +import oshi.software.os.OperatingSystem; +import oshi.util.FormatUtil; + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; +import javax.swing.table.TableModel; +import java.awt.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * NetworkForm + * + * @author RememBerBer + * @since 2021/11/15. + */ +@Getter +public class ProcessesForm { + private static final String[] COLUMNS = {"PID", "PPID", "Threads", "% CPU", "Cumulative", "VSZ", "RSS", "% Memory", + "Process Name"}; + private static final double[] COLUMN_WIDTH_PERCENT = {0.07, 0.07, 0.07, 0.07, 0.09, 0.1, 0.1, 0.08, 0.35}; + + private transient static Map priorSnapshotMap = new HashMap<>(); + + private static final Log logger = LogFactory.get(); + + private static ProcessesForm processesForm; + private JPanel mainPanel; + private JTable processTable; + + public static ProcessesForm getInstance() { + if (processesForm == null) { + processesForm = new ProcessesForm(); + } + return processesForm; + } + + public static void init() { + processesForm = getInstance(); + + initUi(); + initInfo(); + } + + private static void initUi() { + } + + private static void initInfo() { + OperatingSystem os = App.si.getOperatingSystem(); + TableModel model = new DefaultTableModel(parseProcesses(os.getProcesses(null, null, 0), App.si), COLUMNS); + JTable procTable = getInstance().getProcessTable(); + procTable.setModel(model); + resizeColumns(procTable.getColumnModel()); + + Timer timer = new Timer(UiConsts.REFRESH_SLOW, e -> { + DefaultTableModel tableModel = (DefaultTableModel) procTable.getModel(); + Object[][] newData = parseProcesses(os.getProcesses(null, null, 0), App.si); + int rowCount = tableModel.getRowCount(); + for (int row = 0; row < newData.length; row++) { + if (row < rowCount) { + // Overwrite row + for (int col = 0; col < newData[row].length; col++) { + tableModel.setValueAt(newData[row][col], row, col); + } + } else { + // Add row + tableModel.addRow(newData[row]); + } + } + // Delete any extra rows + for (int row = rowCount - 1; row >= newData.length; row--) { + tableModel.removeRow(row); + } + }); + timer.start(); + } + + private static Object[][] parseProcesses(List list, SystemInfo si) { + long totalMem = si.getHardware().getMemory().getTotal(); + int cpuCount = si.getHardware().getProcessor().getLogicalProcessorCount(); + // Build a map with a value for each process to control the sort + Map processSortValueMap = new HashMap<>(); + for (OSProcess p : list) { + int pid = p.getProcessID(); + // Ignore the Idle process on Windows + if (pid > 0 || !SystemInfo.getCurrentPlatform().equals(PlatformEnum.WINDOWS)) { + // Set up for appropriate sort + processSortValueMap.put(p, (double) p.getResidentSetSize()); + } + } + // Now sort the list by the values + List> procList = new ArrayList<>(processSortValueMap.entrySet()); + procList.sort(Map.Entry.comparingByValue()); + // Insert into array in reverse order (lowest sort value last) + int i = procList.size(); + Object[][] procArr = new Object[i][COLUMNS.length]; + // These are in descending CPU order + for (Map.Entry e : procList) { + OSProcess p = e.getKey(); + // Matches order of COLUMNS field + i--; + int pid = p.getProcessID(); + procArr[i][0] = pid; + procArr[i][1] = p.getParentProcessID(); + procArr[i][2] = p.getThreadCount(); + { + procArr[i][3] = String.format("%.1f", + 100d * p.getProcessCpuLoadBetweenTicks(priorSnapshotMap.get(pid))); + procArr[i][4] = String.format("%.1f", 100d * p.getProcessCpuLoadCumulative()); + } + procArr[i][5] = FormatUtil.formatBytes(p.getVirtualSize()); + procArr[i][6] = FormatUtil.formatBytes(p.getResidentSetSize()); + procArr[i][7] = String.format("%.1f", 100d * p.getResidentSetSize() / totalMem); + procArr[i][8] = p.getName(); + } + // Re-populate snapshot map + priorSnapshotMap.clear(); + for (OSProcess p : list) { + priorSnapshotMap.put(p.getProcessID(), p); + } + return procArr; + } + + private static void resizeColumns(TableColumnModel tableColumnModel) { + TableColumn column; + int tW = tableColumnModel.getTotalColumnWidth(); + int cantCols = tableColumnModel.getColumnCount(); + for (int i = 0; i < cantCols; i++) { + column = tableColumnModel.getColumn(i); + int pWidth = (int) Math.round(COLUMN_WIDTH_PERCENT[i] * tW); + column.setPreferredWidth(pWidth); + } + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + mainPanel = new JPanel(); + mainPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + final JScrollPane scrollPane1 = new JScrollPane(); + mainPanel.add(scrollPane1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + processTable = new JTable(); + scrollPane1.setViewportView(processTable); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return mainPanel; + } + +}