Форум сайта python.su
python 3.2.2
gtk3 3.2.2
python-gobject 3.0.2
Пытаюсь создать простенький одноранговый чатик. Как я сумел нагуглить, Gtk.main() является фактически бесконечным циклом. И слушанье порта надо запихнуть в бесконечный цикл. Для их совместной работы надо использовать несколько потоков. Причём в Gtk надо использовать свою собственную систему потоков. Ни как не могу найти адекватного примера её использования для PyGObject, попытался по аналогии из PyGtk перетащить, работает некорректно, Серверная часть стопорится на приёме сообщения(144) и не продолжается пока не случится присоединённого сигнала.
Вот исходник:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
from threading import Thread
from gi.repository import Gdk, Gtk, GLib
class Gui(Thread):
'''
Клас для даботы с интерфейсом.
'''
def __init__(self):
Thread.__init__(self)
def run(self):
Gdk.threads_init()
Gdk.threads_enter()
self.Window = Gtk.Window()
self.Window.set_border_width(8)
self.Window.set_title("Выбор лабораторной")
self.Window.set_default_size(755, 275)
self.Window.connect('destroy', lambda x: self.close_win())
#Создаём контейнер в который всё будет запихано
self.Paned = Gtk.Paned.new(Gtk.Orientation.VERTICAL)
self.Window.add(self.Paned)
self.inBox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 5)
self.Paned.pack1(self.inBox, True, False)
self.outBox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 5)
self.Paned.pack2(self.outBox, True, False)
self.inSupBox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5)
self.inBox.pack_start(self.inSupBox, False, False, 0)
#Ярлык, в который надо будет записать IP с которого было послано сообщение.
self.inLabelIP = Gtk.Label()
self.inSupBox.pack_start(self.inLabelIP, False, False, 0)
#создаём контейнер с возможностью прокрутки.
self.inScrollWin = Gtk.ScrolledWindow()
self.inScrollWin.set_size_request(600, 200)
self.inBox.pack_start(self.inScrollWin, True, True, 0)
#Многострочное текстовое поле.
self.inTextView = Gtk.TextView()
self.inTextView.set_editable(False)
self.inTextView.set_wrap_mode(Gtk.WrapMode.WORD)
self.inScrollWin.add(self.inTextView)
#Для хранения текста в форме TextView нужен буфер.
self.inTextBuffer = Gtk.TextBuffer()
self.inTextView.set_buffer(self.inTextBuffer)
self.outSupBox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5)
self.outBox.pack_start(self.outSupBox, False, False, 0)
#Создаём поле для записи IP4
self.outIP = Gtk.Entry()
self.outIP.set_max_length(15)
self.outIP.set_has_tooltip(True)
self.outIP.set_tooltip_text('IP4 компьютера, на который будет послано сообщение.')
self.outSupBox.pack_start(self.outIP, False, False, 0)
#создаём контейнер с возможностью прокрутки.
self.outScrollWin = Gtk.ScrolledWindow()
self.outScrollWin.set_size_request(600, 55)
self.outBox.pack_start(self.outScrollWin, True, True, 0)
#Многострочное текстовое поле.
self.inTextView = Gtk.TextView()
self.inTextView.set_hexpand(True)
self.inTextView.set_vexpand(True)
self.inTextView.set_wrap_mode(Gtk.WrapMode.WORD)
self.outScrollWin.add(self.inTextView)
#Для хранения текста в форме TextView нужен буфер.
self.inTextBuffer = Gtk.TextBuffer()
self.inTextView.set_buffer(self.inTextBuffer)
self.outBut = Gtk.Button.new_from_stock(Gtk.STOCK_OK)
self.outBut.set_halign(Gtk.Align.END)
self.outBut.set_size_request(150, 35)
self.outBut.connect('clicked', lambda x: self.mess_send())
self.outBox.pack_end(self.outBut, False, False, 0)
self.Window.show_all()
Gtk.main()
def close_win(self):
Gtk.main_quit()
Gdk.threads_leave()
def buffer_add(self, inMess):
self.StartIter = self.inTextBuffer.get_end_iter()
self.inTextBuffer.insert(self.StartIter, "\n\n>>>>> "+inMess)
def ip_set(self, inIp):
self.inLabelIP.set_text(inIp)
class Server(Thread):
'''
Класс отвечающий за приём сообщений
'''
def __init__(self):
Thread.__init__(self)
def run(self):
try:
self.servSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print('Сокет не создаётся.')
try:
self.servSocket.bind(('', 6888))
except:
print('Не запускается слушанье порта')
try:
self.servSocket.listen(1)
except:
print('Я не понимаю эту строчку но она не вышла.')
while True:
try:
inConn, (inIP, tmp) = self.servSocket.accept()
except:
print('Не вышло загнать полученные данные в переменную')
inData = inConn.recv(1024)
inMess = str(inData, 'utf8')
inConn.send(b'data')
class Client:
'''
Клас отвечает за отправку сообщения
'''
def __init__(self):
pass
guiThread = Gui()
guiThread.start()
print('ГУЙ запущен')
serverThread = Server()
serverThread.start()
print('Сервер запущен')
Отредактировано (Ноя. 14, 2011 06:52:57)
Офлайн
В качестве тестового клиента использую это.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Echo client program
import socket
HOST = '127.0.0.1' # The remote host
PORT = 6888 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send(b'sfsdfsfsd')
data = s.recv(1024)
s.close()
print(data)
Офлайн
Atterratio, по пайтону я пока не айс, но по принципу сетевого ввода-вывода могу рассказать многое.
так, во первых, для чего серверу поток? - для того, что ты вешаешь поток на accept`e. т.е. поток тупо висит ожидая соединения, что не логично в 21ом веке. обычно, в таких случаях, используют select/poll/epoll/kqueue(в зависимости от платформы).
во вторых - класс Gui не должен наследоваться от Thread.. ну не нужно оно ему.
строка:
Gtk.main()
Отредактировано (Ноя. 14, 2011 09:58:31)
Офлайн
pupkin2Об этом я думал, в принципе, но сейчас это не важно.
во вторых - класс Gui не должен наследоваться от Thread.. ну не нужно оно ему.
pupkin2Вот здесь пожалуйста по подробнее, ибо я в программировании нуб, а заминка возникает как раз в этом месте.
для чего серверу поток? - для того, что ты вешаешь поток на accept`e. т.е. поток тупо висит ожидая соединения, что не логично в 21ом веке.
Отредактировано (Ноя. 14, 2011 11:10:30)
Офлайн
Atterratioисключи наследование Gui от Thread, в первую очередь.
Если ставить “Gtk.main()” в основную функцию, то почему то вообще GUI не запускается.
Atterratioэй не… что-то ты в корню не верно делаешь. показывай что получилось. экзамплы, кстати, из доки, работают?
Быстренько сварганил на основе “asyncore” проблема та же остаётся.
Офлайн
Тут одно из двух, либо это баг. Либо что бы коректно отдилить Gtk GUI в отделюную нить надо правильно использовать Gdk.threads_*(и видимо ни кто не знает как)
Потому что даже вот такое не правильно работает:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
from threading import Thread
from gi.repository import Gtk, Gdk
class Gui(Thread):
def run(self):
self.Window = Gtk.Window()
self.Window.set_border_width(8)
self.Window.set_title("Некий GUI")
self.Window.connect('destroy', lambda x: self.stop())
self.outBut = Gtk.Button.new_from_stock(Gtk.STOCK_OK)
self.outBut.set_size_request(150, 35)
self.outBut.connect('clicked', lambda x: self.passfun)
self.Window.add(self.outBut)
self.Window.show_all()
Gtk.main()
def stop(self):
Gtk.main_quit()
def passfun(self):
pass
class LoopSleep(Thread):
def run(self):
i = 1
while True:
print(i)
i = i + 1
#time.sleep(1)
gui = Gui()
gui.start()
loopSleep = LoopSleep()
loopSleep.start()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
from threading import Thread
from gi.repository import Gtk, Gdk
class Gui():
def run(self):
self.Window = Gtk.Window()
self.Window.set_border_width(8)
self.Window.set_title("Некий GUI")
self.Window.connect('destroy', lambda x: self.stop())
self.outBut = Gtk.Button.new_from_stock(Gtk.STOCK_OK)
self.outBut.set_size_request(150, 35)
self.outBut.connect('clicked', lambda x: self.passfun)
self.Window.add(self.outBut)
self.Window.show_all()
def stop(self):
Gtk.main_quit()
Gdk.threads_leave()
def passfun(self):
pass
class LoopSleep(Thread):
def run(self):
i = 1
while True:
print(i)
i = i + 1
#time.sleep(1)
Gdk.threads_init()
Gdk.threads_enter()
gui = Gui()
gui.run()
loopSleep = LoopSleep()
loopSleep.start()
Gtk.main()
Отредактировано (Ноя. 14, 2011 11:40:56)
Офлайн
Atterratioтрэд тут зачем?
class Gui(Thread):
Офлайн
Что с ним что без него, всё равно не работает.
Сейчас я спать, а завтра пойду постить вопрос на иностранный сайт.
Отредактировано (Ноя. 14, 2011 11:59:37)
Офлайн
не знаю.. какие-то ошибки у меня вываливаются при использовании PyGtk. так что “умываю руки”.
Офлайн
Дак тут же не PyGtk, а PyGObject.
Офлайн