目录
PB 的 JVM 配置(System Options)
创建 MySQL 数据库 student (若已经创建请跳过,但最好跟我(课本)一样,要不然代码里要相应修改)
JDBC 连接 MySQL
建立工作空间
创建数据窗口
创建功能窗口
生成可执行程序
本教程基于:董建全《数据库实用教程》(第三版)
请准备好 JDBC 连接 MySQL 的驱动 jar 包:mysql-connector-java-5.1.46.jar (如已经有了就不需要再下载)
由于 PB 的原因,大概率会出现无法连接 64位 JDK 的问题,所以最好安装32位的 JDK 并配置好系统环境变量。
最后的:生成可执行程序,没有实现。
点击导航栏顶部的 Tools,打开 System Options 并选择 Java,在 Classpaths 右侧点击虚线方框,在文件管理中选择你刚刚下载好的 jar 包,
在右下方 Set JDK Location 中修改你安装的 JDK 的路径,以及相应的 JRE 路径,要注意只有32位的 JRE 中才有 client 文件
OK,在下方 JVM Status 中应该是这样的信息:
如果 Load Status 不是 Loaded 状态,那么之后连接数据库就会出现 PB 无法加载 JVM 的问题。
其中各个表的设计如下:
c 表(课程表)
s 表(学生表)
sc 表(学生成绩表)
注意外键约束 :
打开 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 中有你创建好的表:
详情请参考《数据库实用教程》从 开始。
创建完成如图所示:
双击 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
我傻逼了,这些教程就在书里啊……,此部分详情请参考 董建全《数据库实用教程》(第三版) -
学生成绩报告单(d_student_score_report)数据窗口,以及成绩分布(d_score_dis)数据窗口要仔细看
课本中的 图13.49 以及图 13.50 中的复选框选择和计算公式,以及各个字段的摆放,否则,不好看。
进行这里之前你要从课本的 跟着教程走到
。
创建窗口,添加控件、绑定数据窗口这些,都完全跟着课本教程走,但是代码都用我的,因为是完整的。
我们在上面已经在 open 窗口中打了代码,不需要重复。
接下来选择 PB 主窗口中 “View” 菜单下的 “Variable” 子菜单,打开 “Declare Instance Variable” 子窗口,在下拉列表框中选择 “Global Variable”,在窗口空白区域输入全局变量:
string s_info, s_credit, c_info, cname_info, teacher
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)
关闭按钮我都觉得没必要。
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
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
open 事件脚本:(课本中没有,但这是必要的……太坑了)
// 学生成绩单窗口 w_select_student_score_report 的 open 事件脚本
dw_1.settransobject(sqlca)
dw_1.retrieve(s_info)
dw_1.object.datawindow.readonly="yes"
open 事件脚本:(太坑了……)
// 成绩分布子窗口 w_course_score_dis 的 open 事件脚本
dw_1.settransobject(sqlca)
dw_1.retrieve(s_info)
dw_1.object.datawindow.readonly="yes"
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)
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 脚本修改
s_info = 's1'
open(w_select_course)
// 注释掉上面两句,修改为:
open(w_login)
可以运行了。
之后添加菜单的教程可以跟着课本走了,前面的坑基本都踩过了。
这里使用 JDBC 连接 PB 操作 MySQL 数据库是通过 settransobject(sqlca),遗憾的是 MySQL 并不支持环境外的这种操作,所以生成 exe 文件后执行会报错,在下至今无解。我们只能在 PB 里面运行这个项目,不妨参考评论区的大佬使用 ODBC 来连接。