数据决定程序结构

共鸣

今近日一直在阅读《编程珠玑》这一本书,阅读后,非常惊艳作者在基于多年程序员工作上,而积累的对编程的真知灼见。同时对于作者的一些感触,自己也不禁产生共鸣。例如在第三章中的《数据决定程序结构》这一章节中共鸣异常强烈,故因写下此篇博文,与诸君共赏。

我在大一的第一个学期,就开始学习编程了,第一门语言是令人喜爱的 C 语言, 有人说C语言很难,我一开始也是这么觉得的,在学习的第一门语言的时候,的确是非常艰难的,因为自己的计算机知识还不足够(例如对于内存,地址、操作系统一些概念),所以在我第一个学期学完之后,C语言的基础知识是有了,但是还有些概念没有完全的弄清楚,面对一个问题,还不能够转换成程序的准确描述。所以要说怎么编写一个漂亮,能够让人入眼的程序,我是说不出的。

但是在第二学期的时候我学习了Java语言的同时,还学习了数据结构与算法(C语言实现),在学习数据结构与算法的时候,自己就知道了对于程序的如何写好有了慢慢的体会了————在后面的学习中,自己也越加强烈的体会到 数据决定程序的结构, 作者的真的观点真的是太对了,对这种看法我是深有共鸣。

案例

在大一暑假期间,在西安微易码计算机科技有限公司的项目实训中,我接到的任务是,完成公司管理信息信系统中,主界面菜单根据用户类型动态的显示菜单(不同用户具有不同的使用权限),在后期,可以灵活的增加和减少菜单,设置用户权限。

任务要求

所有的菜单项都从数据库中取得,取得的是一个字符串,成序分菜单,一级菜单,二级菜单和以下的菜单

  • 菜单权限设置

    1、如果需要对不同的用户采取权限设置,可以建立相关的数据库表,进行设置,程序可以提取数据,自动生成
    设置有权限的菜单。(本例子中代码有从权限数据库表中取 得相关用户的菜单权限)。

    2、菜单可见和不可见。
    3、菜单可用和不可用(灰色状态)。

  • 自动生成菜单
    1、数据库表中所包含的字段有:菜单编号,菜单名字,菜单所对应类名字,父菜单编号,菜单类型。
    2、若用户想增加或减少菜单,只需改变数据库表,而程序不需要更改。

  • 多级菜单的生成
    1、生成多级菜单只需更改数据库表,在数据库表中填写清楚菜单类型,和子菜单编号,父菜单的编号。
    2、多级菜单的寻找方案为递归寻找。

主要技术点

  • 数据库
  • Java反射技术

数据库数据

根据要求,数据库以Access为例,我对数据库表的设计是这样的,字段有:

Menu_Id(菜单编号 ,短文本)、Menu_Name(菜单名,短文本)、Class_Name(菜单项对应的类名,短文本)、Father_Id(父菜单的编号、短文本)、Menu_Type(菜单类型、数字)

对于主菜单项,没有父菜单的编号,那么对于后面的菜单来说,每一个菜单都记录着自己的父菜单编号,所以一遇到拥有子菜单的菜单项,就去后面寻找属于他的子菜单,所有等到所有主菜单遍历完了之后,所有菜单也就按部就班的”归位”了。所以根据这个思路设计数据库表,然后根据设计的表数据机构,编写实现的程序。

如下图:
数据库表

注意:数据库表是怎么设计的,那么就在编写程序的时候,围绕数据进行编写,所以数据结构决定程序。

那么说道第到底是要实现什么样的效果来呢?直接放图吧。就是要实现下面的这个效果:
要实现的效果图

针对于这个项目的要求,我整体的实现是如下:

  • 连接数据库类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 此类供调用者完成对数据库的链接,并对数据进行操作的工作
