LINUX.ORG.RU

PyQt окна

 , ,


0

1

Доброго времени. Как в PyQt реализуются связи между окнами? Передача даных их полей, получение события закртия дчернего окна? В сулчае если оба окна это разные классы, т.е. в QTdesigner созданные два разных ui файла. Наверное можно перефразировтаь вопрос так: как между классами реализуется передача значений переменных?

Ответ на: комментарий от Kilte

Да, и с ними я уже пробовал сво задачу реализовать. Но во первых ничего в интернете не нашёл как можно из одно класса вызывать в другом классе (когда эта функция использует глобальные переменные или переменные из дргих функций этого-же класса). А во вторых они решают проблему наполовину, мне ещё надо передать значения переменных в функцию в другом классе.

wojaovlad
() автор топика
Ответ на: комментарий от wojaovlad

Через сигналы-слоты тоже можно передавать данные, внезапно. Технически это просто вызов функции, о внутренностях её вызывающее окно даже не знает.

Если у тебя одно окно вызывает второе модально, передавай нужные данные в конструкторе.

Если это немодальный диалог с постоянным обновлением, держи указатель на него в главном окне и вызывай нужный метод руками.

Возможно, тебе подойдёт MVC (если ты знаешь, что это).

А по-хорошему нужно такую функциональность вынести в отдельные классы и уже их связывать с окнами (MVC примерно это и делает).

E ★★★
()

получение события

Сигналы и слоты.

передача значений переменных

Ну методы жe. Пусть у тебя в одном экземпляре класса будет ссылка на другой экземпляр класса, ты оттуда и вызывай все необходимое. Например пусть в дочернем окне будет self.parent, и уже из парента получай все что нужно. С другой стороны, если тебе нужно получать инфу из дочернего окна, тогда просто при инициализации дочернего окна из родительского окна делай что-то типа

self.childrenWindow = UserInfoWindow(self)
(здесь ты как раз дочернему передаешь род. экземпляр для ссылок), в классе род. окна тогда можно делать нечто вроде:
def childrenInfoUpdate(self):
    self.foo = self.children.getFoo()
    self.bar = self.children.count
Ну и уже связывать сигналом изменение чего либо в дочернем окне с self.childrenInfoUpdate()

destabilizer
()
Ответ на: комментарий от wojaovlad

ЯННП.

Возьмём простой пример. Тебе надо заполнить список, когда пользователь выбрал директорий.

Сам листинг:

сlass Listing(QtGui.QWidget):
    def populate(self, directory):
        # TODO
        pass

Слот:

class OnDirectorySelected(object):
    def __init__(self, listing):
        self.listing = listing

    def __call__(self, directory):
        self.listing.populate(directory)

Диалог:

from PyQt4 import QtCore, QtGui

class SelectorWidget(QtGui.QWidget):
    directorySelected = QtCore.pyqtSignal(str)
    u"""Сигнал, по которому можем узнать, какой директорий был выбран."""

    def __init__(self):
        super(SelectorWidget, self).__init__()
        self.__fileDialog = QtGui.QFileDialog()
        self.__dialogOptions = QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.ReadOnly
        self.__input = QtGui.QLineEdit()
        self.__input.setReadOnly(True)
        self.__browse = QtGui.QPushButton('Browse...')
        self.__browse.clicked.connect(self.selectDirectory)
        layout = QtGui.QHBoxLayout()
        layout.addWidget(self.__input)
        layout.addWidget(self.__browse)
        self.setLayout(layout)

    def selectDirectory(self):
        directory = str(self.__fileDialog.getExistingDirectory(None, 'Select Directory', '', self.__dialogOptions))
        if directory:
            self.__input.setText(directory)
            self.directorySelected.emit(directory)

Коннектимся к сигналу:

listing = Listing()
dirSelector = SelectorWidget()
dirSelector.directorySelected.connect(OnDirectorySelected(listing))

Вот, как-то так.

Kilte ★★★★★
()
Ответ на: комментарий от Kilte

