通过互联网发送请求时 kivy 屏幕冻结

问题描述 投票:0回答:3

我对 kivy 完全陌生,我正在将其作为一个实践项目。我搜索了很多但找不到解决方案。基本上问题是当我通过互联网发送请求时我的kivy屏幕冻结一段时间。因此,我的旋转器(MDSpinner)无法工作。请任何人帮助我。

我的main.py代码:

from kivy.metrics import dp
from kivymd.app import MDApp
from kivymd.uix.datatables import MDDataTable
from kivy.uix.screenmanager import ScreenManager, Screen
import requests
import shutil
from bs4 import BeautifulSoup as Soup
import re
import os



#Not Real Url for some security reason
Login_URL = "http://some_url.com/login"
Back_URL = "http://some_url.com/info"
Profile_URL = "http://some_url.com/profile"

SESSION = None
sm = ScreenManager()

stu_name = None
stu_id = None


def login(uname_passw):
    
    uname,passw = uname_passw.split(":::")

    s = requests.Session()

    data = {'email': uname, 'password': passw}

    try:
        r = s.post(Login_URL, data=data)
        text = r.text
    except:
        text = "<div>Net Problem > Login > </div>"

    soup = Soup(text, 'html.parser')

    error = soup.find(class_="error_msg")
    if error is not None:
        error_msg = error.get_text()
        error_msg = error_msg.split(".")[0] + "."

        return error_msg

    else:
        global SESSION
        SESSION = s

        return True


def get_info(session):
    s = SESSION
    url = Back_URL

    try:

        r = s.get(url)
        text = r.text
    except:
        text = "<div>Net Problem > Get_Info > </div>"

    soup = Soup(text, "html.parser")

    tables = soup.find_all(class_="table table-striped table-responsive table-bordered table-hover")
    stu_basic_info = tables[0]
    stu_drop_change = tables[1]

    basic_tds = stu_basic_info.find_all("td")

    basic_finfo = []
    for td in basic_tds:
        t = td.get_text()
        if "Admission Fee" in str(t):
            t = t + soup.find(id="sum_admission_fee").get("value")
        basic_finfo.append(t)

    drop_tds = stu_drop_change.find_all("td")

    drop_change_finfo = []
    for td in drop_tds:
        t = td.get_text()
        drop_change_finfo.append(t)

    basic_info = {}

    for i in basic_finfo:
        if "Attempted credit" in i:
            break
        txt = i.split(":")
        points = txt[0]
        answer = txt[1]

        pattern = '[A-z0-9.]+'

        s1 = re.findall(pattern, points)
        s1 = " ".join(s1)

        s2 = re.findall(pattern, answer)
        s2 = " ".join(s2)

        basic_info[s1] = s2

    total_fee = basic_info['Total Fee']
    discount = basic_info['Waiver Discount']

    payable = str(int(total_fee) - int(discount))

    basic_info['Payable Amount'] = payable

    d = []
    for i in drop_change_finfo:
        c = " ".join(re.findall(pattern, i))
        d.append(c)

    drop_change_finfo = d

    numbers = []
    names = []
    for i in drop_change_finfo:
        r = " ".join(re.findall('[0-9]+', i))
        if r != '':
            numbers.append(r)
        r2 = " ".join(re.findall('[A-z]+', i))
        if r2 != '':
            names.append(r2)

    extra_info = {}
    for name, num in zip(names, numbers):
        extra_info[name] = num

    return basic_info, extra_info


class LoginScreen(Screen):
    def on_pre_enter(self, *args):
        dir_list = os.listdir(os.getcwd())

        for file in dir_list:
            if "img" in file:
                os.remove(file)
    
    

    def user_login(self):
        self.ids.spinner1.active = True
        
        
        uname = self.ids.uname.text
        passw = self.ids.passw.text
        
        uname_passw = f"{uname}:::{passw}"
            
            
        self.user_login_var = login(uname_passw)

        if self.user_login_var is not True:
            msg = self.ids.msg
            msg.text = str(self.user_login_var)
            msg.theme_text_color = "Error"
            msg.font_style = "Subtitle1"
            msg.pos_hint = {'center_x': 0.5, 'center_y': 0.6}
        else:
            sm.switch_to(InfoScreen(name='info'))


class InfoScreen(Screen):

    def on_pre_enter(self, *args):
        self.info_dict, self.extra_info = get_info(SESSION)

    def on_enter(self, *args):

        global stu_name
        global stu_id

        stu_name, stu_id = self.info_dict['Student Name'], self.info_dict['Student ID']

        nickname = stu_name.split(" ")
        nickname = nickname[-1]
        self.ids.tool.title = f"Hi, {nickname}"

        a = []
        for item in self.info_dict.items():
            a.append(item)
        for item in self.extra_info.items():
            r, t = item
            if "SL NO" in r:
                pass
            else:
                a.append(item)

        table = MDDataTable(
            pos_hint={'center_x': 0.5, 'center_y': 0.5},
            size_hint=(1, 0.7),
            rows_num=21,
            column_data=[
                ("Name", dp(30)),
                ("Details", dp(30))
            ],
            row_data=a
        )

        self.ids.spinner.active = False
        self.add_widget(table)

    def change_screen(self, name):
        if name == 'profile':
            sm.switch_to(ProfileScreen(name='profile'))
        else:
            sm.switch_to(LoginScreen(name='login'))


