python tkinter动态追加按钮等控件可能遇到的问题

  小爬最近给同事制作一个小爬虫:具体要求:

1、每天自动定时触发;

2、模拟用户自动登陆;

3、自动爬取对应API接口数据;

4、对爬取结果进行逻辑判断,对符合条件的数据进行规则化列示;

5、列示的行项目支持超链接,如果用用户已经通过浏览器登陆过,该超链接需要能支持单击后在浏览器内新建选项卡并直接进入对应的表单,无需再次登陆。

  小爬思考了下:整个程序的功能实现中,2、3、4步骤涉及的功能在先前小爬编写的一些自动化工具中已经有实现过,所以与小爬而言,核心问题就是步骤1和5;经过翻阅相关资料,“每天自动定时触发”可以通过Windows标准的“任务计划程序"来实现:

  该功能可以实现 按特定频次自动触发特定程序或脚本,且支持传参,配置过程非常简单易用;

唯一的问题,如果经由此功能启动特定脚本,则通过"os.getcwd()"得到的路径是"C:\windows\system32",而不是脚本自身所在的路径,可能会与您的预期不一致;所以如果您的脚本中涉及调用一个同目录下的excel文件,那么如何自动获得该"excel"的路径呢,可以通过下面的代码实现:

1 filepath=os.path.abspath(sys.argv[0])
2 filepath=os.path.dirname(filepath)

  至于tkinter怎么动态追加按钮并附上超链接事件,中间涉及到两个问题:

1.按钮数量不固定,如何动态追加,按钮名怎么动态生成;

2.按钮如何绑定事件,进行超链接到系统默认浏览器.

问题1的python其中一种解决方法是:

1 names=locals()
2 for i in range(len(afFormNumberList)):
3   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))

 4   names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[i]))

5   names["link%s"%i].pack()    

上面的代码中,当我们对这些button进行事件绑定且动态传参时,如果我们绑定的url中动态引用了变量i,则事件不会马上触发event,而是在用户点击该button时才会进行事件响应,此时,i的值永远是循环的最后一个数,那么我们动态生成的所有的button链接的地址或者说事件永远是一样的,这显然不是我们想要的结果,我们可能希望的结果是:

 1 if i==0:
 2     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[0]))
 3 elif i==1:
 4     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[1]))
 5 elif i==2:
 6     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[2]))
 7 elif i==3:
 8     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[3]))
 9 elif i==4:
10     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[4]))
11 elif i==5:
12     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[5]))
13 elif i==6:
14     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[6]))
15 elif i==7:
16     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[7]))
17 elif i==8:
18     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[8]))
19 elif i==9:
20     names["link%s"%i].bind("<Button-1>",lambda event:open_url(event,afFromUrlList[9]))
21 elif i==10:
22     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,用户需要再次登陆,这是出于安全考虑,但是操作步骤变得繁琐).