Вот попробовал на простом примере реализовать:

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui


class MainWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.resize(200, 150)
        button = QtGui.QPushButton(u'Нажми меня', self)
        self.connect(button, QtCore.SIGNAL("clicked()"), Window())

    def lol(self):
        self.u = 9

    def on_click(self):
        print u'Все пучком'
        print self.u

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
    def __call__(self):
        self.main = MainWindow()
        self.button1 = QtGui.QPushButton(u"Пробуй", self)
        self.button1.setMinimumSize(QtCore.QSize(150, 70))
        self.button1.clicked.connect(self.main.on_click)
        self.show()

    def closeEvent(self, event):
        self.main.on_click()


app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())


Я специально сделал функцию "lol" чтобы проверить доступность переменной. Если я в init переменную объявляю, то всё ок. Как сделать чтобы из функции "lol" была видна переменная?
 Сейчас такая ошибка 
    print self.u
AttributeError: 'MainWindow' object has no attribute 'u'
wojaovlad
() автор топика
Ответ на: комментарий от wojaovlad

затупил

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui


class MainWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.resize(200, 150)
        button = QtGui.QPushButton(u'Нажми меня', self)
        self.connect(button, QtCore.SIGNAL("clicked()"), Window())
        self.lol()

    def lol(self):
        self.u = 9

    def on_click(self):
        print u'Все пучком'
        print self.u

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
    def __call__(self):
        self.main = MainWindow()
        self.button1 = QtGui.QPushButton(u"Пробуй", self)
        self.button1.setMinimumSize(QtCore.QSize(150, 70))
        self.button1.clicked.connect(self.main.on_click)
        self.show()

    def closeEvent(self, event):
        self.main.on_click()


app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

wojaovlad
() автор топика
Ответ на: комментарий от wojaovlad

Жесть какая-то. Зачем несколько раз создавать MainWindow()?

import sys

from PyQt4 import QtCore, QtGui


class MainWindow(QtGui.QWidget):
    def __init__(self, child):
        super().__init__()
        button = QtGui.QPushButton('Нажми меня', self)
        button.clicked.connect(child.show)
        self.data = 'OK';
        self.resize(200, 150)

    def printData(self):
        print(self.data)


class Child(QtGui.QWidget):
    def __init__(self):
        super().__init__()
        self.mainWindow = None

    def setMainWindow(self, window):
        if self.mainWindow is not None:
            raise Exception('Failed!')
        self.mainWindow = window
        button = QtGui.QPushButton('Пробуй', self)
        button.setMinimumSize(QtCore.QSize(150, 70))
        button.clicked.connect(self.mainWindow.printData)

    def closeEvent(self, event):
        self.mainWindow.printData()


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    child = Child()
    main = MainWindow(child)
    child.setMainWindow(main)
    main.show()
    sys.exit(app.exec_())
Kilte ★★★★★
()
Ответ на: комментарий от Kilte

Не знаю, не задумывался в принципе. Возможно дело привычки, как-то уже начал с этой ветки, и мануалов вроде побольше...

data не должна сразу инициализироваться. Но я уже разобрался в принципе. Сейчас моё извращение заработало, только как-то не полностью. Если не лень помочь, то посмотрите, пожалуйста. На код не ругайтесь сильно, я пока не достиг того уровня.

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'table_cards.ui'
#
# Created: Mon Apr 20 12:47:33 2015
#      by: PyQt4 UI code generator 4.9.1
#
# WARNING! All changes made in this file will be lost!

import os
import sys, time
import config
import sqlite3 as db
from PyQt4 import QtCore, QtGui
from edit_cards import Ui_Card_dialog


