基于JavaFX的Linux进程树

8 篇文章 1 订阅

前言

最近学Linux,有一个Linux进程树的作业,本来是有C源码的,为了练手,写了一个Java带有GUI版本的。
本博客和源代码原创,转载请注明!
本文链接
个人博客:https://ronglin.fun/?p=138
PDF链接:见博客网站
CSDN: https://blog.csdn.net/RongLin02/article/details/116244641
先看成果,可配合一起食用:Linux学习之打印进程树
在这里插入图片描述

源代码

工程目录结构如下:
在这里插入图片描述
源码一共700多行

Fxml文件

Main.fxml 文件,用Scene Builder生成的

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.MainController">
   <top>
      <HBox alignment="CENTER" prefHeight="50.0" prefWidth="600.0" BorderPane.alignment="CENTER">
         <children>
            <HBox alignment="CENTER" nodeOrientation="LEFT_TO_RIGHT" prefHeight="50.0" prefWidth="325.0">
               <children>
                  <Label fx:id="Label_Time" style="-fx-background-color: #D4F2E7;" text="1970年01月01日00:00:00" underline="true">
                     <font>
                        <Font size="18.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
               <children>
                  <Button fx:id="button_fresh" mnemonicParsing="false" onAction="#freshPage" prefHeight="50.0" prefWidth="150.0" text="刷新" textAlignment="CENTER" textFill="RED" HBox.hgrow="ALWAYS">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Button>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="50.0" prefWidth="325.0">
               <children>
                  <Label fx:id="Label_IP" style="-fx-background-color: #D4F2E7;" text="192.168.255.255" underline="true">
                     <font>
                        <Font size="18.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
         </children>
      </HBox>
   </top>
   <left>
      <ScrollPane fitToHeight="true" fitToWidth="true" prefWidth="400.0">
         <content>
            <VBox>
               <children>
                  <TreeView fx:id="treeView_procs" VBox.vgrow="ALWAYS" />
               </children>
            </VBox>
         </content>
      </ScrollPane>
   </left>
   <center>
      <GridPane alignment="CENTER" gridLinesVisible="true" style="-fx-background-color: #87CEFA;" BorderPane.alignment="CENTER">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
               <children>
                  <Label text="Name:">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1">
               <children>
                  <Label fx:id="Label_Name" text="systemd" textAlignment="CENTER" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="1">
               <children>
                  <Label text="State:">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1">
               <children>
                  <Label fx:id="Label_State" text="S" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="2">
               <children>
                  <Label text="Pid:" textAlignment="CENTER">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="2">
               <children>
                  <Label fx:id="Label_Pid" text="1" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="3">
               <children>
                  <Label text="PPid:" textAlignment="CENTER">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="3">
               <children>
                  <Label fx:id="Label_PPid" text="0" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="4">
               <children>
                  <Label text="NStgid:">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="4">
               <children>
                  <Label fx:id="Label_NStgid" text="1" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="5">
               <children>
                  <Label text="NSpid:">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="5">
               <children>
                  <Label fx:id="Label_NSpid" text="1" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="6">
               <children>
                  <Label text="NSpgid:">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="6">
               <children>
                  <Label fx:id="Label_NSpgid" text="1" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="7">
               <children>
                  <Label text="NSsid:">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="7">
               <children>
                  <Label fx:id="Label_NSsid" text="1" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="8">
               <children>
                  <Label text="Threads:">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="8">
               <children>
                  <Label fx:id="Label_Threads" text="1" underline="true">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="9">
               <children>
                  <Label text="By:">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="9">
               <children>
                  <Label text="RongLin">
                     <font>
                        <Font size="24.0" />
                     </font>
                  </Label>
               </children>
            </HBox>
         </children>
      </GridPane>
   </center>
</BorderPane>

controller

MainController.java文件

package Controller;


import application.Readproc;
import application.Process;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ResourceBundle;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.util.Duration;
import javafx.fxml.Initializable;

public class MainController implements Initializable{
	
	final String ROOT = "/proc";
	@FXML
    private Label Label_IP;
	@FXML
    private Label Label_Time;

	@FXML
    private Label Label_Name;
    @FXML
    private Label Label_State;
    @FXML
    private Label Label_Pid;
    @FXML
    private Label Label_PPid;
    @FXML
    private Label Label_NStgid;
    @FXML
    private Label Label_NSpid;
    @FXML
    private Label Label_NSpgid;
    @FXML
    private Label Label_NSsid;
    @FXML
    private Label Label_Threads;
    
    @FXML
    private Button button_fresh;
    @FXML
    private TreeView<Process> treeView_procs;
    
