java上位机开发(GUI设计)

Posted 嵌入式-老费

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java上位机开发(GUI设计)相关的知识,希望对你有一定的参考价值。

 【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        对于上位机来说,GUI设计是很重要的一个环节。如果没有GUI,那就成了命令行工具了。对于java来说,图形库主要有swing和awt两种,选择哪一种可以根据个人的喜好进行选择,差别不大。另外,和大多数图形库一样,java图形库也提供了label、edit、button、dialog、menu这些常用控件。如果是不太常用的控件,那就需要自己绘制了。

        这里我们选择awt进行开发。当然,选好了控件库之后,下面就是设计自己的上位机界面了。一般来说,设计的原则就是简单、有效,不必过于花哨。一来没有必要,二来过度设计往往会导致程序的不稳定。此外,界面设计部分,最好用一些设计工具来做正向设计。它的好处就是方便自己从整体来根据客户的需求做程序交互设计。这里,不妨以一个简单的上位机程序作为背景,来描述应该怎么设计图形界面。

1、GUI设计

        假设我们的需求就是给开发板发一个任务,然后定时检测这个任务的状态。拿到这个需求的时候,正常情况下,想一想应该怎么设计?

         这是程序的主界面,从布局上看比较简洁。第一行是标题;第二行是菜单;中间分成两部分,一部分是Task工作区域,一部分是日志打印区域。最后一行是状态栏。每增加一个Task,就会增加相应的Task条目。执行结束后,Task条目会被删除。在task执行的过程中,不管执行顺利与否,都会在log中间添加相应的打印信息。这个时候,如果需要添加Task,应该怎么设计?单击Menu,就会弹出对应的对话框,如下图所示,

         对话框的内容比较简单,图中仅仅描述了TaskID和TaskName这两个属性。实际情况可以根据具体业务灵活做出选择。所有属性编写结束后,就可以按下ok按钮。如果不希望执行Task,按下Cancel退出即可。

        在执行的过程中,退出程序也是可以的。但是,在程序退出前,必须给出对应的告警信息,这也是常规的操作,

2、程序编写部分

2.1 构建基本窗口

        在熟悉awt之前,第一步应该就是编写最简单的界面程序,增加一点自己的信心。比如这样,

import java.awt.*;    

public class process 

    public static void main(String[] args) 
        Frame frm = new Frame("Application");
        frm.setSize(600, 400);    
        frm.setVisible(true);   
    

        经过之前的java基础,这部分内容是可以自己搞明白的。直接输入编译命令,即javac process.java && java process,你就会看到这样的图形,

        虽然对话框里面什么也没有,但是好歹走出了第一步。美中不足的是,这个窗口没有办法关闭,只能自己ctrl+c来解决,这部分确实不太合理,接着我们就会修改一下。

2.2、添加关闭窗口功能

        要做到窗口可以正常关闭,本质上还是添加一个事件响应函数,比如像这样,

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class process 

    public static void main(String[] args) 
        Frame frm = new Frame("Application");
        frm.setSize(600, 400);
		frm.addWindowListener(new WindowAdapter() 
	          @Override
	          public void windowClosing(WindowEvent e)
	          
	             System.exit(0);
	          
	      );
        frm.setVisible(true);   
    

        有了这个响应函数,就可以正常关闭窗口了。

2.3 添加label

        添加标签是最基本的动作,可以很容易地完成。

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class process 

	static Label notification = new Label("Are you sure to leave?", Label.CENTER);
	
    public static void main(String[] args) 
        Frame frm = new Frame("Application");
        frm.setSize(600, 400);
		frm.addWindowListener(new WindowAdapter() 
	          @Override
	          public void windowClosing(WindowEvent e)
	          
	             System.exit(0);
	          
	      );
		
		frm.add(notification);
        frm.setVisible(true);   
    

        这里添加了一个notification的label,编译后,执行的结果是这样的,

