C/C++ Qt 数据库与ComBox多级联动
Qt中的SQL数据库组件可以与ComBox组件形成多级联动效果,在日常开发中多级联动效果应用非常广泛,例如当我们选择指定用户时,我们让其在另一个ComBox组件中列举出该用户所维护的主机列表,又或者当用户选择省份时,自动列举出该省份下面的城市列表等。今天给大家分享二级ComBox菜单如何与数据库形成联动,在进行联动之前需要创建两张表,表结构内容介绍如下:User表:存储指定用户的ID号与用户名UserAddressList表:与User表中的用户名相关联,存储该用户所管理的主机列表信息void InitMultipleSQL()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("./lyshark.db");
if (!db.open())
{
std::cout << db.lastError().text().toStdString()<< std::endl;
return;
}
// 执行SQL创建User表并插入测试数据
// https://www.cnblogs.com/lyshark
db.exec("DROP TABLE User");
db.exec("CREATE TABLE User ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name VARCHAR(40) NOT NULL)"
);
db.exec("INSERT INTO User(name) VALUES('lyshark')");
db.exec("INSERT INTO User(name) VALUES('root')");
db.exec("INSERT INTO User(name) VALUES('admin')");
// 创建第二张表,与第一张表通过姓名关联起来
db.exec("DROP TABLE UserAddressList");
db.exec("CREATE TABLE UserAddressList("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name VARCHAR(40) NOT NULL, "
"address VARCHAR(128) NOT NULL"
")");
db.exec("INSERT INTO UserAddressList(name,address) VALUES ('lyshark','192.168.1.1')");
db.exec("INSERT INTO UserAddressList(name,address) VALUES ('lyshark','192.168.1.2')");
db.exec("INSERT INTO UserAddressList(name,address) VALUES ('lyshark','192.168.1.3')");
db.exec("INSERT INTO UserAddressList(name,address) VALUES ('root','192.168.10.10')");
db.exec("INSERT INTO UserAddressList(name,address) VALUES ('root','192.168.10.11')");
db.exec("INSERT INTO UserAddressList(name,address) VALUES ('admin','192.168.100.100')");
db.commit();
db.close();
}初始化表结构以后就得到了两张表,当程序运行时默认在构造函数处填充第一个ComBox组件,也就是执行一次数据库查询,并将结果通过ui->comboBox_1->addItem();放入到第一个组件内。QSqlDatabase db;
// https://www.cnblogs.com/lyshark
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
InitMultipleSQL();
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("./lyshark.db");
if (!db.open())
{
std::cout << db.lastError().text().toStdString()<< std::endl;
return;
}
QSqlQuery query;
query.exec("select * from User;");
QSqlRecord rec = query.record();
while(query.next())
{
int index_name = rec.indexOf("name");
QString data_name = query.value(index_name).toString();
ui->comboBox->addItem(data_name);
}
}
MainWindow::~MainWindow()
{
delete ui;
}代码运行后第一个ComBox会显示所有用户名:此时回到UI编辑界面,我们在第一个ComBox上转到槽函数on_comboBox_activated(const QString &arg1)上面。当用户选择第一个ComBox选择框时,自动查询数据库中与该选择框对应的字段,并关联到第二个选择框内,代码如下:void MainWindow::on_comboBox_activated(const QString &arg1)
{
std::cout << "www.lyshark.com Name = " << arg1.toStdString()<<std::endl;
if(db.open())
{
QSqlQuery query;
query.prepare("select * from UserAddressList where name = :x");
query.bindValue(":x",arg1);
query.exec();
QSqlRecord rec = query.record();
ui->comboBox_2->clear();
while(query.next())
{
int index = rec.indexOf("address");
QString data_ = query.value(index).toString();
ui->comboBox_2->addItem(data_);
}
}
}最终关联效果如下,当选择用户是自动关联到所维护的主机列表上面:
Ext.net中ComboBox如何绑定数据库中的值
今天在项目中再次碰到了问题,就是Combobox中的值如果是直接绑定很简单。简单添加项就行了。代码如下:
<ext:ComboBox ID="ComBox_SecretsLevel" runat="server" FieldLabel="密级" Width="250" EmptyText="请选择密级..." >
<Items>
<ext:ListItem Text="公开" Value="1"/>
<ext:ListItem Text="保密" Value="2" />
<ext:ListItem Text="绝密" Value="3" />
</Items>
</ext:ComboBox>
但是要从数据库中获取绑定该如何操作呢?
找了下网上的质量好像挺少的,去官网找了些Combobox的例子。虽然不是写死在控件上,但是发现他也只不过是通过获取后台的数组,然后绑定数据来操作的,也没有真正的操作数据库。于是我通过尝试,结合了例子和实际,实现了绑定后台数据库的要求,这边与大家分享下。
这边数据库中的参数及值如图:
获取表中数据只要简单的sql查询语句,这边就不详细讲解了。
在页面中,首先是aspx页面的代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="LR_FileReg.aspx.cs" Inherits="EasyCreate.DFMS.WebUI.LR_FileReg" %>
<%@ Register assembly="Ext.Net" namespace="Ext.Net" tagprefix="ext" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>绑定Combobox后台数据</title>
</head>
<body>
<form id="form1" runat="server">
<ext:ResourceManager ID="ResourceManager1" runat="server"/>
<ext:Store ID="Store_SecretsCom" runat="server">
<Reader>
<ext:JsonReader>
<Fields>
<ext:RecordField Name="SecretsLevelID" Type="Int"/>
<ext:RecordField Name="SecretsLevelName" Type="String" />
</Fields>
</ext:JsonReader>
</Reader>
</ext:Store>
<ext:ComboBox ID="ComBox_SecretsLevel" runat="server" FieldLabel="密级" Width="250" EmptyText="请选择密级..."
StoreID="Store_SecretsCom" ValueField="SecretsLevelID" DisplayField="SecretsLevelName">
</ext:ComboBox>
</form>
</body>
</html>
最新内容请见作者的GitHub页:http://qaseven.github.io/
Bootstrap级联下拉菜单,你肯定用得到
版权声明:欢迎转载,请注明沉默王二原创。 https://blog.csdn.net/qing_gee/article/details/50983189
今天我将介绍自定义的bootstrap级联下拉菜单(你肯定用得到),主要应用场合有省市级关联菜单等等,那么就先拿这个例子来讲,当然其他场景的关联菜单也同样适用。说实话,封装好一个通用的组件还是需要花费很多精力的和时间的,所谓通用,自然要考虑周全,叹!这次整理的Bootstrap关联select,里面也涉及到了很多jquery、ajax、springMVC等等知识点,可谓包罗万象!
首先,请允许我代表该自定义组件做一番小小的介绍。
“hi,你好,我叫yunm.combox.js,主人给我起的名字,其实呢,挺俗的。我主要通过为select组件增加两个自定义属性来完成相应的数据加载,数据请求使用了ajax,后端数据处理使用了springMVC(当然其他方式也可以,只需要返回对应的json数据即可),使用起来呢,就非常非常简单了!”
一、界面效果
选中状态
非选中状态(我是默认北京-北京)
当然了,从界面上完全看不出来一个组件封装的好坏,但至少,你感觉很简洁漂亮,那么好了,有了这层印象,你是否有兴趣继续看下去?我想答案是肯定的。
二、使用方法
①、procity.jsp
首先呢,在页面上加载yunm.combox.js(稍候介绍,至于其他的bootstrap的css和js,不在本章介绍范围内,略过),同时呢,创建两个select,具体格式见如下:
<script type="text/javascript" src="${ctx}/components/yunm/yunm.combox.js"></script>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<select name="province_code" class="form-control combox" ref="city_select"
refUrl="${ctx}/procity?pro_code={value}&city_code=HSLY">
</select>
</div>
<div class="col-md-6">
<select name="city_code" id="city_select" class="form-control">
</select>
</div>
</div>
</div>
<script type="text/javascript">
<!--
$(function() {
if ($.fn.combox) {
$("select.combox", $p).combox();
}
});
//-->
</script>
我去,这么简单,你是否也有点小惊喜?没错,就这么简单。
两个select组件,一个为province_code、一个为city_code。
省级菜单上增加了两个属性。
ref指定关联菜单为市级菜单city_select
refUrl指定菜单获取数据的URL
pro_code作为获取市级数据的关键因子
{value}呢,则为通配符,稍候在介绍组件的时候继续讲到
city_code=HSLY,主要用于选中指定的省市菜单,诸如上文中的(河南、洛阳),如果不选中,则city_code=为空
class=”combox” 为该省级下拉框增加jquery选择器
页面加载完毕后执行combox组件的关键方法,下面详细介绍
②、yunm.combox.js
喏,现在我们来看看关键的组件内容吧!
(function($) {
var _onchange = function(event) {
var $ref = $("#" + event.data.ref);
if ($ref.size() == 0)
return false;
var refUrl = event.data.refUrl;
var value = encodeURIComponent(event.data.$this.val());
YUNM.debug(value);
$.ajax({
type : 'POST',
dataType : "json",
url : refUrl.replace("{value}", value),
cache : false,
data : {},
success : function(response) {
$ref.empty();
addHtml(response, $ref);
$ref.trigger("change").combox();
},
error : YUNM.ajaxError
});
};
var addHtml = function(response, $this) {
var json = YUNM.jsonEval(response);
if (!json)
return;
var html = '';
$.each(json, function(i) {
if (json[i]) {
html += '<option value="' + json[i].value + '"';
if (json[i].selected) {
html += ' selected="' + json[i].selected;
}
html += '">' + json[i].name + '</option>';
}
});
$this.html(html);
};
$.extend($.fn, {
combox : function() {
return this.each(function(i) {
var $this = $(this);
var value = $this.val() || '';
var ref = $this.attr("ref");
var refUrl = $this.attr("refUrl") || "";
if (refUrl) {
refUrl = refUrl.replace("{value}", encodeURIComponent(value));
}
if (refUrl) {
$.ajax({
type : 'POST',
dataType : "json",
url : refUrl,
cache : false,
data : {},
success : function(response) {
addHtml(response, $this);
if (ref && $this.attr("refUrl")) {
$this.unbind("change", _onchange).bind("change", {
ref : ref,
refUrl : $this.attr("refUrl"),
$this : $this,
}, _onchange).trigger("change");
}
},
error : YUNM.ajaxError
});
}
});
}
});
})(jQuery);
通过$.extend($.fn, { combox : function() {为jquery增加一个叫combox的底层(可以查询jquery帮助文档)方法。
通过(function($){_onchange、addHtml})(jQuery);为该组件在页面初始加载时创建两个方法onchange和addHtml,至于(function($) {})(jQuery);我想你如果不了解的话,赶紧百度吧!
先来看combox 方法
获取ref、refUrl,通过ajax向refUrl请求省级菜单数据,当获取成功后,通过addHtml方法将json转换后的option绑定到省级菜单select上
然后呢,为省级菜单select绑定change事件,传递的参数为ref(市级菜单)、refUrl(市级数据获取的url)、$this(省级菜单,便于change事件获取对应选中项,如效果图中的河南)
通过trigger方法立即执行change事件,便于获取对应的市级菜单内容。
再来看_onchange方法,主要是点击省级菜单时触发,用于获取市级菜单列表
refUrl,向服务端请求的URL
value,用于获取省级菜单的选中项目,然后通过该value值获取省级对应的市级菜单
$ref.empty();用于清空市级菜单
通过ajax继续获取市级菜单内容,然后通过addHtml方法添加到市级菜单中。
addHtml方法
通过jsonEval方法对服务端传递回来的数据进行eval(eval('(' + data + ')'),如有不懂,可百度)方法处理,否则会出错。
$.each(json, function(i) {遍历json,通过jquery创建option对象,然后加入到select中。
③、ProcityController
前端介绍完了,我们回到后端进行介绍,当然了,你也可以忽略本节,因为不是所用的关联数据都通过springMVC这种方法获取,那么先预览一下代码吧!
package com.honzh.spring.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.honzh.biz.database.entity.City;
import com.honzh.biz.database.entity.Option;
import com.honzh.biz.database.entity.Provincial;
import com.honzh.common.util.JsonUtil;
import com.honzh.spring.service.CityService;
import com.honzh.spring.service.ProvincialService;
@Controller
@RequestMapping(value = "/procity")
public class ProcityController extends BaseController {
private static Logger logger = Logger.getLogger(ProcityController.class);
/**
* 当传递city_code,则表明下拉框要被选中,否则不选中
*/
@RequestMapping("")
public void index(@RequestParam(value = "city_code", required = false) String city_code,
@RequestParam(value = "pro_code", required = false) String pro_code, HttpServletResponse response) {
try {
logger.debug("获取所在地区" + city_code + ", 省" + pro_code);
// 如果pro_code为””,则表明要获取城市菜单,否则获取市级菜单
if (!pro_code.equals("")) {
Integer pro_id = ProvincialService.getInstance().getByProvincialcode(pro_code).getId();
List<City> citys = CityService.getInstance().getCitysByProvincialId(pro_id);
List<Option> coptions = new ArrayList<Option>(citys.size());
for (City city : citys) {
Option coption = new Option();
coption.setId(city.getId());
coption.setName(city.getCname());
coption.setValue(city.getCode());
// 市级菜单被选中
if (city_code != null && !city_code.equals("")) {
if (city.getCode().equals(city_code)) {
coption.setSelected("selected");
}
}
coptions.add(coption);
}
renderJson(response, coptions);
} else {
List<Provincial> provincials = ProvincialService.getInstance().getProvincials();
// 转换成标准的option属性(name,value,selected)
List<Option> options = new ArrayList<Option>(provincials.size());
// 被选中的省市
// 则说明是展示页面,此时需要为省级菜单和市级菜单设置选择项
if (city_code != null && !city_code.equals("")) {
Provincial selected_provincial = ProvincialService.getInstance().getProvincialByCitycode(city_code);
pro_code = selected_provincial.getProcode();
} else {
pro_code = provincials.get(0) == null ? "" : provincials.get(0).getProcode();
}
for (Provincial provincial : provincials) {
Option option = new Option();
option.setId(provincial.getId());
option.setName(provincial.getProname());
option.setValue(provincial.getProcode());
if (!pro_code.equals("") && provincial.getProcode().equals(pro_code)) {
option.setSelected("selected");
}
options.add(option);
}
renderJson(response, JsonUtil.toJson(options));
}
} catch (Exception e) {
logger.error(e.getMessage());
logger.error(e.getMessage(), e);
renderJson(response, null);
}
}
}
@RequestParam(value = "city_code", required = false) String city_code,对于RequestParam注解,其实非常好用,这里就不多做解释,只是推广一下,固定个数的参数,用该注解更易于代码的维护。
ProvincialService类、CityService类就是两个单例,尽量把数据放置在内存当中,减少查询数据库的次数,稍候贴出来一个例子。
Option类就是单纯的封装前端option组件的关键属性,便于组件的通用化。
renderJson(response, JsonUtil.toJson(options));将数据json化后返回,稍候贴上详细代码。
④、ProvincialService.java
只贴出来代码例子,不做详细解释,毕竟不是本章重点。
package com.honzh.spring.service;
import java.util.ArrayList;
import java.util.List;
import com.honzh.biz.database.entity.City;
import com.honzh.biz.database.entity.Provincial;
import com.honzh.biz.database.mapper.ProvincialMapper;
import com.honzh.common.spring.SpringContextHolder;
public class ProvincialService {
private static Object lock = new Object();
private static ProvincialService config = null;
private ProvincialService() {
provincials = new ArrayList<Provincial>();
ProvincialMapper mapper = SpringContextHolder.getBean(ProvincialMapper.class);
provincials.addAll(mapper.getProvincials());
}
public static ProvincialService getInstance() {
synchronized (lock) {
if (null == config) {
config = new ProvincialService();
}
}
return (config);
}
public Provincial getByProvincialcode(String provincial_code) {
for (Provincial provincial : provincials) {
if (provincial.getProcode().equals(provincial_code)) {
return provincial;
}
}
return null;
}
private List<Provincial> provincials = null;
public List<Provincial> getProvincials() {
return provincials;
}
public Provincial getProvincialByCitycode(String city_code) {
City city = CityService.getInstance().getCityByCode(city_code);
for (Provincial provincial : provincials) {
if (provincial.getId().intValue() == city.getProid().intValue()) {
return provincial;
}
}
return null;
}
public Provincial getProvincialByCode(String province_code) {
for (Provincial provincial : provincials) {
if (provincial.getProcode().equals(province_code)) {
return provincial;
}
}
return null;
}
}
⑤、renderJson方法
/**
* 如果出错的话,response直接返回404
*/
protected void renderJson(HttpServletResponse response, Object responseObject) {
PrintWriter out = null;
try {
if (responseObject == null) {
response.sendError(404);
return;
}
// 将实体对象转换为JSON Object转换
String responseStr = JsonUtil.toJson(responseObject);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
out = response.getWriter();
out.append(responseStr);
logger.debug("返回是:" + responseStr);
} catch (IOException e) {
logger.error(e.getMessage());
logger.error(e.getMessage(), e);
} finally {
if (out != null) {
out.close();
}
}
}
相关文章
git下载地址-Bootstrap关联select
感谢您阅读【沉默王二的博客】,如果王二的博客给您带来一丝帮助或感动,我(也就是王二)将不甚荣幸。
如果您碰巧喜欢,可以留言或者私信我,这将是我鼓捣更多优秀文章的最强动力。
【Asp.Net使用EasyUI】EasyUI combox实现联动
很多时候都会用到combox的联动效果,选择上一个combox的值就自动带出这个值对应的其它信息,比如省市联动,最近我也刚好遇到了类似的要求,是用EasyUI combobox 控件完成的,如果是ASP.NET 里面的DropDownList的话,那就很简单了,一个SelectIndexChange事件再加一个AutoPostBack就行了,下面就是我实现的功能,其实很简单,但是对于像我这样刚接触EasyUI,并且对JQ不熟悉的人来说还是有点费神。
首先是数据库:为此我特地做了一个测试数据库用来测试效果。
tb_Factory表为最上层tb_Factory表中的FactoryID与tb_WorkCenter表中的FactoryID为主外键关系tb_WorkCenter表中的WorkCenterID与tb_Lines表中的WorkCenterID为主外键关系
下面是前台页面代码,引用那些JQ的就不写了:
<body>
<form id="form1" runat="server">
<div>
<div id="divcenter" style="width: 400px; height: 500px; position: absolute">
<div id="divQuery" class="easyui-panel" title="查询">
<table style="border: 0; width: 100%">
<tr style="height: 30px;">
<td style="text-align: right;" class="style2" align="right">
工厂:
</td>
<td style="text-align: left;" class="style1">
<select id="SelectF" class="easyui-combobox" data-options="valueField:'FactoryID',textField:'FactoryName',url:'Index.aspx?Oper=GetAllFactory',width:200,modal:true">
</select>
</td>
</tr>
<tr style="height: 30px;">
<td style="text-align: right;" class="style2" align="right">
工作中心:
</td>
<td style="text-align: left;" class="style1">
<select id="SelectW" class="easyui-combobox" data-options="valueField:'WorkCenterID',textField:'WorkCenterName',width:200">
</select>
</td>
</tr>
<tr style="height: 30px;">
<td style="text-align: right;" class="style2" align="right">
线别:
</td>
<td style="text-align: left;" class="style1">
<select id="SelectL" class="easyui-combobox" data-options="valueField:'LineID',textField:'LineName',width:200">
</select>
</td>
</tr>
<tr style="height: 30px;">
<td style="text-align: right;" class="style2" align="right">
日期:
</td>
<td style="text-align: left; font-weight: bold; padding-left: 10px;" class="style1">
<input id="StartDate_WorkGroup" type="text" style="width: 90px;" class="easyui-datebox" />至
<input id="EndDate_WorkGroup" type="text" style="width: 90px;" class="easyui-datebox" />
</td>
</tr>
</table>
</div>
</div>
</div>
</form>
</body>
以下是脚本代码,通过JQ来实现combox的onSelect事件,重新创建新的URL,通过这个URL来使目标combox重新加载数据,在API上看到的方法:reload。
<script language="javascript" type="text/javascript">
$(document).ready(function () {
//Start:居中显示
$("#divcenter").css("left", (($(document).width()) / 2 - (parseInt($("#divcenter").width()) / 2)) + "px");
$("#divcenter").css("top", (($(document).height()) / 2 - (parseInt($("#divcenter").height()) / 2)) + "px");
//End:居中显示
//Start:设置combox的选择事件
$('#SelectF').combobox({
onSelect: function () {
var url = 'Index.aspx?Oper=GetWorkCenterListByFactoryID&FactoryID=' + $('#SelectF').combobox('getValue');
$('#SelectW').combobox('reload', url);
}
});
$('#SelectW').combobox({
onSelect: function () {
var url = 'Index.aspx?Oper=GetLineListByWorkCenterID&WorkCenterID=' + $('#SelectW').combobox('getValue');
$('#SelectL').combobox('reload', url);
}
});
//End:设置combox的选择事件
});
</script>
下面在cs文件里面根据前台的请求,分别作出相应的处理,比如前台请求查询工厂,那后台就执行查询工厂的方法,其它的也是一样:
1 using System;
2 using System.Collections.Generic;
3
4 using System.Web;
5 using System.Web.UI;
6 using System.Web.UI.WebControls;
7
8 namespace Test
9 {
10 public partial class Index : System.Web.UI.Page
11 {
12 protected void Page_Load(object sender, EventArgs e)
13 {
14 if (Request.QueryString["Oper"] != null)
15 {
16 string _FactoryID;
17 string _WorkCenterID;
18
19 //根据前台的请求进行分别处理。
20 switch (Request.QueryString["Oper"])
21 {
22 //初始化的时候加载所有的工厂。
23 case "GetAllFactory":
24 GetAllFactory();
25 break;
26 case "GetWorkCenterListByFactoryID":
27 //前台发出请求的时候会传递一个工厂ID的参数进来,这里接收到这个参数,
28 //作为条件进行查询该工厂下面的工作中心。
29 _FactoryID = Request.QueryString["FactoryID"];
30 GetWorkCenterByFactoryID(_FactoryID);
31 break;
32 case "GetLineListByWorkCenterID":
33 //同上
34 _WorkCenterID = Request.QueryString["WorkCenterID"];
35 GetLineByWorkCenterID(_WorkCenterID);
36 break;
37 }
38 }
39 }
40
41 //*******************************************
42 //以下部分的函数都是将DataTable类型的结果转换为JSON格式
43 //*******************************************
44
45 /// <summary>
46 /// Get all factory
47 /// </summary>
48 /// <returns></returns>
49 public void GetAllFactory()
50 {
51 var dt =new DAL().GetAllFactoryList();
52 var json = JsonHelper.ConvertDataTable(dt);
53 Response.Write(json);
54 Response.End();
55 }
56
57 /// <summary>
58 /// Get all workcenter by factory id
59 /// </summary>
60 /// <param name="FactoryID">Factory ID</param>
61 /// <returns></returns>
62 public void GetWorkCenterByFactoryID(string FactoryID)
63 {
64 var dt = new DAL().GetWorkCenterListByFactoryID(FactoryID);
65 var json = JsonHelper.ConvertDataTable(dt);
66 Response.Write(json);
67 Response.End();
68 }
69
70 /// <summary>
71 /// Get all lines by workcenter id
72 /// </summary>
73 /// <param name="WorkCenterID">Workcenter ID</param>
74 /// <returns></returns>
75 public void GetLineByWorkCenterID(string WorkCenterID)
76 {
77 var dt = new DAL().GetLineListByWorkCenterID(WorkCenterID);
78 var json = JsonHelper.ConvertDataTable(dt);
79 Response.Write(json);
80 Response.End();
81 }
82 }
83 }
1 using System;
2 using System.Collections.Generic;
3 using System.Web;
4 using System.Data;
5 namespace Test
6 {
7 public class DAL
8 {
9 /// <summary>
10 /// Get all factory
11 /// </summary>
12 /// <returns></returns>
13 public DataTable GetAllFactoryList()
14 {
15 string strSql = "SELECT FactoryID,FactoryName FROM dbo.tb_Factory (NOLOCK) ORDER BY 2 ";
16 return new DataAccess().GetDataTable(strSql);
17 }
18
19 /// <summary>
20 /// Get all workcenter by factory id
21 /// </summary>
22 /// <param name="FactoryID">Factory ID</param>
23 /// <returns></returns>
24 public DataTable GetWorkCenterListByFactoryID(string FactoryID)
25 {
26 string strSql = "SELECT WorkCenterID,WorkCenterName FROM tb_WorkCenter (NOLOCK) WHERE FactoryID='" + FactoryID + "' ORDER BY WorkCenterName";
27 return new DataAccess().GetDataTable(strSql);
28 }
29
30 /// <summary>
31 /// Get all lines by workcenter id
32 /// </summary>
33 /// <param name="WorkCenterID">Workcenter ID</param>
34 /// <returns></returns>
35 public DataTable GetLineListByWorkCenterID(string WorkCenterID)
36 {
37 string strSql = " SELECT LineID,LineName FROM tb_Lines (NOLOCK) WHERE WorkCenterID='" + WorkCenterID + "' ORDER BY LineName";
38 return new DataAccess().GetDataTable(strSql);
39 }
40 }
41 }
最后看一下效果:
PS:
要注意一点:我总是不习惯JQ的那些写法,比如说每次开始和结尾的两个括号,要是跟C#里面一样就好了,上下各一个对齐,感觉JQ里面的括号特别"不好看",括号多了就容易看错,我在这个问题上犯了好几次错误了.
例子源码
C/C++ Qt 数据库与SqlTableModel组件应用
SqlTableModel 组件可以将数据库中的特定字段动态显示在TableView表格组件中,通常设置QSqlTableModel类的变量作为数据模型后就可以显示数据表内容,界面组件中则通过QDataWidgetMapper类实例设置为与某个数据库字段相关联,则可以实现自动显示字段的内容,不仅是显示,其还支持动态增删改查等各种复杂操作,期间不需要使用任何SQL语句。首先绘制好UI界面,本次案例界面稍显复杂,左侧是一个TableView组件,其他地方均为LineEdit组件与Button组件。先来生成数据库表记录,此处我们只需要增加一个Student学生表,并插入两条测试数据即可,运行以下代码完成数据创建。#include <iostream>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QtSql>
#include <QDataWidgetMapper>
QSqlDatabase DB; // 数据库连接
void MainWindow::InitSQL()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("./lyshark.db");
if (!db.open())
{
return;
}
// 执行SQL创建表
// https://Www.cnbloGs.com/lyshark
db.exec("DROP TABLE Student");
db.exec("CREATE TABLE Student ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name VARCHAR(40) NOT NULL, "
"sex VARCHAR(40) NOT NULL, "
"age INTEGER NOT NULL,"
"mobile VARCHAR(40) NOT NULL,"
"city VARCHAR(40) NOT NULL)"
);
// 逐条插入数据
db.exec("INSERT INTO Student(name,sex,age,mobile,city) ""VALUES ('lyshark.cnblogs.com','m','25','1234567890','beijing')");
db.exec("INSERT INTO Student(name,sex,age,mobile,city) ""VALUES ('www.lyshark.com','x','22','4567890987','shanghai')");
db.commit();
db.close();
}数据库创建后表内记录如下:程序运行后我们将在MainWindow::MainWindow(QWidget *parent)构造函数内完成数据库表记录与TableView组件字段的对应关系绑定,将数据库绑定到QDataWidgetMapper对象上,绑定代码如下。MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 打开数据库
DB=QSqlDatabase::addDatabase("QSQLITE"); // 添加 SQL LITE数据库驱动
DB.setDatabaseName("./lyshark.db"); // 设置数据库名称
if (!DB.open())
{
return;
}
// 打开数据表
tabModel=new QSqlTableModel(this,DB); // 数据表
tabModel->setTable("Student"); // 设置数据表
tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit); // 数据保存方式,OnManualSubmit , OnRowChange
tabModel->setSort(tabModel->fieldIndex("id"),Qt::AscendingOrder); // 排序
if (!(tabModel->select())) // 查询数据
{
return;
}
// 设置字段名称
tabModel->setHeaderData(tabModel->fieldIndex("id"),Qt::Horizontal,"Uid");
tabModel->setHeaderData(tabModel->fieldIndex("name"),Qt::Horizontal,"Uname");
tabModel->setHeaderData(tabModel->fieldIndex("sex"),Qt::Horizontal,"Usex");
tabModel->setHeaderData(tabModel->fieldIndex("age"),Qt::Horizontal,"Uage");
tabModel->setHeaderData(tabModel->fieldIndex("mobile"),Qt::Horizontal,"Umobile");
tabModel->setHeaderData(tabModel->fieldIndex("city"),Qt::Horizontal,"Ucity");
theSelection=new QItemSelectionModel(tabModel); // 关联选择模型
ui->tableView->setModel(tabModel); // 设置数据模型
ui->tableView->setSelectionModel(theSelection); // 设置选择模型
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); // 行选择模式
// 添加数据映射,将选中字段映射到指定编辑框中
// https://www.cnblogs.com/lysharK
dataMapper= new QDataWidgetMapper();
dataMapper->setModel(tabModel);
dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
dataMapper->addMapping(ui->lineEdit_name,tabModel->fieldIndex("name")); // 设置映射字段
dataMapper->addMapping(ui->lineEdit_mobile,tabModel->fieldIndex("mobile")); // 第二个映射字段
dataMapper->toFirst(); // 默认选中首条映射记录
// 绑定信号,当鼠标选择时,在底部编辑框中输出
connect(theSelection,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentRowChanged(QModelIndex,QModelIndex)));
getFieldNames();
}
MainWindow::~MainWindow()
{
delete ui;
}绑定成功后运行程序即可看到如下效果,数据库中的记录被映射到了组件内.当用户点击TableView组件内的某一行记录时,则触发MainWindow::on_currentRowChanged函数。执行获取name/mobile字段,并放入映射数据集中的 lineEdit编辑框中void MainWindow::on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
Q_UNUSED(previous);
dataMapper->setCurrentIndex(current.row()); // 更细数据映射的行号
int curRecNo=current.row(); // 获取行号
QSqlRecord curRec=tabModel->record(curRecNo); // 获取当前记录
QString uname = curRec.value("name").toString(); // 取出数据
QString mobile = curRec.value("mobile").toString();
ui->lineEdit_name->setText(uname); // 设置到编辑框
ui->lineEdit_mobile->setText(mobile);
}运行效果如下:增加插入与删除记录实现方法都是调用TabModel提供的默认函数,通过获取当前选中行号,并对该行号执行增删改查方法即可。// 新增一条记录
// https://www.cnblogS.com/lyshark
void MainWindow::on_pushButton_add_clicked()
{
tabModel->insertRow(tabModel->rowCount(),QModelIndex()); // 在末尾添加一个记录
QModelIndex curIndex=tabModel->index(tabModel->rowCount()-1,1); // 创建最后一行的ModelIndex
theSelection->clearSelection(); // 清空选择项
theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select); // 设置刚插入的行为当前选择行
int currow=curIndex.row(); // 获得当前行
tabModel->setData(tabModel->index(currow,0),1000+tabModel->rowCount()); // 自动生成编号
tabModel->setData(tabModel->index(currow,2),"M"); // 默认为男
tabModel->setData(tabModel->index(currow,3),"0"); // 默认年龄0
}
// 插入一条记录
void MainWindow::on_pushButton_insert_clicked()
{
QModelIndex curIndex=ui->tableView->currentIndex();
int currow=curIndex.row(); // 获得当前行
tabModel->insertRow(curIndex.row(),QModelIndex());
tabModel->setData(tabModel->index(currow,0),1000+tabModel->rowCount()); // 自动生成编号
theSelection->clearSelection(); // 清除已有选择
theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}
// 删除一条记录
void MainWindow::on_pushButton_delete_clicked()
{
QModelIndex curIndex=theSelection->currentIndex(); // 获取当前选择单元格的模型索引
tabModel->removeRow(curIndex.row()); // 删除最后一行
}
// 保存修改数据
void MainWindow::on_pushButton_save_clicked()
{
bool res=tabModel->submitAll();
if (!res)
{
std::cout << "save as ok" << std::endl;
}
}
// 恢复原始状态
void MainWindow::on_pushButton_reset_clicked()
{
tabModel->revertAll();
}增删改查实现如下:针对与排序与过滤的实现方式如下,同样是调用了标准函数。// 以Combox中的字段对目标 升序排列
void MainWindow::on_pushButton_ascending_clicked()
{
tabModel->setSort(ui->comboBox->currentIndex(),Qt::AscendingOrder);
tabModel->select();
}
// 以Combox中的字段对目标 降序排列
// https://www.Cnblogs.com/LyShark
void MainWindow::on_pushButton_descending_clicked()
{
tabModel->setSort(ui->comboBox->currentIndex(),Qt::DescendingOrder);
tabModel->select();
}
// 过滤出所有男记录
void MainWindow::on_pushButton_filter_man_clicked()
{
tabModel->setFilter(" sex = 'M' ");
}
// 恢复默认过滤器
void MainWindow::on_pushButton_default_clicked()
{
tabModel->setFilter("");
}过滤效果如下所示:批量修改某个字段,其实现原理是首先通过i<tabModel->rowCount()获取记录总行数,然后通过aRec.setValue设置指定字段数值,并最终tabModel->submitAll()提交到表格中。void MainWindow::on_pushButton_clicked()
{
if (tabModel->rowCount()==0)
return;
for (int i=0;i<tabModel->rowCount();i++)
{
QSqlRecord aRec=tabModel->record(i); // 获取当前记录
aRec.setValue("age",ui->lineEdit->text()); // 设置数据
tabModel->setRecord(i,aRec);
}
tabModel->submitAll(); // 提交修改
}循环修改实现效果如下:上方代码中,如果需要修改或增加特定行或记录我们只需要点击相应的按钮,并在选中行直接编辑即可实现向数据库中插入数据,而有时我们不希望通过在原表上操作,而是通过新建窗体并在窗体中完成增删改,此时就需要使用Dialog窗体并配合原生SQL语句来实现对记录的操作了。以增加为例,主窗体中直接弹出增加选项卡,并填写相关参数,直接提交即可。// https://www.cnblogs.com/LyShark
void MainWindow::on_pushButton_insert_clicked()
{
QSqlQuery query;
query.exec("select * from Student where id =-1"); // 查询字段信息,是否存在
QSqlRecord curRec=query.record(); // 获取当前记录,实际为空记录
curRec.setValue("id",qryModel->rowCount()+1001);
Dialog *WindowPtr=new Dialog(this);
Qt::WindowFlags flags=WindowPtr->windowFlags();
WindowPtr->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); // 设置对话框固定大小
WindowPtr->setInsertRecord(curRec); // 插入记录
int ret=WindowPtr->exec(); // 以模态方式显示对话框
if (ret==QDialog::Accepted) // OK键被按下
{
QSqlRecord recData=WindowPtr->getRecordData();
query.prepare("INSERT INTO Student(id,name,sex,age,mobile,city)"
" VALUES(:Id, :Name, :Sex, :Age, :Mobile, :City)");
query.bindValue(":Id",recData.value("id"));
query.bindValue(":Name",recData.value("name"));
query.bindValue(":Sex",recData.value("sex"));
query.bindValue(":Age",recData.value("age"));
query.bindValue(":Mobile",recData.value("mobile"));
query.bindValue(":City",recData.value("city"));
if (query.exec())
{
QString sqlStr=qryModel->query().executedQuery(); // 执行过的SELECT语句
qryModel->setQuery(sqlStr); // 重新查询数据
}
}
delete WindowPtr;
}Dialog增加效果如下:
4-2 ADO.NET-查询和检索数据7
u实验步骤(5):
用鼠标双击所有Button控件,进入.cs文件编辑状态准备进行开发。代码加下:
//==========执行主界面功能================
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public partial class Form10 : Form
{
public Form10()
{
InitializeComponent();
}
DataBase mydatabase = new DataBase();
/// <summary>
/// 添加
/// </summary>
private void button1_Click(object sender, EventArgs e)
{
int i=mydatabase.ExecuteSQL("insert into student(sno,sname,class) values("+textBox1.Text.Trim()+",'"+ textBox2.Text.Trim() +"','"+ textBox3.Text.Trim() +"')");
if (i > 1)
{
MessageBox.Show("成功插入","信息");
}
}
/// <summary>
/// 自定义方法:填充combox控件之中的内容
/// </summary>
private void fillcombox()
{
ArrayList al = mydatabase.GetListArray("select sno from student", 0);
foreach (int sno in al)
{
comboBox1.Items.Add(sno.ToString());
}
this.comboBox1.SelectedIndex = 0;
}
/// <summary>
/// 表单初始化事件:加载fillcombox()方法,以填充combox控件之中的内容
/// </summary>
private void Form10_Load(object sender, EventArgs e)
{
fillcombox();
}
}
}
4-2 DataGridView控件 — 显示和操作数据
在4-2节中我们主要学习并掌握了以下几个知识点,包括:
n在DataSet对象内表示的数据是数据库的部分或全部的断开式内存副本
nDataAdapter对象用来填充数据集和用来更新数据集到数据库,这样方便了数据库和数据集之间的交互
n类型化数据集对象是DataSet类的派生类的实例,这些类都基于XML结构
nDataTable表示一个内存数据表,而DataColumn表示DataTable中列的结构
nDataView是DataTable中存储的数据的表示层
nDataReader对象提供只进、只读和连接式数据访问,并使用专用的数据连接
nDataReader对象提供检索强类型化数据的方法
u
n了解DataGridView控件常见的属性和方法
n掌握DataGridView的数据绑定
n掌握在DataGridView控件中插入、更新和删除数据
n掌握定制DataGridView界面
4-3-1 DataGridView控件概述
1.为什么使用DataGridView
我们在实际项目研发中经常会遇到这样的问题:怎样高效的显示DataSet对象中的数据呢?DataSet对象中有若干数据表DataTable,每个DataTable对象中包含若干表示数据记录的DataRow对象。这种典型的二维结构表信息显然通过电子表格的形式呈现出来,数据显示的效果是最好的。
在前面章节里,应用程序显示DataSet对象中的数据是通过在窗体里每次显示一条记录的方式,即每次显示一个DataRow对象内容。这时由若干个控件分别显示DataRow对象的各个字段,但每次只能显示一条记录信息。如图4-50所示:
图4-50 显示单条记录的窗体图
但怎样才能把DataSet对象中某个数据表DataTable里的所有数据记录一并全部显示在一个窗体界面上呢?如图4-51所示:
图4-71 显示全部记录的窗体图
这里就用到DataGridView控件,仅仅一个DataGridView控件就可以显示数据表DataTable里的全部数据记录。DataGridView控件的工作示意如图4-52所示:
图4-52 DataGridView控件的工作示意图
从图4-52中可以看出,数据集DataSet中的某个数据表可以整个显示在某个窗体界面上,非常方便用户查看。由此可以看出DataGridView控件的强大方面,该控件的特点主要表现为:
n强大而灵活地显示数据
n轻松定义控件外观
n像Excel表格一样方便
n一行代码实现数据绑定
n可视化操作
2.DataGridView控件的简介
DataGridView是.NET 2.0中的一个新控件,是针对.NET 1.x中功能较差的标准DataGrid控件而设计的。有许多改进方面,包括:DataGridView支持大量自定义和细致的格式设置、灵活的大小调整和选择、更好的性能以及更丰富的事件模型。
DataGridView控件提供一种强大而灵活的以表格形式显示数据的方式。可以使用DataGridView控件来显示少量数据的只读视图,也可以对其进行缩放以显示特大数据集的可编辑视图。
可以用很多方式扩展DataGridView控件,以便将自定义行为内置在应用程序中。例如,可以采用编程方式指定自己的排序算法,以及创建自己的单元格类型。通过选择一些属性,可以轻松地自定义DataGridView控件的外观。可以将许多类型的数据存储区用作数据源,也可以在没有绑定数据源的情况下操作DataGridView控件。
在不使用DataGridView控件来显示数据情况下,一般使用多个可视组件来显示数据,过程示意如图4-53所示:
图4-53 多个可视组件显示记录数据工作示意图
这样有很多不便利的方面,主要表现为:
n没法同时对多个记录信息进行比较。
n需要配置多个可视组件,工作复杂。
n多个可视组件的数据绑定,操作编码工作量大。
n界面不容易规划美观。
n难以控制。
而VS .NET开发平台中的DataGridView控件成为有效数据使用者。DataGridView控件是 Winform中最通用、最强大和最灵活的数据控件。DataGridView控件的工作原理如图4-54所示:
图4-54 DataGridView控件的工作原理示意图
从图4-54中可以看出:DataGridView控件可以与数据集等数据源进行相互绑定。“数据绑定”是指将数据源的元素映射到图形界面组件,从而该组件可以自动使用这些数据。这个绑定过程可以在窗体设计阶段通过设置DataGridView控件的DataSource、DataMember等属性完成,也可以在程序中对其绑定编码直至运行时完成绑定。进行数据绑定的DataGridView控件与数据源有相同的数据列。程序运行后,数据源中被填充了数据,DataGridView控件就会立即显示数据源中的数据。此外,DataGridView控件还支持编辑功能,当某数据记录需要修改时,可以在DataGridView控件中直接修改数据,数据源中的数据也会得到相应的修改。
3.DataGridView控件的使用
(1)DataGridView控件的属性
DataGridView控件常用的属性请参见表4-28所示:
表4-28 DataGridView控件常用属性表
AllowUserToAddRows
获取或设置一个值,该值指示是否向用户显示添加行的选项。
AllowUserToDeleteRows
获取或设置一个值,该值指示是否允许用户从DataGridView中删除行。
AllowUserToOrderColumns
获取或设置一个值,该值指示是否允许通过手动对列重新定位。
AllowUserToResizeColumns
获取或设置一个值,该值指示用户是否可以调整列的大小。
AllowUserToResizeRows
获取或设置一个值,该值指示用户是否可以调整行的大小。
DataSource
获取或设置DataGridView所显示数据的数据源
Columns
获取一个包含控件中所有列的集合。
(未完待续)
本文转自 qianshao 51CTO博客,原文链接:http://blog.51cto.com/qianshao/216103,如需转载请自行联系原作者
Blend 3.0入门之SketchFlow详解(下)
接上一篇Blend 3.0入门之SketchFlow详解(上),因发布限制,所以分为两篇,不好意思啊:-)
你可以通过三种方式浏览各个页面a. 通过Navigate导航,下面的滑块控制页面大小。这个里面包含了很好的层次结构,当然,也包括并不直观的控件页嵌套b.通过Map导航右上角的是放大在右侧View中。c.最后一种当然就是通过你在程序中为各个控件设定的NavigateTo来导航了单击数据项可以跳转到DetailProducts页面,但是问题也来了为什么会是空白呢?这其实是数据绑定的问题,需要通过代码解决。但是客户可不是这么认为的,他要做出一些FeedBack(反馈)以提示你这边应该显示数据。Blend SketchFlow很好的考虑了这一点点击FEEDBACK ,选择画笔(有粗细两种),另外一个是Eraser(橡皮擦),选择某颜色,然后就像做批注一样有人问灯泡干嘛用的?是用来隐藏页面上批注的,注意是隐藏不是清除。
好的,现在客户审批完了,需要把反馈结果发送给项目部,所以我们要把结果导出,点击那个文件夹
当你的项目部门收到客户反馈后,必须把它导入到原有工程中,才能根据要求开会作出讨论并修改按加号导入反馈文件,点亮旁边的灯泡,看到如下图一切搞定,现在按客户要求作出整改,至于怎么修复Bug,有很多方法,这里简要介绍下将下面的代码<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Collection[0], Source={StaticResource SampleDataSource}}" > <local:Head Height="108" Margin="36,4,39,0" VerticalAlignment="Top" d:IsPrototypingComposition="True"/> <Grid Margin="51,123,37,89" Background="#FFD8DEF8" >替换修改下<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource SampleDataSource}}" > <local:Head Height="108" Margin="36,4,39,0" VerticalAlignment="Top" d:IsPrototypingComposition="True"/> <Grid Margin="51,123,37,89" Background="#FFD8DEF8" d:DataContext="{Binding Collection[0]}">将与Name属性绑定的TextBlock删除从控件库中拖动一个ComBox_Sketch到白板,注意不要拖进蓝色Grid区域中(此Grid被默认绑定到对象,不接受集合类型的控件然后拖动Data面板中的Name属性到ComBox,绑定完成。现在将其拖入区域中合适位置(此时是使用相对坐标,而不是层嵌套,所以Blend会提示你按下Alt键才能把元素嵌入Grid)。但现在还不能实现将选中项的数据对象绑定到各个控件。我们选择蓝色区域的Grid,更改其数据绑定点击右边的小正方形按钮,选择黄色DataBinding最后,打开项目面板中DetailProducts.xaml.cs文件,在页面初始化函数之后加上一句代码:public Screen_1_4(){ // Required to initialize variables InitializeComponent(); this.comboBox.Loaded +=(s,e)=>this.comboBox.SelectedIndex = 0;}
OK,再次运行我们的程序。点击我们的列表项后自动跳转到详细页,Ok,数据也自动绑定好了,带可以让用户自由选择。
关于更改样式先自己做个客户自定义样式,至于怎么做,请参考Blend 2 的相关教程,网上有很多,这里不详细介绍我的样式已经做好,是一个ButtonStyle在需要应用样式的按钮上右击Edit Template –> Apply Resource –> ButtonStyle 勾选。样式更改其实很简单,而且这样一来,逻辑架构设计和样式设计可以并行处理,从而真正的高效率地开发项目。最后一睹完整的页面
所有关于SketchFlow的介绍到此结束,若有遗漏或者疏忽,请多多交流。
作者 :双宇本文系原创文章,转载请注明出处,谢谢!
VC++中动态生成菜单技巧
下载源代码
一.前言 在实际运用中,经常需要根据操作来增减菜单和菜单项。在VC++开发环境下,动态生成菜单的方法有多种。例如:可以利用资源编辑器创建菜单资源,然后在程序运行中动态加入菜单,这种动态生成菜单的方法比较常见,运用比较多。用这种方法动态增加菜单时,首先需要在Resource.h中添加菜单ID;由于是动态生成的菜单选项,所以要实现它的功能就不能在ClassWizard中映射函数了,需要在头文件中手动添加消息函数原型,在代码文件中手动添加消息映射和添加消息响应函数。动态生成菜单的另一种方法,不能事先对每个菜单ID进行定义,比如从数据库中读出的每条记录内容动态添加为菜单项,菜单项的数量不是固定的,可以在动态添加菜单项时使菜单项的ID顺序递增;对菜单项的消息响应不能事先写出响应代码,而需要根据菜单ID动态响应函数。二.菜单相关知识2.1 常用菜单操作函数文中涉及到的VC++中常见的菜单只要操作如下:GetMenu() - 获得与框架窗口相链接的菜单。InsertMenu() – 在指定位置插入新的菜单项,其他的选项向下移。GetSubMenu() – 获得子菜单指针。GetMenuItemCount() – 得到菜单下的菜单项的个数。AppendMenu() – 添加一个新菜单。GetMenuString() – 获得指定菜单项的标记。DeleteMenu() – 删除菜单。2.2 菜单消息处理 Windows消息分为3类:标准Windows消息、命令消息、控件通知消息。标准消息指除WM_COMMAND之外,所以以WM_前缀开始的消息,包括键盘消息和窗口消息等;命令消息,指来自菜单、快捷键、工具栏按钮等用户界面对象发出的WM_COMMAND消息。其中,在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。控件通知消息,是对控件操作而引起的消息,是控件和子窗口向其父窗口发出的WM_COMMAND通知消息。菜单命令则属于命令消息,一个菜单命令可以映射到框架类、视图类或文档类的某一个成员函数,但不能同时映射到多个成员函数上。即使将一个菜单命令同时映射到多个不同的成员函数上,同时只有一个成员的映射是有效的。在MFC文档/视图结构中映射有效的优先级高低顺序为视图类、文档类、框架类。菜单消息一旦在其中一个类中响应则不再在其他类中查找响应函数。具体来说,菜单命令消息路由过程是这样的:当点击一个菜单项的时候,最先接受到菜单项消息的是CMainFrame框架类,CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行处理;如果View类检测到没对该菜单项消息做响应,则View类把菜单项消息交由文档类Doc类进行处理;如果Doc类检测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给View类,由View类再交还给CMainFrame类处理。如果CMainFrame类查看到CMainFrame类中也没对该消息做响应,则最终交给App类进行处理。而且一个消息一旦在某个类中被响应过,则不再接着传递。三.编程实例3.1 菜单实例工程(1)新建工程 VC++中新建工程DynamicMenu:第一步选择“单文档“,接下来几步不用修改使用默认设置,到最后一步将Base class下拉菜单选”CFormView“,即建立基于FormView的MFC运用程序。本项目中3.3节以动态创建控件为例,而视图中FormView可以放置控件,因此选FormView。(2)创建菜单资源 在Resource中Menu下的菜单中,添加菜单“动态菜单示例“,下设两个菜单项,分别是”添加例一菜单““添加例二菜单”如图1所示。ID分别为ID_FIRSTMENU和ID_SECMENU。点击这两个菜单项,通过两种方式动态添加两个菜单。仅添加了菜单,并没有实现菜单的功能,即没有对应的命令处理函数与菜单项对应,因此,添加的菜单项是灰色的,即为当前不可用状态。添加新菜单项后,还应该为新的菜单项指定一个消息响应函数。 图一 新建两个菜单项
通过MFC ClassWizard在View下为两菜单项添加消息响应函数,ID_FIRSTMENU的响应函数为void CDynamicMenuView::OnFirstMenu(),ID_SECMENU的响应函数为void CDynamicMenuView::OnSecmenu()。 3.2 动态添加菜单 本例适用于菜单项名称、数量事先固定,仅在需要时将事先定义好的菜单动态添加到主菜单中,不需要时删除即可。响应函数需要通过手动添加的,更改菜单项时需要重新修改代码。 本例功能:通过点击上述DynamicMenu工程中的菜单“动态菜单示例”下的“添加例一菜单”,添加新的动态菜单“动态菜单一“,点击其下的菜单项”First1“即进行菜单响应,弹出提示框,菜单项”First2“未定义消息响应则不可,如图2所示。 图2 运行界面主要编程步骤:建立菜单资源,手动加入菜单ID、消息映射、消息响应函数。实现步骤:(1)在以上DynamicMenu工程中的Resource.h中添加要生成的菜单ID,如:
#define ID_FIRST1 32733 //手动加入的菜单ID_FIRST1
#define ID_FIRST2 32734 //手动加入的菜单ID_FIRST2
(2)在MainFrm.h中手动添加命令响应函数原型。Protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//NOTE – the ClassWizard will add and remove member functions here.
//DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
Afx_msg void OnFIRST1();//手动添加的消息响应函数宏
DECLARE_MESSAGE_MAP()
(3)手动添加消息映射,在MainFrm.cpp用ON_COMMAND宏关联消息响应函数BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
//DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_COMMAND(ID_FIRST1,OnFIRST1)//手动添加IDM_HELLO到函数OnHello的映
END_MESSAGE_MAP()
(4)新增菜单,添加的菜单项往往是灰色的,不可用,只有为此菜单项定义有相信的响应函数才会可用。为ID_FIRST1菜单项定义了消息响应函数,则菜单项为可用。没有为ID_FIRST2定义消息响应函数,则定义的菜单色为灰色。在MainFrm.cpp中手动编写消息响应函数如下:void CMainFrame::OnFIRST1()
{
MessageBox(“动态菜单示例1!”);
}
(5)点击”动态菜单示例“下的”添加例一菜单“时,在菜单末尾添加”动态菜单一“。通过MFC ClassWizard在CDynamicMenuView下为菜单项ID_FIRSTMENU添加消息响应函数如下:void CDynamicMenuView::OnFirstmenu()
{
// TODO: Add your command handler code here
CMenu menu;
menu.CreatePopupMenu(); //创建空菜单
GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"动态菜单一"); //把菜单添加到现有菜单末尾
menu.AppendMenu(MF_STRING|MF_ENABLED,ID_FIRST1,"First1");
menu.AppendMenu(MF_STRING|MF_ENABLED,ID_FIRST2,"First2");
menu.Detach();
GetParent()->DrawMenuBar(); //重绘菜单
}
3.3 将数据库中读出的记录动态添加为菜单项 本列适用于菜单项数量和菜单项显示名称事先不固定的场合,这需将菜单项写入数据库,对数据库内容进行更新维护即可。在需要时读取数据库中记录,动态添加为菜单项。本列功能:通过点击上述DynamicMenu工程中的菜单“动态菜单示例“下的”添加例二菜单“,即在菜单末尾添加新的动态菜单”动态菜单二“,其中的菜单项由数据库中读出记录内容添加而成,点击各菜单项即进行菜单响应,如图3. 图三 运行界面
点击新添加的菜单项,根据菜单项的名称和当前数据库中的记录内容,动态建立控件。如菜单项名为“文本框“,数据库中当前记录中类型字段contype为”文本“,当点击该菜单项时在程序运行界面中动态建立一文本框。如为”下拉框“,数据库中当前记录中类型字段contype为”选择“,点击该菜单项时在程序运行界面中动态建立一下拉框。编程步骤:建立数据库,其中的记录即为菜单二的菜单项;动态添加菜单项时使菜单项的ID顺序递增;菜单项数据量不固定,对每个菜单项的消息响应也不能事先写出响应代码,需要动态响应函数,因此根据菜单ID并结合数据库记录内容在菜单项响应函数中进行功能分类并响应。实现步骤:(1)建立Access数据库menu,表名dynamicmenu,表中设两个字段分别是myname、contype,字段类型均为“文本“。表中添加两条记录:文本框,文本;下拉框,选择,如图4所示。以下根据contype的值动态建立控件,并将myname值作为控件中显示内容。 图4 表结构与数据(2) 在dynamicmenu工程中连接数据库。在DynamicMenu.cpp文件的InitInstance()中添加如下连接代码: BOOL CDynamicMenuApp::InitInstance()
{
…
m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=menu.mdb","","",adModeUnknown);
…
}
(3)在CDynamicMenuView中设置全局变量flag作为判断是否添加了“示例菜单二“的标志,并在CDynamicMenuView的构造函数中设置初值为false,代码如下:CDynamicMenuView::CDynamicMenuView()
: CFormView(CDynamicMenuView::IDD)
{
//{{AFX_DATA_INIT(CDynamicMenuView)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// TODO: add construction code here
flag=false;
}
(4)点击菜单项“添加例二菜单“时,从数据库中读取记录,添加为动态菜单项,菜单添加成功后将flag置为true,便于在菜单响应时进行判断。通过MFC ClassWizard在CDynamicMenuView下为菜单ID_SECMENU添加消息响应函数如下:void CDynamicMenuView::OnSecmenu()//读取数据库中的记录,添加动态菜单项
{
CMenu menu;
menu.CreatePopupMenu(); //创建空菜单
GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"动态菜单二"); //把菜单添加到现有菜单末尾
int j=8999;
_RecordsetPtr m_pRecordset;
m_pRecordset.CreateInstance(__uuidof(Recordset));
try
{
m_pRecordset->Open("SELECT * FROM DynamicMenu",// 查询DemoTable表中所有字段
m_pConnection.GetInterfacePtr(), // 获取库接库的IDispatch指针
adOpenDynamic,
adLockOptimistic,
adCmdText);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
if(!m_pRecordset->BOF)
m_pRecordset->MoveFirst();
else
{
AfxMessageBox("没有记录!!");
return;
}
//读取记录,添加为菜单项
m_pRecordset->MoveFirst();
while(!m_pRecordset->adoEOF)
{
j=j+1;//菜单项ID递增
_variant_t var;
var=m_pRecordset->GetCollect("myname");//读取记录值
CString str=vtos(var);
//添加为菜单项
menu.AppendMenu(MF_STRING| MF_ENABLED | MF_CHECKED,j,str);
m_pRecordset->MoveNext();
}
menu.Detach();
GetParent()->DrawMenuBar();
flag=true;//菜单添加完毕,设置菜单项添加标志,便于在菜单消息响应中判断
}
(5)添加菜单项消息响应函数。 MFC确定一个Command ID 是否有Handler与之对应是通过OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO* pHandlerInfo),然后根据返回值来确定的。返回值为true,表示有对应的处理函数;返回值为false,表示没有。其中参数nID就是发送过来的消息ID号,对于菜单,就是菜单的ID;参数nCode为0表示是命令消息,如单击菜单项发出的消息,为-1就表示是UPDATE_COMMAND_UI消息;参数pHandleInfo不为NULL时,表示在检测;当其为NULL时表示是在路由这个命令消息,希望能得到处理。重载了CDynamicMenuView的OnCmdMsg()函数,因为要在CDynamicMenuView中处理这些动态添加的菜单项。通过calss wizard,为CDynamicMenuView添加消息响应函数OnCmdMsg,添加代码如下:BOOL CDynamicMenuView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// TODO: Add your specialized code here and/or call the base class
if(flag)//判读是否添加“示例菜单二“
{
//得到“示例菜单二“的菜单项总个数
int n = GetParent()->GetMenu()->GetSubMenu(6)->GetMenuItemCount() - 1;
if (0 == nCode)//判断是否是命令消息
{
//判断当前单击的菜单ID是否在动态菜单项的范围之内
if (GetParent()->GetMenu()->GetSubMenu(6)->GetMenuItemID(0) <= nID
&& nID<=GetParent()->GetMenu()->GetSubMenu(6)->GetMenuItemID(n))
{
if (pHandlerInfo==NULL )
{
CString strMenuName; //菜单项名
GetParent()->GetMenu()->GetMenuString(nID,strMenuName,MF_STRING);//根据ID得到菜单项名
Handler(strMenuName);
}
return true;
}
}
}
return CFormView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
其中Handler(strMenuName)是用户自定义的菜单项单击的响应代码,参数为当前点击的菜单项的名称,根据菜单项动态建立控件,主要代码如下:void CDynamicMenuView::Handler(CString strMenuName)
{
_RecordsetPtr m_pSet2;
m_pSet2.CreateInstance(__uuidof(Recordset));
CString strsql2="SELECT * FROM DynamicMenu WHERE myname='";
strsql2=strsql2+strMenuName+"'";
if(m_pSet2!=NULL)
{
if(m_pSet2->State)
m_pSet2->Close();
m_pSet2= NULL;
}
m_pSet2.CreateInstance(__uuidof(Recordset));
try
{
m_pSet2->Open((_bstr_t)strsql2, // 查询DemoTable表中所有字段
m_pConnection.GetInterfacePtr(), // 获取库接库的IDispatch指针
adOpenDynamic,adLockOptimistic,adCmdText);
}
catch(_com_error e)
{
AfxMessageBox("对象数据库操作失败!!");
//return NULL;
}
if(!m_pSet2->BOF)
m_pSet2->MoveFirst();
else
{
MessageBox(strMenuName);
AfxMessageBox("没有符合条件的关联对象记录!!");
//return NULL;
}
CString ctype=vtos(m_pSet2->GetCollect("contype"));
m_pSet2->Close();
if(ctype=="选择")
{
CDC *pDC=GetDC();
combox= new CComboBox;
combox->Create(WS_CHILD|WS_VISIBLE| CBS_DROPDOWN,CRect((260),(80),(330),(100)), this, 1999);
combox->SetWindowText(strMenuName);
}
else if (ctype=="文本")
{
CDC *pDC=GetDC();
number= new CEdit;
number->Create(WS_VISIBLE| WS_CHILD | WS_BORDER , CRect((260),(40),(330),(60)), this, 2000);
//number->MoveWindow((30),(80),(70),(20));
//number->ShowWindow(SW_SHOW);
number->SetWindowText(strMenuName);
}
}
四.小结 通过两个实例在VC++6.0中实现动态生成菜单,3.2小节适用于需要添加的菜单项比较固定,需要预先建立菜单项ID,响应函数事先确定并进行手动添加,修改时涉及代码。3.3小节适用于菜单项数量和菜单项显示名称不固定、经常变化的场合,只需将菜单项写入数据库,对数据库内容进行更新维护,免去了一般菜单资源更改时对应用程序代码重新编辑的繁琐。
DataGridView删除多行选中数据
思路是找到最先选择和最后选择到的行 ,弄一个for循环,根据这些行的索引值在执行数据的删除.
我这里用了EF.
DialogResult result = MessageBox.Show("确定删除吗?", "删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
//选中第一行的索引
var first = dataGridView1.Rows.GetFirstRow(DataGridViewElementStates.Selected);
//选中最后一行的索引
var end = dataGridView1.Rows.GetLastRow(DataGridViewElementStates.Selected);
for (int i = first; i <= end; i++)
{
int p_id = int.Parse(this.dataGridView1.Rows[i].Cells["u_id"].Value.ToString());
//1.0 EF 推荐删除方式 - 先查,再删
userinfo gf = db.userinfo.Where(u => u.u_id == p_id).FirstOrDefault();
//1.2 将实体对象删除(就是将 容器中的 代理对象的 State改成 Deleted)
db.userinfo.Remove(gf);
}
//1.3 将EF容器里所有的对象 根据 State 属性值,生成不同sql语句,更新到数据库
db.SaveChanges();
MessageBox.Show("OK");
}
else
{
return;
}
PS:DataGridView里的列有combox的话是不让你FullRowSelect=true的,这时候 if(DataGridView.FullRowSelect=false)
{
switch(操作方法)
{
case"点那个DataGridView中的行标题的列":
return正常的起始和终止索引值
break;
case"": return有问题的起始和终止索引值 --都是-1 break;
}
}
然后今晚博客的编辑器好像抽风了,希望更新维护之后能换个好点的编辑器吧.
基于Java的学生信息管理系统
系统使用技术:Servlet前端技术:EasyUI,js,css,+Ajax等开发工具:eclipse数据库:mysql5.7项目介绍:该系统采用java语言,servlet开发,mysql数据库,具有完整的业务逻辑。系统分为三个角色,功能包含:学生信息维护、班级、教师维护、课程维护、选课信息维护、考勤管理、请假审批、成绩维护及统计等。部分功能展示:下面我们来看看管理员部分相关功能,其他角色由于文章篇幅不在截取。系统登录:首页欢迎页面学生列表查看所有学生信息,并且可以进行维护班级列表查看所有班级信息,并且可以进行维护教师信息对教师信息维护课程列表添加维护课程,指定课程教师等选课学生可以选择对于课程考勤对于学生的考勤进行统计维护学生请假请假信息的审核成绩统计查看某一个课程的成绩区间统计平均分统计查看某一个课程的平均分统计信息修改密码可以修改个人的密码 部分代码:private void editCourse(HttpServletRequest request,
HttpServletResponse response) {
// TODO Auto-generated method stub
String name = request.getParameter("name");
int teacherId = Integer.parseInt(request.getParameter("teacherid").toString());
int maxNum = Integer.parseInt(request.getParameter("maxnum").toString());
int id = Integer.parseInt(request.getParameter("id").toString());
String courseDate = request.getParameter("courseDate");
String info = request.getParameter("info");
Course course = new Course();
course.setId(id);
course.setName(name);
course.setTeacherId(teacherId);
course.setInfo(info);
course.setCourseDate(courseDate);
course.setMaxNum(maxNum);
CourseDao courseDao = new CourseDao();
String msg = "error";
if(courseDao.editCourse(course)){
msg = "success";
}
try {
response.getWriter().write(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
courseDao.closeCon();
}
}
private void getCourseList(HttpServletRequest request,
HttpServletResponse response) {
// TODO Auto-generated method stub
String name = request.getParameter("name");
int teacherId = request.getParameter("teacherid") == null ? 0 : Integer.parseInt(request.getParameter("teacherid").toString());
Integer currentPage = request.getParameter("page") == null ? 1 : Integer.parseInt(request.getParameter("page"));
Integer pageSize = request.getParameter("rows") == null ? 999 : Integer.parseInt(request.getParameter("rows"));
Course course = new Course();
course.setName(name);
course.setTeacherId(teacherId);
CourseDao courseDao = new CourseDao();
List<Course> courseList = courseDao.getCourseList(course, new Page(currentPage, pageSize));
int total = courseDao.getCourseListTotal(course);
courseDao.closeCon();
response.setCharacterEncoding("UTF-8");
Map<String, Object> ret = new HashMap<String, Object>();
ret.put("total", total);
ret.put("rows", courseList);
try {
String from = request.getParameter("from");
if("combox".equals(from)){
response.getWriter().write(JSONArray.fromObject(courseList).toString());
}else{
response.getWriter().write(JSONObject.fromObject(ret).toString());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}以上就是部分功能展示,从整体上来看,本系统功能是十分完整的,界面设计简洁大方,交互友好,数据库设计也很合理,规模适中,比较适合毕业设计和课程设计的相关应用。