id_number = config.id_number
db_filename = config.db_filename
lol = config.lol

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class Ui_Dialog_cards(object):
    def setupUi(self, Dialog_cards):
        Dialog_cards.setObjectName(_fromUtf8("Dialog_cards"))
        Dialog_cards.resize(826, 518)
        self.verticalLayout = QtGui.QVBoxLayout(Dialog_cards)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.tableWidget_cards = QtGui.QTableWidget(Dialog_cards)
        font = QtGui.QFont()
        font.setPointSize(12)
        self.tableWidget_cards.setFont(font)
        self.tableWidget_cards.setObjectName(_fromUtf8("tableWidget_cards"))
        self.tableWidget_cards.setColumnCount(0)
        self.tableWidget_cards.setRowCount(0)
        self.verticalLayout.addWidget(self.tableWidget_cards)
        self.horizontalLayout = QtGui.QHBoxLayout()
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
        self.Add_Button = QtGui.QPushButton(Dialog_cards)
        font = QtGui.QFont()
        font.setPointSize(12)
        self.Add_Button.setFont(font)
        self.Add_Button.setObjectName(_fromUtf8("Add_Button"))
        self.horizontalLayout.addWidget(self.Add_Button)
        self.Change_Button = QtGui.QPushButton(Dialog_cards)
        font = QtGui.QFont()
        font.setPointSize(12)
        self.Change_Button.setFont(font)
        self.Change_Button.setObjectName(_fromUtf8("Change_Button"))
        self.horizontalLayout.addWidget(self.Change_Button)
        self.Delete_Button = QtGui.QPushButton(Dialog_cards)
        font = QtGui.QFont()
        font.setPointSize(12)
        self.Delete_Button.setFont(font)
        self.Delete_Button.setObjectName(_fromUtf8("Delete_Button"))
        self.horizontalLayout.addWidget(self.Delete_Button)
        self.Close_Button = QtGui.QPushButton(Dialog_cards)
        font = QtGui.QFont()
        font.setPointSize(12)
        self.Close_Button.setFont(font)
        self.Close_Button.setObjectName(_fromUtf8("Close_Button"))
        self.horizontalLayout.addWidget(self.Close_Button)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.retranslateUi(Dialog_cards)
        self.second_window = second_window()
        QtCore.QObject.connect(self.Close_Button, QtCore.SIGNAL(_fromUtf8("clicked()")), Dialog_cards.close)
        QtCore.QObject.connect(self.Add_Button, QtCore.SIGNAL(_fromUtf8("clicked()")), self.second_window.show_edit_window)
        QtCore.QObject.connect(self.Delete_Button, QtCore.SIGNAL(_fromUtf8("clicked()")), self.delete)
        QtCore.QMetaObject.connectSlotsByName(Dialog_cards)
        Dialog_cards.setTabOrder(self.Add_Button, self.Change_Button)
        Dialog_cards.setTabOrder(self.Change_Button, self.Delete_Button)
        Dialog_cards.setTabOrder(self.Delete_Button, self.Close_Button)
        Dialog_cards.setTabOrder(self.Close_Button, self.tableWidget_cards)
        self.update()


    def retranslateUi(self, Dialog_cards):
        Dialog_cards.setWindowTitle(QtGui.QApplication.translate("Dialog_cards", "Товары", None, QtGui.QApplication.UnicodeUTF8))
        self.Add_Button.setText(QtGui.QApplication.translate("Dialog_cards", "Добавить", None, QtGui.QApplication.UnicodeUTF8))
        self.Change_Button.setText(QtGui.QApplication.translate("Dialog_cards", "Изменить", None, QtGui.QApplication.UnicodeUTF8))
        self.Delete_Button.setText(QtGui.QApplication.translate("Dialog_cards", "Удалить", None, QtGui.QApplication.UnicodeUTF8))
        self.Close_Button.setText(QtGui.QApplication.translate("Dialog_cards", "Закрыть", None, QtGui.QApplication.UnicodeUTF8))

    def update(self):
        print "Update run"
        global db_filename
        self.tableWidget_cards.clear()
        self.tableWidget_cards.setColumnCount(6)
        self.tableWidget_cards.setRowCount(40) #выставить столько полей, сколько в таблице
        self.tableWidget_cards.setHorizontalHeaderLabels(
            [u'Производитель', u'Наименование', u'Ед. измерения', u'Ставка НДС', u'№РУ', u'Дата истечения'])
        conn = db.connect(db_filename)
        c = conn.cursor()
        db_is_new = not os.path.exists(db_filename)
        if db_is_new:
            print 'Need to create schema'
        else:
            print 'Database exists, assume schema does, too.'
        conn.execute(
            '''CREATE TABLE IF NOT EXISTS cards (id INTEGER PRIMARY KEY AUTOINCREMENT, manufacturer TEXT NOT NULL, name  TEXT NOT NULL, unit TEXT, nds TEXT NOT NULL, ru TEXT NOT NULL, date_end TEXT);''')
        print "Table created successfully"
        i = 0
        rowd = 0
        for row in c.execute("SELECT * FROM cards"):
            a = [row[5], row[2], row[4], row[6], row[1], row[3]]
            for i in range(6):
                name = unicode(a[i])
                self.tableWidget_cards.setItem(rowd, i, QtGui.QTableWidgetItem(name))
                print name
                i += 1
            rowd += 1
            print rowd
        conn.close()
        self.tableWidget_cards.resizeColumnsToContents()
        print "Update end"

    def delete(self):
        print "Delete RUN"
        global db_filename
        cell = self.getsamerowcell()
        print cell
        conn = db.connect(db_filename)
        c = conn.cursor()
        c.execute('DELETE FROM cards WHERE name=?', (cell,))
        conn.commit()
        conn.close
        self.update()
        print "Delete END"

    def getsamerowcell(self):
        matchcol = 0
        row = self.tableWidget_cards.currentItem().row()
        headercount = self.tableWidget_cards.columnCount()
        for x in range(0,headercount,1):
            headertext = self.tableWidget_cards.horizontalHeaderItem(x).text()
            if u'Наименование' == unicode(headertext):
                matchcol = x
                break
        cell = self.tableWidget_cards.item(row,matchcol).text()
        print unicode(cell)
        return unicode(cell)

    def ilol(self):
        Form = QtGui.QWidget()
        self.setupUi(Form)

