月度归档: 2018年8月

python-logging全局日志配置-滚动删除,只保存最近7天的日志,按级别存入不同文件

最近有这样一个需求,需要记录一下用户行为,和记下一些错误日志,放入指定文件夹里不同的文件下,方便后续debug。我决定采用python logging模块。并且使用配置文件,并做一个全局的globalLog.py来使用logging。 (关键词:logging,TimedRotatingFileHandler)

——————————————第一步——————————————

添加配置文件logger_config.ini。文件的后缀名其实无所谓,conf,ini或者别的都行。我把该文件放置在/{$项目名}/resource/路径下。

重点1:TimedRotatingFileHandler用来配置log的滚动删除,arg里的“midnight”, 1, 6,’utf-8′ 表示“每一天午夜12点将当天的日志转存到一份新的日志文件中,并且加上时间戳后缀,最多保存6个文件,编码格式UTF-8,支持中文”

重点2:如果要同时输出到2个文件和屏幕上,那么需要使用三个handler,2个为TimedRotatingFileHandler,还有1个是StreamHandler

重点3:level级别如下,级别越低,打印的日志越详细,例如级别为noset,则会打印出所有信息,如果级别为info,那么不会打印出debug信息。我们的例子中,级别为info,日志里不会打印出debug的信息

 下面是详细的配置文件: 
[loggers] keys=root 
[handlers] keys=rotatingFileHandler,streamHandler,errorHandler 
[formatters] keys=simpleFmt 
[logger_root] level=DEBUG 
handlers=rotatingFileHandler,streamHandler,errorHandler 
[handler_rotatingFileHandler] 
class=handlers.TimedRotatingFileHandler level=INFO formatter=simpleFmt args=(os.path.abspath(os.getcwd() + "/resource/ta_log/default.log"),"midnight", 1, 6,'utf-8') 
[handler_errorHandler] class=handlers.TimedRotatingFileHandler level=ERROR formatter=simpleFmt args=(os.path.abspath(os.getcwd() + "/resource/ta_log/error.log"), "midnight", 1, 6,'utf-8') 
[handler_streamHandler] level=INFO class=StreamHandler formatter=simpleFmt args=(sys.stdout,) 
[formatter_simpleFmt] format=%(asctime)s %(pathname)s(%(lineno)d): %(levelname)s %(message)s

——————————————第二步——————————————

编写globalLog.py 作为全局log的管理入口。

后续别的模块下的python文件需要使用日志功能时,需要导入该模块。该模块的原理也很简单,定位到文件路径,然后通过logger的名字获得要用的logger配置,例如我上面的配置文件中 [loggers] keys=root 所以这里就用了root.然后创建一个全局的logger对象,命名为ta_log

#globalLog.py
import logging
import logging.config
import os
def get_logger(name='root'):
    conf_log = os.path.abspath(os.getcwd() + "/resource/logger_config.ini")
    logging.config.fileConfig(conf_log)
    return logging.getLogger(name)
ta_log = get_logger(__name__)

——————————————第三步——————————————

在需要打印日志的地方使用该方法,例如在main.py里通过ta_log.info()打印日志。该方法会打印各个级别的信息进入两个日志文件中。我们在第四步来看一看日志文件的内容

import sys
from globalLog import ta_log
if __name__ == '__main__':
    ta_log.info("start")
    try:
        print(1 / 0)
    except Exception:
        ta_log.error("error:")
        ta_log.exception(sys.exc_info())
    ta_log.debug("end")

——————————————第四步——————————————

运行程序,检查日志文件。 这是default.log,级别是info.没有记录ta_log.debug()的信息

2018-08-31 13:09:34,928 C:/lzw_programming/test/main.py(6): INFO start
2018-08-31 13:09:34,928 C:/lzw_programming/test/main.py(10): ERROR error:
2018-08-31 13:09:34,930 C:/lzw_programming/test/main.py(11): ERROR (<type 'exceptions.ZeroDivisionError'>, ZeroDivisionError('integer division or modulo by zero',), <traceback object at 0x0000000003B38888>)
Traceback (most recent call last):
  File "C:/lzw_programming/test/main.py", line 8, in <module>
    print(1 / 0)
