nearly finished client GUI with listening support

This commit is contained in:
Xevion
2021-01-08 14:28:01 -06:00
parent e754221aac
commit 4dc14d118b
15 changed files with 515 additions and 98 deletions

View File

@@ -1,33 +0,0 @@
import socket
import threading
nickname = input("Nickname: ")
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 55555))
def receive():
while True:
try:
message = client.recv(1024).decode('ascii')
if message == 'NICK':
client.send(nickname.encode('ascii'))
else:
print(message)
except:
print("Error! Disconnecting.")
client.close()
break
# Sending Messages To Server
def write():
while True:
message = '{}: {}'.format(nickname, input(''))
client.send(message.encode('ascii'))
# Starting Threads For Listening And Writing
receive_thread = threading.Thread(target=receive)
receive_thread.start()
write_thread = threading.Thread(target=write)
write_thread.start()

82
client/MainWindow.py Normal file
View File

@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '.\MainWindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 609)
self.centralwidget = QtWidgets.QWidget(MainWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
self.centralwidget.setSizePolicy(sizePolicy)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textBrowser.sizePolicy().hasHeightForWidth())
self.textBrowser.setSizePolicy(sizePolicy)
self.textBrowser.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.textBrowser.setObjectName("textBrowser")
self.horizontalLayout_2.addWidget(self.textBrowser)
self.gridLayout.addLayout(self.horizontalLayout_2, 0, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.horizontalLayout.setObjectName("horizontalLayout")
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textEdit.sizePolicy().hasHeightForWidth())
self.textEdit.setSizePolicy(sizePolicy)
self.textEdit.setMaximumSize(QtCore.QSize(16777215, 70))
self.textEdit.setObjectName("textEdit")
self.horizontalLayout.addWidget(self.textEdit)
self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionConnect_to = QtWidgets.QAction(MainWindow)
self.actionConnect_to.setObjectName("actionConnect_to")
self.actionSave_chat_to = QtWidgets.QAction(MainWindow)
self.actionSave_chat_to.setObjectName("actionSave_chat_to")
self.actionQuit = QtWidgets.QAction(MainWindow)
self.actionQuit.setObjectName("actionQuit")
self.menuFile.addAction(self.actionConnect_to)
self.menuFile.addAction(self.actionSave_chat_to)
self.menuFile.addAction(self.actionQuit)
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.actionConnect_to.setText(_translate("MainWindow", "Connect to..."))
self.actionSave_chat_to.setText(_translate("MainWindow", "Export chat..."))
self.actionQuit.setText(_translate("MainWindow", "Quit"))

107
client/MainWindow.ui Normal file
View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>609</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0">
<item>
<widget class="QTextBrowser" name="textBrowser">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QTextEdit" name="textEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>70</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionConnect_to"/>
<addaction name="actionSave_chat_to"/>
<addaction name="actionQuit"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionConnect_to">
<property name="text">
<string>Connect to...</string>
</property>
</action>
<action name="actionSave_chat_to">
<property name="text">
<string>Export chat...</string>
</property>
</action>
<action name="actionQuit">
<property name="text">
<string>Quit</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

0
client/__init__.py Normal file
View File

76
client/gui.py Normal file
View File

@@ -0,0 +1,76 @@
import socket
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QDialog, QDialogButtonBox, QVBoxLayout
from config import config
from client.MainWindow import Ui_MainWindow
IP = '127.0.0.1'
PORT = 55555
HEADER_LENGTH = int(config.get(IP, 'HeaderLength'))
class ReceiveWorker(QThread):
messages = pyqtSignal(str)
error = pyqtSignal()
def __init__(self, client: socket.socket, nickname: str, parent=None):
QThread.__init__(self, parent)
self.client = client
self.nickname = nickname
def run(self):
while True:
try:
length = int(self.client.recv(HEADER_LENGTH).decode('ascii'))
message = self.client.recv(length)
if message == 'NICK':
self.client.send(self.nickname.encode('ascii'))
else:
self.messages.emit(message)
except:
self.error.emit()
self.client.close()
break
class CustomDialog(QDialog):
def __init__(self, *args, **kwargs):
super(CustomDialog, self).__init__(*args, **kwargs)
self.setWindowTitle("HELLO!")
buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
self.buttonBox = QDialogButtonBox(buttons)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
self.layout = QVBoxLayout()
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.connect((IP, PORT))
# nicknameDialog = CustomDialog(self)
# if nicknameDialog.exec_():
# print('s')
self.nickname = 'Default'
self.receiveThread = ReceiveWorker(self.client, self.nickname)
self.receiveThread.messages.connect(self.addMessage)
self.receiveThread.start()
self.show()
def addMessage(self, message: str):
self.textBrowser.append(message)

120
client/gui.ui Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>651</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Connections</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QTextEdit" name="messageBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>80</height>
</size>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QTextBrowser" name="messageHistory">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>5</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QListWidget" name="connectionsList">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Chat History</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionConnect_to"/>
<addaction name="actionSave_chat_to"/>
<addaction name="actionQuit"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionConnect_to">
<property name="text">
<string>Connect to...</string>
</property>
</action>
<action name="actionSave_chat_to">
<property name="text">
<string>Export chat...</string>
</property>
</action>
<action name="actionQuit">
<property name="text">
<string>Quit</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

40
client/main.py Normal file
View File

@@ -0,0 +1,40 @@
from PyQt5.QtWidgets import QApplication
from client.gui import MainWindow
import socket
import threading
# nickname = input("Nickname: ")
app = QApplication([])
app.setApplicationName("TCPChat Client")
m = MainWindow()
# client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# client.connect(('127.0.0.1', 55555))
#
# def receive():
# while True:
# try:
# message = client.recv(1024).decode('ascii')
# if message == 'NICK':
# client.send(nickname.encode('ascii'))
# else:
# m.addMessage(message)
# # print(message)
# except:
# print("Error! Disconnecting.")
# client.close()
# break
#
# Sending Messages To Server
# def write():
# while True:
# message = '{}: {}'.format(nickname, input(''))
# client.send(message.encode('ascii'))
#
# Starting Threads For Listening And Writing
# receive_thread = threading.Thread(target=receive)
# receive_thread.start()
app.exec_()

2
config.ini Normal file
View File

@@ -0,0 +1,2 @@
[DEFAULT]
HeaderLength = 10

5
config.py Normal file
View File

@@ -0,0 +1,5 @@
from configparser import ConfigParser
config = ConfigParser()
config.read('config.ini')

0
launch.py Normal file
View File

82
out.py Normal file
View File

@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'client\gui.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 609)
self.centralwidget = QtWidgets.QWidget(MainWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
self.centralwidget.setSizePolicy(sizePolicy)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textBrowser.sizePolicy().hasHeightForWidth())
self.textBrowser.setSizePolicy(sizePolicy)
self.textBrowser.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.textBrowser.setObjectName("textBrowser")
self.horizontalLayout_2.addWidget(self.textBrowser)
self.gridLayout.addLayout(self.horizontalLayout_2, 0, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.horizontalLayout.setObjectName("horizontalLayout")
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textEdit.sizePolicy().hasHeightForWidth())
self.textEdit.setSizePolicy(sizePolicy)
self.textEdit.setMaximumSize(QtCore.QSize(16777215, 70))
self.textEdit.setObjectName("textEdit")
self.horizontalLayout.addWidget(self.textEdit)
self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionConnect_to = QtWidgets.QAction(MainWindow)
self.actionConnect_to.setObjectName("actionConnect_to")
self.actionSave_chat_to = QtWidgets.QAction(MainWindow)
self.actionSave_chat_to.setObjectName("actionSave_chat_to")
self.actionQuit = QtWidgets.QAction(MainWindow)
self.actionQuit.setObjectName("actionQuit")
self.menuFile.addAction(self.actionConnect_to)
self.menuFile.addAction(self.actionSave_chat_to)
self.menuFile.addAction(self.actionQuit)
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.actionConnect_to.setText(_translate("MainWindow", "Connect to..."))
self.actionSave_chat_to.setText(_translate("MainWindow", "Export chat..."))
self.actionQuit.setText(_translate("MainWindow", "Quit"))

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
pyqt5-tools~=5.15

View File

@@ -1,65 +0,0 @@
import socket
import threading
# Connection Data
host = '127.0.0.1'
port = 55555
# Starting Server
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen()
# Lists For Clients and Their Nicknames
clients = []
nicknames = []
# Sending Messages To All Connected Clients
def broadcast(message):
for client in clients:
client.send(message)
# Handling Messages From Clients
def handle(client):
while True:
try:
# Broadcasting Messages
message = client.recv(1024)
broadcast(message)
except:
# Removing And Closing Clients
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast('{} left!'.format(nickname).encode('ascii'))
nicknames.remove(nickname)
break
# Receiving / Listening Function
def receive():
while True:
# Accept Connection
client, address = server.accept()
print("Connected with {}".format(str(address)))
# Request And Store Nickname
client.send('NICK'.encode('ascii'))
nickname = client.recv(1024).decode('ascii')
nicknames.append(nickname)
clients.append(client)
# Print And Broadcast Nickname
print("Nickname is {}".format(nickname))
broadcast("{} joined!".format(nickname).encode('ascii'))
client.send('Connected to server!'.encode('ascii'))
# Start Handling Thread For Client
thread = threading.Thread(target=handle, args=(client,))
thread.start()
receive()

0
server/gui.py Normal file
View File

0
server/main.py Normal file
View File