* @author Administrator
*
*/
public class MECDatabase {
private int databaseType; /*要链接的数据库类型*/
private static final String[] DB_DRIVER = {"oracle.jdbc.OracleDriver", /*链接数据库的驱动*/
"sun.jdbc.odbc.JdbcOdbcDriver",
"com.mysql.jdbc.Driver"};
private static final String[] URL = {"jdbc:oracle:thin:@","jdbc:odbc:","jdbc:mysql://"}; /*链接数据库的URL*/
private static final int ORACLE = 0; /*数据库类型*/
private static final int ACCESS = 1;
private static final int MYSQL = 2;
private Statement stmt;
private Connection con;
private ResultSet rst;
/**
* 带参的构造方法
* @param databaseType 传入要链接的数据库类型(int 类型)
* 0表示链接Oracle数据库
* 1表示链接Access数据库
* 2表示链接MySql数据库
*/
public MECDatabase(int databaseType){
this.databaseType = databaseType;
stmt = null;
con = null;
rst = null;
}
/**
* 获得数据库类型
* @return 返回数据库类型
*/
private int getDatabaseType() {
return databaseType;
}
/**
* 链接不需要IP和端口号的数据库
* @param databaseName 数据源名称
* @throws Exception 链接数据库时遇到的异常
*/
public void connection(String databaseName) throws Exception{
try {
Class.forName(DB_DRIVER[ACCESS]);
con = DriverManager.getConnection(URL[ACCESS]+databaseName);
stmt = con.createStatement();
} catch (ClassNotFoundException e) {
throw new Exception("错误:" + e.getMessage() + "\n" +
"类:MECDatabase\n方法:public void connection() throws Exception\n\n" +
"请咨询微易码开发技术人员,解决这个问题!");
}
}
/**
* 链接数据库
* @param hostIp 主机IP地址
* @param port 端口号
* @param databaseName 数据源名称
* @param userName 用户名
* @param password 密码
* @throws Exception 连接数据库是遇到的异常
*/
public void connection(String hostIp,int port,String databaseName,String userName,String password) throws Exception {
try {
if(this.getDatabaseType() == ORACLE){
Class.forName(DB_DRIVER[ORACLE]);
con = DriverManager.getConnection(URL[ORACLE]+hostIp+":"+port+"/"+databaseName,userName,password);
}else{
Class.forName(DB_DRIVER[MYSQL]);
con = DriverManager.getConnection(URL[MYSQL]+hostIp+":"+port+"/"+databaseName,userName,password);
}
stmt = con.createStatement();
} catch (ClassNotFoundException e1) {
throw new Exception("错误:" + e1.getMessage() + "\n" +
"类:MECDatabase\n方法:public void connection() throws Exception\n\n" +
"请咨询微易码开发技术人员,解决这个问题!");
} catch (SQLException e2) {
throw new Exception("错误:" + e2.getMessage() + "\n" +
"类:MECDatabase\n方法:public void connection() throws Exception\n\n" +
"请咨询微易码开发技术人员,解决这个问题!");
}
}
/**
* 关闭与当前数据库的链接
* @throws Exception 关闭数据库链接时遇到的异常
*/
public void disConnection()throws Exception{
try
{
if(rst != null)
rst.close();
if(stmt != null)
stmt.close();
if(con != null)
con.close();
}catch(SQLException sqle)
{
throw new Exception("错误:" + sqle.getMessage() + "\n" +
"类:MECDatabase\n方法:public void disConnection() throws Exception\n");
}
}
/**
* 执行SQL语句,doSql方法只能完成查询功能
* @param sqlSwing 传入的SQL语句
* @return 返回查询的对象
* @throws Exception 执行SQL语句时遇到的异常
*/
public ResultSet doSql(String sql)throws Exception{
if(stmt != null){
try{
rst = stmt.executeQuery(sql);
}catch(SQLException sqlE){
sqlE.printStackTrace();
throw new Exception("错误:" + sqlE.getMessage() + "\n" +
"类:MECDatabase\n" +
"方法:public ResultSet doSql(String SQL) throws Exception\n");
}
}
return rst;
}
/**
* 执行SQL语句,doSql方法只能完成查询功能,并将查询的内部指针最后指向首位
* @param sqlSwing 传入的SQL语句
* @return 返回查询的对象
* @throws Exception 执行SQL语句时遇到的异常
*/
public ResultSet select(String sql)throws Exception{
if(stmt != null){
try{
//默认的ResultSet对象不可更新,仅有一个向前移动的光标,因此只能迭代它一次,并且只能按从第一行到
//最后一行的顺序进行,可以生成可以滚动的/或可更新的ResultSet对象,以下这句话就是实现该功能,
//不然主程序中result的执行就会出错
stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
rst = stmt.executeQuery(sql);
}catch(SQLException sqlE){
throw new Exception("错误:" + sqlE.getMessage() + "\n" +
"类:MECDatabase\n" +
"方法:public ResultSet select(String SQL) throws Exception\n");
}
}
return rst;
}
/**
* 执行SQL语句,upDate方法可以完成创建,修改,插入,删除等功能
* @param sqlSwing 传入的SQL语句
* @return 返回该操作是否成功
* @throws Exception 执行SQL语句时遇到的异常
*/
public boolean update(String sql)throws Exception{
boolean flag = false;
if(stmt != null){
try{
flag = stmt.execute(sql);
}catch(SQLException sqlE){
throw new Exception("错误:" + sqlE.getMessage() + "\n" +
"类:MECDatabase\n" +
"方法:public ResultSet update(String SQL) throws Exception\n");
}
}
return flag;
}
}
  • 生成菜单代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
