Найти - Пользователи
Полная версия: Python3 + PyGObject + Gdk.threads.
Начало » GUI » Python3 + PyGObject + Gdk.threads.
1 2
Atterratio
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('Сервер запущен')
Atterratio
В качестве тестового клиента использую это.

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

во вторых - класс Gui не должен наследоваться от Thread.. ну не нужно оно ему.
строка:
        Gtk.main()
должна быть в основной функции. она запускает цикл событий.

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

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

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


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

Atterratio
Быстренько сварганил на основе “asyncore” проблема та же остаётся.
эй не… что-то ты в корню не верно делаешь. показывай что получилось. экзамплы, кстати, из доки, работают?
Atterratio
Тут одно из двух, либо это баг. Либо что бы коректно отдилить 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 уходит в бесконечный.
pupkin2
Atterratio
class Gui(Thread):
трэд тут зачем?
Atterratio
Что с ним что без него, всё равно не работает.

Сейчас я спать, а завтра пойду постить вопрос на иностранный сайт.
pupkin2
не знаю.. какие-то ошибки у меня вываливаются при использовании PyGtk. так что “умываю руки”.
Atterratio
Дак тут же не PyGtk, а PyGObject.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB