PowerBuilder 使用 JDBC 连接 MySQL 实现学生选课管理系统

目录

 PB 的 JVM 配置(System Options)

 创建 MySQL 数据库 student (若已经创建请跳过,但最好跟我(课本)一样,要不然代码里要相应修改)

 JDBC 连接 MySQL

 建立工作空间

 创建数据窗口

 创建功能窗口

 生成可执行程序


本教程基于:董建全《数据库实用教程》(第三版)

请准备好 JDBC 连接 MySQL 的驱动 jar 包:mysql-connector-java-5.1.46.jar (如已经有了就不需要再下载)

由于 PB 的原因,大概率会出现无法连接 64位 JDK 的问题,所以最好安装32位的 JDK 并配置好系统环境变量。

最后的:生成可执行程序,没有实现。

  • PB 的 JVM 配置(System Options)

点击导航栏顶部的 Tools,打开 System Options 并选择 Java,在 Classpaths 右侧点击虚线方框,在文件管理中选择你刚刚下载好的 jar 包,

 在右下方 Set JDK Location 中修改你安装的 JDK 的路径,以及相应的 JRE 路径,要注意只有32位的 JRE 中才有 client 文件

OK,在下方 JVM Status 中应该是这样的信息:

如果 Load Status 不是 Loaded 状态,那么之后连接数据库就会出现 PB 无法加载 JVM 的问题。

  • 创建 MySQL 数据库 student (若已经创建请跳过,但最好跟我(课本)一样,要不然代码里要相应修改)

其中各个表的设计如下:

c 表(课程表)

s 表(学生表)

sc 表(学生成绩表)

注意外键约束 :

  •  JDBC 连接 MySQL

打开 DataBase 

右键点击 JDB JDBC --> new profile 新建,在弹出的 Database Profile Setup - JDBC 窗口填写 JDBC 驱动以及你所要连接的数据库表的信息:

Driver Name:org.gjt.mm.mysql.Driver

URL:jdbc:mysql://localhost:3306/你要连接的数据库的名字

Login ID:你登录 MySQL 的用户名

Password:你登录 MySQL 的密码

OK,如果按照前面的配置,你已经连接上 MySQL 了,Tables 中有你创建好的表:

  •  建立工作空间

详情请参考《数据库实用教程》从 P_{320} 开始。

创建完成如图所示:

 双击 student.pbl 目录下的 student,右侧弹出 student 的 Application 窗口,左下角选择 open 填入以下代码,但先不要运行:

// Profile student
SQLCA.DBMS = "JDBC"
SQLCA.LogId = "root"
SQLCA.LogPass = "123456"
SQLCA.AutoCommit = False
SQLCA.DBParm = "Driver='org.gjt.mm.mysql.Driver', Url='jdbc:mysql://localhost:3306/student'"
//CONNECT;
connect using sqlca;
if SQLCA.SQLCODE<>0 then
	MessageBox("对不起,链接不了数据库", SQLCA.SQLERRTEXT)
	halt
	return
else
	s_info = 's1'
	open(w_select_course)
// 下面这行代码在创建了 w_login 后用到,届时要注释掉上面两行
	//open(w_login)
end if
  •  创建数据窗口

我傻逼了,这些教程就在书里啊……,此部分详情请参考 董建全《数据库实用教程》(第三版)P_{323} - P_{336}

学生成绩报告单(d_student_score_report)数据窗口,以及成绩分布(d_score_dis)数据窗口要仔细看图_{13.49}课本中的 图13.49 以及图 13.50 中的复选框选择和计算公式,以及各个字段的摆放,否则,不好看。

  • 创建功能窗口

进行这里之前你要从课本的 P_{336} 跟着教程走到 P_{340} 。

创建窗口,添加控件、绑定数据窗口这些,都完全跟着课本教程走,但是代码都用我的,因为是完整的。

  • 编写应用对象(student.pbl)的脚本:

我们在上面已经在 open 窗口中打了代码,不需要重复。

接下来选择 PB 主窗口中 “View” 菜单下的 “Variable” 子菜单,打开 “Declare Instance Variable” 子窗口,在下拉列表框中选择 “Global Variable”,在窗口空白区域输入全局变量:

string s_info, s_credit, c_info, cname_info, teacher
  • “学生选课”主窗口 w_select_course:

open 事件脚本:

// 窗口 w_select_course 的 open 事件
dw_1.settransobject(sqlca)
dw_1.retrieve(s_info)
dw_1.object.datawindow.readonly = 'yes'
dw_2.settransobject(sqlca)
dw_2.retrieve(s_info)
dw_2.object.datawindow.readonly = 'yes'
dw_3.settransobject(sqlca)
dw_3.retrieve(s_info)
dw_3.object.datawindow.readonly = 'yes'
dw_4.settransobject(sqlca)
dw_4.retrieve(s_info)
dw_4.object.datawindow.readonly = 'yes'
sle_1.SetFocus( )

 选课按钮 clicked 脚本:

// 选课按钮 pb_1 的 clicked 事件脚本
string ccname, ccno
c_info = upper(sle_1.text)
if c_info = "" then
	MessageBox("出错", "请输入课程号")
else
	select c.cname into :ccname from c where c.cno = :c_info;
	if SQLCA.SQLCODE <> 0 then
		MessageBox("出错", "此课程号不存在")
	else
		select sc.cno into :ccno from sc where (sc.cno = :c_info and 
		sc.sno = :s_info);
		if SQLCA.SQLCODE = 0 then
			MessageBox("出错", "此课程已选")
		else
			INSERT INTO sc (sno, cno)
			VALUES (:s_info, :c_info);
			dw_4.reset()
			sle_1.text = ""
			dw_4.settransobject(sqlca)
			dw_4.retrieve(s_info)
		end if
	end if
end if

退课按钮 clicked 脚本:

// 退课 pb_2 clicked 脚本
string ccno, ggrade
if sle_1.text = "" then
	MessageBox("出错", "请输入课程号")
end if
c_info = upper(sle_1.text)
if c_info <> "" then
	select c.cname into :cname_info from c where c.cno = :c_info;
	if SQLCA.SQLCODE <> 0 then
		MessageBox("出错", "此课程号不存在")
	else
		select sc.cno, sc.grade into :ccno, :ggrade from sc where (sc.cno = :c_info and
		sc.sno = :s_info);
		if SQLCA.SQLCODE <> 0 then
			MessageBox("出错", "此课程未选")
		else
			if ggrade <> "" then
				MessageBox("出错", "此课程已登分")
			else
				delete from sc where sno = :s_info and cno = :c_info;
				dw_4.reset()
				sle_1.text = ""
				dw_4.settransobject(sqlca)
				dw_4.retrieve(s_info)
			end if
		end if
	end if
end if

可选课程 doubleclicked 脚本:

// 可选课程 dw_2 的 doubleclicked 脚本:
open(w_select_student_score_report)

关闭按钮我都觉得没必要。

  • “课程信息”窗口 w_course_create :

 open 事件脚本:

// 课程信息窗口 w_course_create 的 open 事件脚本
int sum, hascol
dw_1.settransobject(sqlca);
dw_1.retrieve();
hascol = dw_1.retrieve();
pb_2.enabled = false
st_1.text = string(hascol)

新增按钮 clicked 脚本:

// 新增按钮 pb_1 的 clicked 事件脚本
long l_row
int s
pb_1.enabled = false
s = dw_1.RowCount()
l_row = dw_1.InsertRow(s+1)
dw_1.scrolltorow(s+1)
dw_1.setfocus()
pb_1.enabled = false
pb_2.enabled = true

 保存按钮 clicked 脚本:

// 保存按钮 pb_2 的 clicked 事件脚本
int s, hascol
string kk
s = dw_1.getrow();
c_info = dw_1.getitemstring(s, "cno")
select c.cno into :kk from c where (c.cno = :c_info);
if c_info = kk then
	MessageBox("出错", "不能增加,此课程号已经存在")
else
	dw_1.update()
	hascol = dw_1.retrieve()
	st_1.text = string(hascol)
	pb_1.enabled = true
	pb_2.enabled = false
end if

 删除按钮 clicked 脚本:

