Added second example.
							parent
							
								
									0c72481045
								
							
						
					
					
						commit
						09e345a85a
					
				@ -0,0 +1,138 @@
 | 
				
			|||||||
 | 
					# Byte-compiled / optimized / DLL files
 | 
				
			||||||
 | 
					__pycache__/
 | 
				
			||||||
 | 
					*.py[cod]
 | 
				
			||||||
 | 
					*$py.class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# C extensions
 | 
				
			||||||
 | 
					*.so
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Distribution / packaging
 | 
				
			||||||
 | 
					.Python
 | 
				
			||||||
 | 
					build/
 | 
				
			||||||
 | 
					develop-eggs/
 | 
				
			||||||
 | 
					dist/
 | 
				
			||||||
 | 
					downloads/
 | 
				
			||||||
 | 
					eggs/
 | 
				
			||||||
 | 
					.eggs/
 | 
				
			||||||
 | 
					lib/
 | 
				
			||||||
 | 
					lib64/
 | 
				
			||||||
 | 
					parts/
 | 
				
			||||||
 | 
					sdist/
 | 
				
			||||||
 | 
					var/
 | 
				
			||||||
 | 
					wheels/
 | 
				
			||||||
 | 
					share/python-wheels/
 | 
				
			||||||
 | 
					*.egg-info/
 | 
				
			||||||
 | 
					.installed.cfg
 | 
				
			||||||
 | 
					*.egg
 | 
				
			||||||
 | 
					MANIFEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PyInstaller
 | 
				
			||||||
 | 
					#  Usually these files are written by a python script from a template
 | 
				
			||||||
 | 
					#  before PyInstaller builds the exe, so as to inject date/other infos into it.
 | 
				
			||||||
 | 
					*.manifest
 | 
				
			||||||
 | 
					*.spec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Installer logs
 | 
				
			||||||
 | 
					pip-log.txt
 | 
				
			||||||
 | 
					pip-delete-this-directory.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Unit test / coverage reports
 | 
				
			||||||
 | 
					htmlcov/
 | 
				
			||||||
 | 
					.tox/
 | 
				
			||||||
 | 
					.nox/
 | 
				
			||||||
 | 
					.coverage
 | 
				
			||||||
 | 
					.coverage.*
 | 
				
			||||||
 | 
					.cache
 | 
				
			||||||
 | 
					nosetests.xml
 | 
				
			||||||
 | 
					coverage.xml
 | 
				
			||||||
 | 
					*.cover
 | 
				
			||||||
 | 
					*.py,cover
 | 
				
			||||||
 | 
					.hypothesis/
 | 
				
			||||||
 | 
					.pytest_cache/
 | 
				
			||||||
 | 
					cover/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Translations
 | 
				
			||||||
 | 
					*.mo
 | 
				
			||||||
 | 
					*.pot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Django stuff:
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					local_settings.py
 | 
				
			||||||
 | 
					db.sqlite3
 | 
				
			||||||
 | 
					db.sqlite3-journal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Flask stuff:
 | 
				
			||||||
 | 
					instance/
 | 
				
			||||||
 | 
					.webassets-cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Scrapy stuff:
 | 
				
			||||||
 | 
					.scrapy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Sphinx documentation
 | 
				
			||||||
 | 
					docs/_build/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PyBuilder
 | 
				
			||||||
 | 
					.pybuilder/
 | 
				
			||||||
 | 
					target/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Jupyter Notebook
 | 
				
			||||||
 | 
					.ipynb_checkpoints
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# IPython
 | 
				
			||||||
 | 
					profile_default/
 | 
				
			||||||
 | 
					ipython_config.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# pyenv
 | 
				
			||||||
 | 
					#   For a library or package, you might want to ignore these files since the code is
 | 
				
			||||||
 | 
					#   intended to run in multiple environments; otherwise, check them in:
 | 
				
			||||||
 | 
					# .python-version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# pipenv
 | 
				
			||||||
 | 
					#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
 | 
				
			||||||
 | 
					#   However, in case of collaboration, if having platform-specific dependencies or dependencies
 | 
				
			||||||
 | 
					#   having no cross-platform support, pipenv may install dependencies that don't work, or not
 | 
				
			||||||
 | 
					#   install all needed dependencies.
 | 
				
			||||||
 | 
					#Pipfile.lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PEP 582; used by e.g. github.com/David-OConnor/pyflow
 | 
				
			||||||
 | 
					__pypackages__/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Celery stuff
 | 
				
			||||||
 | 
					celerybeat-schedule
 | 
				
			||||||
 | 
					celerybeat.pid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SageMath parsed files
 | 
				
			||||||
 | 
					*.sage.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Environments
 | 
				
			||||||
 | 
					.env
 | 
				
			||||||
 | 
					.venv
 | 
				
			||||||
 | 
					env/
 | 
				
			||||||
 | 
					venv/
 | 
				
			||||||
 | 
					ENV/
 | 
				
			||||||
 | 
					env.bak/
 | 
				
			||||||
 | 
					venv.bak/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Spyder project settings
 | 
				
			||||||
 | 
					.spyderproject
 | 
				
			||||||
 | 
					.spyproject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Rope project settings
 | 
				
			||||||
 | 
					.ropeproject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# mkdocs documentation
 | 
				
			||||||
 | 
					/site
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# mypy
 | 
				
			||||||
 | 
					.mypy_cache/
 | 
				
			||||||
 | 
					.dmypy.json
 | 
				
			||||||
 | 
					dmypy.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Pyre type checker
 | 
				
			||||||
 | 
					.pyre/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# pytype static type analyzer
 | 
				
			||||||
 | 
					.pytype/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Cython debug symbols
 | 
				
			||||||
 | 
					cython_debug/
 | 
				
			||||||
