Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 14, 2011 06:34:15

Atterratio
От:
Зарегистрирован: 2011-09-17
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

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)

Офлайн

#2 Ноя. 14, 2011 06:42:26

Atterratio
От:
Зарегистрирован: 2011-09-17
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

В качестве тестового клиента использую это.

#!/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)



Офлайн

#3 Ноя. 14, 2011 09:51:23

pupkin2
От:
Зарегистрирован: 2011-10-23
Сообщения: 103
Репутация: +  1  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

Atterratio, по пайтону я пока не айс, но по принципу сетевого ввода-вывода могу рассказать многое.
так, во первых, для чего серверу поток? - для того, что ты вешаешь поток на accept`e. т.е. поток тупо висит ожидая соединения, что не логично в 21ом веке. обычно, в таких случаях, используют select/poll/epoll/kqueue(в зависимости от платформы).

во вторых - класс Gui не должен наследоваться от Thread.. ну не нужно оно ему.
строка:

        Gtk.main()
должна быть в основной функции. она запускает цикл событий.

в третьих - синхронный ввод-вывод, это уже совсем не смешно ;) рекомендовал бы посмотреть на http://docs.python.org/py3k/library/asyncore.html , она вроде как, судя по доке, сделана для человеков.



Отредактировано (Ноя. 14, 2011 09:58:31)

Офлайн

#4 Ноя. 14, 2011 10:57:43

Atterratio
От:
Зарегистрирован: 2011-09-17
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

pupkin2
во вторых - класс Gui не должен наследоваться от Thread.. ну не нужно оно ему.
Об этом я думал, в принципе, но сейчас это не важно.

Если ставить “Gtk.main()” в основную функцию, то почему то вообще GUI не запускается.

pupkin2
для чего серверу поток? - для того, что ты вешаешь поток на accept`e. т.е. поток тупо висит ожидая соединения, что не логично в 21ом веке.
Вот здесь пожалуйста по подробнее, ибо я в программировании нуб, а заминка возникает как раз в этом месте.


Быстренько сварганил на основе “asyncore” проблема та же остаётся.



Отредактировано (Ноя. 14, 2011 11:10:30)

Офлайн

#5 Ноя. 14, 2011 11:23:48

pupkin2
От:
Зарегистрирован: 2011-10-23
Сообщения: 103
Репутация: +  1  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

Atterratio
Если ставить “Gtk.main()” в основную функцию, то почему то вообще GUI не запускается.
исключи наследование Gui от Thread, в первую очередь.
вставь вызов “Gtk.main()” в основную функцию.
и покажи что получилось.

Atterratio
Быстренько сварганил на основе “asyncore” проблема та же остаётся.
эй не… что-то ты в корню не верно делаешь. показывай что получилось. экзамплы, кстати, из доки, работают?



Офлайн

#6 Ноя. 14, 2011 11:35:39

Atterratio
От:
Зарегистрирован: 2011-09-17
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

Тут одно из двух, либо это баг. Либо что бы коректно отдилить 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()
Примерно 250 цилов при нажатии на кнопку пробегает. При закрытии GUI уходит в бесконечный.



Отредактировано (Ноя. 14, 2011 11:40:56)

Офлайн

#7 Ноя. 14, 2011 11:37:30

pupkin2
От:
Зарегистрирован: 2011-10-23
Сообщения: 103
Репутация: +  1  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

Atterratio
class Gui(Thread):
трэд тут зачем?



Офлайн

#8 Ноя. 14, 2011 11:45:33

Atterratio
От:
Зарегистрирован: 2011-09-17
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

Что с ним что без него, всё равно не работает.

Сейчас я спать, а завтра пойду постить вопрос на иностранный сайт.



Отредактировано (Ноя. 14, 2011 11:59:37)

Офлайн

#9 Ноя. 14, 2011 13:52:43

pupkin2
От:
Зарегистрирован: 2011-10-23
Сообщения: 103
Репутация: +  1  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

не знаю.. какие-то ошибки у меня вываливаются при использовании PyGtk. так что “умываю руки”.



Офлайн

#10 Ноя. 14, 2011 13:59:01

Atterratio
От:
Зарегистрирован: 2011-09-17
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 + PyGObject + Gdk.threads.

Дак тут же не PyGtk, а PyGObject.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version