    private TreeItem<Process> rootItem = null;
    
    
    @Override
	public void initialize(URL location, ResourceBundle resources) {
    	
    	//ip地址初始化
		InetAddress localAddress=null;
    	try {
			localAddress=InetAddress.getLocalHost();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	Label_IP.setText(localAddress.getHostAddress());
    	
    	//时间初始化
    	EventHandler<ActionEvent> timeUpdate =e->{
    		final String TimePattern="yyyy年MM月dd日 HH:mm:ss";
    		SimpleDateFormat dateFormat=new SimpleDateFormat(TimePattern);
    		Label_Time.setText(dateFormat.format(new Date(System.currentTimeMillis())));
    	};
    	//500ms获取一下系统时间
    	Timeline animation = new Timeline(new KeyFrame(Duration.millis(500), timeUpdate));
    	animation.setCycleCount(Timeline.INDEFINITE);
    	animation.play();
    	
    	//初始化树视图
    	initTreeView();
    	
    	//初始化表格
    	initGridPane();
		
    	
	}
    
    private void initTreeView()
    {
    	//System.out.println("初始化了树视图");
    	Readproc.readFile(ROOT);
    	Process zero = new Process();
    	zero.setPid(0);
    	zero.setName("zero");
    	
    	rootItem = new TreeItem<Process> (zero);
    	
    	treeView_procs.setRoot(rootItem);
    	treeView_procs.setShowRoot(false);
    	//设置点击节点触发效果
    	treeView_procs.getSelectionModel().selectedItemProperty().addListener(
    			new ChangeListener<TreeItem <Process>>() {
					@Override
					public void changed(ObservableValue<? extends TreeItem<Process>> observable,
							TreeItem<Process> oldValue, TreeItem<Process> newValue) {
						// TODO Auto-generated method stub
						if(newValue != null)
							showGridPane(newValue.getValue());
					}
    			});
    	
    	DFSSetupTreeItem(rootItem,0);
    	
    }
    private void DFSSetupTreeItem(TreeItem<Process> pitem,int ppid)
    {
    	for(int i=0;i<Readproc.procNum;i++)
    	{
    		if(Readproc.procs[i].getPPid() == ppid)
    		{
    			TreeItem<Process> item = new TreeItem<Process> (Readproc.procs[i]);
    			
    			pitem.getChildren().add(item);
    			
    			DFSSetupTreeItem(item,Readproc.procs[i].getPid());
    		}
    	}
    }
    
    private void initGridPane()
    {
    	//System.out.println("初始化了表格");
    	Label_Name.setText("0");
    	Label_State.setText("0");
    	Label_Pid.setText("0");
    	Label_PPid.setText("0");
    	Label_NStgid.setText("0");
    	Label_NSpid.setText("0");
    	Label_NSpgid.setText("0");
    	Label_NSsid.setText("0");
    	Label_Threads.setText("0");	
    }
    
    private void showGridPane(Process proc)
    {
    	//System.out.println("初始化了表格");
    	Label_Name.setText(proc.getName());
    	Label_State.setText(proc.getState());
    	Label_Pid.setText(Integer.toString(proc.getPid()));
    	Label_PPid.setText(Integer.toString(proc.getPPid()));
    	
    	Label_NStgid.setText(Integer.toString(proc.getNStgid()));
    	Label_NSpid.setText(Integer.toString(proc.getNSpid()));
    	Label_NSpgid.setText(Integer.toString(proc.getNSpgid()));
    	Label_NSsid.setText(Integer.toString(proc.getNSsid()));
    	Label_Threads.setText(Integer.toString(proc.getThreads()));	
    }    
    
    @FXML
    void freshPage(ActionEvent event) {
    	
    	Readproc.procNum = 0;
    	Readproc.readFile(ROOT);
    	
    	initGridPane();
    	
    	if(rootItem != null)
    	{
    		rootItem.getChildren().clear();
    		DFSSetupTreeItem(rootItem,0);
    	}
    }

}

控制器的难点在于TreeView的初始化,点击TreeView节点的触发和左上角的时间自动更新,源码上都有,JavaFX的模板性很强,就这样用就可以,要想知道原理,可以去查询API。

Application

这中间有3个类,一个是运行类
Main.java

package application;
	
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;



public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {
			BorderPane mainPane = FXMLLoader.load(getClass().getResource("/Fxml/Main.fxml"));
			Scene mainScene = new Scene(mainPane,800,600);
			primaryStage.setScene(mainScene);
			primaryStage.setTitle("Linux进程树");
			primaryStage.show();	
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		launch(args);
	}
}

一个是进程类,Process.java

package application;

public class Process {
	
	String Name;
	String State;
	
	int Pid;
	int PPid;
	int NStgid;
	int NSpid;
	int NSpgid;
	int NSsid;
	
	int Threads;

	public String getName() {
		return Name;
	}

	public void setName(String name) {
		Name = name;
	}

	public String getState() {
		return State;
	}

	public void setState(String state) {
		State = state;
	}

	public int getPid() {
		return Pid;
	}

	public void setPid(int pid) {
		Pid = pid;
	}

	public int getPPid() {
		return PPid;
	}

	public void setPPid(int pPid) {
		PPid = pPid;
	}

	public int getNStgid() {
		return NStgid;
	}

	public void setNStgid(int nStgid) {
		NStgid = nStgid;
	}

