python tkinter动态追加按钮等控件可能遇到的问题
小爬最近给同事制作一个小爬虫:具体要求:
1、每天自动定时触发;
2、模拟用户自动登陆;
3、自动爬取对应API接口数据;
4、对爬取结果进行逻辑判断,对符合条件的数据进行规则化列示;
5、列示的行项目支持超链接,如果用用户已经通过浏览器登陆过,该超链接需要能支持单击后在浏览器内新建选项卡并直接进入对应的表单,无需再次登陆。
小爬思考了下:整个程序的功能实现中,2、3、4步骤涉及的功能在先前小爬编写的一些自动化工具中已经有实现过,所以与小爬而言,核心问题就是步骤1和5;经过翻阅相关资料,“每天自动定时触发”可以通过Windows标准的“任务计划程序"来实现:
该功能可以实现 按特定频次自动触发特定程序或脚本,且支持传参,配置过程非常简单易用;
唯一的问题,如果经由此功能启动特定脚本,则通过"os.getcwd()"得到的路径是"C:\windows\system32",而不是脚本自身所在的路径,可能会与您的预期不一致;所以如果您的脚本中涉及调用一个同目录下的excel文件,那么如何自动获得该"excel"的路径呢,可以通过下面的代码实现:
filepath=os.path.abspath(sys.argv[0])
filepath=os.path.dirname(filepath)
至于tkinter怎么动态追加按钮并附上超链接事件,中间涉及到两个问题:
1.按钮数量不固定,如何动态追加,按钮名怎么动态生成;
2.按钮如何绑定事件,进行超链接到系统默认浏览器.
问题1的python其中一种解决方法是:
names=locals()
for i in range(len(afFormNumberList)):
names["link%s"%i]=tk.Button(window,text="%s\t%s\t%s\t%s\n\n"%(afFormNumberList[i],afPersonNameList[i],failDateList[i],afFromUrlList[i]),font=('微软雅黑', 10))
names["link%s"%i].pack()
上面的代码中,当我们对这些button进行事件绑定且动态传参时,如果我们绑定的url中动态引用了变量i,则事件不会马上触发event,而是在用户点击该button时才会进行事件响应,此时,i的值永远是循环的最后一个数,那么我们动态生成的所有的button链接的地址或者说事件永远是一样的,这显然不是我们想要的结果,我们可能希望的结果是:
if i==0:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[0]))
elif i==1:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[1]))
elif i==2:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[2]))
elif i==3:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[3]))
elif i==4:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[4]))
elif i==5:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[5]))
elif i==6:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[6]))
elif i==7:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[7]))
elif i==8:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[8]))
elif i==9:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[9]))
elif i==10:
names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[10]))
上段代码通过变量指定,能有效解决超链接永远为最后一个的问题,但是这段代码过于冗长,实现方式太笨,且这种写法是假定按钮动态追加的数量小于预设值.缺乏灵活性!
小爬互联网上找了一圈,最终在stackoverflow中找到了想要的答案:https://stackoverflow.com/questions/20596892/disabling-buttons-after-click-in-tkinter
这段代码中的核心在于"n=letters[index]",随着每次的index递增,我们的n值是不一样的.也就是按钮动态增加的过程中,每次command中绑定的n是不一样的,而不是永远的最后一个"i",另外的巧妙之处在于,代码将button对象追加到一个buttons的空列表中,这样,随着index的递增,我们的buttons[index]就可以对应不同的button.那就是不同index跟不同button之间形成了一一映射关系.这才是这个问题解决的关键.
最后生成的gui界面如下:
通过点击该button,可以自动打开对应表单(如果浏览器已完成该门户的登陆,则无需再次验证登陆,而通过office系列软件集成的超链接在面对此问题时,无论之前是否已登录,都会生成新的cookie和session,用户需要再次登陆,这是出于安全考虑,但是操作步骤变得繁琐).
上文中提到自动化工具的示例代码如下,供诸位参考,一起学习进步:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/7/09 17:15
# @Author : New June
# @Desc :
# @Software: PyCharm
# @修改日期:2019-07-09.内容:支持水泥临时授信业务到期单据的提醒、存档、单进程
# @修改日期:2019-07-11.内容:支持对信息展示,单击对应行能超链接至对应表单页
# @修改日期:2019-07-17.内容:改进代码,使代码能够对未知数量的button进行事件响应,不需要穷举,且支持button点击后置灰,不可用,与未点击的button区分 import time,re,datetime,csv,requests,json,os,easygui,sys
from requests.exceptions import ConnectionError
import webbrowser
import tkinter as tk if __name__ == '__main__':
#记得登陆后时间起点,进入爬取过程
#print(os.getcwd())
def open_url(index,url):
#print(event.x,event.y)
#url=buttons[index]["text"].split(" ")[1]
buttons[index].config(state="disabled") #禁用事件
webbrowser.open("%s"%url, new=0) #打开浏览器 filepath=os.path.abspath(sys.argv[0])
filepath=os.path.dirname(filepath)
filepath=filepath+"\\水泥临时授信存档.txt"
#print(filepath)
with open(filepath,"r",encoding='UTF-8-sig') as t:
history=t.read().strip()
txt=open(filepath,"a",encoding='UTF-8')
username="yourusername"
psw="password" #today=datetime.date.today()
afFormNumberList=[]
afPersonNameList=[]
afFromUrlList=[]
failDateList=[]
#business="水泥(临时授信)" """登陆,拿到登陆后的session"""
loginData={'redirect':'','username':username,'password':psw.lower()}
session=requests.sessions.Session()
response=session.post('http://someurl.com/portal/u/a/login.do',loginData)
text=response.text
if "密码不匹配" in text:
easygui.msgbox("OA登陆密码不正确!")
sys.exit(0)
'''事后抽查-事中'''
data_search={
'page':1,
'rows':100,
'condition':
"""[{"column":"DELETE_STATUS","exp":"=","value":0},{"column":"CREDIT_TYPE","exp":"like","value":"cement-0"},{"column":"AF_STATUS","exp":"=","value":1},{"column":"CREDIT_TYPE","orderType":"default","orderKey":"","direction":"ASC"}]""",
'additionalParams':'{}'
}
try:
response=session.post(url="http://someurl.com/mdm/af/credit/list.do",data=data_search)
if response.status_code==200:
pageContent = response.json()
for element in pageContent['rows']:
temporaryStatus=element['temporaryStatus'] #SAP状态,1代表成功,0代表未处理
failDate=element['failDate'] #授信失效日期 临时授信期限
afFormNumber=element['afFormNumber']
#if failDate == str(datetime.date.today()-datetime.timedelta(days=1)) and temporaryStatus=="1": #失效日期在昨天,且SAP状态为成功
if temporaryStatus=="" and failDate < str(datetime.date.today()) and afFormNumber not in history:
txt.writelines("%s"%afFormNumber)
txt.write("\n")
afFormNumberList.append(afFormNumber) #表单号
afFormId=element['id']
afPersonNameList.append(element['afPersonName'])
failDateList.append(failDate)
afFromUrlList.append("http://someurl.com/mdm/af/credit/temporaryForm.do?_hf_data_id=%s"%afFormId) #表单网址
if afFormNumberList:
# 建立窗口window
window = tk.Tk()
# 给窗口的可视化起名字
window.title('临时授信到期信息')
# 设置窗口的居中显示
screenwidth = window.winfo_screenwidth()
screenheight = window.winfo_screenheight()
width = 1080
height = 700
size = "%dx%d+%d+%d" % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
# 设定窗口的大小(长 * 宽)
window.geometry(size)
names=locals()
navigation=tk.Label(window,text="表单编号\t申请人\t临时授信期限\t表单url地址\n", justify="left",font=('微软雅黑', 14,"bold"),fg="#8B008B")
navigation.pack()
#letters=["A", "T", "D", "M", "E", "A", "S", "R", "M"] #https://stackoverflow.com/questions/20596892/disabling-buttons-after-click-in-tkinter
buttons=[]
for i in range(len(afFormNumberList)):
url=afFromUrlList[i]
index=i
button =tk.Button(window,text="%s\t%s\t%s\t %s\n\n"%(afFormNumberList[i],afPersonNameList[i],failDateList[i],afFromUrlList[i]),font=('微软雅黑', 10),command=lambda index=index,url=url:open_url(index,url)) #names["link%s"%i].place(x=20,y=100*(i+1))
button.pack()
#window.update()
buttons.append(button)
txt.close()
window.mainloop()
else:
txt.close()
easygui.msgbox("今天没有授信到期单据!")
except requests.ConnectionError as e:
print('Error',e.args)
python tkinter动态追加按钮等控件可能遇到的问题的更多相关文章
- Python Tkinter参考资料之(通用控件属性)
大部分控件的共享选项: 选项(别名) 说明 单位 典型值 没有此属性的控件 background(bg) 当控件显示时,给出的正常颜色 color 'gray25''#ff4400' border ...
- asp.net动态生成按钮Button控件
1.动态生成button控件及响应服务端和客户端事件 void BindButtons(){ foreach (var item in items) { Button Btn = new Button ...
- Python实例讲解 -- wxpython 基本的控件 (按钮)
使用按钮工作 在wxPython 中有很多不同类型的按钮.这一节,我们将讨论文本按钮.位图按钮.开关按钮(toggle buttons )和通用(generic )按钮. 如何生成一个按钮? 在第一部 ...
- Python pyQt4/pyQt5 学习笔记1(空白窗口,按钮,控件事件,控件提示,窗体显示到屏幕中间,messagebox)
PyQt4是用来编写有图形界面程序(GUI applications)的一个工具包.PyQt4作为一个Python模块来使用,它有440个类和超过6000种函数和方法.同时它也是一个可以在几乎所有主流 ...
- 八、pyqt5按钮类控件——QPushButton、QRadioButton、QCheckBox
pyqt5中常用的按钮类控件有QPushButton.QRadioButton.QCheckBox.QToolButton等.这些按钮类的基类都是QAbstracButton类.所以这些类有部分方法是 ...
- Qt编写自定义控件8-动画按钮组控件
前言 动画按钮组控件可以用来当做各种漂亮的导航条用,既可以设置成顶部底部+左侧右侧,还自带精美的滑动效果,还可以设置悬停滑动等各种颜色,原创作者雨田哥(QQ:3246214072),驰骋Qt控件界多年 ...
- WPF 中动态创建和删除控件
原文:WPF 中动态创建和删除控件 动态创建控件 1.容器控件.RegisterName("Name",要注册的控件) //注册控件 2.容器控件.FindName(" ...
- iOS开发——UI高级OC篇&自定义控件之调整按钮中子控件(图片和文字)的位置
自定义控件之调整按钮中子控件(图片和文字)的位置 其实还有一种是在storyBoard中实现的,只需要设置对应空间的左右间距: 这里实现前面两种自定义的方式 一:imageRectForContent ...
- WPF编程,通过Double Animation同时动态缩放和旋转控件的一种方法。
原文:WPF编程,通过Double Animation同时动态缩放和旋转控件的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_4330793 ...
随机推荐
- Java面向对象----String对象的声明和创建
String a="abcd" 相等 String b="abcd" String a=new String("abcd") 不等于 ...
- @总结 - 2@ 位运算卷积/子集卷积 —— FWT/FMT
目录 @0 - 参考资料@ @1 - 异或卷积概念及性质@ @2 - 快速沃尔什正变换(异或)@ @3 - 快速沃尔什逆变换(异或)@ @4 - 与卷积.或卷积@ @5 - 参考代码实现@ @6 - ...
- 威胁快报|挖矿团伙8220进化,rootkit挖矿趋势兴起
近日,阿里云安全团队发现8220挖矿团伙为了更持久的驻留主机以获得最大收益,开始使用rootkit技术来进行自我隐藏.这类隐藏技术的使用在watchdogs等挖矿蠕虫使用后开始出现逐渐扩散和进化的趋势 ...
- 一、JVM内存区域组成
一.JVM内存区域组成 java把内存分四种: 1.栈区(stack segment)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等,具体方法执行结束之后,系统自动释放内存资源 2. ...
- iptables 规则(Rules)
iptables的每一条规则(rule),都是由两部分组成的,第一部分包含一或多个「过滤条件」其作用是检查包是否符合处理条件(所有条件都必须成立才算数) :第而部分称为「目标」,用於決定如何处置符合条 ...
- H3C 主机单播IP包发送
- PHP内置服务器
PHP在安装的时候会内置了服务器的功能,我们在使用的过程中如果只是调试,可以选择启动PHP内置的服务器,下面是windows下PHP内置服务器的启动步骤: 1.将php的D:\phpStudy\php ...
- 2016.1.22 扩充临时表空间解决ora-01652错误
今天运行一个复杂查询时报错ora-01652 无法通过128 扩展temp段, 网上说是临时表空间大小不够,运行了脚本调整临时表空间,问题解决 alter database tempfile '/ap ...
- CSS3 box-sizing 盒子布局
在CSS中盒模型被分为两种,第一种是W3C的标准模型,第二种是IE怪异盒模型.不同之处在于后者的宽高定义的是可见元素框的尺寸,而不是元素框的内容区尺寸.目前对于浏览器大多数元素都是基于W3C标准的盒模 ...
- H3C 单路径网络中环路产生过程(1)