ZeroDivisionError: integer division or modulo by zero

这是error.log。级别是error。没有记录ta_log.info()和ta_log.debug()的信息

2018-08-31 13:09:34,928 C:/lzw_programming/testassist/main.py(10): ERROR error:
2018-08-31 13:09:34,930 C:/lzw_programming/testassist/main.py(11): ERROR (<type 'exceptions.ZeroDivisionError'>, ZeroDivisionError('integer division or modulo by zero',), <traceback object at 0x0000000003B38888>)
Traceback (most recent call last):
  File "C:/lzw_programming/testassist/main.py", line 8, in <module>
    print(1 / 0)
ZeroDivisionError: integer division or modulo by zero

——————————————第五步——————————————

运行了3天主程序,查看是否滚动产生了新的日志信息,结果是把历史日志信息滚动复制到了新的文件里,后缀名为日期,如图。

Jira-API的详细使用例子

下面是Jira-API的详细使用的例子,包含:

  • Jira的登陆,通过jql批量查询jira-issue,
  • 获得jira-project下的所有issue,assignee的详细信息,
  • 添加和更新defect
  • 下载和上传附件
  • 通过Jira登录的cookies搭配requsts库发送自定义的一些http请求
 
# -*- coding: UTF-8 -*-
import traceback
import requests
from atlassian import Jira
from jira import JIRA
import globalParam
jira = object
jira2 = object
#url是jira的地址
url = "https://www.Jira.com"
# 登录jira,成功为1,失败为0
def login(username, password):
    global jira, jira2
    result = 2
    try:
        jira = JIRA(server=url, basic_auth=(username, password), max_retries=1, timeout=400)
        jira2 = Jira(url=url, username=username, password=password)
        globalParam.reporter = get_current_user()
    except Exception:
        result = 0
        return result
    result = 1
    return result
# 获得一个项目的所有assignee的信息
def get_all_assignable_users_by_project_key(project_key):
    return jira2.get_all_assignable_users_for_project(project_key)
#下载附件到本地
def download_attachment(jira_attachment_id, filepath):
    attachment = jira.attachment(jira_attachment_id)
    image = attachment.get()
    with open(filepath, 'wb') as f:
        f.write(image)
#删除Jira上的附件
def delete_attachment(jira_attachment_id):
    jira.delete_attachment(jira_attachment_id)
#获得当前登陆的用户名
def get_current_user():
    return jira.myself()['displayName']
#获得当前登陆的用户的Key
def get_current_eid():
    return jira.myself()['key']
#根据jira-key获得开发人员
# key 可以是key'JIRA-1451'
def get_assignee(self, key):
    global jira
    issue = jira.issue(key)
    return issue.fields.assignee
#获得所有的Jira项目
def get_all_project():
    try:
        projects = jira.projects()
    except Exception:
        print(traceback.format_exc())
        result = 0
        return result
    return projects
# 根据jira-project-key参数获得所有的issue的各类信息
def get_issues_by_project_key(project_key):
    # 因为component从jira取出来是list,所以用逗号将它分割,重新组合成string
    jqlstring = "project = " + project_key + " AND issuetype = Defect ORDER BY updated DESC"
    try:
        query = jira.search_issues(
            jql_str=jqlstring,
            json_result=True,
            fields="key,summary,description,environment,comment,"
                   "components,labels,assignee,reporter,status,attachment,updated",
            maxResults=4000)
    except Exception:
        print(traceback.format_exc())
        result = 0
        return result
    issues = query["issues"]
    return issues
# 根据jira-project-key参数和时间获得所有的issue的各类信息
def get_issues_by_project_key_and_time(project_key, last_synctime):
    # 因为component从jira取出来是list,所以用逗号将它分割,重新组合成string
    jqlstring = "project = " + project_key + " AND updatedDate >='" + last_synctime + 
                "' AND issuetype = Defect ORDER BY updated DESC"
    try:
        query = jira.search_issues(
            jql_str=jqlstring,
            json_result=True,
            fields="key,summary,description,environment,comment,"
                   "components,labels,assignee,reporter,status,attachment,updated",
            maxResults=4000)
    except Exception:
        print(traceback.format_exc())
        result = 0
        return result
    issues = query["issues"]
    return issues
#根据jira-project-key参数获得所有的component信息
def get_components_by_project_key(project_key):
    try:
        components = jira.project_components(project_key)
    except Exception:
        print(traceback.format_exc())
        result = 0
        return result
    return components
#根据jira-project-key参数获得所有的version信息
def get_version_by_project_key(project_key):
    jira_project = jira.project(project_key)
    versions = jira_project.versions
    return versions
#添加一个defect
def add_defect(project_key, summary, description, steps_to_reproduce, labels, defect_severity, env, components,
               frequency, product_id, version_name, assignee_eid):
    jira_project = jira.project(project_key)
    label_list = labels.split(",")
    pid = jira_project.id
    if isinstance(product_id, int):
        product_id = str(product_id)
    components_list = []
    components_name = components.split(",")
    for item in components_name:
        components_list.append({"name": item})
    issue_dict = {
        'project': {'id': pid},
        'summary': summary,
        'description': description,
        'issuetype': {'name': 'Defect'},
        'labels': label_list,
        'customfield_10040': {"value": defect_severity},  # BUG的Defect Severity字段
        'customfield_10033': steps_to_reproduce,  # BUG的描述步骤
        'environment': env,
        'components': components_list,
        'customfield_10336': {"value": frequency},
        'customfield_13600': product_id,
        'customfield_11170': {"name": version_name},
        "assignee": {"name": assignee_eid}
    }
    if assignee_eid is None:
        del issue_dict['assignee']
    if env == "":
        del issue_dict['environment']
    if components == "":
        del issue_dict['components']
    if product_id == "" or product_id == "n":
        del issue_dict['customfield_13600']
    if version_name == "":
        del issue_dict['customfield_11170']
    new_issue = jira.create_issue(fields=issue_dict)
    return new_issue.key
#更新一个defect
def update_defect(issue_key, summary, description, steps_to_reproduce,
                  labels, defect_severity, env, components, frequency, product_id, version_name, assignee_eid):
    issue = jira.issue(issue_key)
    label_list = labels.split(",")
    components_list = []
    components_name = components.split(",")
    if components == "":
        pass
    for item in components_name:
        components_list.append({"name": item})
    issue_dict = {
        'summary': summary,
        'description': description,
        'issuetype': {'name': 'Defect'},
        'labels': label_list,
        'customfield_10040': {"value": defect_severity},  # BUG的Defect Severity字段
        'customfield_10033': steps_to_reproduce,  # BUG的描述步骤
        'environment': env,
        'components': components_list,
        'customfield_10336': {"value": frequency},
        'customfield_13600': str(product_id),
        'customfield_11170': {"name": version_name},
        "assignee": {"name": assignee_eid}
    }
    if assignee_eid is None:
        del issue_dict['assignee']
    if env == "":
        del issue_dict['environment']
    if components == "":
        del issue_dict['components']
    if version_name == "":
        del issue_dict['customfield_11170']
    update_issue = issue.update(fields=issue_dict)
    cccc = update_issue
    return issue_key
#将一个本地的附件上传到Jira上
def add_attachment(issue, path, filename):
    newpath = path.encode('utf-8')
    cc = unicode(newpath, "utf-8")
    result = jira.add_attachment(issue=issue, attachment=cc, filename=filename)
    return result
#根据jira-key获得该issue所有的附件
def get_attachment(issue_key):
    issue = jira.issue(issue_key)
    return issue.fields.attachment