2.4 添加按钮

        label的部分是比较容易。有了label的第一步操作,下面就是添加按钮,

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class process 

	static Label notification = new Label("Are you sure to leave?");
	static Button ok_btn = new Button("OK");
	static Button cancel_btn = new Button("Cancel");
	
    public static void main(String[] args) 
        Frame frm = new Frame("Application");
		frm.setLayout(null); 
        frm.setSize(600, 400);
		frm.addWindowListener(new WindowAdapter() 
	          @Override
	          public void windowClosing(WindowEvent e)
	          
	             System.exit(0);
	          
	      );
		
		notification.setBounds(225, 100, 200, 100);
		frm.add(notification);
		
		ok_btn.setBounds(100, 250, 100, 50);
		frm.add(ok_btn);
		
		cancel_btn.setBounds(350, 250, 100, 50);
		frm.add(cancel_btn);
		
        frm.setVisible(true);   
    

        观察发现,除了之前的label,这里还添加了两个按钮,一个是ok_btn,另外一个是cancel_btn。在开始添加控件之前,需要将frame的layout设置为null。接着在添加控件的时候,需要设置下每个控件的大小、范围。这样,经过代码修改后,就可以得到一个合适的布局图形,效果是这样的,

         从布局来看,显然是达到了我们的设计要求,只是看上去不太美观。接下来,就是要对按钮添加响应回调函数。

2.5 按钮回调函数

        按钮的回调函数,本质上还是需要添加一个listener,这和窗口的回调函数,本质上说是一样的。接着我们就编写一个按钮回调函数,

import java.awt.*;
import java.awt.event.*;

public class process 

	static Label notification = new Label("Are you sure to leave?");
	static Button ok_btn = new Button("OK");
	static Button cancel_btn = new Button("Cancel");

    static class myListener implements ActionListener     
        public void actionPerformed(ActionEvent e)    
            String str = e.getActionCommand();    
            if (str.equals("OK"))

				System.out.println("You choose to leave current dialog!");
                System.exit(0);    
			
        
    
	
    public static void main(String[] args) 
        Frame frm = new Frame("Application");
		frm.setLayout(null); 
        frm.setSize(600, 400);
		frm.addWindowListener(new WindowAdapter() 
	          @Override
	          public void windowClosing(WindowEvent e)
	          
	             System.exit(0);
	          
	      );
		
		notification.setBounds(225, 100, 200, 100);
		frm.add(notification);
		
		ok_btn.setBounds(100, 250, 100, 50);
		ok_btn.addActionListener(new myListener());
		frm.add(ok_btn);
		
		cancel_btn.setBounds(350, 250, 100, 50);
		frm.add(cancel_btn);
		
        frm.setVisible(true);   
    

        注意,这里添加了一个myListener,它从ActionListener继承而来。为了使用这个基类,import部分也要做一下修改,即从java.awt.event.WindowEvent;变成java.awt.event.*。类中的函数,需要改写的部分就是actionPerformed,判断一下是不是ok按钮,如果是,先打印一些内容,接着就是退出。

2.6 添加edit

        有了label和button的经验,添加edit编辑框就变得不是那么复杂了。

import java.awt.*;
import java.awt.event.*;

public class process 

	static Label label1 = new Label("TaskID:");
	static Label label2 = new Label("TaskName:");
	static TextField txt1 = new TextField("");
    static TextField txt2 = new TextField("");
	static Button ok_btn = new Button("OK");
	static Button cancel_btn = new Button("Cancel");

    static class myListener implements ActionListener     
        public void actionPerformed(ActionEvent e)    
            String str = e.getActionCommand();    
            if (str.equals("OK"))

				System.out.println("You choose to leave current dialog!");
                System.exit(0);    
			
        
    
	
    public static void main(String[] args) 
        Frame frm = new Frame("Application");
		frm.setLayout(null); 
        frm.setSize(600, 400);
		frm.addWindowListener(new WindowAdapter() 
	          @Override
	          public void windowClosing(WindowEvent e)
	          
	             System.exit(0);
	          
	      );
		
		label1.setBounds(100, 100, 100, 50);
		frm.add(label1);
		label2.setBounds(100, 150, 100, 50);
		frm.add(label2);
		
		txt1.setBounds(250, 100, 200, 30);
		frm.add(txt1);
		txt2.setBounds(250, 150, 200, 30);
		frm.add(txt2);
		
		ok_btn.setBounds(100, 250, 100, 50);
		ok_btn.addActionListener(new myListener());
		frm.add(ok_btn);
		
		cancel_btn.setBounds(350, 250, 100, 50);
		frm.add(cancel_btn);
		
        frm.setVisible(true);   
    

        还是在之前的代码基础上,我们添加了txt1和txt2两个编辑框。除此之外,还调整了label1、label2、txt1、txt2的位置,其他的部分几乎没有做什么调整。编译运行后的结果是这样的,

         从布局上看,基本上是达到了设计的目的。

2.7 菜单的添加

        菜单栏一般是主窗口需要的。对于二级窗口,也就是任务窗口、告警提示窗口,这个菜单一般是不需要的。当然,为了展示的需要,我们可以看一下菜单栏是怎么添加的。

import java.awt.*;
import java.awt.event.*;

public class process 

	static Label label1 = new Label("TaskID:");
	static Label label2 = new Label("TaskName:");
	
	static TextField txt1 = new TextField("");
    static TextField txt2 = new TextField("");
	
	static Button ok_btn = new Button("OK");
	static Button cancel_btn = new Button("Cancel");
	
	static MenuBar mb = new MenuBar();
	static Menu menu1 = new Menu("Task");
	static MenuItem mitem = new MenuItem("New");

    static class myListener implements ActionListener     
        public void actionPerformed(ActionEvent e)    
            String str = e.getActionCommand();    
            if (str.equals("OK"))

				System.out.println("You choose to leave current dialog!");
                System.exit(0);    
			
        
    
	
    public static void main(String[] args) 
        Frame frm = new Frame("Application");
		frm.setLayout(null); 
        frm.setSize(600, 400);
		frm.addWindowListener(new WindowAdapter() 
	          @Override
	          public void windowClosing(WindowEvent e)
	          
	             System.exit(0);
	          
	      );
		
		menu1.add(mitem);
		mb.add(menu1);
		frm.setMenuBar(mb);
		
		label1.setBounds(100, 100, 100, 50);
		frm.add(label1);
		label2.setBounds(100, 150, 100, 50);
		frm.add(label2);
		
		txt1.setBounds(250, 100, 200, 30);
		frm.add(txt1);
		txt2.setBounds(250, 150, 200, 30);
		frm.add(txt2);
		
		ok_btn.setBounds(100, 250, 100, 50);
		ok_btn.addActionListener(new myListener());
		frm.add(ok_btn);
		
		cancel_btn.setBounds(350, 250, 100, 50);
		frm.add(cancel_btn);
		
        frm.setVisible(true);   
    

        从代码上面来看,按钮的添加主要涉及到三个变量。一个是MenuBar,一个是Menu,一个是MenuItem。MenuBar类相当于整个menu的管家,Menu类代表是一级menu,而MenuItem类相当于二级menu,整个逻辑就是这么一回事。编译运行后,整个程序是这么一个效果,

         从一开始的差不多10行代码,走到现在这一步,基本上就有点意思了。整个程序也开始有了软件的味道。这个时候,不要停,我们继续添加状态栏。

2.8 状态栏的添加

        状态栏一般位于窗口的最下方,表示的方法很多,一个比较简单的办法就是用label代替。打上必要的label内容之后,再添加一个灰色的背景,这样就可以做成一个简单的状态栏了。

import java.awt.*;
import java.awt.event.*;

public class process 

	static Label label1 = new Label("TaskID:");
	static Label label2 = new Label("TaskName:");
	
	static TextField txt1 = new TextField("");
    static TextField txt2 = new TextField("");
	
	static Button ok_btn = new Button("OK");
	static Button cancel_btn = new Button("Cancel");
	
	static MenuBar mb = new MenuBar();
	static Menu menu1 = new Menu("Task");
	static MenuItem mitem = new MenuItem("New");
	
	static Label label_status = new Label("   2022/7/10   ");

    static class myListener implements ActionListener     
        public void actionPerformed(ActionEvent e)    
            String str = e.getActionCommand();    
            if (str.equals("OK"))

				System.out.println("You choose to leave current dialog!");
                System.exit(0);    
			
        
    
	
    public static void main(String[] args) 
        Frame frm = new Frame("Application");
		frm.setLayout(null); 
        frm.setSize(600, 400);
		frm.addWindowListener(new WindowAdapter() 
	          @Override
	          public void windowClosing(WindowEvent e)
	          
	             System.exit(0);
	          
	      );
		
		menu1.add(mitem);
		mb.add(menu1);
		frm.setMenuBar(mb);
		
		label1.setBounds(100, 100, 100, 50);
		frm.add(label1);
		label2.setBounds(100, 150, 100, 50);
		frm.add(label2);
		
		txt1.setBounds(250, 100, 200, 30);
		frm.add(txt1);
		txt2.setBounds(250, 150, 200, 30);
		frm.add(txt2);
		
		ok_btn.setBounds(100, 250, 100, 50);
		ok_btn.addActionListener(new myListener());
		frm.add(ok_btn);
		
		cancel_btn.setBounds(350, 250, 100, 50);
		frm.add(cancel_btn);
		
		label_status.setBounds(0, 355, 600, 35);
		label_status.setBackground(Color.gray);
		frm.add(label_status);
		
        frm.setVisible(true);   
    

        如图所示,这里的label_status就是状态栏,它的作用就是显示一些任务的必要信息。比如已经执行了多少任务,多少任务成功,多少任务失败等等。编译,执行查看一下运行效果,

2.9 表格的添加

        之前在设计的时候,对于运行中单个Task的状态,这部分可以用表格来表示。因为之前的代码已经过长,这里我们重新用简单一点的程序来进行说明,

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import java.awt.BorderLayout;

public class process extends JFrame 

	private String[] columns =  "TaskID", "TaskName", "TaskState" ;

	public process() 

		JScrollPane scrollpane = new JScrollPane();
		DefaultTableModel model = new DefaultTableModel(columns, 10);
		JTable table = new JTable(model);
		scrollpane.setViewportView(table);
		add(scrollpane, BorderLayout.CENTER);
		setSize(600, 400);
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		setVisible(true);
	

	public static void main(String[] args) 

		new process();
	

        这里面使用了swing的数据结构,最重要的数据类型其实就是DefaultTableModel这个类,它定义了基本的数据结构,包括表格内容,包括表格行数等等。可以简单运行一下,看下效果,

3、总结

        对于GUI设计来说,设计是根本,用什么控件、什么库来实现这个设计,这个是操作层面的事情,关键是作为设计者心里要有一个基本的判断和计划。这个计划包括,主窗口布局是什么,二级窗口做什么,主要的交互逻辑是什么,哪些信息需要显示,哪些信息不需要显示等等。有了这个设计之后,就可以开始着手选用什么控件,从哪里可以找到对应的示例代码,怎么插入到我们的实际应用中去。所以需求是出发点,设计才是根本,编码只是为了把设计做出来、实现出来。

        最后,对于其他控件有兴趣的同学,可以参考一下这个链接,相信会也有不同的收获。

https://www.javagreat.com/awt/https://www.javagreat.com/awt/

以上是关于java上位机开发(GUI设计)的主要内容,如果未能解决你的问题,请参考以下文章

上位机开发(固件下载软件之架构设计)

上位机开发(怎么开发上位机)

我的自动化设备上位机软件开发设计

我的自动化设备上位机软件开发设计

上位机开发(固件下载软件之详细设计)

如何用C#设计上位机(小白篇)