上文中提到自动化工具的示例代码如下,供诸位参考,一起学习进步:

  1 #!/usr/bin/env python
  2 # -*- coding: utf-8 -*-
  3 # @Time    : 2019/7/09 17:15
  4 # @Author  : New June
  5 # @Desc    :
  6 # @Software: PyCharm
  7 # @修改日期:2019-07-09.内容:支持水泥临时授信业务到期单据的提醒、存档、单进程
  8 # @修改日期:2019-07-11.内容:支持对信息展示,单击对应行能超链接至对应表单页
  9 # @修改日期:2019-07-17.内容:改进代码,使代码能够对未知数量的button进行事件响应,不需要穷举,且支持button点击后置灰,不可用,与未点击的button区分
 10
 11
 12 import time,re,datetime,csv,requests,json,os,easygui,sys
 13 from requests.exceptions import ConnectionError
 14 import webbrowser
 15 import tkinter as tk
 16
 17 if __name__ == ‘__main__‘:
 18     #记得登陆后时间起点,进入爬取过程
 19     #print(os.getcwd())
 20     def open_url(index,url):
 21         #print(event.x,event.y)
 22         #url=buttons[index]["text"].split(" ")[1]
 23         buttons[index].config(state="disabled") #禁用事件
 24         webbrowser.open("%s"%url, new=0) #打开浏览器
 25
 26     filepath=os.path.abspath(sys.argv[0])
 27     filepath=os.path.dirname(filepath)
 28     filepath=filepath+"\\水泥临时授信存档.txt"
 29     #print(filepath)
 30     with open(filepath,"r",encoding=‘UTF-8-sig‘) as t:
 31         history=t.read().strip()
 32     txt=open(filepath,"a",encoding=‘UTF-8‘)
 33     username="yourusername"
 34     psw="password"
 35
 36     #today=datetime.date.today()
 37     afFormNumberList=[]
 38     afPersonNameList=[]
 39     afFromUrlList=[]
 40     failDateList=[]
 41     #business="水泥(临时授信)"
 42
 43     """登陆,拿到登陆后的session"""
 44     loginData={‘redirect‘:‘‘,‘username‘:username,‘password‘:psw.lower()}
 45     session=requests.sessions.Session()
 46     response=session.post(‘http://someurl.com/portal/u/a/login.do‘,loginData)
 47     text=response.text
 48     if "密码不匹配" in text:
 49         easygui.msgbox("OA登陆密码不正确!")
 50         sys.exit(0)
 51     ‘‘‘事后抽查-事中‘‘‘
 52     data_search={
 53         ‘page‘:1,
 54         ‘rows‘:100,
 55         ‘condition‘:
 56         """[{"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"}]""",
 57         ‘additionalParams‘:‘{}‘
 58     }
 59     try:
 60         response=session.post(url="http://someurl.com/mdm/af/credit/list.do",data=data_search)
 61         if response.status_code==200:
 62             pageContent = response.json()
 63             for element in pageContent[‘rows‘]:
 64                 temporaryStatus=element[‘temporaryStatus‘] #SAP状态,1代表成功,0代表未处理
 65                 failDate=element[‘failDate‘] #授信失效日期  临时授信期限
 66                 afFormNumber=element[‘afFormNumber‘]
 67                 #if failDate == str(datetime.date.today()-datetime.timedelta(days=1)) and temporaryStatus=="1": #失效日期在昨天,且SAP状态为成功
 68                 if temporaryStatus=="1" and failDate < str(datetime.date.today()) and afFormNumber not in history:
 69                     txt.writelines("%s"%afFormNumber)
 70                     txt.write("\n")
 71                     afFormNumberList.append(afFormNumber) #表单号
 72                     afFormId=element[‘id‘]
 73                     afPersonNameList.append(element[‘afPersonName‘])
 74                     failDateList.append(failDate)
 75                     afFromUrlList.append("http://someurl.com/mdm/af/credit/temporaryForm.do?_hf_data_id=%s"%afFormId) #表单网址
 76             if afFormNumberList:
 77                 # 建立窗口window
 78                 window = tk.Tk()
 79                 # 给窗口的可视化起名字
 80                 window.title(‘临时授信到期信息‘)
 81                 # 设置窗口的居中显示
 82                 screenwidth = window.winfo_screenwidth()
 83                 screenheight = window.winfo_screenheight()
 84                 width = 1080
 85                 height = 700
 86                 size = "%dx%d+%d+%d" % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
 87                 # 设定窗口的大小(长 * 宽)
 88                 window.geometry(size)
 89                 names=locals()
 90                 navigation=tk.Label(window,text="表单编号\t申请人\t临时授信期限\t表单url地址\n", justify="left",font=(‘微软雅黑‘, 14,"bold"),fg="#8B008B")
 91                 navigation.pack()
 92                 #letters=["A", "T", "D", "M", "E", "A", "S", "R", "M"]  #https://stackoverflow.com/questions/20596892/disabling-buttons-after-click-in-tkinter
 93                 buttons=[]
 94                 for i in range(len(afFormNumberList)):
 95                     url=afFromUrlList[i]
 96                     index=i
 97                     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))
 98
 99                     #names["link%s"%i].place(x=20,y=100*(i+1))
100                     button.pack()
101                     #window.update()
102                     buttons.append(button)
103                 txt.close()
104                 window.mainloop()
105             else:
106                 txt.close()
107                 easygui.msgbox("今天没有授信到期单据!")
108     except requests.ConnectionError as e:
109         print(‘Error‘,e.args)

原文地址:https://www.cnblogs.com/new-june/p/11219661.html

时间: 2024-10-24 23:35:40

python tkinter动态追加按钮等控件可能遇到的问题的相关文章

