Найти - Пользователи
Полная версия: PyQt4 | Как передать сигнал из дочернего окна в родительское?
Начало » GUI » PyQt4 | Как передать сигнал из дочернего окна в родительское?
1 2 3 4 5
py.user.next
Kyrym
Как передать данные из текстового поля дочернего окна при нажатии на кнопку в текстовое поле родительского окна?
У тебя должен быть отдельный объект, который их соединяет по событиям. То, что они сами находятся в какой-то иерархии, никак не должно учитываться. Ты нажимаешь на кнопку, от кнопки посылается сигнал объекту. Объект принимает сигнал и у него там внутри запрограммировано, что при получении этого сигнала он должен отправить такой-то сигнал другому окну. Если же с той стороны должно что-то вернуться на кнопку (бывает их нужно затенять), то это делается точно так же, через объект. Это что-то типа шаблона MVC только на микроуровне.
Rodegast
> И вообще, какой смысл писать сообщения типа “так делать не надо и точка” без всяких объяснений.

Меня задолбало одно и тоже каждый раз объяснять. А так хоть правильное направление знать будешь.

> У тебя должен быть отдельный объект, который их соединяет по событиям. … Это что-то типа шаблона MVC только на микроуровне.

py.user.next
Rodegast если окна друг с другом соединяешь напрямую, то потом при удалении окна нужно из всех окон связи с ним удалять, а они далеко не всегда очевидны. Если же это через объект соединено, то в нём просто вносится правка и таким образом для всех окон удаляемое окно пропадает из программы.
Rodegast
> если окна друг с другом соединяешь напрямую, то потом при удалении окна нужно из всех окон связи с ним удалять

1) Если мне склероз не изменяет, то Qt при закрытии окна сама все к нему подключения прекрасно удалит.
2) Подключать 100500 виджетов одного окна к 100500 виджетом другого ни в коем случае нельзя. Об этом я уже писал.
py.user.next
Rodegast
1) Если мне склероз не изменяет, то Qt при закрытии окна сама все к нему подключения прекрасно удалит.
Я имею в виду разработку. Ты, например, решил вытащить окно и заменить его на другое что-то, на веб-интерфейс, например. Вот чтобы его вытащить из программы, надо его отовсюду отсоединить. Если же оно подключено только к одному объекту, то это всегда понятно и легко делается. Если же оно подсоединено куда-то непонятно куда и как-то сложно общается с разными элементами, то это надо искать всё и ещё потом долго отсоединять и думать, чтобы ничего не сломалось.
Rodegast
> Вот чтобы его вытащить из программы, надо его отовсюду отсоединить

Не надо. Окно это класс который реализует определённый интерфейс. Если захотелось окно заменить то просто заменяешь его другим классом который реализует тот же интерфейс.
Kyrym
Немного переделал код, предложенный PEHDOM, пример 2:
Главное отличие в том, что в данном случае дочернее окно ведёт себя отдельно от родительского, а значит, родительское может перекрыть собой дочернее.

Родитель
 # Python 3. PyQt4
# -*- coding: utf-8 -*-
# Родительское окно может перекрыть дочернее
import sys
import os
from PyQt4 import QtGui, QtCore
import mod_2
# ГРАФИКА
class Window_os(QtGui.QWidget):
    def __init__(self, parent=None):        
        super().__init__(parent)
        self.secondWin = None
        self.opn_frame = None
        
        self.resize(300, 300) # шир / выс окна
        self.setWindowTitle('главное') # Заголовок        
        
        self.lab = QtGui.QLabel('simple text', self)
        self.pole = QtGui.QTextEdit()
        self.but1 = QtGui.QPushButton('open window', self)
        self.but1.clicked.connect(self.on_click)
        # БЛОК РАЗМЕТКИ
        self.mainLayout = QtGui.QVBoxLayout()
        self.mainLayout.addWidget(self.lab)
        self.mainLayout.addWidget(self.pole)
        self.mainLayout.addWidget(self.but1)
        self.setLayout(self.mainLayout)
    def on_click(self):
        if not self.opn_frame: 
            self.secondWin = mod_2.SecondWindow(self)
            self.opn_frame = QtGui.QFrame()                    
            self.opn_frame_lay = QtGui.QHBoxLayout(self.opn_frame)
            self.opn_frame_lay.addWidget(self.secondWin)            
            self.setLayout(self.opn_frame_lay)
        
            self.secondWin.sendText.connect(self.pasteText)
            self.opn_frame.resize(200, 200)
            self.opn_frame.setWindowTitle('дочернее окно') # Заголовок
            self.opn_frame.setWindowIcon(QtGui.QIcon('icon.png')) # Иконка
        self.opn_frame.show()
           
    def pasteText(self,text):
        self.pole.setText(text)
