V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
jin6220
V2EX  ›  Python

求问怎么使用多线程让 tkinter 里的数字跳动?

  •  
  •   jin6220 · 2017-04-29 08:15:23 +08:00 · 7728 次点击
    这是一个创建于 2802 天前的主题,其中的信息可能已经有所发展或是发生改变。

    import tkinter

    import requests

    import threading

    from bs4 import BeautifulSoup

    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36', 'Referer':'https://wallstreetcn.com/live/global' }

    def getprice(url):

      html=requests.get(url, headers=headers).text
      soup=BeautifulSoup(html,'lxml')
      price=soup.find('div',class_='price lt').get_text() #<div class="price lt" data-v-13b642d2="">12438.00</div>
      return price
    

    while True:

    g=getprice('https://wallstreetcn.com/markets/indices/GER30INDEX')
    top = tkinter.Tk()
    label = tkinter.Label(top,text=g)
    label.pack()
    tkinter.mainloop()
    top.wm_attributes('-topmost',1)
    
    15 条回复    2017-04-29 10:17:28 +08:00
    jin6220
        1
    jin6220  
    OP
       2017-04-29 08:18:23 +08:00
    不太会 md 格式 找了个网站贴了代码进去 然后所见所得修改了下贴进来 确实是好看了点
    昨天试了大半天 看了多进程 多线程 锁 队列 但是还是写不出来
    icedx
        2
    icedx  
       2017-04-29 08:19:00 +08:00 via Android
    印象里不能用 while true

    会阻塞界面的绘制
    jin6220
        3
    jin6220  
    OP
       2017-04-29 08:23:37 +08:00
    @icedx 哦 那是不是把 getprice 放进多线程里?通过队列取出这个返回值,但是昨天试了一天还是不成功;或者其他方法怎么实现呐
    icedx
        4
    icedx  
       2017-04-29 08:25:12 +08:00 via Android
    对的
    zjqzxc
        5
    zjqzxc  
       2017-04-29 08:49:48 +08:00
    当然是多线程,在线程中完成对主界面的更新工作

    getprice 操作放进新线程里,每次需要绘制的时候执行一次,修改对应的 label 的 text 属性即可
    jin6220
        6
    jin6220  
    OP
       2017-04-29 08:52:06 +08:00
    import tkinter
    import requests
    import threading
    from bs4 import BeautifulSoup
    import queue #import Queue

    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36',
    'Referer':'https://wallstreetcn.com/live/global'
    }
    def getprice(url):
    html=requests.get(url, headers=headers).text
    soup=BeautifulSoup(html,'lxml')
    price=soup.find('div',class_='price lt').get_text() #<div class="price lt" data-v-13b642d2="">12438.00</div>
    q.put(price)
    return price

    while True:
    q = queue.Queue()
    p = threading.Thread(target=getprice,args=('https://wallstreetcn.com/markets/indices/GER30INDEX',))
    p.start()

    qprice=q.get()
    top = tkinter.Tk()
    label = tkinter.Label(top,text=qprice)
    label.pack()
    tkinter.mainloop()
    top.wm_attributes('-topmost',1)
    写了个 不知道这个爬虫网页价格放到 tk 里随价格变化而变化,实现了没。
    jin6220
        7
    jin6220  
    OP
       2017-04-29 08:57:21 +08:00
    @zjqzxc 您意思是绘制的 tk 也放进一个线程了吗? 6 楼那个怎么样?刚才试了可以显示价格,不知道堵塞没,但是功能太简单了。还想实现这些:价格有变化绘制 tk,没变化不用管。
    zjqzxc
        8
    zjqzxc  
       2017-04-29 09:05:05 +08:00
    from tkinter import *
    import threading
    import time

    root = Tk()
    label1 = Label(root,text='0')
    label1.pack()

    def getPrice():
    return time.time()

    def threadGetPrice():
    while(True):
    label1['text'] = getPrice()
    time.sleep(1)

    t = threading.Thread(target=threadGetPrice,args=(),name='thread-refresh')
    t.setDaemon(True)
    t.start()

    root.mainloop()

    大概是这么个意思
    如果想实现价格变化时绘制(修改 text ),可以在 threadGetPrice()中进行判断
    jin6220
        9
    jin6220  
    OP
       2017-04-29 09:08:33 +08:00
    while 循环一次:构建队列,获取价格并放进队列,然后取出价格并绘制图形界面。
    想实现价格有变化绘制图形,没变化不要管看来有点难度(针对我这种小白哈)
    因为每次循环都是一个新的队列一个, 新的价格啊
    zjqzxc
        10
    zjqzxc  
       2017-04-29 09:15:03 +08:00
    @jin6220 如果只是为了修改界面上的价格,完全没必要使用队列。

    简单的思路是,有一个线程,在 while true:中获取最新价格,然后看是否改变了决定要不要更新主界面对应的 label 标签的 text 值;循环最后加一个 time.sleep(1)每次获取操作间隔 1 秒

    另外:新建线程的操作不要放在 while 中。。更新操作交给新创建的线程来做
    zjqzxc
        11
    zjqzxc  
       2017-04-29 09:25:52 +08:00   ❤️ 1
    import time
    import tkinter
    import requests
    import threading
    from bs4 import BeautifulSoup

    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36',
    'Referer':'https://wallstreetcn.com/live/global'
    }
    def getPrice(url):
    (space)html=requests.get(url, headers=headers).text
    (space)soup=BeautifulSoup(html,'lxml')
    (space)price=soup.find('div',class_='price lt').get_text()
    (space)return price

    root = tkinter.Tk()
    label1 = tkinter.Label(root,text='init...')
    label1.pack()

    def threadGetPrice():
    (space)while(True):
    (space)(space)label1['text'] = getPrice('https://wallstreetcn.com/markets/indices/GER30INDEX')
    (space)(space)time.sleep(5)

    t = threading.Thread(target=threadGetPrice,args=(),name='thread-refresh')
    t.setDaemon(True)
    t.start()

    root.mainloop()
    jin6220
        12
    jin6220  
    OP
       2017-04-29 09:36:20 +08:00
    @zjqzxc 嗯请问下 t.setDaemon(True) 这个是不是更新线程的操作,查了下说这是设置守护线程,如果是更新线程的话,为什么 def threadGetPrice()函数下面还要加一句 while True 呐,
    jin6220
        13
    jin6220  
    OP
       2017-04-29 09:39:55 +08:00
    感觉到了进程 线程 这里 明显到了 python 的易学难精的地方了。。。
    感觉大山来了 当初类 实例之类的马马虎虎地啃下来算是能看懂别人写的代码
    但是进程 线程 锁之类的东西 完全看不懂 自猜: 好像搞懂 python 的运行机制才能玩转这些东西了 :)
    jin6220
        14
    jin6220  
    OP
       2017-04-29 10:11:15 +08:00
    @zjqzxc 有点理解那个 while true 了 交作业了 只能等到周一看行不行了 这样就能桌面显示了

    zjqzxc
        15
    zjqzxc  
       2017-04-29 10:17:28 +08:00
    @jin6220 这个 setDaemon 的作用并不是让代码循环执行。没有 while true,threadGetPrice()里的代码将只执行一次;
    setDaemon(True)的作用:父线程启动了子线程,当父线程结束,子线程跟着同时被 kill;
    setDaemon(False)的作用:父线程启动了子线程,当父线程结束,会等待子线程结束后,主线程才会结束;

    如果把 setDaemon 改为 false,关闭窗体后 threadGetPrice ()继续执行,但此时主窗体已经不存在了,执行更新操作时会报错;

    为啥会发生这个,具体原因我也没有确切答案。
    猜测可能的原因是,tkinter 窗口的线程并不是手动创建的线程的父线程,关闭 tkinter 窗体的操作并不会等待手动创建的线程结束,所以就有问题了;
    表现是:如果 setDaemon ( False ),关闭窗体后进程并不会立刻终止,而是等子线程完成后才会终止。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1073 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 22:56 · PVG 06:56 · LAX 14:56 · JFK 17:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.