#通过项目project_key值,抓取页面上的一些自定义参数,例如自定义参数13600,对应products参数
def get_products_by_project_key(project_key):
    product_map = {}
    jiraproject = jira.project(project_key)
    #jira._session.cookies可以用来搭配requests库,发送请求
    cookies = jira._session.cookies
    body = {"pid": jiraproject.id}
    url = "https://www.jira.com/secure/QuickCreateIssue!default.jspa?decorator=none"
    result = requests.post(url, data=body, cookies=cookies,
                           headers={"Content-type": "application/x-www-form-urlencoded"})
    html = result.text
    try:
        select1 = html.split('"id":"customfield_13600","label":"Product/s","required":false,')[1]
        select2 = select1.split('</select>')[0]
        if not select2.__contains__("\n\tNone\n\n"):
            select3 = select2.split('<option')
            c = select3
            for item in select3:
                if item.__contains__('value='):
                    patern_id = item.split('value=\"')[1]
                    id = patern_id.split('\"')[0]
                    patern_value = item.split("\n    ")
                    value = patern_value[1].strip()
                    product_map[id] = value
    except Exception:
        # print(traceback.format_exc())
        pass
    return product_map
#给一个jira-issue添加comment
def add_comment(issue_key, comment_body):
    comment = jira.add_comment(issue_key, comment_body)
    return comment.id

将Jira获取的UTC时间转本地时间yyyy-MM-dd’T’HH:mm:ss

通过API获得jira 备注(comment)的更新时间,发现获得的UTC时间格式为
2018-08-14T02:52:22.216+0000
这个时候,如果需要转换成datetime :yyyy-MM-dd'T'HH:mm:ss格式,
或者date:yyyy-MM-dd,可以用下面的代码:

#!/usr/bin/python
# -*- coding:utf-8 -*-
import re
import time
from datetime import datetime
def utc2local(utc_st):
    # UTC时间转本地时间(+8:00)
    now_stamp = time.time()
    local_time = datetime.fromtimestamp(now_stamp)
    utc_time = datetime.utcfromtimestamp(now_stamp)
    offset = local_time - utc_time
    local_st = utc_st + offset
    return local_st
def local2utc(local_st):
    # 本地时间转UTC时间(-8:00)
    time_struct = time.mktime(local_st.timetuple())
    utc_st = datetime.utcfromtimestamp(time_struct)
    return utc_st
def utc_format(utcstr):
    """
    将不标准的utc时间字符串转换成datetime格式
    :param utcstr: 不标准的utc字符串,如‘2018-04-23T03:43:35.000+0000’
    :return:
    """
    utcstr = re.sub('.\d\d\d\+0000', '', utcstr, count=1)
    try:
        UTC_FORMAT = "%Y-%m-%dT%H:%M:%S"
        d_time = datetime.strptime(utcstr, UTC_FORMAT)
    except Exception:
        UTC_FORMAT = "%Y-%m-%d %H:%M:%S"
        d_time = datetime.strptime(utcstr, UTC_FORMAT)
    return d_time
def get_local_date(utcstr):
    """
    将jira返回的str类型的时间,转换成datetime格式,并去除日期之后的内容(提供给SprintDailyIssuesBar使用的日期处理接口)
    :param utcstr: jira返回的time字符串
    :return:datetime格式
    """
    utc_st = utc_format(utcstr)
    # print utc_st
    local_st = utc2local(utc_st)
    # print local_st
    local_str = local_st.strftime('%Y-%m-%d')
    local_date = datetime.strptime(local_str, "%Y-%m-%d")
    # print local_date
    return local_date
def get_local_datetime_str(utcstr):
    """
    将jira返回的str类型的UTC时间,转换成str类型的local time,包含具体的时、分、秒(提供给tableData使用,转换时间)
    :param utcstr: jira返回的time字符串
    :return:string
    """
    utc_st = utc_format(utcstr)
    # print utc_st
    local_st = utc2local(utc_st)
    # print local_st
    local_str = local_st.strftime('%Y-%m-%d %H:%M:%S')
    return local_str
 if __name__ == '__main__':
     utcstr1 = '2018-08-14T02:52:22.216+0000'
     tt=get_local_datetime_str(utcstr1)
     print(tt)

将Jira获取的UTC时间转本地时间yyyy-MM-dd’T’HH:mm:ss

通过API获得jira 备注(comment)的更新时间,发现获得的UTC时间格式为
2018-08-14T02:52:22.216+0000
这个时候,如果需要转换成datetime :yyyy-MM-dd'T'HH:mm:ss格式,
或者date:yyyy-MM-dd,可以用下面的代码:

#!/usr/bin/python
# -*- coding:utf-8 -*-
import re
import time
from datetime import datetime
def utc2local(utc_st):
    # UTC时间转本地时间(+8:00)
    now_stamp = time.time()
    local_time = datetime.fromtimestamp(now_stamp)
    utc_time = datetime.utcfromtimestamp(now_stamp)
    offset = local_time - utc_time
    local_st = utc_st + offset
    return local_st
def local2utc(local_st):
    # 本地时间转UTC时间(-8:00)
    time_struct = time.mktime(local_st.timetuple())
    utc_st = datetime.utcfromtimestamp(time_struct)
    return utc_st
def utc_format(utcstr):
    """
    将不标准的utc时间字符串转换成datetime格式
    :param utcstr: 不标准的utc字符串,如‘2018-04-23T03:43:35.000+0000’
    :return:
    """
    utcstr = re.sub('.ddd+0000', '', utcstr, count=1)
    try:
        UTC_FORMAT = "%Y-%m-%dT%H:%M:%S"
        d_time = datetime.strptime(utcstr, UTC_FORMAT)
    except Exception:
        UTC_FORMAT = "%Y-%m-%d %H:%M:%S"
        d_time = datetime.strptime(utcstr, UTC_FORMAT)
    return d_time
def get_local_date(utcstr):
    """
    将jira返回的str类型的时间,转换成datetime格式,并去除日期之后的内容(提供给SprintDailyIssuesBar使用的日期处理接口)
    :param utcstr: jira返回的time字符串
    :return:datetime格式
    """
    utc_st = utc_format(utcstr)
    # print utc_st
    local_st = utc2local(utc_st)
    # print local_st
    local_str = local_st.strftime('%Y-%m-%d')
    local_date = datetime.strptime(local_str, "%Y-%m-%d")
    # print local_date
    return local_date
def get_local_datetime_str(utcstr):
    """
    将jira返回的str类型的UTC时间,转换成str类型的local time,包含具体的时、分、秒(提供给tableData使用,转换时间)
    :param utcstr: jira返回的time字符串
    :return:string
    """
    utc_st = utc_format(utcstr)
    # print utc_st
    local_st = utc2local(utc_st)
    # print local_st
    local_str = local_st.strftime('%Y-%m-%d %H:%M:%S')
    return local_str
 if __name__ == '__main__':
     utcstr1 = '2018-08-14T02:52:22.216+0000'
     tt=get_local_datetime_str(utcstr1)
     print(tt)

图解OWASP ZAP录制登录请求,并且进行SQL注入测试

好了,废话不多说,下面几张图请按顺序观看,是作者用OWASP ZAP对某一个网站进行登录的SQL注入测试,网址和登录密码,作者已经打码了,如有侵权或引起其他不适,请联系作者。
——————————————第一步——————————————

——————————————第二步——————————————

——————————————第三步——————————————
——————————————第四步——————————————
——————————————第五步——————————————

 

记录一次我做的influxDB性能测试

InfluxDB性能测试报告
被测环境:
腾讯云

CPU 内存 带宽 版本号
4核 16G 1Gbit/s Ubuntu 4.8.4-2ubuntu1~14.04.3

 
地址:
 
被测程序:
Docker下安装的influxDB 端口8086
 
压测环境:
腾讯云

CPU 内存 带宽 版本号
2核 8G 1Gbit/s Ubuntu 4.8.4-2ubuntu1~14.04.3

 
地址:
 
测试程序:
从github上找的influxdata公司提供的两款测试工具
influx-stress 用于写入测试
influxdb-comparisons用于查询测试
 
测试场景:

写入测试
工具名称 influx-stress
 
工具github地址 https://github.com/influxdata/influx-stress
测试原理 该工具是通过go语言的fasthttp库编写的。
1.     会在服务器上创建一个数据库stress
2.     然后创建一个MEASUREMENT(类似关系数据库的表)名为ctr
该表有time,n.some三个字段
3.     不断的向stress数据库的ctr表插入数据,每次插入的数据都包含三个字段。每一条数据称为一个points。
插入数据的方法是通过influxDB的HTTP API 发送请求(POST /write?db=stress)
 
测试命令 influx-stress insert -r 60s –strict –pps 200000 –host http://10.XX.XX.XX:8086
 
测试程序运行结果
Points Per Second(发起请求) Write Throughput(points/s)
(数据库实际处理结果)
CPU平均利用率
200000 199713 33%
300000 299280 45%
400000 392873 62%
500000 491135 80%
600000 593542 90%
650000 606036 93%
700000 613791 95%

测试结论:最大的吞吐量为每秒写入60万条数据。这之后,每秒发送的points再多,吞吐量也不会增加,同时CPU利用率已达90%。
 

查询测试
工具名称 influxdb-comparisons
 
工具github地址 https://github.com/influxdata/influxdb-comparisons
测试原理 该工具是通过go语言的fasthttp库编写的。
1.     会在服务器上创建一个数据库benchmark_db
2.     然后创建9个MEASUREMENT :cpu,disk,diskio,kernel,mem,net,nginx,postgresl
每个measurement 有2160行数据。
3.     通过http GET请求”GET /query?db=benchmark_db“查询cpu这张表。
查询语句为:SELECT max(usage_user) from cpu where (hostname = ‘host_0’) and time >= ‘2016-01-01T01:16:32Z’ and time < ‘2016-01-01T02:16:32Z’ group by time(1m)
可以取出61条数据。
 
测试命令 ./bulk_query_gen -query-type “1-host-1-hr” | ./query_benchmarker_influxdb -urls http://10.XX.XX.XX:8086 -limit 1000
 
测试程序运行结果
查询命令执行次数
(-limit)
命令最短执行时间 每条命令平均执行时间 命令最大执行时间 总耗时
100 1.20ms 1.69ms 4.36ms 0.2sec
200 1.20ms 1.71ms 7.40ms 0.3sec
300 1.25ms 1.73ms 7.54ms 0.5sec
400 1.21ms 1.71ms 7.54ms 0.7sec
500 1.20ms 1.70ms 7.54ms 0.8sec
600 1.17ms 1.67ms 7.54ms 1.0sec
700 1.14ms 1.66ms 8.33ms 1.2sec
800 1.14ms 1.65ms 8.33ms 1.3sec
900 1.14ms 1.63ms 8.33ms 1.5sec
1000 1.14ms 1.64ms 8.33ms 1.6sec

测试结论:因为该工具最大只能测到读取1000条数据,所以没有继续加大压力测试。查询操作的消耗时间因为受到被查询表的数据量和查询语句的复杂性影响,所以在influxDate官方给出的被查表和查询语句下,算出来是平均每秒执行600次查询。
 
 
 
 

wxpython 的pub/sub发布订阅,夸窗口传递信息

我们经常会用到两个窗口之间互相传递信息,或者把一个窗口里,文本框输入的值,传递到另外一个frame的另外一个文本框里,
这个时候,我们可以使用wxpython的pub/sub方法。
test.py