// 删除按钮 pb_3 的 clicked 事件脚本
int s, hascol
string kk
s = dw_1.getrow();
c_info = dw_1.getitemstring(s, "cno")
select sc.cno into :kk from sc where (sc.cno = c_info);
if c_info = kk then
	MessageBox("出错", "不能删除,此课程已经有学生选")
else
	dw_1.DeleteRow(s);
	dw_1.update();
	hascol = dw_1.retrieve();
	st_1.text = string(hascol)
end if
pb_1.enabled = true
pb_2.enabled = false
  •  “学生信息”窗口 w_student_create:

 open 事件脚本:

// 学生信息窗口 w_student_create 的 open 事件脚本
int sum, hascol
dw_1.settransobject(sqlca);
dw_1.retrieve();
hascol = dw_1.retrieve();
pb_2.enabled = false
st_1.text = string(hascol)

 新增按钮 clicked 脚本:

// 新增按钮 pb_1 的 clicked 事件脚本
long l_row
int s
s = dw_1.RowCount()
l_row = dw_1.InsertRow(s+1)
dw_1.scrolltorow(s+1)
dw_1.setfocus()
pb_1.enabled = false
pb_2.enabled = true

 保存按钮 clicked 脚本:

// 保存按钮 pb_2 的 clicked 事件脚本
int s, hascol;
string kk
s = dw_1.getrow();
s_info = dw_1.getitemstring(s, "sno")
select s.sno into :kk from s where (s.sno = :s_info);
if s_info = kk then
	MessageBox("出错", "不能增加,此学号已存在")
else
	dw_1.update()
	hascol = dw_1.retrieve()
	st_1.text = string(hascol)
	pb_1.enabled = true
	pb_2.enabled = false
end if

 删除按钮 clicked 脚本:

// 删除按钮 pb_3 的 clicked 事件脚本
int s, hascol;
string kk
s = dw_1.getrow();
s_info = dw_1.getitemstring(s, "sno")
select sc.sno into :kk from sc where (sc.sno = s_info);
if s_info = kk then
	MessageBox("出错", "不能删除,此学生已经选课")
else
	dw_1.DeleteRow(s)
	dw_1.Update()
	hascol = dw_1.retrieve();
	st_1.text = string(hascol)
end if
pb_1.enabled = true
pb_2.enabled = false
  •  “学生成绩单”子窗口 w_select_student_score_report :

 open 事件脚本:(课本中没有,但这是必要的……太坑了)

// 学生成绩单窗口 w_select_student_score_report 的 open 事件脚本
dw_1.settransobject(sqlca)
dw_1.retrieve(s_info)
dw_1.object.datawindow.readonly="yes"
  •  “成绩分布”子窗口 w_course_score_dis: 

 open 事件脚本:(太坑了……)

// 成绩分布子窗口 w_course_score_dis 的 open 事件脚本
dw_1.settransobject(sqlca)
dw_1.retrieve(s_info)
dw_1.object.datawindow.readonly="yes"
  • “成绩管理”主窗口 w_teacher_manage:

 open 事件脚本:

// 成绩管理主窗口 w_teacher_manage 的 open 事件脚本
declare cnamecursor cursor for
	select distinct c.cname
	from c, sc
	where c.cno = sc.cno;
open cnamecursor;
if sqlca.sqlcode = -1 then
	MessageBox("sql error", string(sqlca.sqldbcode) + ":" + sqlca.sqlerrtext)
else
	cname_info = ""
	do
		if cname_info <> "" then
			ddlb_cname.additem(cname_info)
		end if
		fetch cnamecursor into :cname_info;
	loop while sqlca.sqlcode = 0
	if sqlca.sqlcode = -1 then
		MessageBox("sql error", string(sqlca.sqldbcode) + ":" + sqlca.sqlerrtext)
	end if
end if
close cnamecursor;
pb_2.enabled = false

查询按钮 clicked 脚本:

// 查询按钮 pb_1 的 clicked 事件脚本
if ddlb_cname.text = "" then
	MessageBox("出错", "请选择课程名")
