推荐学习书目
› 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 · Apr 29, 2017 · 8463 views
  •   You need to sign in to view this topic
    This topic created in 3462 days ago, the information mentioned may be changed or developed.

    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 replies  •  2017-04-29 10:17:28 +08:00
    jin6220
        1
    jin6220  
    OP
       Apr 29, 2017
    不太会 md 格式 找了个网站贴了代码进去 然后所见所得修改了下贴进来 确实是好看了点
    昨天试了大半天 看了多进程 多线程 锁 队列 但是还是写不出来
    icedx
        2
    icedx  
       Apr 29, 2017 via Android
    印象里不能用 while true

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

    getprice 操作放进新线程里,每次需要绘制的时候执行一次,修改对应的 label 的 text 属性即可
    jin6220
        6
    jin6220  
    OP
       Apr 29, 2017
    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
       Apr 29, 2017
    @zjqzxc 您意思是绘制的 tk 也放进一个线程了吗? 6 楼那个怎么样?刚才试了可以显示价格,不知道堵塞没,但是功能太简单了。还想实现这些:价格有变化绘制 tk,没变化不用管。
    zjqzxc
        8
    zjqzxc  
       Apr 29, 2017
    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
       Apr 29, 2017
    while 循环一次:构建队列,获取价格并放进队列,然后取出价格并绘制图形界面。
    想实现价格有变化绘制图形,没变化不要管看来有点难度(针对我这种小白哈)
    因为每次循环都是一个新的队列一个, 新的价格啊
    zjqzxc
        10
    zjqzxc  
       Apr 29, 2017
    @jin6220 如果只是为了修改界面上的价格,完全没必要使用队列。

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

    另外:新建线程的操作不要放在 while 中。。更新操作交给新创建的线程来做
    zjqzxc
        11
    zjqzxc  
       Apr 29, 2017   ❤️ 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
       Apr 29, 2017
    @zjqzxc 嗯请问下 t.setDaemon(True) 这个是不是更新线程的操作,查了下说这是设置守护线程,如果是更新线程的话,为什么 def threadGetPrice()函数下面还要加一句 while True 呐,
    jin6220
        13
    jin6220  
    OP
       Apr 29, 2017
    感觉到了进程 线程 这里 明显到了 python 的易学难精的地方了。。。
    感觉大山来了 当初类 实例之类的马马虎虎地啃下来算是能看懂别人写的代码
    但是进程 线程 锁之类的东西 完全看不懂 自猜: 好像搞懂 python 的运行机制才能玩转这些东西了 :)
    jin6220
        14
    jin6220  
    OP
       Apr 29, 2017
    @zjqzxc 有点理解那个 while true 了 交作业了 只能等到周一看行不行了 这样就能桌面显示了

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

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

    为啥会发生这个,具体原因我也没有确切答案。
    猜测可能的原因是,tkinter 窗口的线程并不是手动创建的线程的父线程,关闭 tkinter 窗体的操作并不会等待手动创建的线程结束,所以就有问题了;
    表现是:如果 setDaemon ( False ),关闭窗体后进程并不会立刻终止,而是等子线程完成后才会终止。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   5960 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 138ms · UTC 02:14 · PVG 10:14 · LAX 19:14 · JFK 22:14
    ♥ Do have faith in what you're doing.