class Main(wx.App):
          def __init__(self):
                  #mainFrame 是用wxglade画的一个frame导出来的python文件
                   self.frame1 = mainFrame.MyFrame(None, wx.ID_ANY, "")
                   self.frame1.Show()
                   self.children=test2.children()
                  #定义一个name1属性,值来自于窗口上的文本框控件
                   self.name1 = self.frame1.text_ctrl_1
                  #  离开焦点,就把fram1的文本框里的值传入children的另外一个文本框内
                  self.name1 .Bind(wx.EVT_COMMAND_KILL_FOCUS, self.save)
                  #发布一个叫in_sync的主题,触发sync函数
                   pub.subscribe(self.sync, "in_sync")
          def sync(self, msg):
                  #给children的text_ctrl_2字段设置值
                  self.children.frame.text_ctrl_2.SetValue(msg)
          def save(self,evt):
                    value=self.name1.GetValue()
                    #调用一下in_sync方法,如果in_sync方法在别的class里,
                    #也是可以调用pub.sendMessage成功的
                    self.children.in_sync(value)

test2.py

class children(wx.App):
           def __init__(self):
                  #mainFrame 是用wxglade画的一个frame导出来的python文件
                   self.frame = mainFrame.MyFrame(None, wx.ID_ANY, "")
                   self.frame.Show()
           def in_sync(text):
                 #订阅"in_sync"主题
                 wx.CallAfter(pub.sendMessage, "in_sync", msg=text)

wxpython 根据item的名字找到tree_ctrl对应的节点

业务场景,需要在一个tree_ctrl中找到一个节点,并且给该节点添加子节点

def get_item_by_label(self, tree, search_text, root_item):
    item, cookie = tree.GetFirstChild(root_item)
    while item.IsOk():
        text = tree.GetItemText(item)
        if text.lower() == search_text.lower():
            return item
        if tree.ItemHasChildren(item):
            match = self.get_item_by_label(tree, search_text, item)
            if match.IsOk():
                return match
        item, cookie = tree.GetNextChild(root_item, cookie)
    return wx.TreeItemId()
result = get_item_by_label(tree, '已有节点', tree.GetRootItem())
if result.IsOk():
    print('We have a match!')
    new_item = tree.AppendItem(result , "新节点")

wxpython一个event,多个handler,先绑定的后执行

Q:为什么会有一次event,多次handler的需求呢?
A:因为wxpython 目前有一个BUG,在一个event函数中,无法使用两次Dialog.showModal方法。当第一个Dialog消失后,第二个dialog再弹出,会造成系统卡死。所以必须把两个dialog.showModal放入两个event中。
绑定规则:先绑定的后执行
给按钮sync_button 绑定三个事件,第一次执行的在下,第二次执行的在上,如下:
给按钮绑定事件

        self.sync_button.Bind(wx.EVT_BUTTON, self.sync_three_event)
        self.sync_button.Bind(wx.EVT_BUTTON, self.sync_two_event)
        self.sync_button.Bind(wx.EVT_BUTTON, self.sync_one_event)

编写事件的event

    def sync_one_event(self, event):
        print("第一次触发事件" )
        event.Skip()
    def sync_two_event(self, event):
        print("第二次触发事件" )
        event.Skip()
    def sync_three_event(self, event):
        print("第三次触发事件" )
        event.Skip()

最后触发的结果是:

第一次触发事件
第二次触发事件
第三次触发事件

实现wxpython的拖拽上传功能

实现wxpython的拖拽上传功能
1.从FileDropTarget继承

···
class MyFileDropTarget(wx.FileDropTarget):
def init(self):
wx.FileDropTarget.init(self)
def OnDropFiles(self, x, y, filepath):
# file=os.path.basename(filepath[0])
#各种文件操作之类的
return False ···

2.给panel绑定拖拽功能

    filedrop = MyFileDropTarget()
    self.frame.panel_2.SetDropTarget(filedrop)

3.注意事项:
一次只能拖拽一个文件上去,如果一次拖拽A,B,C三个文件。最后filepath只能获取到A文件,B,C丢失


苏ICP备18047533号-2