	public int getNSpid() {
		return NSpid;
	}

	public void setNSpid(int nSpid) {
		NSpid = nSpid;
	}

	public int getNSpgid() {
		return NSpgid;
	}

	public void setNSpgid(int nSpgid) {
		NSpgid = nSpgid;
	}

	public int getNSsid() {
		return NSsid;
	}

	public void setNSsid(int nSsid) {
		NSsid = nSsid;
	}

	public int getThreads() {
		return Threads;
	}

	public void setThreads(int threads) {
		Threads = threads;
	}
	
//	public String toString()
//	{
//		String str ="Name:" + this.Name + "\n" +
//					"State:" + this.State + "\n" +
//					"Pid:" + this.Pid + "\n" +
//					"PPid:" + this.PPid + "\n" +
//					"NStgid:" + this.NStgid + "\n" +
//					"NSpid:" + this.NSpid + "\n" + 
//					"NSpgid:" + this.NSpgid + "\n" +
//					"NSsid:" + this.NSsid + "\n" +
//					"Threads:" + this.Threads + "\n";
//		return str;
//	}
	
	public String toString()
	{
		return this.Pid+":"+this.Name;
	}
}

一个是从文件中读取进程信息的类,定义的都是静态方法
Readproc.java

package application;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Readproc {
	final static int MAX = 1024*1024;
	final static int MAX_PROC_NUM= 1024;
	
	public static Process[] procs = new Process[MAX_PROC_NUM];
	public static int procNum = 0;
	
	static byte[] buff = new byte[MAX];
	
	public static boolean readFile(String path)
	{
		File rootFile = new File(path);
		
		if(! rootFile.exists())
		{
			System.out.println("目录不存在");
			
			return false;
		}
		
		procNum = 0;
		
		File[] procFiles =  rootFile.listFiles();
		
		for(File file : procFiles)
		{
			if(isNumeric(file.getName()) == true)
			{
				procs[procNum] = getProcessFromStatus(file);
				if(procs[procNum] != null)
					procNum++;
			}
		}
		
		return true;
	}
		
	private static boolean isNumeric(String str)
	{
		Pattern pattern = Pattern.compile("[0-9]*");
		Matcher isNum = pattern.matcher(str);
		if (!isNum.matches())
		{
			return false;
		}
		else 
		{
			return true;
		}
	}
	
	private static Process getProcessFromStatus(File file)
	{
		Process proc = new Process();
		
		int len = 0;
		FileInputStream input = null ;
		StringBuffer buffer = new StringBuffer();
		String path = file.getPath() + "/status";
		
		
		try {
			input = new FileInputStream(path);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			System.out.println(path);
			System.out.println("status文件没找到");
			return null;
		}
		
		try {
			while(( (len = input.read(buff) )!= -1 ))
			{
				buffer.append(new String(buff,0,len));
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("status文件读写失败");
			return null;
		}
		
		String[] statusPart = buffer.toString().split("\\s+");
		
		for(int i=0;i<statusPart.length;i++)
		{
			
			if(statusPart[i].compareTo("Name:") == 0)
			{
				proc.Name = new String(statusPart[i+1]);
			}
			else if(statusPart[i].compareTo("State:") == 0)
			{
				proc.State = new String(statusPart[i+1] + statusPart[i+2]);
			}
			else if(statusPart[i].compareTo("Pid:") == 0)
			{
				proc.Pid = Integer.parseInt(statusPart[i+1]);
			}
			else if(statusPart[i].compareTo("PPid:") == 0)
			{
				proc.PPid = Integer.parseInt(statusPart[i+1]);
			}
			else if(statusPart[i].compareTo("NStgid:") == 0)
			{
				proc.NStgid = Integer.parseInt(statusPart[i+1]);
			}
			else if(statusPart[i].compareTo("NSpid:") == 0)
			{
				proc.NSpid = Integer.parseInt(statusPart[i+1]);
			}
			else if(statusPart[i].compareTo("NSpgid:") == 0)
			{
				proc.NSpgid = Integer.parseInt(statusPart[i+1]);
			}
			else if(statusPart[i].compareTo("NSsid:") == 0)
			{
				proc.NSsid = Integer.parseInt(statusPart[i+1]);
			}
			else if(statusPart[i].compareTo("Threads:") == 0)
			{
				proc.Threads = Integer.parseInt(statusPart[i+1]);
			}
			
		}
		
		try {
			input.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			System.out.println("input流关闭失败");
			return null;
		}
		
		return proc;
	}
	
//	public static void main(String[] args) {
//		Readproc.readFile("F:/Desktop/proc");
//		
//		System.out.println("共有"+procNum+"个进程");
//		
//		for(int i=0;i<procNum;i++)
//		{
//			System.out.println(procs[i]);
//		}
//		
//	}
	
}

总结

原理很简单,难点在于JavaFX基本控件的使用和GUI的布局,丑了一点,不过重点在于熟悉Linux系统的进程概念。
代码原创,欢迎指点,=w=

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值