# КОНЕЦ
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window_os() # создаёт экземпляр окна из класса
    window.move(400, 300) # сдвиг окна от верхнего левого угла экрана    
    window.show() # запускает окно
    sys.exit(app.exec_())
   

Файл mod_2.py
 import sys
from PyQt4 import QtGui, QtCore
class SecondWindow(QtGui.QWidget):
    sendText = QtCore.pyqtSignal(str)  # сигнал
    def __init__(self, parent=None):
        # Передаём ссылку на родительский элемент и чтобы виджет
        # отображался как самостоятельное окно указываем тип окна
        super().__init__(parent, QtCore.Qt.Window)
        self.resize(100, 100)
        self.pole_2 = QtGui.QTextEdit()
        self.button_0 = QtGui.QPushButton('Жми')
        # Блок разметки
        self.mainLayout = QtGui.QVBoxLayout()
        self.mainLayout.addWidget(self.pole_2)
        self.mainLayout.addWidget(self.button_0)
        self.setLayout(self.mainLayout)
        self.button_0.clicked.connect(self.on_click_1)
    def on_click_1(self, text):
        q = self.pole_2.toPlainText()
        self.sendText.emit(q) #посылаем сигнал по клику

Вообще, мне не понятно, зачем делать так:
 ...
    self.build()
def build(self):
...
Т.е. для чего делать 2 функции, когда всё “на ура” проходит и в одной?
MrViktor
Kyrym
self.build() def build(self):

def build(self): - описание (объявление) метода класса
self.build() - вызов метода экземпляра класса

И где это в исходнике? или это не в вашем?
vic57
Kyrym а так не проще?
 import sys
from PyQt4.Qt import *
class Dialog(QDialog):
    dataChanged = pyqtSignal(str)
    def __init__(self,parent=None):
        QDialog.__init__(self)        
        self.btnApply = QPushButton(u'Применить')
        self.btnOK = QPushButton(u'Закрыть')
        self.line = QLineEdit()
        grid = QGridLayout(self)
        grid.addWidget(self.line,0,0,1,3)
        grid.addWidget(self.btnOK,1,1)
        grid.addWidget(self.btnApply,1,2)
        self.btnOK.clicked.connect(self.accept)
        self.btnApply.clicked.connect(self.getData)
        self.line.setFocus()
    def getData(self):
        self.dataChanged.emit(self.line.text())
class W(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.btn = QPushButton("Push")
        self.line = QLineEdit()
        grid = QGridLayout(self)
        grid.addWidget(self.line,0,0)
        grid.addWidget(self.btn,1,0)
        self.btn.clicked.connect(self.btnClick)
    def btnClick(self):
        d = Dialog()
        d.dataChanged.connect(self.setData)
        d.exec_()
        d.dataChanged.disconnect(self.setData)
        del d
    def setData(self,data):
        self.line.setText(data)
def app_quit():
    sys.exit()
    
if __name__=="__main__":
    app = QApplication([])
    app.lastWindowClosed.connect(app_quit)
    w = W()
    w.show()
    app.exec_()
Kyrym
vic57
Kyrym а так не проще?
Я же написал, что дочернее окно должно работать отдельно от родительского.

MrViktor
И где это в исходнике? или это не в вашем?
Это в варианте PEHDOM. Я как-раз и убрал “лишнюю” функцию.
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