@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import socket
 | 
				
			||||||
 | 
					import threading
 | 
				
			||||||
 | 
					import messages
 | 
				
			||||||
 | 
					import model
 | 
				
			||||||
 | 
					import view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BUFFER_SIZE = 2 ** 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Application(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    instance = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, args):
 | 
				
			||||||
 | 
					        self.args = args
 | 
				
			||||||
 | 
					        self.closing = False
 | 
				
			||||||
 | 
					        self.host = None
 | 
				
			||||||
 | 
					        self.port = None
 | 
				
			||||||
 | 
					        self.receive_worker = None
 | 
				
			||||||
 | 
					        self.sock = None
 | 
				
			||||||
 | 
					        self.username = None
 | 
				
			||||||
 | 
					        self.ui = view.EzChatUI(self)
 | 
				
			||||||
 | 
					        Application.instance = self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        if not self.ui.show():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.sock.connect((self.host, self.port))
 | 
				
			||||||
 | 
					        except (socket.error, OverflowError):
 | 
				
			||||||
 | 
					            self.ui.alert(messages.ERROR, messages.CONNECTION_ERROR)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.receive_worker = threading.Thread(target=self.receive)
 | 
				
			||||||
 | 
					        self.receive_worker.start()
 | 
				
			||||||
 | 
					        self.ui.loop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def receive(self):
 | 
				
			||||||
 | 
					        while True:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                message = model.Message(**json.loads(self.receive_all()))
 | 
				
			||||||
 | 
					            except (ConnectionAbortedError, ConnectionResetError):
 | 
				
			||||||
 | 
					                if not self.closing:
 | 
				
			||||||
 | 
					                    self.ui.alert(messages.ERROR, messages.CONNECTION_ERROR)
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            self.ui.show_message(message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def receive_all(self):
 | 
				
			||||||
 | 
					        buffer = ""
 | 
				
			||||||
 | 
					        while not buffer.endswith(model.END_CHARACTER):
 | 
				
			||||||
 | 
					            buffer += self.sock.recv(BUFFER_SIZE).decode(model.TARGET_ENCODING)
 | 
				
			||||||
 | 
					        return buffer[:-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def send(self, event=None):
 | 
				
			||||||
 | 
					        message = self.ui.message.get()
 | 
				
			||||||
 | 
					        if len(message) == 0:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.ui.message.set("")
 | 
				
			||||||
 | 
					        message = model.Message(username=self.username, message=message, quit=False)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.sock.sendall(message.marshal())
 | 
				
			||||||
 | 
					        except (ConnectionAbortedError, ConnectionResetError):
 | 
				
			||||||
 | 
					            if not self.closing:
 | 
				
			||||||
 | 
					                self.ui.alert(messages.ERROR, messages.CONNECTION_ERROR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exit(self):
 | 
				
			||||||
 | 
					        self.closing = True
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.sock.sendall(model.Message(username=self.username, message="", quit=True).marshal())
 | 
				
			||||||
 | 
					        except (ConnectionResetError, ConnectionAbortedError, OSError):
 | 
				
			||||||
 | 
					            print(messages.CONNECTION_ERROR)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.sock.close()
 | 
				
			||||||
@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main(args):
 | 
				
			||||||
 | 
					    app = application.Application(args)
 | 
				
			||||||
 | 
					    app.execute()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main(sys.argv)
 | 
				
			||||||
@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					    # -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONNECTION_ERROR = "Could not connect to server"
 | 
				
			||||||
 | 
					ERROR = "Error"
 | 
				
			||||||
 | 
					INPUT_SERVER_HOST = "Input Server Host"
 | 
				
			||||||
 | 
					INPUT_SERVER_PORT = "Input Server Port"
 | 
				
			||||||
 | 
					INPUT_USERNAME = "Input your username"
 | 
				
			||||||
 | 
					SEND = "Send"
 | 
				
			||||||
 | 
					SERVER_HOST = "Server Host"
 | 
				
			||||||
 | 
					SERVER_PORT = "Server Port"
 | 
				
			||||||
 | 
					TITLE = "ezChat"
 | 
				
			||||||
 | 
					USERNAME = "Username"
 | 
				
			||||||
@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					END_CHARACTER = "\0"
 | 
				
			||||||
 | 
					MESSAGE_PATTERN = "{username}>{message}"
 | 
				
			||||||
 | 
					TARGET_ENCODING = "utf-8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Message(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, **kwargs):
 | 
				
			||||||
 | 
					        self.username = None
 | 
				
			||||||
 | 
					        self.message = None
 | 
				
			||||||
 | 
					        self.quit = False
 | 
				
			||||||
 | 
					        self.__dict__.update(kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return MESSAGE_PATTERN.format(**self.__dict__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def marshal(self):
 | 
				
			||||||
 | 
					        return (json.dumps(self.__dict__) + END_CHARACTER).encode(TARGET_ENCODING)
 | 
				
			||||||
@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import socket
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import threading
 | 
				
			||||||
 | 
					import model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BUFFER_SIZE = 2 ** 10
 | 
				
			||||||
 | 
					CLOSING = "Application closing..."
 | 
				
			||||||
 | 
					CONNECTION_ABORTED = "Connection aborted"
 | 
				
			||||||
 | 
					CONNECTED_PATTERN = "Client connected: {}:{}"
 | 
				
			||||||
 | 
					ERROR_ARGUMENTS = "Provide port number as the first command line argument"
 | 
				
			||||||
 | 
					ERROR_OCCURRED = "Error Occurred"
 | 
				
			||||||
 | 
					EXIT = "exit"
 | 
				
			||||||
 | 
					JOIN_PATTERN = "{username} has joined"
 | 
				
			||||||
 | 
					RUNNING = "Server is running..."
 | 
				
			||||||
 | 
					SERVER = "SERVER"
 | 
				
			||||||
 | 
					SHUTDOWN_MESSAGE = "shutdown"
 | 
				
			||||||
 | 
					TYPE_EXIT = "Type 'exit' to exit>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Server(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, argv):
 | 
				
			||||||
 | 
					        self.clients = set()
 | 
				
			||||||
 | 
					        self.listen_thread = None
 | 
				
			||||||
 | 
					        self.port = None
 | 
				
			||||||
 | 
					        self.sock = None
 | 
				
			||||||
 | 
					        self.parse_args(argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def listen(self):
 | 
				
			||||||
 | 
					        self.sock.listen(1)
 | 
				
			||||||
 | 
					        while True:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                client, address = self.sock.accept()
 | 
				
			||||||
 | 
					            except OSError:
 | 
				
			||||||
 | 
					                print(CONNECTION_ABORTED)
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            print(CONNECTED_PATTERN.format(*address))
 | 
				
			||||||
 | 
					            self.clients.add(client)
 | 
				
			||||||
 | 
					            threading.Thread(target=self.handle, args=(client,)).start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def handle(self, client):
 | 
				
			||||||
 | 
					        while True:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                message = model.Message(**json.loads(self.receive(client)))
 | 
				
			||||||
 | 
					            except (ConnectionAbortedError, ConnectionResetError):
 | 
				
			||||||
 | 
					                print(CONNECTION_ABORTED)
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            if message.quit:
 | 
				
			||||||
 | 
					                client.close()
 | 
				
			||||||
 | 
					                self.clients.remove(client)
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            print(str(message))
 | 
				
			||||||
 | 
					            if SHUTDOWN_MESSAGE.lower() == message.message.lower():
 | 
				
			||||||
 | 
					                self.exit()
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            self.broadcast(message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def broadcast(self, message):
 | 
				
			||||||
 | 
					        for client in self.clients:
 | 
				
			||||||
 | 
					            client.sendall(message.marshal())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def receive(self, client):
 | 
				
			||||||
 | 
					        buffer = ""
 | 
				
			||||||
 | 
					        while not buffer.endswith(model.END_CHARACTER):
 | 
				
			||||||
 | 
					            buffer += client.recv(BUFFER_SIZE).decode(model.TARGET_ENCODING)
 | 
				
			||||||
 | 
					        return buffer[:-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        print(RUNNING)
 | 
				
			||||||
 | 
					        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 | 
				
			||||||
 | 
					        self.sock.bind(("", self.port))
 | 
				
			||||||
 | 
					        self.listen_thread = threading.Thread(target=self.listen)
 | 
				
			||||||
 | 
					        self.listen_thread.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def parse_args(self, argv):
 | 
				
			||||||
 | 
					        if len(argv) != 2:
 | 
				
			||||||
 | 
					            raise RuntimeError(ERROR_ARGUMENTS)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.port = int(argv[1])
 | 
				
			||||||
 | 
					        except ValueError:
 | 
				
			||||||
 | 
					            raise RuntimeError(ERROR_ARGUMENTS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exit(self):
 | 
				
			||||||
 | 
					        self.sock.close()
 | 
				
			||||||
 | 
					        for client in self.clients:
 | 
				
			||||||
 | 
					            client.close()
 | 
				
			||||||
 | 
					        print(CLOSING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        Server(sys.argv).run()
 | 
				
			||||||
 | 
					    except RuntimeError as error:
 | 
				
			||||||
 | 
					        print(ERROR_OCCURRED)
 | 
				
			||||||
 | 
					        print(str(error))
 | 
				
			||||||
@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					import tkinter
 | 
				
			||||||
 | 
					import messages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from tkinter import messagebox, simpledialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CLOSING_PROTOCOL = "WM_DELETE_WINDOW"
 | 
				
			||||||
 | 
					END_OF_LINE = "\n"
 | 
				
			||||||
 | 
					KEY_RETURN = "<Return>"
 | 
				
			||||||
 | 
					TEXT_STATE_DISABLED = "disabled"
 | 
				
			||||||
 | 
					TEXT_STATE_NORMAL = "normal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EzChatUI(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, application):
 | 
				
			||||||
 | 
					        self.application = application
 | 
				
			||||||
 | 
					        self.gui = None
 | 
				
			||||||
 | 
					        self.frame = None
 | 
				
			||||||
 | 
					        self.input_field = None
 | 
				
			||||||
 | 
					        self.message = None
 | 
				
			||||||
 | 
					        self.message_list = None
 | 
				
			||||||
 | 
					        self.scrollbar = None
 | 
				
			||||||
 | 
					        self.send_button = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show(self):
 | 
				
			||||||
 | 
					        self.gui = tkinter.Tk()
 | 
				
			||||||
 | 
					        self.gui.title(messages.TITLE)
 | 
				
			||||||
 | 
					        self.fill_frame()
 | 
				
			||||||
 | 
					        self.gui.protocol(CLOSING_PROTOCOL, self.on_closing)
 | 
				
			||||||
 | 
					        return self.input_dialogs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def loop(self):
 | 
				
			||||||
 | 
					        self.gui.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fill_frame(self):
 | 
				
			||||||
 | 
					        self.frame = tkinter.Frame(self.gui)
 | 
				
			||||||
 | 
					        self.scrollbar = tkinter.Scrollbar(self.frame)
 | 
				
			||||||
 | 
					        self.message_list = tkinter.Text(self.frame, state=TEXT_STATE_DISABLED)
 | 
				
			||||||
 | 
					        self.scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
 | 
				
			||||||
 | 
					        self.message_list.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
 | 
				
			||||||
 | 
					        self.message = tkinter.StringVar()
 | 
				
			||||||
 | 
					        self.frame.pack()
 | 
				
			||||||
 | 
					        self.input_field = tkinter.Entry(self.gui, textvariable=self.message)
 | 
				
			||||||
 | 
					        self.input_field.pack()
 | 
				
			||||||
 | 
					        self.input_field.bind(KEY_RETURN, self.application.send)
 | 
				
			||||||
 | 
					        self.send_button = tkinter.Button(self.gui, text=messages.SEND, command=self.application.send)
 | 
				
			||||||
 | 
					        self.send_button.pack()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def input_dialogs(self):
 | 
				
			||||||
 | 
					        self.gui.lower()
 | 
				
			||||||
 | 
					        self.application.username = simpledialog.askstring(messages.USERNAME, messages.INPUT_USERNAME, parent=self.gui)
 | 
				
			||||||
 | 
					        if self.application.username is None:
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        self.application.host = simpledialog.askstring(messages.SERVER_HOST, messages.INPUT_SERVER_HOST,
 | 
				
			||||||
 | 
					                parent=self.gui)
 | 
				
			||||||
 | 
					        if self.application.host is None:
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        self.application.port = simpledialog.askinteger(messages.SERVER_PORT, messages.INPUT_SERVER_PORT,
 | 
				
			||||||
 | 
					                parent=self.gui)
 | 
				
			||||||
 | 
					        if self.application.port is None:
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def alert(self, title, message):
 | 
				
			||||||
 | 
					        messagebox.showerror(title, message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_message(self, message):
 | 
				
			||||||
 | 
					        self.message_list.configure(state=TEXT_STATE_NORMAL)
 | 
				
			||||||
 | 
					        self.message_list.insert(tkinter.END, str(message) + END_OF_LINE)
 | 
				
			||||||
 | 
					        self.message_list.configure(state=TEXT_STATE_DISABLED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_closing(self):
 | 
				
			||||||
 | 
					        self.application.exit()
 | 
				
			||||||
 | 
					        self.gui.destroy()
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue