© karobben |
由於語法渲染問題而影響閱讀體驗, 請移步博客閱讀~
本文GitPage地址
Introduction of kivy:
Youtube Vedio
Text Tutorial
Installation: Skip
python: python=3.7.5 is strongly recommended!!
If you wants to know why, go to check This blog
So, if you want to write an app for windows, linux, IOS, and Android with only one set of code, then, Kivy is the best choice for you.
Hello World
first, you’d like to import kivy
and from kivy.app import App
;
Then, you’d like from kivy.uix.label import Label
so you can add some text
Add kivy.require("1.10.1")
to assign the version of the kivy. (PS: actually, mine is 1.11.1)
Then, we can start to class a class EpicApp(App)
import kivy
from kivy.app import App
from kivy.uix.label import Label # so you can add some text
kviy.require("1.10.1") # Assign the version of the kivy so every body would be on the same page
class EpicApp(App):
''' After class, we'd like to initializing the App'''
def build(self):
return Label(text="Hello world")
if __name__ == "__main__":
EpicApp().run()
So, it’ll be your first kivy app!
It is not interesting at all, actually. So, Let’s move one for GridLayout
GridLayout
Now, let’s add from kivy.uix.gridlayout import GridLayout
to import the Layout style for organizing sort of things;
from kivy.uix.textinput import TextInput
to add a TextInput
box.
Now, Our class are becoming more complicated
So, during the initiation in build
section, we not return
to a simple text Label
anymore. Let’s say, to return
to a class named ConnectPage
.
And let’s sorting stuff in ConnectPage
by GridLayout
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout # one of many layout structures
from kivy.uix.textinput import TextInput # allow for ...text input.
kivy.require("1.10.1")
## An actual app is likely to consist of many different
## "pages" or "screens." Inherit from GridLayout
class ConnectPage(GridLayout):
# runs on initialization
def __init__(self, **kwargs):
# we want to run __init__ of both ConnectPage AAAAND GridLayout
super().__init__(**kwargs)
self.cols = 2 # used for our grid
# widgets added in order, so mind the order.
self.add_widget(Label(text='IP:')) # widget #1, top left
self.ip = TextInput(multiline=False) # defining self.ip...
self.add_widget(self.ip) # widget #2, top right
self.add_widget(Label(text='Port:'))
self.port = TextInput(multiline=False)
self.add_widget(self.port)
self.add_widget(Label(text='Username:'))
self.username = TextInput(multiline=False)
self.add_widget(self.username)
class EpicApp(App):
def build(self):
return ConnectPage()
if __name__ == "__main__":
EpicApp().run()
And that is what will we get! Awesome, hum?
Lesson3
import socket
import errno
from threading import Thread
HEADER_LENGTH = 10
client_socket = None
## Connects to the server
def connect(ip, port, my_username, error_callback):
global client_socket
# Create a socket
# socket.AF_INET - address family, IPv4, some otehr possible are AF_INET6, AF_BLUETOOTH, AF_UNIX
# socket.SOCK_STREAM - TCP, conection-based, socket.SOCK_DGRAM - UDP, connectionless, datagrams, socket.SOCK_RAW - raw IP packets
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Connect to a given ip and port
client_socket.connect((ip, port))
except Exception as e:
# Connection error
error_callback('Connection error: {}'.format(str(e)))
return False
# Prepare username and header and send them
# We need to encode username to bytes, then count number of bytes and prepare header of fixed size, that we encode to bytes as well
username = my_username.encode('utf-8')
username_header = f"{len(username):<{HEADER_LENGTH}}".encode('utf-8')
client_socket.send(username_header + username)
return True
## Sends a message to the server
def send(message):
# Encode message to bytes, prepare header and convert to bytes, like for username above, then send
message = message.encode('utf-8')
message_header = f"{len(message):<{HEADER_LENGTH}}".encode('utf-8')
client_socket.send(message_header + message)
## Starts listening function in a thread
## incoming_message_callback - callback to be called when new message arrives
## error_callback - callback to be called on error
def start_listening(incoming_message_callback, error_callback):
Thread(target=listen, args=(incoming_message_callback, error_callback), daemon=True).start()
## Listens for incomming messages
def listen(incoming_message_callback, error_callback):
while True:
try:
# Now we want to loop over received messages (there might be more than one) and print them
while True:
# Receive our "header" containing username length, it's size is defined and constant
username_header = client_socket.recv(HEADER_LENGTH)
# If we received no data, server gracefully closed a connection, for example using socket.close() or socket.shutdown(socket.SHUT_RDWR)
if not len(username_header):
error_callback('Connection closed by the server')
# Convert header to int value
username_length = int(username_header.decode('utf-8').strip())
# Receive and decode username
username = client_socket.recv(username_length).decode('utf-8')
# Now do the same for message (as we received username, we received whole message, there's no need to check if it has any length)
message_header = client_socket.recv(HEADER_LENGTH)
message_length = int(message_header.decode('utf-8').strip())
message = client_socket.recv(message_length).decode('utf-8')
# Print message
incoming_message_callback(username, message)
except Exception as e:
# Any other exception - something happened, exit
error_callback('Reading error: {}'.format(str(e)))
Enjoy~
由於語法渲染問題而影響閱讀體驗, 請移步博客閱讀~
本文GitPage地址
GitHub: Karobben
Blog:Karobben
BiliBili:史上最不正經的生物狗