public class myWindowsDate2
{
/** 创建窗口的基本组件 */
private JFrame jfrmMain;
private Container con;
private JMenuBar jmenbTopBar = new JMenuBar();
private JInternalFrame jInternalFrame;
private DesktopPane DesktopPane ;
private JToolBar toolBar ;
/** 分别用来存储SQL语句,取出的结果集,菜单类名字 */
String SQlString;
ResultSet ResString ;
ResultSet result;
String className;
/** 连接数据库 */
Connection connection ;
/** 存储从数据库中取出的菜单的类型(类型有0、1、2) */
int type;
/** 接收登入界面传入的用户姓名和ID*/
private String userId;
private String userName;
/** 存放已点击的菜单所调用的相对应的类名 */
private ArrayList<String> arrayListWindowCanSee = new ArrayList<String>();
/** 存放可见和可用的的菜单项 */
private ArrayList<String> arrayListDo = new ArrayList<String>();
private ArrayList<String> arrayListIsCanUse = new ArrayList<String>();
/**
* 建立基本的窗体
* @author 王长春
* @param void
* @return void
* @exception void
* */
public void creatJFram()
{
jfrmMain = new JFrame("微易码科技管理信息系统");
con = jfrmMain.getContentPane();
jfrmMain.setVisible(true);
jfrmMain.setExtendedState(jfrmMain.MAXIMIZED_BOTH);
Dimension don =Toolkit.getDefaultToolkit().getScreenSize();
jfrmMain.setSize(don.width,don.height);
jfrmMain.setLocation(0, 0);
DesktopPane = new DesktopPane(jfrmMain.getWidth(),jfrmMain.getHeight());
toolBar = new JToolBar();
con.add("North",toolBar);
con.add(DesktopPane);
jfrmMain.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jfrmMain.setVisible(true);
}
/**
* 从数据库中取得菜单信息
* @author 王长春
* @param void
* @return void
* @exception 连接数据库和执行SQL语句,断开数据库时会出现异常
* */
public void DateFromDateBase()
{
SQlString = "SELECT Menu_Id, Menu_Name, Class_Name, Father_Id, Menu_Type " +
"FROM SYS_INF_MAINMENU ";
MECDatabase date = new MECDatabase(1);
try
{
//连接数据库
date.connection("SYS_MEC_INFOTABLE");
result = date.select(SQlString);
//调用获得权限的方法
getPowerState();
//调用区分区分菜单项的方法
soutJMenu();
//断开数据库
date.disConnection();;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从数据库中取得用户对应的菜单应有的菜单权限
* @author 王长春
* @param void
* @return void
* @exception 连接数据库和执行SQL语句,断开数据库时会出现异常
* */
public void getPowerState()
{
String sqlString;
String menuIdString;
int state;
//这里为简化操作(应该从登入界面传入的id号区别用户身份,直接从权限表中取得编号为02用户的权限
sqlString = "SELECT MenuId, MenuState FROM SYS_INF_POWER WHERE PostId = '02'";
MECDatabase date1 = new MECDatabase(1);
try
{
date1.connection("SYS_MEC_INFOTABLE");
ResString = date1.select(sqlString);
} catch (Exception e)
{
e.printStackTrace();
}
try
{ //将用户可见和可用的挑出,并存放起来
while (ResString.next())
{
menuIdString = ResString.getString("MenuId");
state = ResString.getInt("MenuState");
if(state != 0)
arrayListDo.add(menuIdString);
if (state == 2 )
arrayListIsCanUse.add(menuIdString);
}
date1.disConnection();
} catch (SQLException e)
{
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/** 区分菜单项所属的属性
* @author 王长春
* @param void
* @return void
* @exception ClassNotFoundException,InstantiationException,
* IllegalAccessException,SQLException
*
* */
public void soutJMenu()
{
int Finger_Move = 1;
try
{
while (result.next())
{
String idString =result.getString("Menu_Id");
String name = result.getString("Menu_Name");
className = result.getString("Class_Name");
String fatherIdString = result.getString("Father_Id");
int type = result.getInt("Menu_Type");
if (0 == type && fatherIdString.equals("0000"))
{//建立主菜单项
JMenu tempJmenu = new JMenu(name);
setJMenuItem(name, idString, fatherIdString, tempJmenu);
}else if(2 == type)
{//建立工具栏
final JButton tempjButton = new JButton(name);
tempjButton.setName(className);
tempjButton.setFont(new Font("隶书",Font.BOLD,20));
toolBar.add(tempjButton);
tempjButton.addActionListener
(
new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
try {//调用反射机制的方法
creatNewWindow(tempjButton.getName(), userId, userName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
);
}
Finger_Move++;
result.absolute(Finger_Move);
}
}catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 建立菜单项并且实现多级菜单的建立
* @author 王长春
* @return Cycle_Index int类型,记录的是result.next的执行次数,为返回result的指向做准备
* @param nameString(String) idstString(String) fathetidString(String) jmenu(String)
* 传入soutJMenu()中的菜单名称,菜单编号,父菜单编号,和建立的JMenu
* @exception ClassNotFoundException, InstantiationException,IllegalAccessException
* */
public int setJMenuItem(String nameString, String idstString, String fathetidString, JMenu jmenu) throws SQLException
{
int Cycle_Index = 0;
boolean isSetSeparator = false;
boolean ifHeadhasItem = false;
if (fathetidString.equals("0000"))
jmenbTopBar.add(jmenu);
while (result.next())
{
Cycle_Index++;
String id = result.getString("Menu_Id");
String Name = result.getString("Menu_Name");
className = result.getString("Class_Name");
String fatherIdString = result.getString("Father_Id");
int type = result.getInt("Menu_Type");
if (fatherIdString.equals(idstString))
{
if (0 == type)
{
if(ifHeadhasItem && isSetSeparator)
{
jmenu.addSeparator();
isSetSeparator = false;
}
if (arrayListDo.contains(id))
{
JMenu tempjmenu = new JMenu(Name);
//递归调用
int count = setJMenuItem(Name, id, fatherIdString, tempjmenu);
jmenu.add(tempjmenu);
//将 result的游标往回指
result.absolute(-count);
}
}
else
{
if(Name.equals("-"))
isSetSeparator = true;
else
{ //添加分隔线,因为根据不同用户的权限不同,出现多根分隔线时只能添加一条,这里保证了
//既不多添加,也不少添加
if(ifHeadhasItem && isSetSeparator)
{
jmenu.addSeparator();
isSetSeparator = false;
ifHeadhasItem = false;
}
if (arrayListDo.contains(id))
{
//建立菜单项
final JMenuItem tempJMenuItem = new JMenuItem(Name);
tempJMenuItem.setName(className);
jmenu.add(tempJMenuItem);
ifHeadhasItem = true;
//判断是否可用
if (arrayListIsCanUse.contains(id))
tempJMenuItem.setEnabled(false);
tempJMenuItem.addActionListener
(
new ActionListener()
{
<span style="white-space:pre"> </span>public void actionPerformed(ActionEvent arg0)
{
<span style="white-space:pre"> </span>String ItemName = tempJMenuItem.getName();
try {
if (!(arrayListWindowCanSee.contains(ItemName)))
{//计算器和万年历窗口要依附在我的主窗口中,两个是特殊处理
if (!ItemName.equals("MECCalender") && !ItemName.equals("Calculator")) { <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>creatNewWindow(ItemName, userId, userName);
arrayListWindowCanSee.add(ItemName);
DealAction(tempJMenuItem);
}
else
creatSpecliWindow(ItemName, userId, userName);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
);
}
}
}
}
}
return Cycle_Index + 1;
}
/**
* 调用用户所点击的菜单项对应的类,弹出各个模块
* @author 王长春
* @param string(String)类名字,id(String)用户编号, iString(String)用户名字
* @return void
* @exception ClassNotFoundException,InstantiationException,IllegalAccessException
* <span style="white-space:pre"> </span> NoSuchMethodException,SecurityException,InvocationTargetException
* */
public void creatNewWindow(String string, String id ,String name) throws ClassNotFoundException, Instantia<span style="white-space:pre"> </span>tionException, IllegalAccessException
{
try {
Class class1 = Class.forName(string);
//要调用的方法的参数类型
Class[] paramType = {String.class, String.class};
//实际传入的参数
Object[] param = {id , name};
//得到参数类型相同的构造方法
Constructor constructor =class1.getConstructor(paramType);
//传入参数,并执行构造方法
Object object = constructor.newInstance(param);
//调用getJframe的方法(各个模块统一留出一致的方法,),传入的参数为空
Method method = class1.getMethod("getJframe", new Class[] {});
//执行该方法
Object mObject =method.invoke(object, new Object[] {});
jInternalFrame = (JInternalFrame) mObject;
//将反回的窗体加入到我的窗体里面,成为我的子窗口
DesktopPane.add(jInternalFrame);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 调用用户所点击的菜单项中工具对应的类,弹出各个模块
* @author 王长春
* @param string(String) 类名字,id(String)用户编号, iString(String)用户姓名
* @return void
* @exception ClassNotFoundException,InstantiationException,IllegalAccessException
* <span style="white-space:pre"> </span>NoSuchMethodException,SecurityException,InvocationTargetException,NoSuchMethodException
* */
public void creatSpecliWindow(String ClassName,String userIdString, String userNameString )
{
try {
Class clas2 = Class.forName(ClassName);
//要调用的方法的参数类型
Class[] patrem = {JFrame.class, String.class, String.class};
//实际要传入的参数
Object[] valueObjects = {jfrmMain, userIdString, userNameString};
//得到参数类型相同的构造方法
Constructor constructor1 = clas2.getConstructor(patrem);
//传入参数,并执行构造方法
Object pObject = constructor1.newInstance(valueObjects);
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 对添加的JInterNalFream窗口进行事件监听
* @author 王长春
* @param tempString(String) 事件监听时的菜单对象
* @return void
* @exception void
*
* */
public void DealAction(final JMenuItem tempItem)
{
jInternalFrame.addInternalFrameListener
(//对子窗体进行事件监听,子窗体没有关闭,再点击该菜单项不能在弹出该窗体
new InternalFrameListener() {
public void internalFrameOpened(InternalFrameEvent e) {
}
public void internalFrameIconified(InternalFrameEvent e) {}
public void internalFrameDeiconified(InternalFrameEvent e) {}
public void internalFrameDeactivated(InternalFrameEvent e) {
}
public void internalFrameClosing(InternalFrameEvent e) {}
public void internalFrameClosed(InternalFrameEvent e){
arrayListWindowCanSee.remove(tempItem.getName());
}
public void internalFrameActivated(InternalFrameEvent e){}
}
);
}
/**初始化界面
* 构造方法
* @author 王长春
* @param void
* @return void
* @exception void
* */
public myWindowsDate2()
{
creatJFram();
jfrmMain.setJMenuBar(jmenbTopBar);
DateFromDateBase();
jfrmMain.setVisible(true);
}
/**
* 带两个参数的构造方法,登入界面传入参数
* @author 王长春
* @param String userId 登入界面传入的用户编号, String userName 登入界面传入的用户姓名
* @return void
* @exception void
* */
public myWindowsDate2(String userId, String userName)
{
this.userId = userId;
this.userName = userName;
creatJFram();
jfrmMain.setJMenuBar(jmenbTopBar);
DateFromDateBase();
jfrmMain.setVisible(true);
}
/**
* 主函数
* @author 王长春
* @param void
* @return void
* @exception void
* */
public static void main(String[] args)
{
new myWindowsDate2();
}
}

最后实现的效果就是是如下的图:
运行截图

点击一个菜单项的时候,调用相应的模块(本文章中没有列出相应的代码),显示的效果如下图:
点击菜单项截图

再次重申

在我上面的项目案例中,使用数据库和我现在认为的比较合理的数据结构与算法,所实现的需求的要求,并且大大节省了冗杂重复的代码,而且灵活性也更加高,但是也是有局限性的,因为我这个程序的数据源是来自数据库,数据库中的表设计中的数据规范限制了数据(对数据进行要求),才能够完成,所以说数据结构决定了程序结构。

最后,再总结《编程珠玑》中的几点:

  • 将大程序缩减为小程序。数据结构设计还有很多其他正面影响,包括节省时间和空间,提高可移植性和维护性。
  • 程序员在节省空间方面无计可施的时候,将自己从代码中国解脱出来,退回起点并集中心力研究数据,常常能有奇效,(数据的)表示形式是程序设计的根本。(后面的几点是退回起点进行思考时的几条原则。)
  • 使用数组重新编写重复的代码。冗长的相似代码常常可以使用最简单的数据结构———数组来更好地表述。
  • 封装复杂结构。当需要非常复杂的数据结构时,使用抽象语进行定义,并将操作表示为类。
  • 尽可能使用高级工具。超文本,名字–值对,电子表格,数据库,编程语言等都是特定问题领域中的强大工具。
  • 从数据得出程序的结构。在动手编写代码之前,优秀的程序员会彻底的理解输入、输出和中间数据结构,并围绕这些结构创建程序。
坚持原创技术分享,您的支持将鼓励我继续创作!