Python Tkinter参考资料之(通用控件属性)

大部分控件的共享选项: 选项(别名) 说明 单位 典型值 没有此属性的控件 background(bg) 当控件显示时,给出的正常颜色 color 'gray25''#ff4400'   borderwidth(bd) 设置一个非负值,该值显示画控件外围3D边界的宽度;(特别的由relief选项决定这项决定).控件内部的3D效果也可以使用该值,该值可以是Tkinter(Tk_GetPixels)接受的任何格式  pixel 3   cursor 指定控件使用的鼠标光标,该值可以是Tkinter(

asp.net动态生成按钮Button控件

1.动态生成button控件及响应服务端和客户端事件 void BindButtons(){ foreach (var item in items) { Button Btn = new Button(); Btn.OnClientClick = "showLoading();return true;"; //客户端事件 //Btn.Attributes.Add("OnClientClick ", "this.disabled=true;return tr

Python实例讲解 -- wxpython 基本的控件 (按钮)

使用按钮工作 在wxPython 中有很多不同类型的按钮.这一节,我们将讨论文本按钮.位图按钮.开关按钮(toggle buttons )和通用(generic )按钮. 如何生成一个按钮? 在第一部分(part 1)中,我们已经说明了几个按钮的例子,所以这里我们只简短的涉及它的一些基本的东西.图7.4显示了一个简单的按钮. 图7.4 使用按钮是非常简单的.例7.4显示了该简单按钮的代码. Python代码   import wx class ButtonFrame(wx.Frame): def

iOS开发——UI高级OC篇&amp;自定义控件之调整按钮中子控件(图片和文字)的位置

自定义控件之调整按钮中子控件(图片和文字)的位置 其实还有一种是在storyBoard中实现的,只需要设置对应空间的左右间距: 这里实现前面两种自定义的方式 一:imageRectForContentRect/titleRectForContentRect 自定义一个按钮控件在系统自带的位置设置方法中实现对应子控件位置调整 1 /** 2 3 * 设置内部图标的frame 4 5 */ 6 7 - (CGRect)imageRectForContentRect:(CGRect)contentRe

ASP.NET动态加载用户控件的方法

方法是使用LoadControl方法,根据用户控件的相对路径,动态生成用户控件对象 用户控件 public class UserControlA :UserControl { public UserControlA(string name) { //TODO } } 需要动态生成控件的地方 string ucPath = "../UserControls/UserControlA.ascx"; UserControlA ca = Page.LoadControl(ucPath) as

动态创建asp.net控件

int i=0;            try            {                i = Int16.Parse(txt_num.Text);            } catch { } TextBox _txt;//创建text 对象            if (i > 0)            {                for (int _i = 0; _i < i; _i++)                {                    _

VC MFC按钮(CButton)控件

VC MFC按钮(CButton)控件 2012年11月11日 19:15   作者:TCEO   分类:技术文章   浏览:4,298 按钮控件 1如何在按钮控件上显示图片 首先确定你要显示在按钮控件的图片类型是什么,这里我是ico图标,由于要在按钮里显示ico图标,所以要把按钮控件的属性改一下, 方法是右击按钮控件,选择属性,单击样式选项卡,把图标这一项给勾上. 然后为这个按钮控件关联一个变量如:m_Quit,类型是”Control”,以后不做说明的话,类型都是”Control”. 按钮控件

另类的动态加载用户控件

最新更新:原本在看到此方案的时候觉的想到这方案的朋友特别高深,后来本人把本文写出来想和大家分享下,才知道这个就是Dottext方案中的一个模块而已.真是汗啊,嫌自己见识太浅.既然写了就当复习了一次Dottext..这还是我第一次听说Dottext.     在BS架构这块,我们平时建一个网站,通常是创建一个WebSite网站,或者是创建一个WebApplication.然后在WEB项目里面建立相应的aspx文件,以及用户控件,自定义控件等等.但是做为一个新加入此项目的你要去修改里面的某一个功能模

WPF编程,通过Double Animation同时动态缩放和旋转控件的一种方法。

原文:WPF编程,通过Double Animation同时动态缩放和旋转控件的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/details/87260287 ?1. 可直接调用.需要将控件的名称,缩放的位数,时间等参数传进去.? /// <summary> /// 同时旋转和缩放的动画 /// </summary> /// <param name="element&quo