class ProfileScreen(Screen):

    def on_pre_enter(self, *args):
        self.ids.welcome.text = f"Welcome {stu_name}"

        s = SESSION
        url = Profile_URL + stu_id

        try:
            r = s.get(url)
            self.text = r.text
        except:
            self.text = "<div>Net Problem > Profile > </div>"

    def on_enter(self, *args):

        soup = Soup(self.text, 'html.parser')

        tables = soup.find_all("table")

        stu_data = tables[1]
        img_data = tables[2]
        academic_data = tables[3]

        img_url = img_data.find("img").get("src")

        response = requests.get(img_url, stream=True)

        img_file = f"img_{str(stu_id)}.png"

        with open(img_file, 'wb') as out_file:
            shutil.copyfileobj(response.raw, out_file)

        self.ids.bg_image.source = img_file

    def change_screen(self):
        sm.switch_to(InfoScreen(name='info'))


class SuLoginApp(MDApp):
    def build(self):
        global sm

        sm.add_widget(LoginScreen(name='login'))
        sm.add_widget(InfoScreen(name='info'))
        sm.add_widget(ProfileScreen(name='profile'))

        return sm


SuLoginApp().run()

sulogin.kv代码:



<LoginScreen>:
    MDSpinner:
        id:spinner1
        size_hint: None, None
        size: dp(30), dp(30)
        pos_hint: {'center_x': .5, 'center_y': .5}
        active: False
    MDLabel:
        id:msg
        text: "Student Login"
        halign: "center"
        pos_hint:{'center_x':0.5,'center_y':0.8}
        font_style:'H2'
    MDTextField:
        id:uname
        text: "CSE2201025001"
        hint_text: "Username"
        helper_text_mode: "on_focus"
        pos_hint:{'center_x':0.5,'center_y':0.5}
        size_hint:None,0.1
        width:root.width*0.8
        mode: "rectangle"
        helper_text_mode: "on_error"
        required: True
    MDTextField:
        id:passw
        text:"123456"
        hint_text: "Password"
        helper_text_mode: "on_focus"
        pos_hint:{'center_x':0.5,'center_y':0.38}
        size_hint:None,0.1
        width:root.width*0.8
        mode: "rectangle"
        helper_text_mode: "on_error"
        required: True
    
    MDRectangleFlatButton:
        text: "Login"
        pos_hint:{'center_x':0.5,'center_y':0.2}
        size_hint:None,0.1
        width:root.width*0.5
        on_press: root.user_login()


        
<InfoScreen>:
    BoxLayout:
        orientation: 'vertical'

        MDToolbar:
            id:tool
            elevation: 10
            right_action_items: [['account-circle', lambda x:root.change_screen('profile') ]]
            left_action_items: [['logout', lambda x:root.change_screen('login') ]]
        Widget:
        MDSpinner:
            id:spinner
            size_hint: None, None
            size: dp(30), dp(30)
            pos_hint: {'center_x': .5, 'center_y': .5}
            active: True

<ProfileScreen>:
    
    MDCard:
        elevation: 10
        radius: [36, ]

        FitImage:
            id: bg_image
            size_hint_y: .35
            pos_hint: {"top": 1}
            radius: 36, 36, 0, 0
    MDLabel:
        id:welcome
        halign:'center'
        font_style:'H6'
    
    MDRectangleFlatButton:
        text:"Back"
        on_press:root.change_screen()
        pos_hint: {'center_x': .5, 'center_y': .2}
python kivy freeze kivymd
3个回答
0
投票

为了在获取/发送数据时保持 UI 活动,您可以使用线程。

首先创建一个新方法,如

init_login
中的
.py
,用于创建新线程,

    def init_login(self):
        """Function to start a new thread each time."""
        self.new_thread = threading.Thread(target = self.user_login) # Now call that function from this a new thread.
        self.new_thread.start() # You can use this thread instance later if you want.

    ...
    def user_login(self, *args):
        self.ids.spinner1.active = True
        
        
        uname = self.ids.uname.text
        passw = self.ids.passw.text
    ...

然后调用该方法

init_login
,而不是直接在
user_login
中调用
.kv

    ...
    MDRectangleFlatButton:
        text: "Login"
        pos_hint:{'center_x':0.5,'center_y':0.2}
        size_hint:None,0.1
        width:root.width*0.5
        on_press: root.init_login()
    ...

我这样做只是为了保持方法

user_login
原样(几乎),你可以尝试其他方法。


0
投票

您不应该在主线程中执行与 UI 相关的任务,因为 openGL 操作应该在主线程中完成。否则,使用@mainthread装饰器。

查看此文档 - https://github.com/kivy/kivy/wiki/Working-with-Python-threads-inside-a-Kivy-application


0
投票

进口猕猴桃 从 kivy.app 导入 App 从 kivy.uix.button 导入按钮 进口螺纹

MyApp类(应用程序): def 构建(自身): self.button = Button(text="发送请求") self.button.bind(on_press=self.send_request) 返回自我按钮

def send_request(self, instance):
    # Create a new thread to send the request
    request_thread = threading.Thread(target=self.send_request_in_thread)
    request_thread.start()

def send_request_in_thread(self):
    # This function will run in a separate thread
    # Place your network request code here
    # For example, you can use the requests library

    import requests

    try:
        response = requests.get('https://example.com')
        # Process the response here
    except Exception as e:
        # Handle exceptions here
        print(f"Error: {e}")

if name == 'main': MyApp().run()

© www.soinside.com 2019 - 2024. All rights reserved.