class second_window(QtGui.QWidget, Ui_Card_dialog):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        Ui_Card_dialog.__init__(self)
        Ui_Dialog_cards.__init__(self)
        self.main = Ui_Dialog_cards()
        self.setupUi(self)
    def show_edit_window(self):
        self.show()
    def closeEvent(self, event):
        print "close"
        self.main.ilol()




if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    Form = QtGui.QWidget()
    ex = Ui_Dialog_cards()
    ex.setupUi(Form)
    Form.show()
    app.exec_()

Я из класса second_window на закрытие окна должен обновить таблицу запустив функцию update. Вот таким макаром у меня получилось добиться её запуска, только она выполняейтся, а визуально таблица не обновляется_)

wojaovlad
() автор топика
Ответ на: комментарий от wojaovlad

На код не ругайтесь сильно, я пока не достиг того уровня.

Ох. Лол. Да я и сам любитель.

Начнём с того, что не нужно создавать несколько экземпляров одного и того же класса без необходимости. В идеале лучше использовать внедрение зависимостей. И я гарантирую, что переписав этот код так, как предложено, получится избавится от этого бага.

Честно сказать, я не до конца понял, что там творится. Зачем-то создаётся виджет, передаётся в setupUi(), потом при закрытии дочернего окна снова создаётся виджет и передаётся в setupUi(). Ошибка кроется именно в этом.

Грубо говоря, тот виджет, который был показан изначально, не имеет тех данных, что были получены при повторном вызове update, так как экземпляр виджета уже другой.

Kilte ★★★★★
()
Последнее исправление: Kilte (всего исправлений: 3)
Ответ на: комментарий от Kilte

А можете пример какой-нибудь показать где вместо сосзлания нескольких экземпляров, делаете внедрение? Можно на части моего кода, было бы здорово_)

wojaovlad
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.