else
	cname_info = upper(ddlb_cname.text)
	select cno, tname into :c_info, :teacher
	from c
	where cname = :cname_info;
	st_5.text = ddlb_cname.text
	st_6.text = teacher
	dw_1.settransobject(sqlca)
	dw_1.retrieve(c_info)
	dw_1.object.datawindow.readonly = "yes"
	pb_2.enabled = true
end if

输入成绩按钮 clicked 脚本:

// 输入成绩 pb_2 的 clicked 事件脚本
if pb_2.text = '输入成绩' then
	// 有这一句才能编辑成绩:(太坑了……)
	dw_1.modify( "grade.TabSequence = 10" )
	dw_1.object.datawindow.readonly = 'no'
	pb_2.text = '保存'
	pb_1.enabled = false
	pb_3.enabled = false
	st_4.text = '请输入成绩:'
else
	dw_1.UPDATE()
	dw_1.retrieve(c_info)
	dw_1.object.datawindow.readonly = 'yes'
	pb_2.text = '输入成绩'
	pb_1.enabled = true
	pb_2.enabled = true
	pb_3.enabled = true
	st_4.text = "已选修此课的学生:"
end if

成绩分布按钮 clicked 脚本:

// 成绩分布按钮 pb_3 clicked 事件脚本
open(w_course_score_dis)
  • 登录窗口 w_login:

open 事件我没图,没写

sle_user 控件 checkkey 或 modified 脚本:

// w_login 窗口的 sle_user 控件 checkkey 或 modified 事件脚本
if keydown(KeyEnter!) then
	sle_pwd.setfocus()
end if

sle_pwd 控件 checkkey 脚本:

// w_login 窗口的 sle_pwd 控件 checkkey 事件脚本
if keydown(KeyEnter!) then
	pb_login.setfocus()
end if

登录按钮 pb_login 的 clicked 脚本:

// 登录按钮 pb_login 的 clicked 事件脚本
if sle_user.text = "" then
	MessageBox("提醒", "请输入用户名")
	sle_user.setfocus()
	return
end if
if sle_pwd.text = "" then
	MessageBox("提醒", "请输入密码")
	sle_pwd.setfocus()
	return
end if
string ls_user, ls_pwd, ls_confirm_user, ls_confirm_pwd
// 此处做了修改,system 用户登录不要大写
// ls_user = upper(sle_user.text)
// ls_pwd = upper(sle_pwd.text)
ls_user = sle_user.text
ls_pwd = sle_pwd.text
ls_confirm_pwd = ""
ls_confirm_user = ""
if (ls_user = 'system' and ls_pwd = 'system') then
	open(w_teacher_manage)
	close(parent)
else
// 此处 SQL 语句中的双引号去掉了
	select s.logn, s.pswd, s.sno
	into :ls_confirm_user, :ls_confirm_pwd, :s_info
	from s where s.logn = :ls_user;
	s_info = trim(s_info)
	if ls_user <> trim(ls_confirm_user) then
		MessageBox("警告!", "用户名错,重新注册", stopSign!)
		sle_user.text = ""
		sle_pwd.text = ""
		sle_user.setfocus()
	elseif ls_pwd <> trim(ls_confirm_pwd) then
		MessageBox("警告!", "密码错误,重新注册", stopSign!)
		sle_pwd.text = ""
		sle_pwd.setfocus()
	else
		open(w_select_course)
		close(parent)
	end if
end if

退出按钮的 clicked 脚本:

// 退出按钮 pb_exit 的 clicked 事件脚本
close(parent)
  • 修改应用对象(student.pbl)的脚本(前面有过注释):
// student 脚本修改
s_info = 's1'
open(w_select_course)

// 注释掉上面两句,修改为:
open(w_login)

可以运行了。

之后添加菜单的教程可以跟着课本走了,前面的坑基本都踩过了。

  • 生成可执行程序

这里使用 JDBC 连接 PB 操作 MySQL 数据库是通过 settransobject(sqlca),遗憾的是 MySQL 并不支持环境外的这种操作,所以生成 exe 文件后执行会报错,在下至今无解。我们只能在 PB 里面运行这个项目,不妨参考评论区的大佬使用 ODBC 来连接。

发布了26 篇原创文章 · 获赞 22 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Run_Bomb/article/details/88345071