精华内容
下载资源
问答
  • Wassup是使用socket.io和JavaScript的实时聊天应用程序 安装 下载或克隆后,运行npm install安装所有依赖项。 :folded_hands: 如果您认为此回购很有用,请别忘了开始 :sparkle: 到此存储库。 :)
  • AngryBirdsStage2.5 《愤怒的小鸟》第2.5阶段具有类继承和图像
  • WordPress的WassUp实时分析 贡献者:michelem,helened捐赠链接: 标签:分析,计数器,在线,seo,统计信息,统计信息,跟踪器,流量,趋势,用户,访问者,网络至少需要:WordPress 2.2经过测试:5.3.2需要...
  • PoP网站:Wassup 安装 通过作曲家 composer require pop-sites-wassup/wassup 发展 源代码托管在 。 用法 初始化组件: \ PoP \ Root \ AppLoader :: addComponentClassesToInitialize ([ \ PoPSitesWassup \ ...
  • wassup-源码

    2021-03-27 03:16:35
    浪费
  • Wassup聊天 我从这个存储库中克隆了这个: : 现在在Heroku上运行
  • 这允许远程攻击者通过注入任意sql代码控制sql查询。

    这允许远程攻击者通过注入任意sql代码控制sql查询。

    展开全文
  • 语言X 一种自定义为JavaScript的语言,用于学习...>>> fun wassup(a b) = { ... let c = a + b + magic ... ... return c ... } undefined >>> main wassup(3, 5) 50 程序 程序可以有一个main声明作为其入口点: ma
  • slug ( 'yo wassup' , function ( error , result ) { error // => undefined result // => yo-wassup } ) ; 如果您的服务器为yo-wassup返回 false 值,则将返回以下选项中的第一个可用值; yo-wassup-new yo...
  • Supverse-crx插件

    2021-04-03 10:29:32
    Supverse是WasSup的UniVerse,它使您可以在整个Internet的任何页面上创建临时讨论。 讨论可以只是给自己的笔记,也可以是与他人进行的激烈辩论。 使用Supverse个人资料上的个人主题标签来组织所有这些页面和评论,...
  • wassup书呆子 :vulcan_salute: 我是后端开发人员和FOSS热心者。 当我了解了for循环的工作原理时,我对编程产生了兴趣 :face_with_open_mouth: 从2015年开始,我对CS产生了兴趣,从此再也没有回头。 现在,我以该...
  • wassup 和 passwd 以及您对 public(feed) 的可见性。 邀请朋友 在Me部分,用户可以生成好友代码成为其他用户的好友。 一旦用户单击生成按钮,就会设置一个uuid代码并且可以共享。 此外,一旦其他用户填写了代码,它...
  • Sniper 3D Mod Apk-crx插件

    2021-04-03 16:20:03
    狙击手3d mod apk v3.8.6下载2020 Hello Guys Wassup,今天我会告诉你关于Sniper 3D Mod APK下载,这是一个游戏娱乐和人民额外播放狙击手3D Mod APK 2020的运动。这场比赛是一个去射击并杀死一些人民到这个娱乐狙击...
  • MySQL详细基础语法2

    2021-04-19 04:02:25
    GROUP BYGROUP BY即分组 主要作用是把一个集合中根据group by后面的关键字进行分组,里面包含2个计算去掉重复值(参考丁奇文章)当没有索引时,根据group by后面的列,在内存中创建一个对应列为pk的临时表。...

    GROUP BY

    GROUP BY即分组 主要作用是把一个集合中根据group by后面的关键字进行分组,里面包含2个计算

    去掉重复值(参考丁奇文章)

    当没有索引时,根据group by后面的列,在内存中创建一个对应列为pk的临时表。对数据集进行遍历,没有则插入临时表,有则对对应的聚合函数列进行比较和更新,使最终结果中没有重复值

    有索引时,直接使用索引,只需要一个计数器,对索引列进行更新,不需要维护临时表。

    所以对group by进行优化的方式之一就是对group by后面的列添加索引,减少临时表(use tempfile)的产生和维护

    减少use tempfile的两种方式

    Loose Index Scan索引跳跃式扫描

    要实现跳跃式扫描要满足如下条件

    联合索引的前列选择率要低且必须在索引中,group by依次按照索引顺序,且select列中只有索引的左边的一部分且不能回表

    例如如下表结构和执行计划

    CREATE TABLE `t_group6` (

    `emp_no` int(11) NOT NULL,

    `dept_no` char(4) NOT NULL,

    `from_date` date NOT NULL,

    `to_date` date NOT NULL,

    KEY `ix_empno_to_date` (`dept_no`,`to_date`,`emp_no`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    按照索引顺序的语句执行计划如下

    bdd47c084552

    group1.png

    但不按照索引顺序的时候则没有优化效果

    bdd47c084552

    group2.png

    2. 前导列是关键

    Tight Index Scan

    range scan或者index scan

    创建索引的时候必须按照where条件中的等号字段再加上group后面的列的顺序来创建

    bdd47c084552

    group3.png

    进行排序(5.5~5.7),8.0开始不在对group by后面的关键字进行排序

    group by的排序方式,字符类型是按照ascii码从左到右进行排序的。当含有空和null时 NULL在前空在后

    相关参数

    5.7 tmp_table_size,max_heap_table_size

    group by分为完全模式和不完全模式

    开启完全group by形式之后 select后面的字段中不能出现非聚合函数包裹的字段否则会报错

    通过set session sql_mode = ' '; 这个配置来控制

    并且不完全group模式会随着执行计划不同导致结果不同

    例如有如下的表,索引情况和数据如下

    bdd47c084552

    group4.png

    当使用ix_torder_2索引时,执行结果如下

    bdd47c084552

    group5.png

    当时用ix_torder_3索引时,执行结果就改变了

    bdd47c084552

    group6.png

    DISTINCT

    和group by一样,可以去掉重复值。区别在于distinct不排序。

    在内存中创建一个对应列为pk的临时表。对数据集进行遍历,没有则插入临时表,有则违反uk约束

    从执行计划上也能看出distinct和group by的区别

    bdd47c084552

    group.png

    order by

    order by后面可以写数字表示列名,如下例子中1表示emp_no

    bdd47c084552

    order.png

    order by有两种排序方式

    single pass

    原理:一次性把sql中涉及的字段全部多出来,然后依据排序字段排序,最后直接返回结果。

    优点:只需要一次顺序I/O,无需任何随机I/O,大大降低I/O开销

    缺点:内存容不下大量数据时,可能会先放到磁盘上对数据切分,对小数据块逐个排序,然后将结果集merge,在返回结果集

    例子如下,下图为数据库排序相关数据记录,sort_merge_passes为0,一般表示执行了一次排序

    bdd47c084552

    order1.png

    执行语句如下

    SELECT emp_no,first_name,last_name FROM employees ORDER BY first_name LIMIT 100;

    执行后的数据纪录如下

    bdd47c084552

    order2.png

    执行计划如下

    bdd47c084552

    order3.png

    简单的说就是把emp_no,first_name,last_name全部装到sort_buffer中排序

    SQL单次排序效率与order by后面的字段以及select后面的字段都有关系,主要优化点在于减少数据集面积。所以查询的时候一般不要用*

    two pass

    原理:先读取行指针和排序字段进行排序,然后依据排序结果在读取所需数据

    优点:排序数据量小,完全可以在内存中完成

    缺点:第二次读取时,会发生大量随机I/O,太昂贵

    two pass有两个要求

    排序的列的值要大于max_length_for_sort_data

    select列当中包含blob或者text的值

    实例如下,下图为排序语句执行前的数据库记录

    bdd47c084552

    order1.png

    执行语句如下

    SELECT SQL_NO_CACHE COUNT(1) FROM (

    SELECT * FROM t11 IGNORE INDEX (PRIMARY) ORDER BY c10 DESC LIMIT 10000

    ) a;

    执行语句后,服务器记录如下

    bdd47c084552

    order4.png

    sort_merge_pass超过sort buffer大小时 排序数据就会写入temp file中 temp file合并的次数 数据的大小都和sort_buffer_size有直接关系

    order by limit有重复列的情况

    如下表,其中ID不是primary key

    bdd47c084552

    order5.png

    三个问题

    当只有8条数据记录的时候,用create_time排序分页会有数据重复和丢失的问题,而用age则没有出现,age也有重复值

    运行SQL如下

    SELECT * FROM test ORDER BY create_time LIMIT 0,4;

    SELECT * FROM test ORDER BY create_time LIMIT 4,4;

    运行结果如下

    bdd47c084552

    order6.png

    如图所示,id=8的数据重复,$\color{red}{原因是create_time重复,MySQL再回表查询剩余数据的时候,只要找到符合当前create_time的数据即可,所以造成了数据重复}$

    当增加了4条记录后,用create_time排序分页没有问题,而使用age排序会出现数据重复或者丢失,age的重复值没有create_time多

    给排序列加索引对这个问题没有帮助

    math?formula=%5Ccolor%7Bred%7D%7B(%E5%85%B7%E4%BD%93%E8%AF%B4%E6%98%8E%E8%A7%81http%3A%2F%2Fmysql.taobao.org%2Fmonthly%2F2015%2F06%2F04%2F)%7D

    解决方法

    加入id列作为二级排序列

    切换innodb引擎,对create_time列添加索引

    创建内部视图,使用distinct关键字阻止视图合并

    语句如下

    SELECT * FROM (SELECT DISTINCT t.* FROM test t ORDER BY create_time) a LIMIT 0,4;

    COUNT

    count不计算NULL,在不影响业务的情况下可以使用count(1)或者count(*)。但是由于count是不计算NULL的,所以最好使用非空并且not null的列进行统计,如自增的primary key

    count优化的例子

    有如下的两条SQL

    1. SELECT COUNT(fid=6 AND displayorder >= 0) AS posts FROM cdb_threads;

    2. SELECT COUNT(fid) AS threads FROM cdb_threads WHERE fid=6 AND displayorder >= 0;

    上面两条SQL对比,2要比1效率高,主要原因在于count的调用次数。假设当前表没有任何索引,查询fid=6并且displayorder >= 0的数据都需要全表扫描,效果相同。如果结果集数据为100条,2只需要对结果集进行一次count,但是1在整个过程中要进行100次count,显然1的效率更低

    原语句如下

    SELECT COUNT(emp_no IS NULL) AS c1 FROM t_order;

    优化语句如下

    1. SELECT COUNT(*) c1 FROM t_order WHERE emp_no IS NULL;

    2. SELECT COUNT(case when emp_no is null then 1 end) c1 FROM t_order;

    如上两个SQL 2相对1来说,效率会低。原因是行数不同。1会根据条件进行过滤,然后count统计实际的数据量。2则是全表扫描,会产生大量I/O

    MIN/MAX

    min和max可以求出数据列的最大最小值,但是不包含null

    min/max使用例子

    查看employess表中是否存在emp_no=1000111,存在返回1不存在返回0。直接使用case加where不能满足,如图

    bdd47c084552

    max.png

    根据图片我们可以发现,直接使用case加where有值返回1,但是没值不会返回0。我们可以使用max或者min解决上面的问题,如图

    bdd47c084552

    max1.png

    max/min在没有值返回的时候,会返回NULL,可以使用这个特性解决问题

    实际优化案例

    有如下语句,运行时间超过5s

    SELECT t.systen_phone AS plattorm, t.platform_name AS channel,

    COALESCE(

    sum(case

    when t.is_success='T' and t.create_time >= '2018-04-24' and t.create_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as applytotal ,

    COALESCE(

    sum(case

    when is_påss='T' and tcl.is_refuse = 'F' and t.create_time >= '2018-04-24' and t.create_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as tpasscount,

    COALESCE(

    sum(case

    when (status >= 40 or status = -40) and yrd_time IS NOT NULL and t.yrd_time >= '2018-04-24' and t.yrd_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as transportnum,

    COALESCE(

    sum(case

    when (status >= 40 or status = -40)and yrd_time IS NOT NULL and t.yrd_time >= '2018-04-24' and t.yrd_time <= '2018-04-24 23:59:59'

    then t.apply_amount/10000 else 0 end

    )

    ,0) as transportamount,

    COALESCE(

    sum(

    case

    when audit_time IS NOT NULL and t.audit_time >= '2018-04-24' and t.audit_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as cponum,

    COALESCE(

    sum(

    case

    when (status !=50 ) and audit_time IS NOT NULL and t.audit_time >= '2018-04-24' and t.audit_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as cpopassnum,

    COALESCE(

    sum(

    case when (status !=50 ) and audit_time IS NOT NULL and t.audit_time >= '2018-04-24' and t.audit_time <= '2018-04-24 23:59:59'

    then t.apply_amount/10000 else 0 end

    )

    ,0) as cpopassamount,

    COALESCE(

    sum(

    case

    when (status = 90 or status = 80 or status = 60) and tc.contractamount is not NULL and t.loan_date >= '2018-04-24' and t.loan_date <= '2018-04-24 23:59:59'

    then tc.contractamount/10000

    when (status = 90 or status = 80 or status = 60 ) and tc.contractamount is NULL and t.loan_date >= '2018-04-24' and t.loan_date <= '2018-04-24 23:59:59'

    then t.applt_amount/10000 else 0 end

    )

    ,0) as contractamount,

    COALESCE(

    sum(

    case when (status = 90 or status = 80 or status = 60) and t.loan_date >= '2018-04-24' and t.loan_date <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as closenum

    FROM tb_cbm_transport_yrd AS t

    LEFT JOIN tb_cbm_transport_result tc ON t.id = tc.transport_id

    LEFT JOIN tb_cbm_1imit tcl ON t.limit_id = tcl.limit_id

    WHERE t.tools_platorm_code = 'uxWap'

    GROUP BY left(t.system_phone,1);

    执行计划如下图

    bdd47c084552

    max2.png

    查询效率低的主要是原因是where条件提前,造成全表扫描,I/O较大,优化思路就是where条件优化,提取公共部分,并且创建索引

    优化后语句如下,优化后时间为0.07s。可以看出优化的主要位置是将where提取出来

    SELECT t.systen_phone AS plattorm, t.platform_name AS channel,

    COALESCE(

    sum(case

    when t.is_success='T' and t.create_time >= '2018-04-24' and t.create_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as applytotal ,

    COALESCE(

    sum(case

    when is_påss='T' and tcl.is_refuse = 'F' and t.create_time >= '2018-04-24' and t.create_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as tpasscount,

    COALESCE(

    sum(case

    when (status >= 40 or status = -40) and yrd_time IS NOT NULL and t.yrd_time >= '2018-04-24' and t.yrd_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as transportnum,

    COALESCE(

    sum(case

    when (status >= 40 or status = -40)and yrd_time IS NOT NULL and t.yrd_time >= '2018-04-24' and t.yrd_time <= '2018-04-24 23:59:59'

    then t.apply_amount/10000 else 0 end

    )

    ,0) as transportamount,

    COALESCE(

    sum(case

    when audit_time IS NOT NULL and t.audit_time >= '2018-04-24' and t.audit_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as cponum,

    COALESCE(

    sum(case

    when (status !=50 ) and audit_time IS NOT NULL and t.audit_time >= '2018-04-24' and t.audit_time <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as cpopassnum,

    COALESCE(

    sum(case

    when (status !=50 ) and audit_time IS NOT NULL and t.audit_time >= '2018-04-24' and t.audit_time <= '2018-04-24 23:59:59'

    then t.apply_amount/10000 else 0 end

    )

    ,0) as cpopassamount,

    COALESCE(

    sum(case

    when (status = 90 or status = 80 or status = 60) and tc.contractamount is not NULL and t.loan_date >= '2018-04-24' and t.loan_date <= '2018-04-24 23:59:59'

    then tc.contractamount/10000

    when (status = 90 or status = 80 or status = 60 ) and tc.contractamount is NULL and t.loan_date >= '2016-04-24' and t.loan_date <= '2018-04-24 23:59:59'

    then t.applt_amount/10000 else 0 end

    )

    ,0) as contractamount,

    COALESCE(

    sum(case

    when (status = 90 or status = 80 or status = 60) and t.loan_date >= '2018-04-24' and t.loan_date <= '2018-04-24 23:59:59'

    then 1 else 0 end

    )

    ,0) as closenum

    FROM(

    SELECT ifnull(max(t.system_phone) , 'androld') system_phone,

    ifnull(max(t.platform_name),'YRD_APP') platform_name,

    t.is_success, t.create_time ,t.is_påss,t.status,t.yrd_time,

    t.apply_amount, t.audit_time, t.loan_date,t.id ,t.limit_id

    FROM

    tb_cbm_transport_yrd AS t

    where t.tools_platorm_code = 'uxWap'

    and e.system_phone = 'android'

    and t.create_time >= '2018-04-24' and t.create_time <= '2018-04-24 23:59:59'

    and (

    (t.create_time >= '2018-04-24' and t.create_time <= '2018-04-24 23:59:59')

    or (t.yrd_time >= '2018-04-24' and t.yrd_time <= '2018-04-24 23:59:59')

    or (t.audit_time >= '2018-04-24' and t.audit_time <= '2018-04-24 23:59:59')

    or (t.loan_date >= '2018-04-24' and t.loan_date <= '2018-04-24 23:59:59')

    )

    union all

    SELECT ifnull(max(t.system_phone) , 'androld') system_phone,

    ifnull(max(t.platform_name),'YRD_APP') platform_name,

    t.is_success, t.create_time ,t.is_påss,t.status,t.yrd_time,

    t.apply_amount, t.audit_time, t.loan_date,t.id ,t.limit_id

    FROM

    tb_cbm_transport_yrd AS t

    where t.tools_platorm_code = 'uxWap'

    and e.system_phone = 'ios'

    and t.create_time >= '2018-04-24' and t.create_time <= '2018-04-24 23:59:59'

    and (

    (t.create_time >= '2018-04-24' and t.create_time <= '2018-04-24 23:59:59')

    or (t.yrd_time >= '2018-04-24' and t.yrd_time <= '2018-04-24 23:59:59')

    or (t.audit_time >= '2018-04-24' and t.audit_time <= '2018-04-24 23:59:59')

    or (t.loan_date >= '2018-04-24' and t.loan_date <= '2018-04-24 23:59:59')

    )

    ) t

    LEFT JOIN tb_cbm_transport_result tc ON t.id = tc.transport_id

    LEFT JOIN tb_cbm_1imit tcl ON t.limit_id = tcl.limit_id

    WHERE t.tools_platorm_code = 'uxWap' GROUP BY left(t.system_phone,1);

    sum/avg

    只能对数字或者能转化成数字的字符串类型计算

    在MySQL中1/0返回NULL,如下图

    bdd47c084552

    sum.png

    avg是不会计算NULL那一行的,有如下例子

    bdd47c084552

    sum1.png

    math?formula=%5Ccolor%7Bred%7D%7B%E7%94%A8avg%E8%AE%A1%E7%AE%97%E5%B9%B3%E5%9D%87%E6%95%B0%E5%92%8C%E4%BD%BF%E7%94%A8sum%E5%8A%A0count%E8%AE%A1%E7%AE%97%E5%B9%B3%E5%9D%87%E6%95%B0%E7%9A%84%E5%80%BC%E5%AD%98%E5%9C%A8%E5%B7%AE%E5%BC%82%EF%BC%8C%E5%8E%9F%E5%9B%A0%E6%98%AFavg%E4%BC%9A%E6%8E%92%E9%99%A4NULL%E9%82%A3%E4%B8%80%E8%A1%8C%EF%BC%8C%E4%B8%8D%E8%BF%9B%E8%A1%8C%E8%AE%A1%E7%AE%97%E3%80%82%E4%BB%8Ecount%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%EF%BC%8Ccount%E8%BF%9B%E8%A1%8C%E7%BB%9F%E8%AE%A1%E6%97%B6%EF%BC%8C%E4%BD%BF%E7%94%A8*%E4%BC%9A%E7%BB%9F%E8%AE%A1%E5%85%A8%E9%83%A8%E7%9A%84%E8%A1%8C%E6%95%B0%EF%BC%8C%E4%BD%86%E6%98%AF%E4%BD%BF%E7%94%A8%E5%88%97%E5%90%8D%E5%88%99%E4%BC%9A%E6%8E%92%E9%99%A4%E7%A9%BA%E8%A1%8C%EF%BC%8C%E6%89%80%E4%BB%A5avg%E6%98%AF%E6%80%BB%E6%95%B0%E9%99%A4%E4%BB%A59%E8%A1%8C%E7%9A%84%E7%BB%93%E6%9E%9C%E3%80%82%7D

    HAVING

    having主要用于group by后的二次过滤

    having可以减少子查询嵌套,如下例子

    SELECT * FROM (SELECT 'wassup' AS hi FROM (select 1) x) a WHERE hi = 'wassup';

    可以使用having改写,简化嵌套

    SELECT 'wassup' AS hi FROM (select 1) x HAVING hi = 'wassup';

    行转列,列转行

    行转列

    bdd47c084552

    line.png

    列转行

    bdd47c084552

    line1.png

    思路:

    先把一行边两行

    math?formula=%5Ccolor%7Bred%7D%7B(%E8%BF%99%E7%A7%8D%E5%A4%8D%E5%88%B6%E6%93%8D%E4%BD%9C%E4%BA%A7%E7%94%9F%E7%AC%9B%E5%8D%A1%E5%B0%94%E7%A7%AF%E4%B8%80%E5%AE%9A%E8%A6%81%E5%8F%91%E7%94%9F%E5%9C%A8%E5%85%A8%E9%83%A8%E6%9F%A5%E8%AF%A2%E4%B9%8B%E5%90%8E%EF%BC%8C%E5%90%A6%E5%88%99%E4%B8%A5%E9%87%8D%E5%BD%B1%E5%93%8D%E6%95%88%E7%8E%87)%7D

    bdd47c084552

    line2.png

    使用case when分类

    bdd47c084552

    line3.png

    GROUP BY和JOIN优化案例

    有如下语句,运行时间为166s

    SELECT product_sku.branch_id AS branchId,product_sku.product_id AS productId,

    sum((product_sku.num - ifnull(branch_return_goods_info.num,0))) AS totalNum,

    sum((product_sku.unit_price * product_sku.num) - ifnull(branch_return_goods_info.money,0)) AS totalMoney,

    sum(ifnull(branch_return_goods_info.num,0)) returnNum,

    sum(ifnull(branch_return_goods_info.money,0)) returnMoney,

    product_info.branch_name AS branchName,

    product_info.brand_name AS brandName,

    product_info.product_name AS productName,

    product_info.cate_one_name AS cateOneName,

    product_info.cate_two_name AS cateTwoName,

    product_info.cate_three_name AS cateThreeName,

    sk.miniNum AS miniNum,

    product_info.sell_unit_convert AS sellUnitConvert,

    sk.stockMoney As stockMoney

    FROM product_sku_201704 poduct_sku FORCE INDEX (IDX_time_order)

    INNER JOIN product_info on product_info.branch_id= product_sku.branch_id AND product_info.pcoduct_id= poduct_sku.product_id

    AND product_sku.store_id NOT in (108,109)

    LEFT JOIN branch_return_goods_info on branch_return_goods_info.order_id = product_sku.orderNo AND branch_return_goods_info.hmp_id = product_sku.product_id AND branch_return_goods_info.type = 2

    LEFT JOIN stock_turnover as sk on sk.store_id = product_sku.store_id AND sk.product_id = product_sku.product_id and sk.datetime ='2017-04-25'

    WHERE product_sku.order_type >= 0

    AND product_sku.orderNo not like 'YL%'

    AND product_sku.ordetrNo not like 'PT%'

    AND product_sku.order_time >= '2017-04-01 00:00:00'

    AND product_sku.order_time <= '2017-04-25 23:59:59'

    AND product_sku.orderState = 100

    GROUP BY product_sku.product_id,product_sku.branch_id;

    执行计划如下

    bdd47c084552

    group7.png

    从执行计划我们可以看出,

    math?formula=%5Ccolor%7Bred%7D%7Busing%20where%EF%BC%8Cusing%20temporary%EF%BC%8Cusing%20filesort%E5%90%8C%E6%97%B6%E4%BA%A7%E7%94%9F%EF%BC%8C%E8%AF%B4%E6%98%8Egroup%20by%E5%8F%91%E7%94%9F%E5%9C%A8join%E4%B9%8B%E5%90%8E%EF%BC%8C%E6%98%AF%E5%AF%B9%E6%95%B4%E4%B8%AA%E7%BB%93%E6%9E%9C%E9%9B%86%E8%BF%9B%E8%A1%8C%E6%93%8D%E4%BD%9C%EF%BC%8C%E6%80%A7%E8%83%BD%E4%BC%9A%E6%AF%94%E8%BE%83%E5%B7%AE%E3%80%82%7D阅读上述SQL可以发现,where过滤条件只和product_sku表有关,和join表没有关系,所以优化思路是先过滤,缩小结果集,然后join

    优化后的SQL如下,优化后执行时间为25s

    SELECT

    product_sku.btanch_id as btanchId,

    product_sku.ptoduct_id As ptoductId,

    sum((product_sku.num - ifnull(branch_return_goods_info.num,0))) AS totalNum,

    sum((product_sku.unit_price * product_sku.num) - ifnull(branch_return_goods_info.money,0)) AS totalMoney,

    sum(ifnull(branch_return_goods_info.num,0)) returnNum,

    sum(ifnull(branch_return_goods_info.money,0)) returnMoney,

    product_info.branch_name AS branchName,

    product_info.brand_name AS brandName,

    product_info.product_name AS productName,

    product_info.cate_one_name AS cateOneName,

    product_info.cate_two_name AS cateTwoName,

    product_info.cate_three_name AS cateThreeName,

    sk.miniNum AS miniNum,

    product_info.sell_unit_convert AS sellUnitConvert,

    sk.stockMoney As stockMoney

    FROM (

    SELECT

    product_sku.prcdct_id,

    pcoduct_sku.branch_id,

    sum(product_sku.num) num,

    SUM(product_sku.unit_price) unit_price,

    product_sku.orderNo,

    product_sku.store_id

    FROM proauct_sku_201704 produet_sku

    WHERE product_sku.order_type >= 0

    AND product_sku.orderNo not like 'YL%'

    AND product_sku.ordetrNo not like 'PT%'

    AND product_sku.order_time >= '2017-04-01 00:00:00'

    AND product_sku.order_time <= '2017-04-25 23:59:59'

    AND product_sku.orderState = 100

    AND product_sku.store_id NOT in (108,109)

    GROUP BY product_sku.product_id,product_sku.branch_id

    ) product_sku

    INNER JOIN product_info on product_info.branch_id= product_sku.branch_id AND product_info.pcoduct_id= poduct_sku.product_id

    LEFT JOIN branch_return_goods_info on branch_return_goods_info.order_id = product_sku.orderNo AND branch_return_goods_info.hmp_id = product_sku.product_id AND branch_return_goods_info.type = 2

    LEFT JOIN stock_turnover as sk on sk.store_id = product_sku.store_id AND sk.product_id = product_sku.product_id and sk.datetime ='2017-04-25'

    GROUP BY product_sku.product_id,product_sku.branch_id;

    优化后执行计划如下

    bdd47c084552

    group8.png

    展开全文
  • It’s time for wassup bro ;)" ; 5: 6: } 7: } Step 4. 运行并测试  按 F5 键,在地址栏中以“ControllerName/ActionName”这样的形式输入,需要注意的输入控制器名称时,不能输入”...

    ASP.NET vs MVC vs WebForms

    许多ASP.NET开发人员开始接触MVC认为MVC与ASP.NET完全没有关系,是一个全新的Web开发,事实上ASP.NET是创建WEB应用的框架而MVC是能够用更好的方法来组织并管理代码的一种更高级架构体系,所以可以称之为ASP.NET MVC。

    我们可将原来的ASP.NET称为 ASP.NET Webforms,新的MVC 称为ASP.NET MVC.

    ASP.NET Web Form

    ASP.NET 在过去的十二年里,已经服务并成功实现Web 应用的开发。我们首先了解一下为什么ASP.NET能够如此流行,并成功应用。

    微软编程语言从VB开始就能够成为流行并广泛应用,都源于其提供的强大的Visual studio能够进行可视化的编程,实现快速开发。

    使用VS时,开发人员能够通过拖拽UI元素,并在后台自动生成这些界面的代码。称为后台代码。在后台代码中开发人员可以添加操作这些UI元素的逻辑代码。

    clip_image002

    因此微软的可视化RAD架构体系有两方面组成,一方面是UI,一方面是后台代码。因此ASP.NET Web 窗体,包含ASPX和ASPX.CS,WPF包含XAML/XAML.CS等。

    ASP.NET Web Form存在的问题

    我们不得不考虑的问题是,既然ASP.NET Web Form 如此成功且具有优势,为什么微软还要推出ASP.NET MVC?主要是因为ASP.NET Webform的性能问题。在Web应用程序中从两方面来定义性能:

    1. 响应时间: 服务器响应请求的耗时

    2. 带宽消耗: 同时可传输多少数据。

    响应时间

    我们可以理解为什么ASP.NET Webform比较慢,如图我们做了一些小的加载测试。分别使用ASP.Net MVC和ASP.Net Webform,发现ASP.Net MVC的响应时间比Webform快了两倍。

    clip_image003

    接下来我们在思考一个问题为什么ASP.NET MVC的性能更好?看看下面这个示例,简单的UI代码和UI的后台代码。

    假如一个textbox的ASPX页面:

    <asp:TextBox ID="TextBox1" runat="server">

    对应的UI后台代码:

       1:  protected void Page_Load(object sender, EventArgs e)
       2:  {      
       3:        TextBox1.Text = "Make it simple";            
       4:        TextBox1.BackColor = Color.Aqua;
       5:  }

    运行结果:

    clip_image004

    如果查看HTML输出,则会显示如下代码:

    <input name="TextBox1" type="text" value="Make it simple" id="TextBox1" style="background-color:Aqua;" />

    我们再来思考上面提到的问题

    1. 这种HTML生成方式是否很有效?我们是否为了获取如此简单的HTML而长时间的消耗服务器

    2. 开发人员是否可以直接编写HTML?很难实现吗?

     

    clip_image005

    通过分析我们可以得知,每一次请求都有转换逻辑,运行并转换服务器控件为HTML输出。如果我们的页面使用表格,树形控件等复杂控件,转换就会变得很糟糕且非常复杂。HTML输出也是非常复杂的。由于这些不必要的转换从而增加了响应时间。该问题的解决方案就是摆脱后台代码,写成纯HTML代码。

    带宽消耗

    ASP.NET开发人员都非常熟悉Viewstates,因为它能够自动保存post返回的状态,减少开发时间。但是这种开发时间的减少会带来巨大的消耗,Viewstate增加了页面的大小。在做的加载测试中,与MVC 对比,我们发现Viewstate增加了两倍的页面存储。以下是测试结果:

     

    clip_image006

    页面尺寸的增加是因为viewstate产生了额外的字节。下图就是Viewstate的截图。许多人可能会不同意此观点,但是众所周知,开发人员是如何工作的,如果有选择,他们肯定会采取别的选择。

     

    clip_image008

    1. HTML 消耗

    现在因为我们都是后台代码和ASP.NET web server控件的努力,我们对于怎样得到HTML以及如何使他们更有效没有更好的办法。如下面展示的ASPX 代码,你能确定会生成什么样的HTML代码吗?


    • <asp:Label ID="Label1" runat="server" Text="I am label">

       
    •   
      <asp:Literal ID="Literal1" runat="server" Text="I am a literal">
       
    • <asp:Panel ID="Panel1" runat="server">I am a panel

       

       

    Lable标签会生成DIV标签还是SPAN标签?运行后生成的HTML代码的结果如下:label生成了span标签,Literal生成了转换为了简单的文本,而panel转换为了DIV标签。

     <span id="Label1">I am label</span>I am a literal

    • I am a panel

    因此与其生成HTML代码,还不如直接编写HTML代码,并实现HTML控件。

    所以该问题的解决方案是:不使用服务器控件,直接编写HTML代码。

    直接编写HTML代码的好处在于web设计者可以与开发人员紧密合作及时沟通。设计人员可以使用他们喜爱的设计工具来设计HTMl代码,像dream weaver,前端页面等,设计独立。如果我们使用服务器控件,这些设计者工具可能不会识别。

           2. 后台代码类的重用性
    如果仔细观察一些专业的ASP.NET Webform项目,你会发现后台代码类往往都包含了大量的代码,并且这些代码也是非常复杂的。而现在,后台代码类继承了“System.Web.UI.Page”类。但是这些类并不像普通的类一样能够到处复用和实例化。换句话来讲,在Weform类中永远都不可能执行以下代码中的操作:
       1: WebForm1 obj = new WebForm1();obj.Button1_Click();

     

    •   3. 单元测试

    既然无法实例化后台代码类,单元测试也是非常困难的,也无法执行自动化测试。必须手动测试。

    • 解决方案

    既然讲了ASP.Net Webform存在的两大问题即服务器控件和后台代码,以下是根源图,

    clip_image009

    那么解决方案是什么?

    就是我们需要将后台代码迁移到独立的简单的类库,并且拜托ASP.Net服务器控件,并写一些HTML示例。

    ASP.NET Webform 和MVC 比较,如下图:

    clip_image010

    Microsoft Asp.Net MVC 是如何弥补Web Form存在的问题的?

    后台代码和服务器控件是一切问题的根源。所以如果你查看当前的WebForm体系结构,开发者正在使用的包含3层体系结构。三层体系结构是由UI包含ASPX及CS 后台代码。

    UI,业务逻辑以及包含数据访问的中间层

    clip_image011

    Asp.Net MVC 由Model,View,Controller三部分组成。Controller中包含后台代码逻辑,View是ASPX,如纯HTML代码,Model是中间层。通过上图可获得这三部分的关系。

    所以会发现MVC的改变有两点,View变成简单的HTML,后台代码移到简单的.NET类中,称为控制器。

    以下是ASP.NET MVC 请求流的通用步骤:

    Step 1:首先获取控制器。

    Step 2:依赖行为控制器创建Model对象,Model通过转换调用数据访问层。

    Step 3:数据填充Model之后,传递到View 显示层,实现显示的目的。

    clip_image012

    到这里我们就已经了解了ASP.Net MVC的各个组件。下面我们做一些小的实验深入了解MVC的各组件。首先我们从Controller 控制器开始,因为Controller是MVC体系架构的核心部分。

    你是否真的理解Asp.Net MVC的Controller(控制器)?

    为了我们能够更好的理解Controller,我们首先需要理解Controller中涉及的专业术语:用户交互逻辑。

    什么是用户交互逻辑?

    场景1

    你是否想过当用户输入URL摁下回车键时,会发生什么事情?

    clip_image013

    浏览器首先需要给服务器发送请求,服务器再做出响应。

    clip_image014

    通过这些请求之后,客户端正尝试与服务器交互,服务器能够反馈响应,因为服务器端存在一些判断逻辑来处理这些请求。这些能够处理用户请求以及用户交互行为的业务逻辑称为用户交互逻辑。

    场景2

    有一种常见的情况,服务器端发送的请求是HTML请求。HTML请求是由一组输入控件和提交按钮组成的。

    clip_image015

    当用户点击“Save”按钮之后会发生什么?

    如果你的回答是有一些事件处理器来处理button点击事件,那么很抱歉回答是错误的。

    在Web编程中是没有事件的概念的,Asp.net Web forms 根据我们的行为自动添加了处理代码,所以给我们带来的错觉认为是事件驱动的编程。这只是一种抽象的描述。

    当点击Button时,一个简单的HTTP请求会发送到服务器。差别在于Customer Name,Address以及Age中输入的内容将随着请求一起发送。最终,如果是有个请求,服务器端则有对应的逻辑,使服务器能够更好响应请求。简单来说是将用户交互逻辑写在服务器端。

    在Asp.Net MVC中,C代表Controller,就是用来处理用户交互逻辑的。

    实验一:简单的MVC Hello world,着重处理Controller。

    • Step1 创建一个Asp.Net MVC 5项目

    打开Visual studio 2013 点“文件”->新建->项目。

    clip_image016

    • Step 1.2 选择Web 应用,输入项目名称,选择存放路径,点击确定。

    clip_image017

    • Step 1.3 选择MVC 模板

    clip_image018

    • Step 1.4 选择Change Authentication(改变授权),弹出对话框中选择“No Authentication”,并点击确定。

    clip_image019

    • Step 2 –创建控制器
    • Step 2.1,在资源管理器中,右击controller文件夹,选择添加->Controller(控制器)

    clip_image020

    • Step 2.2 选择空 MVC 5 Controller 并点击添加

    clip_image021

    • Step 2.3 输入控制器的名称”TestController“,点击添加。

    在这一步骤中,要特别注意千万不能删除名称中的” Controller”关键字。名称中必须包含Controller关键字。

    clip_image022

    • Step 3. 创建行为方法

    打开新建的TestController 类,可以发现已生成的Index 方法,将该方法删除,并且添加新方法命名为GetString ,代码如下:

       1:  public class TestController : Controller
       2:  {
       3:      public string GetString() 
       4:     {        return "Hello World is old now. It’s time for wassup bro ;)"; 
       5:   
       6:    }
       7:  }
    • Step 4. 运行并测试 按 F5 键,在地址栏中以“ControllerName/ActionName”这样的形式输入,需要注意的输入控制器名称时,不能输入”Controller“只输入”Test”。

    clip_image023

     

    实验一:Q&A

    1. TestController 和Test之间的关系是什么?

    TestController是类名称,而Test是Controller的名称,请注意,当你在URL中输入controller的名称,不需要输入Controller这个单词。

    2. Action(行为) 方法是什么?

    Action 方法 简单的来说就是一个Controller内置的public类型的方法,能够接收并处理用户的请求,上例中,GetString 方法返回了一个字符串类型的响应。

    注意:在Asp.Net Web Forms中默认的返回请求是HTML的,如果需要返回其他类型的请求,就必须创建HTTP 处理器,重写内容类型。这些操作在Asp.net中是很困难的。在Asp.net MVC中是非常简单的。如果返回类型是”String“直接返回,不需要发送完整的HTML。

    3. 如果从Action 方法中返回对象值会出现什么意外情况?

    请浏览以下代码

       1:  namespace WebApplication1.Controllers
       2:  {
       3:      public class Customer
       4:      {
       5:          public string CustomerName { get; set; }
       6:          public string Address { get; set; }
       7:      }
       8:      public class TestController : Controller
       9:      {
      10:          public Customer GetCustomer()
      11:          {
      12:              Customer c = new Customer();
      13:              c.CustomerName = "Customer 1";
      14:              c.Address = "Address1";
      15:              return c;
      16:          }
      17:      }
      18:  }

     输出结果如下所示: 

     

     

    clip_image024
    当返回类型如“Customer”这样类似的对象时,将调用ToString()方法,返回“NameSpace.ClassName”形式的类名。

    4. 如果需要获得上面例子中的属性值,要如何操作?

    简单重写类的“ToString”方法,如下:

       1:  public override string ToString()
       2:  {
       3:       return this.CustomerName+"|"+this.Address;
       4:  }

     

     

    运行结果:

    clip_image025

    5. Action 方法是否只能用Public修饰符来修饰?

    答案是肯定的,每个公有方法都会自动称为Action 方法。

    6. 非public方法是什么?

    类的方法都比较简单,并且并不是公共可用的。无法在Web中调用。

    7. 如果我们需要其他函数来完成一些特定功能,但不是Action Method要如何实现?

    使用NonAction属性修饰,如下:

     

     

       1:  [NonAction] 
       2:  public string SimpleMethod()
       3:  { 
       4:     return "Hi, I am not action method";
       5:  }

     

     

    当尝试给以上Action 方法发送请求时,会获得以下结果: 

    clip_image026

    View部分

    Controller是处理用户请求,并做出响应,通常情况下响应都是以显示在浏览器中,使用HTML代码,浏览器才可识别。HTML有图像,文本,输入控件等。通常称为用户界面的设计即UI层,在ASP.net MVC称为View。

    实验二——深入理解View

    在实验二中,创建一个简单的MVC应用,仅仅具有Controller和简单的字符串类型的返回值。让我们来了解MVC中的View部分吧。

    • Step1 –创建新的Action 方法

    在TestController中添加新的Action 方法,如下:

       1:  public ActionResult GetView()
       2:  { 
       3:     return View("MyView");
       4:  }

     

    • Step 2 创建View
    • Step 2.1 右击上述创建的Action 方法,选择“添加View”

     

    clip_image027

    • Step 2.2 在添加View的对话框中输入View名称“MyView”,取消选择“使用布局”的复选框,点击添加。

    clip_image028

    资源管理器重的Views/Test文件夹中会添加一个新的View文件。

    clip_image029

    • Step3 在View中添加内容

    打开MyView.cshtml 文件,并添加以下内容:

    @{Layout = null;}
    <!DOCTYPE html>
    <html><head><meta name="viewport" content="width=device-width" />
    <title>MyView</title>
    </head><body>Welcome to MVC 5 Step by Step learning
    </body></html>
    • Step 4. 运行 按F5键运行应用

    clip_image030

    实验二:Q&A

    1. 为什么View会放在Test的文件夹中?

    View是与放置在特定目录下的Controller相关。这个特定文件夹是以”ControllerName”命名的,并且放在View文件夹内

    2. 在多个控制器中无法重用View吗?

    当然可以,我们需要在将这些文件放在特定的Shared文件夹中。将View 放在Shared文件夹中所有的Controller都可用。

    clip_image031

    3. 单个Action 方法中可引用多个View吗?

    可以,ASP.NET MVC的view和Controller不是严格的匹配的,一个Action Method可以引用多个view,而一个View也可以被一个Action方法使用如下代码所示:

       1:  public ActionResult GetView()
       2:  {
       3:      if(Some_Condition_Is_Matching)
       4:      { 
       5:         return View("MyView");
       6:      }
       7:      else
       8:      {
       9:         return View("YourView");
      10:      }
      11:  }

     

     

    4. View函数的功能是什么?

     创建 ViewResult 对象将会渲染成视图来给用户反馈

     

    • ViewResult 创建了ViewPageActivator 对象
    • ViewResult 选择了正确的ViewEngine,并且会给ViewEngine的构造函数传ViewPageActivator对象的参数
    • ViewEngine 创建View类的对象
    • ViewEngine 调用View的RenderView 方法。

    5. ActionResult和 ViewResult的关系是什么?

    ActionResult是抽象类,而ViewResult是ActionResult的多级孩子节点,多级是因为ViewResult是ViewResultBase的子类,而ViewResultBase是ActionResult的孩子节点。

    6. 什么是ContentResult?

    ViewResult是HTML响应而ContentResult是标准的文本响应,仅返回字符串类型。区别就在于ContentResult是ActionResult的子类。

    经过了本节MVC基础知识的学习,相信大家对MVC已经有了基本的认识。大家在进行ASP.NET MVC的开发时,还可以借助一些开发工具。ComponentOne Studio ASP.NET MVC 是一款轻量级控件,与Visual Studio无缝集成,完全与MVC6和ASP.NET 5.0兼容,将大幅提高工作效率。

    展开全文
  • => wassup ghetto 要翻译整个网站: Gizoogle::Webpage.translate('github.com') => <html><head>...translated html here... 命令行使用 安装 gem 后,您就有了一个命令行可执行文件gizoogle 。 $ ...
  • [‘Ahoy‘,27 ‘Good day‘,28 ‘Hello‘,29 ‘Heyo‘,30 ‘Hi‘,31 ‘Salutations‘,32 ‘Wassup‘,33 ‘Yo‘]34 #Create and fill the combo box to choose the salutation 35 self.salutation =QComboBox(self)36...

    标签:

    PySide——Python图形化界面入门教程(二)

    ——交互Widget和布局容器

    ——Interactive Widgets and Layout Containers

    原文链接:http://pythoncentral.io/pyside-pyqt-tutorial-interactive-widgets-and-layout-containers/

    上一个教程中,我们了解了一些QWidget提供的功能,还有一个特殊的子类QLabel。更进一步的,我们完成了一个用来说明简单Python/Qt应用的例子。但是,我们掌握的远远不能满足用户的需求,因为我们只能给他们显示文本,我们的应用只会唱独角戏!我们需要一些方法让用户可以和我们的程序交互,让独角戏变成二人转。Qt提供了丰富的交互式widgets,这里我们将要学习其中的一小部分;我们将使用他们体验如何在图形化(form)上布置widgets。下一个教程,我们将学习如何使用信号和槽来响应用户的交互。

    交互式Widgets

    Python/Qt有一系列的widgets,可以非常简单的实现与用户交互,并且容易和你的应用逻辑联系。

    按钮(Buttons)

    一个最简单的交互方式就是让用户点击按钮,Qt中就是QPushButton。QPushButton构造器有三个结构:

    1 QPushButton(parent=None)2 QPushButton(text, [parent=None])3 QPushButton(icon, text, [parent=None])

    parent参数是一个QWidget,text是一个Python string或unicode,icon是一个QIcon。创建一个被some-form拥有的带有文字“Go”的按钮,可以这样:

    go_button = QPushButton(‘Go‘, some_form)

    如果我们想为按钮设置一个键盘快捷键,如Alt-G,我们可以在‘Go’前添加一个‘&G’:

    go_button= QPushButton(‘&Go‘, some_form)

    这还有一些按钮的其他功能,还拿go_button做例子,你可以将其设置为form的默认按键:

    go_button.setDefault(True)

    还可以设置成平的:

    go_button.setFlat(True)

    将False传递到方法中会有相反的作用。一个按钮还可以在被点击时弹出一个菜单(menu):传递一个QMenu对象给按钮的setMenu方法。(我们以后再研究菜单)

    文本框(Textboxes)

    Qt的文本框控件是QLineEdit;它允许用户输入编辑单行的简单文本,其构造器有如下两种:

    1 QLineEdit(parent=None)2 QLineEdit(text, [parent=None])

    他们的不同就是第二个允许用text参数设置包含的文本。QLineEdit对象有许多的方法,但是我们只关心几个最基本的。你可以使用text()方法取回文本,用setText(text)设置文本,使用setMaxLength(chars)设置最大可输入长度。它可以通过setReadOnly(True)设置为只读的,使用setPlaceholderText(text)设置占位文字(placeholder text,就是那种你输入前提示说明的字)。QLineEdit还有更多的高级属性:可以设置输入过滤器,处理选择和输入历史等等。

    组合框(Comboboxes)

    QComboBox widget是用来给用户提供多个文本或文本/图标的选择,用户必须选择其一。(多项选择参见QListView和QListWidget)它的构造器如下:

    1 QComboBox(parent)

    它的构造如此简单,但是目前还没有任何选项。你可以用多种方式添加选项。如果你的所有选项都是文字的,你可以使用addItems(texts),texts是字符串列表。一个一个的添加选项可以使用addItem,它有两个有效的方式

    1 addItem(icon, text, [userData=None])2 addItem(text, [userData=None])

    参数icon是QIcon,text是一个unicode对象,userData是任何对象。你可以使用insertItem插入选项:

    1 insertItem(index, icon, text, [userData=None])2 insertItem(index, text, [userData=None])

    QComboBox是一个灵活的widget,用它还可以做更多的事情。

    例子程序:总览

    接下来,我们将学习如何把小部件组合成一个表单布局,但在我们可以做到这一点之前,让我们先看一下这个示例应用程序。

    正如你所看到的,这是一个非常简单的应用程序。用户可以选择一个称呼和进入的人的姓名(或其他单位)他们要打招呼,当他们点击“建立问候,问候将在窗体上显示一个标签。

    布局管理(Layout Management)

    PySide和PyQt有两个可用的方法来管理布局:使用绝对位置,开发者必须明确设置每个widget和位置和大小;使用的布局容器(layout containers),自动安排位置和调整大小。我们将用两种方法构建上面提到的例子程序。

    绝对位置

    去设置widget的无力位置,你需要使用widget的move(x, y)方法;x和y是水平和垂直距离,这个距离是从外框(form)的左上角到widget的左上角。这是我们使用绝对距离创建的外形:

    1 #Every Qt application must have one and only one QApplication object;

    2 #it receives the command line arguments passed to the script, as they

    3 #can be used to customize the application‘s appearance and behavior

    4 qt_app =QApplication(sys.argv)5

    6 classAbsolutePositioningExample(QWidget):7 ‘‘‘An example of PySide absolute positioning; the main window8 inherits from QWidget, a convenient widget for an empty window.‘‘‘

    9 def __init__(self):10 #Initialize the object as a QWidget

    11 QWidget.__init__(self)12

    13 #We have to set the size of the main window

    14 #ourselves, since we control the entire layout

    15 self.setMinimumSize(400, 185)16 self.setWindowTitle(‘Dynamic Greeter‘)17

    18 #Create the controls with this object as their parent and set

    19 #their position individually; each row is a label followed by

    20 #another control

    21

    22 #Label for the salutation chooser

    23 self.salutation_lbl = QLabel(‘Salutation:‘, self)24 self.salutation_lbl.move(5, 5) #offset the first control 5px

    25 #from top and left

    26 self.salutations = [‘Ahoy‘,27 ‘Good day‘,28 ‘Hello‘,29 ‘Heyo‘,30 ‘Hi‘,31 ‘Salutations‘,32 ‘Wassup‘,33 ‘Yo‘]34 #Create and fill the combo box to choose the salutation

    35 self.salutation =QComboBox(self)36 self.salutation.addItems(self.salutations)37

    38 #Allow 100px for the label and 5px each for borders at the

    39 #far left, between the label and the combobox, and at the far

    40 #right

    41 self.salutation.setMinimumWidth(285)42 #Place it five pixels to the right of the end of the label

    43 self.salutation.move(110, 5)44

    45 #The label for the recipient control

    46 self.recipient_lbl = QLabel(‘Recipient:‘, self)47 #5 pixel indent, 25 pixels lower than last pair of widgets

    48 self.recipient_lbl.move(5, 30)49

    50 #The recipient control is an entry textbox

    51 self.recipient =QLineEdit(self)52 #Add some ghost text to indicate what sort of thing to enter

    53 self.recipient.setPlaceholderText(‘world‘ or ‘Matey‘)54 #Same width as the salutation

    55 self.recipient.setMinimumWidth(285)56 #Same indent as salutation but 25 pixels lower

    57 self.recipient.move(110, 30)58

    59 #The label for the greeting widget

    60 self.greeting_lbl = QLabel(‘Greeting:‘, self)61 #Same indent as the others, but 45 pixels lower so it has

    62 #physical separation, indicating difference of function

    63 self.greeting_lbl.move(5, 75)64

    65 #The greeting widget is also a label

    66 self.greeting = QLabel(‘‘, self)67 #Same indent as the other controls

    68 self.greeting.move(110, 75)69

    70 #The build button is a push button

    71 self.build_button = QPushButton(‘&Build Greeting‘, self)72

    73 #Place it at the bottom right, narrower than

    74 #the other interactive widgets

    75 self.build_button.setMinimumWidth(145)76 self.build_button.move(250, 150)77

    78 defrun(self):79 #Show the form

    80 self.show()81 #Run the Qt application

    82 qt_app.exec_()83

    84 #Create an instance of the application window and run it

    85 app =AbsolutePositioningExample()86 app.run()

    不用说,一个大型的应用程序可能会变得非常麻烦。另外,它也没有大小改变的反应;标签只是坐在指定的位置。不仅如此,想象一下,如果有视觉障碍的用户想把他们的字体设置的大一些;使用固定的位置,您设置的控件将不再适当。

    布局容器(Layout Containers)

    由于上述种种原因,布局容器比绝对位置更为常用,他们更加灵活,替程序员分担了计算确切位置的任务,并且他们可以调整布局去适应不同平台的GUI设置,如GTK+, KDE, Mac OS X等等。这有5个主要的布局容器,他们都是继承自QLayout:

    QHBoxLayout

    QVBoxLayout

    QGridLayout

    QStackedLayout

    QFormLayout

    他们用来满足不同的需求。简而言之,QHBoxLayout和QVBoxLayout将widgets一个挨一个的水平(horizontally)、垂直(vertically)排列;QGridLayout可按照任意大小表格布局;QStackedLayout将他们一个放在一个的上面(就像stack栈一样);QFormLayout是一个特殊的两栏布局,它提供特殊的方法用标签安排内容在第一列,在第二列安排相关的空间。这些布局非常有用,但是你的布局选项不局限于他们,你可以将布局嵌套组合来创建更复杂易用的用户接口。现在,我们来看看水平、垂直布局和QFormLayout。

    QVBoxLayout和QHBoxLayout

    盒子布局(box layouts)非常的直截了当。使用它作为最上层的布局,创建布局非常简单——它的构造器需要任何参数——并且使用望名知义的方法addWidget来添加widget。接下来你就可以设置它所属的窗口。例如:

    1 win =QWidget()2

    3 #The three labels

    4 lbl_1 = QLabel("We‘re")

    5 lbl_2 = QLabel(‘stacked‘)6 lbl_3 = QLabel(‘up.‘)7

    8 #A vertical box layout

    9 layout =QVBoxLayout()10

    11 #Add the widgets to the layout

    12 layout.addWidget(lbl_1)13 layout.addWidget(lbl_2)14 layout.addWidget(lbl_3)15

    16 #Set layout as the layout for the window

    17 win.setLayout(layout)

    QHBoxLayout也可以被同样使用,尽管它不常作为最上层的布局。它常常被作为子布局。为一个布局中添加另一个布局,使用该布局容器的addLayout方法,例如:

    1 layout =QVBoxLayout()2 sub_layout =QHBoxLayout()3

    4 #... Fill the layouts with widgets ...

    5

    6 layout.addLayout(sub_layout)

    盒子布局有另一个更重要并且常用的方法:addStretch。一个常见的布局有很多的控件,他们之间具有灵活的空间。为了完成这个目的,在盒子的开始添加widgets,然后添加一个设置大于0的空闲空间,layout.addStretch(1),然后再添加剩下的widgets。

    QFormLayout

    QFormLayout非常像QVBoxLayout,但是它可以不用创建子布局就轻松的将每一行分成两列。这通过使用外观布局的addRow方法,它有很多重载(overloaded?)。单参数的版本:

    1 addRow(QWidget)2 addRow(QLayout)

    添加widget或布局在整个QFormLayout的最后。双参数版本:

    1 unicode, QLayout2 unicode, QWidget3 QWidget, QWidget4 QWidget, QLayout

    作为一个“标签”在第一列中初始化元素,第二个是第二列。unicode参数作为QLabel的文本,QWidget可以是任意的widget。

    盒子布局的例子(Box Layout Example)

    现在我们已经了解了如何创建交互式widget和用灵活的布局管理他们,现在我们重新创建例子应用。我们窗口的主布局是QVBoxLayout,它有两个子布局,一个QformLayout包含所有的标签控件,和一个QHBoxLayout来管理右下角的按钮位置。我们将使用addStretch来分离QFormLayout,并且把按钮挤到QHBoxLayout的右边。你会注意到,许多代码同绝对位置版本是一样的;比如,创建单独控件的时候。

    1 qt_app =QApplication(sys.argv)2

    3 classLayoutExample(QWidget):4 ‘‘‘An example of PySide/PyQt absolute positioning; the main window5 inherits from QWidget, a convenient widget for an empty window.‘‘‘

    6

    7 def __init__(self):8 #Initialize the object as a QWidget and

    9 #set its title and minimum width

    10 QWidget.__init__(self)11 self.setWindowTitle(‘Dynamic Greeter‘)12 self.setMinimumWidth(400)13

    14 #Create the QVBoxLayout that lays out the whole form

    15 self.layout =QVBoxLayout()16

    17 #Create the form layout that manages the labeled controls

    18 self.form_layout =QFormLayout()19

    20 #The salutations that we want to make available

    21 self.salutations = [‘Ahoy‘,22 ‘Good day‘,23 ‘Hello‘,24 ‘Heyo‘,25 ‘Hi‘,26 ‘Salutations‘,27 ‘Wassup‘,28 ‘Yo‘]29

    30 #Create and fill the combo box to choose the salutation

    31 self.salutation =QComboBox(self)32 self.salutation.addItems(self.salutations)33

    34 #Add it to the form layout with a label

    35 self.form_layout.addRow(‘&Salutation:‘, self.salutation)36

    37 #Create the entry control to specify a recipient

    38 #and set its placeholder text

    39 self.recipient =QLineEdit(self)40 self.recipient.setPlaceholderText("e.g. ‘world‘ or ‘Matey‘")41

    42 #Add it to the form layout with a label

    43 self.form_layout.addRow(‘&Recipient:‘, self.recipient)44

    45 #Create and add the label to show the greeting text

    46 self.greeting = QLabel(‘‘, self)47 self.form_layout.addRow(‘Greeting:‘, self.greeting)48

    49 #Add the form layout to the main VBox layout

    50 self.layout.addLayout(self.form_layout)51

    52 #Add stretch to separate the form layout from the button

    53 self.layout.addStretch(1)54

    55 #Create a horizontal box layout to hold the button

    56 self.button_box =QHBoxLayout()57

    58 #Add stretch to push the button to the far right

    59 self.button_box.addStretch(1)60

    61 #Create the build button with its caption

    62 self.build_button = QPushButton(‘&Build Greeting‘, self)63

    64 #Add it to the button box

    65 self.button_box.addWidget(self.build_button)66

    67 #Add the button box to the bottom of the main VBox layout

    68 self.layout.addLayout(self.button_box)69

    70 #Set the VBox layout as the window‘s main layout

    71 self.setLayout(self.layout)72

    73 defrun(self):74 #Show the form

    75 self.show()76 #Run the qt application

    77 qt_app.exec_()78

    79 #Create an instance of the application window and run it

    80 app =LayoutExample()81 app.run()

    注意到这些对程序员来说是多么的容易。当代码不太短的时候——不是每个便捷都会使代码量减少,创建和嵌套布局有一定的代码开销的时候——精神上的负担就小多了。开发人员只需完成一个组合的布局,产生所需的效果,并创建他们;控件的创建和修改是隔离的,很少再要去考虑其影响到布局和其他控件。下一部分,我们将以这个例子创建的界面,让它实际上做些事。

    By Ascii0x03

    转载请注明出处:http://www.cnblogs.com/ascii0x03/p/5496699.html

    标签:

    展开全文
  • c#多线程

    2019-10-03 16:52:47
    概述与概念 C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行。一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多...
  • greetings: ['Hi', 'Hello', 'Hey', 'Wassup'], positive_adjectives: ['great', 'super', 'awesome', 'amazing'], }, }); 开始旋转! whorl.spin('{greeting}, thanks for using whorl'); // Randomly ...
  • C#中的线程(四)高级话题   Keywords:C# 线程Source:http://www.albahari.com/threading/Author: Joe AlbahariTranslator: Swanky WuPublished: ...
  • C#中的多线程

    2014-06-05 15:33:36
    By Joseph Albahari, Translated by Swanky Wu Based on "C# 3.0 in a Nutshell" by Joseph Albahari and Ben Albahari (O'Reilly Media) http://www.albahari.com/nutshell/ ...
  • composer require pop-sites-wassup/system-mutations 发展历程 源代码托管在 。 用法 初始化组件: \ PoP \ Root \ ComponentLoader :: initializeComponents ([ \ PoPSitesWassup \ SystemMutations \ Component...
  • composer require pop-sites-wassup/post-mutations 发展 源代码托管在 。 用法 初始化组件: \ PoP \ Root \ AppLoader :: addComponentClassesToInitialize ([ \ PoPSitesWassup \ PostMutations \ Component ::...
  • C语言每日一练——第90天:青蛙跳台阶(升级版)

    千次阅读 多人点赞 2022-01-14 17:35:37
    前言 Wassup guys,我是你们的机哥 (好几个朋友发私信都叫我机哥) 今天是C语言每日一练,第90天! Let’s get it! 文章目录 1. 基础问题 题目描述 解题思路 代码实现 递归升级 动态规划解法 2. 问题升级 题目描述...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 161
精华内容 64
热门标签
关键字:

wassup