karulyana
@karulyana
Начинающий питонист

Python — как реализовать ООП с PyQt (connect)?

Есть окно в PyQt в нем кнопка Оpen для загрузки файла
В том же окне есть таблица, которая заполняется содержимым файл
Не могу грамотно соединить все(

Вот части программы:

class open_kn(QPushButton):
    def __init__(self, parent=None):
        super(open_kn, self).__init__(parent)
        self.setText('Open')
        self.resize(self.sizeHint())
        self.clicked.connect(FileDialog)
        

class FileDialog(QFileDialog):
    def __init__(self):
        super().__init__()
        try:
            self.fileName = self.getOpenFileName(self, 'Open file', 'D:\\')[0]
            #self.textEdit.setText(self.fileName)
            f = open(self.fileName, 'r')
            data = []
            with f as f:
                for i in f.readlines():
                    data.append(i)
            TableWidget.data = data
        except IOError:
            print('Не могу открыть', self.fileName)
        except ImportError as err:
            print('Error: импортировать файл не удалось!', err)
        except ValueError as err:
            print('Error: не тот формат данных!', err)
        except:
            print('Неожиданная ошибка:', sys.exc_info()[0])


class TableWidget(QTableWidget):
    def __init__(self, parent=None, data=[]):
        super(TableWidget, self).__init__(parent)
        #data = []
        self.setColumnCount(1)
        self.setRowCount(len(data))
        for i, entry in enumerate(data, start=1):
            self.setRowCount(i)
            item = QTableWidgetItem()
            item.setText(str(entry))

Сама таблица вставляется QGridLayout:
я думала может в класс задать переменной данные с файла и там уже просто обьявить таблицу с атрибутом
но не знаю как это реализовать
Вот класс
class HBox4(QGridLayout):
    def __init__(self, parent=None):
        super(HBox4, self).__init__(parent)
        table = TableWidget()
        self.addWidget(table, *(0,0))
        self.addWidget(TabDemo(), *(0,1))


Я только начала изучать программирование не судите строго

Я думаю, может так вообще делать нельзя(
  • Вопрос задан
  • 1995 просмотров
Решения вопроса 2
@kgbplus
Сделайте в классе HBox4 метод update:

class HBox4(QGridLayout):
    def __init__(self, parent=None):
        super(HBox4, self).__init__(parent)
        self.table = TableWidget()
        self.addWidget(self.table, *(0,0))
        self.addWidget(TabDemo(), *(0,1))
    def update(self,data):
        self.table.update(data)


Ну и в классе Table то же самое:

class TableWidget(QTableWidget):
    def __init__(self, parent=None, data=[]):
        super(TableWidget, self).__init__(parent)
        #data = []
        self.setColumnCount(1)
        self.setRowCount(len(data))
        for i, entry in enumerate(data, start=1):
            self.setRowCount(i)
            item = QTableWidgetItem()
            item.setText(str(entry))
   def update(self,data):
        self.clearContents ()
        #тут очищаем таблицу, затем тот же код, что и в init
        self.setColumnCount(1)
        self.setRowCount(len(data))
        for i, entry in enumerate(data, start=1):
            self.setRowCount(i)
            item = QTableWidgetItem()
            item.setText(str(entry))


Как то так....
Ответ написан
@Sergey6661313
# у меня python версии 3.5
# pyqt - 5-ой версии.

## Минимальная затравка для запуска кода  :
# coding=UTF8
# это чтобы можно было переменные по русски называть.
#  обязательно при этом сохранять py фаил в UTF

# импорты:
import sys
from PyQt5.Qt import QApplication, QPushButton, QFileDialog,\
    QTableWidget, QTableWidgetItem, QGridLayout, QWidget, pyqtSignal
app = QApplication([])

# ну а теперь будем мудрить. Честно говоря ваш уровень
#  владения python-м совсем не ясен. Потому начнём с супер нуля.
# None и pass - обозначают пустату (т.е. ничто).
#  Она нам понадобится в дальнейшем :).

кнопка = None       # надеюсь понятия переменные
#  обьяснять не надо. Кнопку назовём кнопка.
# КЭП уплывёт, а кнопка останется в памяти интерпретатора.

# для начало нам нужно знать что всё что отображается
#  на экране это какие то объекты, а не их описание.
class open_kn(QPushButton): pass    # - это описание.
#  Оно как ДНК для будущего ребёнка,
#  но при этом само ребёнком не является.

# детки создаются как-то так:
open_kn()           # - это создание экземпляра класса.
# Мы как бы говорим интерпретатору что хотим "породить"
#  один экземпляр всего того что описано в "ДНК" open_kn.
# при этом обычно выполняются все инструкции в нутри
#  конструктора класса (это тот который def __init__)
# но у нас пока что такой метод не назначен поэтому
#  "ребёнок" просто унаследует всё что есть в QPushButton

# но созданный экземпляр как и КЭП появившись и
# пояснив компьютеру что мы от него хотим сразу самовыпиливается.
# поэтому нам нужна переменная для его хранения:
кнопка = open_kn()      # кнопка - наш ребёнок, а  open_kn - наше ДНК.

# так нам надо ещё сделать на ней текст и заставить отрисовыватся на экране:
# вообще эти два метода могли быть и в конструкторе :
class open_kn(QPushButton):
    def __init__(self):
        # а кстати да - методы создаются именно через
        #  def %название_метода%(аргументы):
        self.setText('Open')    # устанавливаем текст на кнопке

# но всё это нафиг не нужно если в вашем классе всего
#  один метод, и тот конструктор -
# тогда зачем вам вообще такой класс?
кнопка = QPushButton()
кнопка.setText('Open')

def всё_что_будет_происходить_при_нажатии_на_кнопку():
    # аналогично не обязательно переопределять целый класс FileDialog всего для одного метода...
    # так с кнопкой разобрались. Теперь нам нужен диалог и таблица.
    fileName = QFileDialog.getOpenFileName \
        (кнопка, 'Простой пример', 'd:\\',"Текст (*.txt)")[0] # ваш код, не буду его коментировать.
    f = open(fileName, 'r', encoding="utf8")
    # я добавил encoding="utf8" потому что мои txt именно в таком формате
    # кстати говоря именно ваши "try, except" и скрывают от вас настоящию ошибку.
    # "Неожиданная ошибка:" - очень информативно...

    # тут пока без изменеинй.
    data = []
    with f as f:
        for i in f.readlines():
            data.append(i)

    # TableWidget.data = data # ага какой нафиг TableWidget когда мы его ещё не определили?
    #  впрочем х*@ с ним...
    # вы же сами сказали что ваш table в HBox4 ? значит путь бедет примерно такой:
    экземпляр_класса_HBox4.table.update(data) # мы просто напрямую вызываем нужный нам метод

# РИСУЕМ!

class TableWidget(QTableWidget):
    #  я немного переделал: сразу перенёс всю настройку таблици в метод update

    def __init__(self, parent=None, data=[]):
        super(TableWidget, self).__init__(parent)
        self.update() # ну и чтобы не повторятся просто вызываю этот метод

    def update(self, data=[]):
        self.setColumnCount(1)
        self.setRowCount(len(data))
        for i, entry in enumerate(data, start=1): # у вас "нулевая" строка в txt
            #  - комментарий?
            self.setRowCount(i)
            item = QTableWidgetItem()
            item.setText(str(entry))
            self.setItem(i-1, 0, item) #  - либо тут "-1" либо начинать с нулевого элемента,
            #  либо в setRowCount делать +1...
        print(data) # - для отладки посмотрим: а вдруг данные всё таки передаются,
        #  а в таблицу не пишутся?

class HBox4(QGridLayout):
    def __init__(self, parent=None):
        super(HBox4, self).__init__(parent)
        table = TableWidget()       # - так не правильно.
        # поясню: Вы  только что создали переменную внутри метода.
        #  фишка в том что python по окончании метода
        #  забывает напроч обо всех созданных внутри него переменных. так-то.
        self.table = TableWidget()  # - так правильно. + мы сможем к нему обращятся.
        self.addWidget(кнопка, 0, 0)
        self.addWidget(self.table, 1, 0)

экземпляр_класса_HBox4 = HBox4()

# сам QGridLayout отображатся не умеет вне виджета
#  я создам для него виджет.
widget = QWidget()
widget.setLayout(экземпляр_класса_HBox4)
widget.show()       # пуф!..

# да мы забыли связать события нажатия на кнопку и наш метод:
кнопка.pressed.connect(всё_что_будет_происходить_при_нажатии_на_кнопку)




#В принципе на этом можно было бы и остановится,
#  но в идеале было бы пользоватся сигналами и слотами:
#  они вам понадобятся позже когда вы начнёте вызывать методы одновременно
#  или например из потоков.
class TableWidget(QTableWidget):
    my_signal_update = pyqtSignal(list) # придумываем сигнал my_signal_update
    # (в качесте параметров он принимать будет list (там могло быть что угодно: int, str)

    def __init__(self, parent=None, data=[]):
        super(TableWidget, self).__init__(parent)
        self.update()
        self.my_signal_update.connect(self.update) # добавлено

    def my_slot_update(self, data):     # добавлено
        print(data, flush=True)         # добавлено
        self.update()                   # добавлено

    # ну а дальше без изменений.
    def update(self, data=[]):
        self.setColumnCount(1)
        self.setRowCount(len(data))
        for i, entry in enumerate(data, start=1):
            self.setRowCount(i)
            item = QTableWidgetItem()
            item.setText(str(entry))
            self.setItem(i-1, 0, item)

def всё_что_будет_происходить_при_нажатии_на_кнопку():
    fileName = QFileDialog.getOpenFileName \
        (кнопка, 'Пример с сигналом и слотом', 'd:\\', "Текст (*.txt)")[0]
    f = open(fileName, 'r',  encoding="utf8")
    data = []
    with f as f:
        for i in f.readlines():
            data.append(i)
    table.my_signal_update.emit(data)  # мы просто НЕ напрямую вызываем нужный нам метод...

кнопка.pressed.connect(всё_что_будет_происходить_при_нажатии_на_кнопку)

table = TableWidget()
экземпляр_класса_HBox4.addWidget(table, 2, 0)




# ну и последний кусочек для минимальнно рабочего приложения на pyqt
app.exec_() # без этого ничего не запустится...
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы