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设计)的主要内容,如果未能解决你的问题,请参考以下文章